Git commit --amend merged two commits

10,682

Solution 1

If you have staged files and do

git commit --amend

You will create a new commit with everything in the previous commit plus everything staged and this new commit will replace the previous commit as the tip of the branch you have checked out.

git commit --amend without any staged files can be used to change commit message but notice that even in the case where you have no staged files you will get a new sha1, in other words a new commit.

From the documentation:

Used to amend the tip of the current branch. Prepare the tree object you would want to replace the latest commit as usual (this includes the usual -i/-o and explicit paths), and the commit log editor is seeded with the commit message from the tip of the current branch. The commit you create replaces the current tip — if it was a merge, it will have the parents of the current tip as parents — so the current top commit is discarded.

Solution 2

This is expected behaviour. From the git commit documentation.

--amend

Replace the tip of the current branch by creating a new commit. The recorded tree is prepared as usual (including the effect of the -i and -o options and explicit pathspec), and the message from the original commit is used as the starting point, instead of an empty message, when no other message is specified from the command line via options such as -m, -F, -c, etc. The new commit has the same parents and author as the current one (the --reset-author option can countermand this).

It is a rough equivalent for:

$ git reset --soft HEAD^
$ ... do something else to come up with the right tree ...
$ git commit -c ORIG_HEAD

but can be used to amend a merge commit.

You should understand the implications of rewriting history if you amend a commit that has already been published. (See the "RECOVERING FROM UPSTREAM REBASE" section in git-rebase[1].)


The important part to understand is git reset --soft HEAD^. This will "remove" the commit from your history but won't change your working tree or index.

Take a look at the documentation of git reset. Emphasis mine.

--soft

Does not touch the index file or the working tree at all (but resets the head to , just like all modes do). This leaves all your changed files "Changes to be committed", as git status would put it.

Solution 3

git commit --amend will add staged changes to the most recent commit. Since it merged your two I would suspect that there was not two commits but one.

The man page explains this:

--amend
    Replace the tip of the current branch by creating a new commit. The
    recorded tree is prepared as usual (including the effect of the -i and
    -o options and explicit pathspec), and the message from the original
    commit is used as the starting point, instead of an empty message, when
    no other message is specified from the command line via options such as
    -m, -F, -c, etc. The new commit has the same parents and author as the
    current one (the --reset-author option can countermand this).

    It is a rough equivalent for:

        $ git reset --soft HEAD^
        $ ... do something else to come up with the right tree ...
        $ git commit -c ORIG_HEAD

    but can be used to amend a merge commit.

    You should understand the implications of rewriting history if you
    amend a commit that has already been published. (See the "RECOVERING
    FROM UPSTREAM REBASE" section in git-rebase[1].)

Because you described working on more than one commit I'll explain how the above describe workflow could have gone instead:

A--B (origin/dev) (dev)

Edit files, and add staging (git add -u) then:

$ git commit # edit a good message (see below)

A--B (origin/dev)
    \
     C (dev)

Now repeat:

$ git commit # edit another awesome message (see below)

A--B (origin/dev)
    \
     C--D (dev)

But now you realize commit C has a bad commit message. So we do a rebase:

$ git rebase -i origin/dev

In the editor you'll see commits C and D with their subject lines and a keyword pick. Find the commit you want to fix and change the pick to reword then save the file.

git will open another editor and let you fix the commit message. Save and continue.

A note about commit messages (because I am trying to spread the word):

https://thoughtbot.com/blog/5-useful-tips-for-a-better-commit-message

Capitalized, short (50 chars or less) summary

More detailed explanatory text, if necessary.  Wrap it to about 72
characters or so.  In some contexts, the first line is treated as the
subject of an email and the rest of the text as the body.  The blank
line separating the summary from the body is critical (unless you omit
the body entirely); tools like rebase can get confused if you run the
two together.

Write your commit message in the imperative: "Fix bug" and not "Fixed bug"
or "Fixes bug."  This convention matches up with commit messages generated
by commands like git merge and git revert.

Further paragraphs come after blank lines.

- Bullet points are okay, too

- Typically a hyphen or asterisk is used for the bullet, followed by a
  single space, with blank lines in between, but conventions vary here

- Use a hanging indent
Share:
10,682
shkschneider
Author by

shkschneider

Open-Source believer Android enthousiast

Updated on June 10, 2022

Comments

  • shkschneider
    shkschneider almost 2 years

    I have a remote 'dev' branch and was working on it locally.

    I made a first commit on 'dev' with a commit message "my_feature", putting my local branch ahead of the remote by 1 commit.

    I then developed some new stuff and made a git add -u, getting ready to commit. I then realized I wanted to rework the previous commit message as "my_feature (1/2)" to make my current commit message as "my_feature (2/2)", putting my local branch ahead of the remote by 2 commits.

    So I made a git commit --amend (thinking it would only edit the previous commit's message), edited the "my_feature" commit message as "my_feature (1/2)" and... ended up with a single commit labelled "my_feature (1/2)" having all my changes (first commit + staging files diffs) -- my index is now clean.

    So if I got it right, my command actually did a commit, also committed the staging files, which produced a single (merged?) commit?

    I was not expecting Git to do such a thing. I just wanted to edit my old commit message, not to merge the old one with my current staging files. (Now that I think about it a rebase could have been better.)

    While I can understand why git commit --amend could commit (even if I only wanted to edit a commit message), I have problems to understand how Git merged my two commits into one with a commit command.

    Anyone could clarify this to me?

    $ git --version
    git version 1.7.10.4