I understand that the correct way of amending an old Git commit is to use rebase --interactive
, but just to get clear on the concepts, I would like to understand what happens when I do
git checkout <commit>
git commit . --amend
When I do this, instead of amending the commit, it branches a new commit off of the PARENT of that same commit.
Is this just Git's way of telling me that I cannot amend a commit that already has children commits?
In Git, once a commit is created, it's set in stone; you cannot change it. All you can do—by amending it, cherry-picking it, etc.—is create a new commit that "resembles" it.
I understand your confusion: "amend" is a bit of a misnomer; it's somewhat misleading, as it suggests modifying something in place. In Git, amending a commit actually consists in creating a brand new commit that has the same parent(s) as the original commit.
As an example, let's assume that, after running git checkout B
, you're in the following situation:
(Your HEAD
is detached, but that's beside the point.) Whether or not you make and stage changes, running git commit --amend
will put you in this situation:
Commit D
may be very, very similar to B
; in particular, it may have exactly the same patch, exactly the same commit message as B
, etc.. However, (commit, author) timestamps will usually differ (unless you can amend a commit under a second!), which means the SHA-1 of D
will differ from that of B
; and if two commits don't have the same SHA, they're not the same commit.
When we say B
is a parent commit of C
, we mean commit C
references commit B
by its SHA.
However, commit C
has no way of knowing anything about the SHA of commit D
, because commit D
was created after C
. Therefore, D
cannot be C
's parent. That's why commit D
goes off on a tangent and doesn't have any descendants.
If you want to land in the following state,
where B'
is even only slightly different from B
, you should use git rebase -i
, not git commit --amend
.