Sometimes I squash a bunch of commits together. Usually my commands follow this pattern:
git reset --hard HEAD~4
git merge --squash HEAD@{1}
git commit
Today, though, at step 2, I got distracted by something (squirrel? Slack? Facebook?) and I forgot to end the git merge --squash
command with HEAD@{1}
. Yet it magically did what I wanted.
I can't find any documentation that omitting the target of the merge will default to HEAD@{1}
, but it was nice that it worked out.
Is there documentation on this somewhere?
I see the following from git help merge
, but it doesn't seem to answer the question:
--squash, --no-squash
Produce the working tree and index state as if a real merge happened (except for the merge information), but do not actually make a commit, move the HEAD, or record $GIT_DIR/MERGE_HEAD (to cause the next git commit command to create a merge commit). This
allows you to create a single commit on top of the current branch whose effect is the same as merging another branch (or more in case of an octopus).
With --no-squash perform the merge and commit the result. This option can be used to override --squash.
With --squash, --commit is not allowed, and will fail.
Running:
git merge
(with no options and no arguments) "means":
git merge @{upstream}
Adding options, such as --squash
, does not change this, so:
git merge --squash
is a synonym for:
git merge --squash @{upstream}
The @{upstream}
syntax means locate the commit pointed-to by the upstream of the current branch. The upstream of master
is pretty typically origin/master
. The upstream of dev
is pretty typically origin/dev
. This pattern repeats. The actual upstream can be found with git rev-parse
:
git rev-parse --symbolic-full-name @{upstream}
which for instance in my Git clone of the Git repository for Git produces:
$ git rev-parse --symbolic-full-name @{u}
refs/remotes/origin/master
i.e., I'm on master
and its upstream is origin/master
. (This particular clone is primarily a reference clone for me, so I just keep its master in sync with the other various duplicates of the Git repository for Git. @{u}
is a shorter way to write @{upstream}
: less mnemonic, but easier to type in.) Whatever commit @{u}
meant, that's the one that Git squash-merged with.
As jthill noted in a comment, you should consider git reset --soft
for your particular goal. The soft reset moves the current branch, without touching the index and working tree, which avoids doing the work that git merge --squash
would have to perform. The resulting index-and-work-tree will be the same either way, and since --squash
does not create .git/MERGE_HEAD
(and does imply --no-commit
) the final git commit
will behave the same way as well.