Git: Interactively rebase a range of commits

24.5k Views Asked by At

I'm trying to rebase -i a few commits that occurred a while back in my history. Say I have a log like this:

* 5e32fb0 (HEAD -> master) Add latest feature
* 106c31a Add new feature
* 2bdac33 Add great feature
...100 other commits...
* 64bd9e7 Add test 3
* 3e1066e Add test 2
* 26c612d Add test 1
* 694bdda Initialize repo

and I want to squash the 3 test commits. In these circumstances, git rebase -i HEAD~106 isn't very practical. What I'm looking for instead is something like git rebase -i 64bd9e7:26c612d.

Does git have this sort of behaviour, and if so, how can I use it?

I had a look at this post, but it didn't answer my question.

3

There are 3 best solutions below

0
On BEST ANSWER

In order to squash those three commits, you'll need to re-write history for the entire repository. That is, all the commit hashes for commits after those test commits will be modified. The most straight-forward way to do it, in my opinion, is to:

  1. Create a temporary branch and checkout pointing at 64bd9e7.
  2. Squash the three commits together.
  3. Checkout your main branch, and reset it to the commit immediately after 64bd9e7.
  4. Rebase it onto your temporary branch
0
On

Just use rebase -i and squash only those commits.

git rebase -i <main_branch>
# Now just add `s` in front of all the commits you want to squash

If you have many commits, I'd suggest you to take a look at rebase --onto -

git rebase --onto <final_base_commit> <initial_base_commit> <head>

git rebase --onto 694bdda 64bd9e7 5e32fb0

Note: Rewriting history is an advanced operation, so tread with care.

Git rebase tutorial

0
On

You say "git rebase -i HEAD~106 isn't very practical".

If you mean that the resultant script file is >100 lines long, it's not great, but it'll work.

If you mean that it's tedious to count back, to work out that you need the 106 commits - as sometimes happens to me, then there is a solution.

You need the hash of the parent of the earliest commit you want, then you can do:

git rebase -i <parent-hash> my-branch

Or you can do

git rebase -i <parent-hash> HEAD

which afterwards will leave you on a detached head that you can do what you want with.

So in your example, you could have done

git rebase -i 694bdda HEAD

(But I would still agree with the other comments, about whether you really want to be changing things that far back. I think it's a bit of a code smell, when I find myself doing it. It's unusual for me to have such a long branch without pushing/sharing it. I'd make a backup branch to test it on, too.)