0

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).

LeanMan
  • 474
  • 1
  • 4
  • 18
  • This reads like a rant - can you delete the opinion based paragraph around focus of development and cut it down to the actual question; which is “what does cherry pick do?”. – Boris the Spider Oct 23 '21 at 06:54
  • 1
    This might work, can you check it now. – LeanMan Oct 23 '21 at 06:56
  • I guess another thing I didn't think of when I was writing this is that cherry-pick probably only applies the objects saved at that commit, so objects created in other commits probably don't get applied to HEAD which I guess is the way git would do it if it was going to. I'll test that out. (I've been testing this feature out but only on a single file so that is probably why its not making sense). – LeanMan Oct 23 '21 at 06:59
  • @LeanMan You keep using "objects" in a non-git meaning here, and it's a bit confusing since git objects (blobs, trees, commits, tags) are a thing, and you're talking about something else (files? code blocks? I'm still unsure) – Romain Valeri Oct 23 '21 at 08:11
  • Aren't objects the blobs (that is the file)? I guess I forgot. I'm talking about the immutable file that is saved with the name changed to its hash in the .git/ folder. You're probably right but I'm trying to point out the file blob. – LeanMan Oct 23 '21 at 08:21
  • 3
    Your description of what you thought cherry pick does sounds right to me. The [description in the manual](https://git-scm.com/docs/git-cherry-pick) is: "Given one or more existing commits, apply the change each one introduces, recording a new commit for each." Perhaps rather than this slightly vague question, you could explain the test you did, and ask why it didn't have the result you expected? – IMSoP Oct 23 '21 at 08:54
  • Do you think there is no use case for `git rebase`? In order to be consistent, you must think that, because `git rebase` _is_ `git cherry-pick`. – matt Oct 23 '21 at 22:08
  • I did not say there is no use case for git rebase. Please reread the question. Clearly asks what is the use case. – LeanMan Oct 25 '21 at 02:59

3 Answers3

3

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.

jingx
  • 3,698
  • 3
  • 24
  • 40
  • In that example (with some foresight) it would be better to commit the fix to the release branch and then propagate that change by merging the release branch into the development branch. – Guildenstern Apr 01 '23 at 21:04
2

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:

  1. 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.
  2. 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.
  3. 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
  4. Note that this all uses—at least potentially—the sequencer (to do multiple commits), as do git revert and modern git 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.

torek
  • 448,244
  • 59
  • 642
  • 775
0

cherry-pick is something I never use for permanent development history. Well, I have in fact used it one or two times in the last few years, but that was because we had included a commit on one branch and then forgot to merge it into another branch; we unfortunately had three development branches at the time that we needed to keep in synch (now we thankfully just have one).

I never use it for permanent development history unless I have made a mistake somewhere and need to catch a branch up, somehow.

But cherry-pick is pretty useful when I’m making temporary changes on my own branches. For example, you could introduce some configuration code in order to toggle certain options on or off when testing certain things. But either I’m too lazy to do that (most likely option) or the upstream integrator wouldn’t want to introduce that kind of complexity. So what do I do? I change the code directly and then store the change in a branch which is effectively just one commit that I can cherry-pick when I need it. And then I rebase that branch on top of upstream every now and again in order to resolve conflicts. One example which is pretty recent were some warning log messages that I wanted to turn into an error (exception) because I was suspicious that my changes could trigger those conditions. So I just changed the code to do that, marked the commit as TEMP, and continued with my work. If that change turns out to be useful later I can turn that commit into a branch which I can store for later temporary cherry-picks.

For this to work you have to make sure that the temporary changes do not overlap with the work (“actual”) changes that you are doing. Or else you’ll just get bogged down in conflicts.

Another possibility to consider is long-living branches that live on top of (are rebased) upstream, maybe because upstream won’t accept them (so they’re only in your repository). Maybe you care about the history of that branch and so things are split into dozens of commits. But sometimes you might not care about the history and then you could just squash the commits into one commit which is rebased or cherry-picked on top of upstream.

Guildenstern
  • 2,179
  • 1
  • 17
  • 39