29

I have seen 'git commit --amend' in detached HEAD state. The question requires the answer to be more complex than needs be.

I'd like to understand just how git commit --amend works in a normal HEAD situation.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Shaun Luttin
  • 133,272
  • 81
  • 405
  • 467

4 Answers4

49

Assume that you're in a clean working state and that your repository looks as follows:

Enter image description here

If you then run

git commit --amend

write a commit message, save and quit your editor, the following happens:

  1. Your staging area—which, if you haven't staged any new changes, will be identical to commit f42c5—is used to create a new commit: 31b8e. Its parent(s) will be the same as that (those) of the commit you're amending: f42c5.
  2. The master branch reference is moved to point to that new commit (31b8e).
  3. The HEAD reference follows master.

Enter image description here

Note that the amended commit (f42c5) is now unreachable from any reference in your repository (hence its "transparent" style on my graph). It still lives in your repository's object database, but it will eventually be deleted for good, when Git runs its periodic housekeeping, or if you trigger it explicitly by running git gc (garbage collection).


Addendum (based on Jason Baker's comment): Note that, as long as the amended commit, f42c5, still exists in your repository and you have a way of finding out its commit ID (for example, by fishing it out of the master branch's reflog), you can still check it out. Running

git checkout master # just to be sure that master is the current branch
git reset --hard f42c5

or (assuming you haven't, in the meantime, made any new commit on master, reset master, or otherwise moved the master branch reference)

git checkout master # just to be sure that master is the current branch
git reset --hard master@{1}

would put you in the following situation:

Enter image description here

However, commit 31b8e would now be unreachable.


jub0bs
  • 60,866
  • 25
  • 183
  • 186
  • Can you get back to `f42c5` by doing a `checkout`, or by going through the reflog? I admit that it would be a silly thing to do, but I'm curious if the old commit can be accessed *at all* – Jason Baker Sep 26 '14 at 00:59
  • 1
    @JasonBaker Yes, you can always check out the amended (now unreachable) commit, as long as it has hasn't been garbage collected, and you have a way of referring to it. – jub0bs Sep 26 '14 at 01:11
  • 1
    Heh, now the commands are not quite right, `git reset` *always* resets the *current* branch (which means `HEAD` must not be detached, too). Put the `checkout master` first, etc... – torek Sep 26 '14 at 01:19
  • @torek Sh*t... I'll get it eventually... It's too late for this kind of gymnastics, in my time zone `:)` – jub0bs Sep 26 '14 at 01:20
  • Not if you're already on it. It's just to make sure that we know what `reset` is re-setting. – torek Sep 26 '14 at 01:27
  • @torek I'll add it for safety. – jub0bs Sep 26 '14 at 01:27
  • @jub0bs could I said that when something goes wrong with a commit (data corrruption or something) I could use the the --amend parameter to rebase from the previous pointer but including the stage? I'm not sure how normal is that but I had a few of those situations (data corruption) and I fixed them manually because those were personal projects.. [new repo :D] – Karmavil Nov 11 '20 at 09:11
  • I would assume a common use case for amend is that you forgot to include a change or that you included a change too many. Do you do something before the amend to set the staging status to pre-commit status or does git figure out how to combine f4 with the staging status automatically? Since you are working on top of f4 then most of the intended changes are already checked in. – Tormod Jan 18 '22 at 12:13
11

Say you just committed "B"

... --- A --- B
              ^
              |
            master
             HEAD

Amending "B" will create a parallel commit which becomes the new branch head.

        +---- B
        |
... --- A --- B'
              ^
              |
            master
             HEAD

B' is the commit resulting from a combination of the changes from B plus the changes you had staged when you issued the git commit --amend.

ikegami
  • 367,544
  • 15
  • 269
  • 518
  • 2
    To build on this answer, B' will contain the combination of the changes from B, and any staged changes that you have sitting in your repo right now – Jason Baker Sep 26 '14 at 00:47
  • What is meant by *"combination"*, exactly? Perhaps update the answer? – Peter Mortensen Dec 30 '21 at 20:45
  • `B' is the commit resulting from a combination of the changes from B plus the changes you had staged when you issued the git commit --amend. ` is very important for me. Until now I used to use `git commit --amend` only to change commit messages. I didn't know I could use `git commit --amend` to update changes in a commit. – bit Jun 06 '23 at 09:15
  • 1
    @bit Absolutely. In fact, I often use `-C HEAD` (instead of `-m'...'`) to *avoid* changing the message. – ikegami Jun 06 '23 at 17:13
1

According to my knowledge, amend works thus:

For git commit --amend works the changes to amend must be into the stagging area (SA)

  1. It makes git reset -- soft for bring back changes committed in the last commit (commit to amend) to the SA and move the index to previous commit (commit before commit to amend). Everything keep how it was before the git commit command were used.
  2. It makes git add with all files to add to new commit (it will be the amended commit). The files to add are those were into the SA before the git reset --soft was landed, and after reset these files are kept in the working directory (WD), so it is necessary add them to the SA for generate the amended commit.
  3. It makes a Git commit. It will generate a new commit and hence a new id for the amended commit. For this, git commit --amend should not be used with pushed commits.

If you use --no-edit the comment is reused in the amended commit, else you must introduce a new comment (because it is a new commit and every commit needs a comment).

For more information about the staging area and working directory, see Reset Demystified.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
TomasMolina
  • 581
  • 5
  • 13
-1

Suppose you create two files test1.txt and test2.txt then you you run

git add test1.txt && git commit -m “test1.txt and test2.txt “

later you remember you did not add test2.txt So you want to add the missing test2.txt file and modify the previous commit git add test2.txt

git commit --amend -m "test1.txt & test2.txt added"

git log [to see that the previous commit message updated and test2.txt file added]
Nazmul Haque
  • 720
  • 8
  • 13