28

Can I squash a range of commits for a local feature/topic branch using rebase that does not include the most recent commit? This is for commits that I want to prepare before they get merged and pushed to a public repo.

I was working quickly and made a bunch of minor changes with poor titles and descriptions that I want to squash into two or three separate logical commits with a great comments. Can I select a range of commits between 329aed9 and af39283 that could be at any point in this feature branch's short history?

git rebase -i RANGE_START_COMMIT_ID RANGE_LAST_COMMIT_ID

Thanks!

Dylan Valade
  • 5,565
  • 6
  • 42
  • 56
  • If you're using vim (which Git does, by default), you can use visual block mode (ctrl-v) to change arbitrarily many picks to squashes at once. – Cascabel Oct 14 '11 at 01:34
  • 4
    Thanks Jefromi. I finally figured out how to pick and squash using vim. For other beginners, run 'git rebase -i mybranch~5' where 5 is the number of most recent commits to handle. If you want a commit to stay as-is then leave its prefix as 'pick'. Otherwise change its line prefix from 'pick' to 'squash' and rebase will condense every 'squash' commit into the first commit labeled 'pick' above it. If you have 10 commits and you leave three as 'pick' and the rest as 'squash' then you'll get a result of three commits total after rebase. I'll post a screenshot showing how this works. – Dylan Valade Oct 14 '11 at 03:16
  • Isn't that almost exactly what the help below the list of commits says? – Cascabel Oct 14 '11 at 04:26
  • 1
    Yes but it's not readily apparent from the help that you can use pick to both leave some commits unchanged while modifying others in a single rebase. At least that was the disconnect for me and hopefully this helps others. – Dylan Valade Oct 14 '11 at 12:42

2 Answers2

12

You could always create a new branch with git checkout -b new_branch af39283, and then rebase that. However, if you want to include the later commits at some future point, there's no getting around rebasing them as well. The SHA1 for a commit depends on all its ancestor commits.

Karl Bielefeldt
  • 47,314
  • 10
  • 60
  • 94
  • Karl, thanks for that tip. I didn't realize it was possible to generate a new branch up to a SHA but I tried it and liked it. If we are talking about creating four different squashes, then with this approach it seems that a new branch would be created for last three squashes. The original feature branch would be rebased as the first squash. Finally, each of the other three "git checkout -b new_branch SHA#" would get merged into the original feature branch to create a glorious perfect branch? – Dylan Valade Oct 13 '11 at 20:30
  • Are you saying your desired end result is one branch with 3 squashed commits followed by your original commit? If that's the case, in the commit list that pops up when you do a `rebase -i`, you just change `pick` to `reword` for each of the first commits of your squashes, choose `squash` for everything else, and leave your untouched commit as `pick`. – Karl Bielefeldt Oct 13 '11 at 22:57
  • 2
    @Karl: You don't need to reword the first commits of squashes; Git automatically lets you edit them and provides the messages of all the squashed commits as a starting point. – Cascabel Oct 14 '11 at 01:31
2

So, it's not entirely clear what you mean by "not including" the most recent commit, but when you do a rebase -i you're able to squash/re-order/reword/fixup/remove prior commits without having to do anything to the last commit. You're rewriting the history underneath it of course, so its diff will be re-applied and it will be a different commit object following the rebase, but since you haven't pushed this publicly (and you're rewriting the rest of it) that shouldn't matter much.

Matt Enright
  • 7,245
  • 4
  • 33
  • 32
  • Thanks for your help. "not including" meant that I wanted to make separate squashes but leave my most recent commit unchanged. The very last commit is good and I would like it to remain independent (not squashed with any others). Then there are groups of about 20 very small commits that can be condensed into a few squashed commits. In the end it's taking about 60 small commits and creating 4 reasonable ones for merging into a public repo. – Dylan Valade Oct 13 '11 at 19:45