- Published on
#TIL: Using git rebase to combine commits
I normally use git rebase
with --fixup
commits, and haven't had a need [until now] to take a bunch of commits made at different times and combine them.
Where possible, I prefer commits on the main
branch to represent some "unit" of work1, to prevent a bunch of commits where you might be going back and forth on something from cluttering up the history2.
The PRs3 I submit day-to-day are normally isolated features that make this easy to accomplish. I use rebase
a lot within a branch for myself before submitting a PR, but the extent is normally:
$ git add -p # add the specific thing I want to revise
$ git commit --fixup <hash> # mark this as a fixup
$ git rebase -i --autosquash <hash>~1 # go to 1 commit _before_ the commit to be fixed
However, in building this blog there's been a few times where I added bits of things at different times, 20+ commits apart, and (for whatever reason4) didn't realize I wanted them all combined at the time of committing.
Specifically, I wanted to combine some commits to know "here's everything I did to get <specific feature>
working".
Fortunately, git rebase
makes this easy and includes helpful instructions in the rebase message:
These lines can be re-ordered; they are executed from top to bottom.
It's clearly laid out if you follow along on the git docs and is as simple as re-ordering the lines so that the commits to be combined are together, and marking them as squash
.
For example, given a repo where these are all the commits:
$ git log --oneline
60d10b7 (HEAD -> example) finally figured out A
e68f105 did something for C
f8b495c hack related to A
2ce4970 did something for B
240ffc7 did something for A
ff37364 initial
Using git rebase -i 240ffc7~1
will show you:
pick 240ffc7 did something for A
pick 2ce4970 did something for B
pick f8b495c hack related to A
pick e68f105 did something for C
pick 60d10b7 finally figured out A
# Rebase ff37364..60d10b7 onto ff37364 (5 commands)
If you want to combine everything related to A
(the 3 lines above), you can just reorder them like below and mark the two commits to be merged as squash
:
pick 240ffc7 did something for A
squash f8b495c hack related to A
squash 60d10b7 finally figured out A
pick 2ce4970 did something for B
pick e68f105 did something for C
# Rebase ff37364..60d10b7 onto ff37364 (5 commands)
Then just save and close, and when you're done 5 it will look like:
$ git log --oneline
179c64f (HEAD -> example) did something for C
092aa5f did something for B
79f744b did something for A
ff37364 initial
Footnotes
"Unit" as in, if you're submitting a PR for a new feature, that PR would get "squashed" into 1 commit.
The PR itself should still have multiple commits to make it easy to follow along and review.
It's a personal preference and not everyone likes this. ↩
You can always dig back into the PR to see the back and forth if you really wanted. ↩
PR means "Pull Request" ↩
Probably because lately it's been after 3am when I'm working on this 😅 ↩
assuming you have no merge conflicts 🏆 ↩