Originally, I thought git cherry-pick does a diff on its parent, produces a patch file and then applies that patch onto your HEAD, which I think is far more interesting and unique and I haven't seen in a git command that does this yet. Such a command could be useful if you have simple fixes like you want two branches to produce the same log output but you only fixed it on one branch and you want to cherry-pick
that ONE line change and apply it to your other branch so that you can now compare results. But if it is just bringing in the entire object onto your HEAD, then I don't see the point.
So my question is, what use case would I use cherry-pick for? Because it seems like its only for commit history management (i.e., not merging in all the parent commits of the cherry-picked commit into the current HEAD).
CodePudding user response:
Your description of what you thought git cherry-pick
does is close enough to what it actually does to serve as the initial description. (Your proposed use case is thus the main use case.) All we need to do to make it completely accurate is:
- Note that Git's internal implementation uses Git's merge engine, so that you will sometimes see a "merge conflict". In this case, the cherry-pick operation stops in the middle, requiring that you resolve the conflict and use
--continue
to finish it. - Note that you may cherry-pick more than one commit at a time: in this case Git does each selected commit, one at a time, as in note 1, and then moves on to the next commit.
- Note that with without
-n
, each cherry-pick step (a) requires that the working tree and index be "clean" (match the current commit, more or less) at the beginning, and each commit being copied will have its commit message copied as well, into a new commit, resulting again in this clean state; but with-n
, the initial setup need not be "fully clean" and the operation will not make a new commit on its own.1 - Note that this all uses—at least potentially—the sequencer (to do multiple commits), as do
git revert
and moderngit rebase
, and the sequencer can only do one thing at a time, so if you're in the middle of a revert or rebase, some use cases are limited.
As a side note regarding the comments, the term object, in Git, refers to Git's internal object storage. There are four object types: blobs, trees, commits, and annotated tags. A blob object stores any unique file contents (but not a file's name, nor its x vs -x chmod
state) and this is how Git de-duplicates files whose content is shared between, or even within, any given set of commits. A tree object stores the file name and mode information, a commit object stores the commit metadata (including the hash ID of the tree object that saves the snapshot), and a tag object stores annotated tag data for use by git tag -a
and company. If we ignore the special case of annotated tags, commits need just the remaining three objects: one to store the commit itself, one or more to store tree data, and zero or more to store the file-contents that are stored as the commit's snapshot.
Cherry-picking views the commit as a whole, and compares parent P
vs child C
to see what changed in the given pair of commits. In order to apply those changes to the current (HEAD) commit, it then compares P
vs HEAD
as well, which is why and how it ends up using the merge engine. (For -n
style cherry-picks, it uses the current index rather than the HEAD
commit. Since non--n
cherry-picks require that HEAD
and index match, it can actually just always use the index.)
1There's no proper, strict definition of clean, and the actual implementation tends to be ad-hoc: any command that requires a "clean state" does its own checking and hence determines what it means, for that particular command, to be "clean". However, there is a require_clean_work_tree
function in git-sh-setup
, and this provides a very good starting point for a proper definition. Note how submodules tend to be ignored here, which may not always be appropriate.
CodePudding user response:
It's actually incredibly useful to be able to "copy" a commit from one branch to another, without having to do a merge, and without having to manually redo all the edits.
For instance, in your use case, imagine that it's not a one line log output, but an important bug fix you made on the development branch. Now you want this fix backported to your release branch, for a patch release, but you obviously don't want to merge the development branch to the release branch, because there has been a lot of stuff committed there since the release. What do you do? You git cherry-pick
.