Reputation: 1195
I have already pushed a commit on the remote branch and now I want to change its content, so I tried git amend
.
If do git status
it says that the two branches have 1 and 1 different commits each, respectively.
Now if I push the amended commit with the same commit message, will that add a new commit or it will change the last commit I have pushed?
Upvotes: 9
Views: 6860
Reputation: 59923
Pushing an amended commit means pushing a different commit.
The unique ID of a commit is made up of the SHA-1 hash of its metadata. Which metadata? One of the ways to find out is by using the cat-file
plumbing command:
git cat-file -p HEAD
After you run this command you'll see a list containing these fields:
If any of these fields change, their SHA-1 hash is also going to change granting the commit a whole new ID.
That's why if you amend a commit – for example by changing its message – it's going to have a different ID than it had previously. You're effectively rewriting history.
Note that the ID of the commit's parent is also included in the metadata. This means that once a commit changes ID, all of its descendants are also going to change IDs like a domino effect.
Upvotes: 2
Reputation: 387825
git commit --amend
, just like git rebase
, will create a new commit object. That object is based on a previously existing commit but it is still a new commit and replaces the old one completely.
Looking at the history, this could look like this:
master
↓
* --- * --- * --- A
Considering that A
is the original commit. If we now amend this commit, then we get the following result:
* --- * --- * --- A
\
--- A'
↑
master
So we get a different commit object A'
, with a different hash, and the branch we were on (here: master) is updated to point to this one.
Now, if we add a remote repository to that view, and we pushed A
previously to the remote, then it looks like this:
origin/master
↓
* --- * --- * --- A
\
--- A'
↑
master
So the remote still points at the original commit A
, but our local branch points at the modified A'
. This is a problem because we cannot push A'
and make origin/master
point at A'
as this would remove the already pushed commit A
from the history.
We can perform a forced push using git push --force
to force Git to update the remote branch and indeed delete A
from the history. It is important to note though that this will break everyone’s history who already fetched A
from the remote. If some other developer has A
and now the remote points at A'
, then they have a conflict which they have to fix manually. This is often a pain to do, so there is a rule you should follow at all times:
Never rebase (or amend) previously published commits.
The better alternative is to add a new commit B
which simply does the fixes to A
:
origin/master
↓
* --- * --- * --- A --- B
↑
master
That way, the already published history is still compatible with the new history, so we can push B
to the remote without conflicts, and everyone is happy.
Upvotes: 15
Reputation: 9042
Once you have pushed to the remote you should not amend any existing commits locally.
You've essentially created a new commit locally (there is a new commit ID) and replaced the old one but the old one still exists on the remote. This causes the 1 ahead and 1 behind message you see.
To resolve you'll need to create a new branch to keep your amendments, check back out the initial branch, reset back to before you made the amendment, pull down the change from the remote. Then merge in your separate branch and push back up.
Upvotes: 1