4

I'm trying to squash last 3 commits using autosquash options provided by git-rebase. I have the following history:

* commit 78a7e4844fa32d2ef1bb7bd9b44c4a1b9551d31a (HEAD, new)
| Author: maxim koretskyi <mkoretskyi@company.com>
| Date:   Fri Feb 20 10:29:48 2015 +0200
|
|     squash! s3
|
* commit f25491cadc646baf14bd7e951245c6777230a1d7
| Author: maxim koretskyi <mkoretskyi@company.com>
| Date:   Fri Feb 20 10:29:42 2015 +0200
|
|     squash! s2
|
* commit b988237356ffb59752e49049d083c558373f9486
| Author: maxim koretskyi <mkoretskyi@company.com>
| Date:   Fri Feb 20 10:29:24 2015 +0200
|
|     squash! s1
|
* commit abbcdc833e5eaabe79681bd82087b4d7969e8599 (new1, ne, 9484)
| Author: maxim koretskyi <mkoretskyi@company.com>
| Date:   Wed Feb 18 18:21:58 2015 +0200
|
|     3

So I want commits with messages s1, s2 and s3 prefixed with squash! to be squashed. Now I issue the following command:

$ git rebase -i abbcdc833 --autosquash

And so git opens a text editor with the following content:

pick b988237 squash! s1
pick f25491c squash! s2
pick 78a7e48 squash! s3

But I expected it to be like this:

pick b988237 squash! s1
squash f25491c squash! s2
squash 78a7e48 squash! s3

What am I doing wrong?

Max Koretskyi
  • 101,079
  • 60
  • 333
  • 488
  • 2
    Make sure to use Git 2.20+ (Q4 2018) when doing a `rebase --autostash`: https://stackoverflow.com/a/52504818/6309 – VonC Sep 25 '18 at 18:55

1 Answers1

15

From the documentation, but emphasis mine:

When the commit log message begins with "squash! ..." (or "fixup! ..."), and there is a commit whose title begins with the same ..., automatically modify the todo list of rebase -i so that the commit marked for squashing comes right after the commit to be modified, and change the action of the moved commit from pick to squash (or fixup). Ignores subsequent "fixup! " or "squash! " after the first, in case you referred to an earlier fixup/squash with git commit --fixup/--squash.

Your first squash! has s3 as its ... portion. So, rebase looks for a commit that has s3 as its "title" (this is never defined in the documentation, but it appears to mean "one-line description", i.e., the first line of the log message). There are no such commits in the list.

Moving on to the second, we find the same problem, and likewise with the third.

If your first commit (with title s1) were followed by a commit whose title was squash! s1, that particular one would get a "squash" word.

(Note that git commit --fixup=<id> or git commit --squash=<id> will create this kind of "same title" commit for you. The "ignores subsequent" stuff is because you can do this while working:

git add ...; git commit -m thing1
... edit ...
git add ...; git commit -m thing2
# now fix thing1 bug noticed while working on thing2
... edit ...
git add ...; git commit --no-edit --fixup=HEAD^
... edit/test some more, discover fixup was not complete
git add ...; git commit --no-edit --fixup=HEAD

In this case, the second fixup's line is fixup! fixup! thing1; rebase just looks for a commit whose "title" is thing1, again.)

torek
  • 448,244
  • 59
  • 642
  • 775
  • thanks a lot! You're of great help to me on my way to learning Git :). I've tried with equal message and it did the trick. The interesting thing is that after I rebase commits after `abbcd` the `squash` doesn't work. Any idea why it that? – Max Koretskyi Feb 20 '15 at 10:26
  • there is also a mentioning of the `rebase.autosquash` option with the exlanation: `If set to true enable --autosquash option by default.`. Does it mean that if this option is `true` I don't need to specify `--autosquash` with `git rebase` and git will automatically look for commits with `squash!`? – Max Koretskyi Feb 20 '15 at 10:31
  • For the topic to match and autosquash to do its thing, the one-line text must be in the set of commands that `rebase -i` is going to execute. Think of it this way: `rebase -i` first makes a complete list of nothing but `pick` commands. Then, if autosquash is on, the rebase script looks for lines that have `squash!` and `fixup!` right after the commit-ID part. It takes those lines and treats them as "instructions for modifying another pick line". If there isn't a pick line to modify, the instructions are left alone; if there *is* a pick line to modify, the instructions are followed. – torek Feb 20 '15 at 17:31
  • 1
    And, yes, `rebase.autosquash = true` means that `--autosquash` is done automatically (`rebase` has a `--no-autosquash` option to turn it off manually for one rebase, if needed, or of course you can change your configuration options). – torek Feb 20 '15 at 17:33
  • In my experience, it's simpler to just use 'git reset ' and then [git commit --amend](https://www.atlassian.com/git/tutorials/rewriting-history). Just be sure to avoid using using 'git reset --hard' in that case! For example, if you have 4 commits on a feature branch, and you want the last 3 'squashed' into the first one, you can use 'git reset <1st commit>', then use 'git commit --amend ...' (see git docs for complete usage). – Andy Alt Feb 09 '22 at 22:39
  • @ArchStanton: I don't use this mode much myself, I'm just describing how it's intended to be used. I tried it out a few times and decided it wasn't for me... – torek Feb 10 '22 at 00:03