|
| 1 | +--- |
| 2 | +title: Retroactive Commits |
| 3 | +tags: |
| 4 | + - git |
| 5 | +url: git-retroactive-commits |
| 6 | +--- |
| 7 | +Imagine that you're working on a project you want to publish or share with others. You look at your commit history and realize you squashed commits a little too much. There are commits combining multiple unrelated changes, and you wish you could go back in time and break them down properly. |
| 8 | + |
| 9 | +Thankfully, Git allows you to do this. While it’s not exactly a quick task, using **interactive rebase** makes it possible to split old commits while preserving history, authorship, and dates — and avoids the risks and pitfalls of orphan branches or force-rebuilding your repo from scratch. |
| 10 | +## The Process |
| 11 | +>[!warning] Backup! |
| 12 | +>Before making history changes, make a backup branch or clone the repo. If anything goes wrong, you’ll be glad you did. |
| 13 | +
|
| 14 | +1. Figure out how far back you want to start adding retroactive commits in the past. Use `git log` and identify the **parent commit** of the one you want to start making commits from. For example, in the log below we want to start making commits from `d22135`, so we'd choose it's parent, `d22135^` |
| 15 | + ```log |
| 16 | + commit 514f026d7895f38e8526d255444169bcdef8aed2 (HEAD -> main, origin/main, origin/HEAD) |
| 17 | + |
| 18 | + Date: Fri Apr 25 08:28:00 2025 +0930 |
| 19 | + |
| 20 | + style(quartz): set code indent tab-size to 2 and change margins on images after a paragraph |
| 21 | + |
| 22 | + . |
| 23 | + . |
| 24 | + . |
| 25 | + |
| 26 | + commit d22135af0b6f4bb89e0fd9c21e44a2f3f6bb82d3 |
| 27 | + |
| 28 | + Date: Tue Apr 8 16:41:00 2025 +0930 |
| 29 | + |
| 30 | + docs(springboot): add note on java springboot project layout |
| 31 | + ``` |
| 32 | +2. Start an interactive rebase using the parent commit: |
| 33 | + ```sh |
| 34 | + git rebase -i d22135^ |
| 35 | + ``` |
| 36 | +3. In the editor that opens, find the commits you want to split into multiple and change `pick` to `edit` for those lines. For example: |
| 37 | + ```log |
| 38 | + edit d22135a docs(springboot): add note on java springboot project layout |
| 39 | + pick 162d6aa docs(licensing): add initial notes on software licensing |
| 40 | + edit 791c39d docs: add lots of notes in one big commit |
| 41 | + pick 514f026 style(quartz): set code indent tab-size to 2 and change margins on images after a paragraph |
| 42 | + ``` |
| 43 | +4. When editing each commit, unstage everything in the commit (this keeps the changes in your working directory so you can manually commit each one): |
| 44 | + ```sh |
| 45 | + git reset HEAD~ |
| 46 | + ``` |
| 47 | +5. Create smaller commits manually, making sure to manually specify the commit date to be somewhat consistent with the original commit you're splitting up. |
| 48 | + |
| 49 | + Note the use of both `GIT_COMMITTER_DATE` and `--date`. Both are required if you want remote repositories like GitHub to show the correct commit dates in the repository: |
| 50 | + ```sh |
| 51 | + git add some-file |
| 52 | + GIT_COMMITTER_DATE="Fri, Apr 25 08:28:00 2025 +0930" git commit --date="Fri, Apr 25 08:28:00 2025 +0930" -m "feat: a more specific commit" |
| 53 | + |
| 54 | + git add another-file |
| 55 | + GIT_COMMITTER_DATE="Fri, Apr 25 08:47:00 2025 +0930" git commit --date="Fri, Apr 25 08:47:00 2025 +0930" -m "feat: another more specific commit" |
| 56 | + ``` |
| 57 | +6. Continue the rebase until finished: |
| 58 | + ```sh |
| 59 | + git rebase --continue |
| 60 | + ``` |
| 61 | +7. Once you're done, force push the updated history: |
| 62 | + ```sh |
| 63 | + git push --force-with-lease |
| 64 | + ``` |
0 commit comments