Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

git commit --amend in detached HEAD state

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>
  • change something in a file
  • add the changed file to the index
  • and then 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?

like image 931
Chris Avatar asked Sep 20 '14 11:09

Chris


1 Answers

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:

enter image description here

(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:

enter image description here

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,

enter image description here

where B' is even only slightly different from B, you should use git rebase -i, not git commit --amend.

like image 122
jub0bs Avatar answered Oct 07 '22 21:10

jub0bs