How does commit amending help you switch branches in Git?

Viewed 49

I am reading the Git book, and it has a curious aside about commit amending:

However, before you [change branches], note that if your working directory or staging area has uncommitted changes that conflict with the branch you’re checking out, Git won’t let you switch branches. It’s best to have a clean working state when you switch branches. There are ways to get around this (namely, stashing and commit amending) that we’ll cover later on

https://git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging

I understand how stashing could help since you basically store your uncommitted changes in a stash so that you can reapply them later, leaving your working/staging locations without any uncommitted changes. But I don't really see how commit amending could be used to help in such a situation. Any ideas?

2 Answers

As they say there, "that we’ll cover later on". :-) The key is that you can go ahead and commit right now, making a permanent,1 unchangeable copy of your temporary work state. You might start with this:

...--o--o   <-- master
      \
       o--o--o   <-- feature

and you're in the middle of working on the next commit for feature. It's not really ready yet, but you have to fix something elsewhere (in master or some other branch). So if you git add everything and git commit you get a new, permanent-but-you-want-it-to-be-temporary commit:

...--o--o   <-- master
      \
       o--o--o--●   <-- feature

Later, you come back to branch feature, which has this bad (solid black circle) commit. Now you finish the work for the commit you intended to make, and you use git commit --amend.

What git commit --amend does is to make the new commit as usual, except instead of adding it to the tip of the branch, it shoves the current commit aside:

...--o--o   <-- master
      \
       o--o--o--o   <-- feature
              \
               ●   [abandoned]

This now-abandoned commit, which is still as permanent and unchangeable as any Git commit, is no longer findable. If you look for commits starting from feature and working backwards (leftwards), you won't see it. If you look for commits starting from master and working backwards, you won't see it. The only way you can find it is to use Git's reflogs, which hang on to these abandoned commits for a while—at least 30 days, by default.

Eventually, the reflog entry or entries that are keeping commit ● around expire. At this point, the commit is unprotected from the ravaging hyenas of git gc: they will eventually find and dismember the commit, consuming it bones and all, and it will seem never to have been after all.


1As permanent as anything is in Git, that is: Git will try hard to remember it, but once there is no way to find it, such commits are collected up as garbage and thrown out. Mercurial is a bit different: permanent commits are totally and completely permanent, just like in Git, until you run hg strip, which removes them and all their descendants.

Using git amend changes your existing commit to a different one because the message is different. Then you are essentially on the same branch, and you can commit your uncommitted changes. If you want to go back to your other branch, you can still issue a 'checkout' command to get there, that doesn't contain your uncommitted changes.

I should add that if you are amending you really need to keep track of the commit hashes so you don't get lost. Using a real (eg. feature) branch, or stashing is more a standard way of doing it. I would think that amend is really meant for it's name.. to amend the commit message, not to play around with hashes.

Related