Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What difference does `.git/CHERRY_PICK_HEAD` make when committing?

NB: This is a rewording of an earlier post of mine (now deleted). The rewording intends to give the post a different focus.


Upon running git cherry-pick, git reported that there was a conflict. I resolved the conflict, and then ran git cherry-pick --continue. At this point, $GIT_EDITOR popped up a COMMIT_EDITMSG buffer pre-populated with the cherry-picked commit's original message along with some additional info, which included the warning:

# It looks like you may be committing a cherry-pick.
# If this is not correct, please remove the file
#   .git/CHERRY_PICK_HEAD
# and try again.

I checked to see what happened if I "deleted" (actually, just temporarily renamed) the .git/CHERRY_PICK_HEAD file. The immediate outward effect this had was to remove the |CHERRY-PICKING indication from my git-aware prompt.

Other than this change in my prompt, and possibly some differences in the pre-populated information in the COMMIT_EDITMSG buffer, what difference would it make to perform the commit with or without the .git/CHERRY_PICK_HEAD file in place?


To be more precise, I'm trying to compare two scenarios here.

In the first scenario, I run

% git cherry-pick --continue

...and (disregarding the warning quoted earlier) I proceed with the commit as usual.

In the second scenario, I run

% rm .git/CHERRY_PICK_HEAD
% git commit

...and proceed with the commit as usual.

(Assume that I use the same commit message in both scenarios.)

How would the end results of these two scenarios differ?

like image 913
kjo Avatar asked Feb 07 '17 12:02

kjo


People also ask

Does git cherry pick Create a new commit?

Examples of git cherry pick The --no-commit option will execute the cherry pick but instead of making a new commit it will move the contents of the target commit into the working directory of the current branch.

How do you commit cherry pick changes?

To change the commit message when cherry-picking, use “git cherry-pick” with the “-e” option. As illustrated in this example, your default editor will open and it will let you change the commit message. When you are satisfied with the edits, save your file and your commit message should be saved successfully.

What does it mean by cherry pick?

to choose only the best or most suitable from a group of people or things: They cherry-picked the most promising potential customers and concentrated their efforts on them.


1 Answers

The answer depends on what you were doing. Using --continue finishes the sequence—but if the sequence was just the one cherry-pick, there wasn't really a sequence anyway.

Either way, however, removing the .git/CHERRY_PICK_HEAD definitely has one additional significant effect: finishing a conflicted cherry-pick re-uses the original commit's author-name-email-and-date information. You are always the committer of any new commit, but all commits have not just one person-and-timestamp: each new commit has two entries, one for "committer" (you, making the commit, just now) and one for "author" (whoever wrote the original commit, and whenever they did that). Cherry-pick preserves the authorship information from the original commit.

The sequencer

Both git cherry-pick and git revert—which are actually the same command internally; revert just "works backwards"—use what Git calls the sequencer. That is, you can pick multiple commits all at once:

git cherry-pick notthis..that thistoo

to cherry pick all commits "after" notthis, up through and including that, and also the one specific commit thistoo. You might, for instance, decide to cherry-pick every commit on feature/X that grows from develop, plus one bug fix commit fix-1234, for testing purposes:

git checkout master
git checkout -b testbranch
git cherry-pick develop..feature/X fix-1234

Anyway, the point here is that this might cherry-pick a dozen or more commits, and somewhere along the way there could be a merge conflict, that requires that git cherry-pick stop and get assistance.

Aside: the model here—the Unix/Linux command line—is that you enter a command into a command-interpreter called a shell. The shell passes control of the human-interface to the new command, which retains it until the command finishes and exits. Once the command exits, there is no trace left of the command itself: anything permanent must be saved in files.

So: If cherry-pick must stop, how will it know where to resume? The answer is by saving information in files. If you're cherry-picking a single commit, Git saves just the CHERRY_PICK_HEAD file, which records the ID of the commit being cherry-picked. If you're cherry-picking multiple commits, though, Git saves the conflicted commit as for a single commit, and saves the remaining information in a sequencing directory (whose location has moved some over time).

Running git cherry-pick --continue directs the (new, separate instance of) cherry pick command to pick up where the previous one left off. Git will first run a git commit for you, then locate the sequencing information and finish as much of the sequence as it can, stopping again at the next conflict, or finishing all the cherry-picks.

Running git commit instead, Git will notice the CHERRY_PICK_HEAD file and use that as you have seen. When the commit finishes, that command exits and does nothing with the sequencer. If there is sequencer data left behind, you can now git cherry-pick --continue: Git will notice that the commit is already done and simply continue / finish the sequencer operation.

Note that you can, instead of finishing the operation, use git cherry-pick --abort. This terminates the operation and puts things back to the way they were before you started. As of Git 2.19, you can instead use git cherry-pick --quit to stop (a la --abort) but not put things back to how they were before you started. That is, it stops any future cherry-picking operations, without undoing the ones you have done so far. (This operation was missing before 2.19.)

The git status command now notices if there is a sequence in progress, and reports that you are in the middle of whatever it is you were doing. (This is a big improvement from the Git 1.7 era, when it didn't.)

like image 124
torek Avatar answered Oct 05 '22 08:10

torek