Home > Enterprise >  How far back does git cherry-pick go?
How far back does git cherry-pick go?

Time:10-12

Suppose I have done the following:

  1. Create branch My-new-feature from master
  2. My-new-feature code changes part 1
  3. merge from (a recently pulled) master locally
  4. My-new-feature code changes part 2
  5. Create branch release-2 from master
  6. merge from (a recently pulled) master locally
  7. commit and push My-new-feature

If I now want to cherry pick my changes from steps 2 and 4 into the release-2 branch, which step(s) commit numbers do I need to use?

a) Just from step 7 (because cherry-pick is smart enough to go all the way back to the branch from master), or

b) from steps 2 and 4 (to avoid bringing in recent changes to master), or

c) something else?

CodePudding user response:

If I now want to cherry pick my changes from steps 2 and 4 into the release-2 branch, which step(s) commit numbers do I need to use?

git cherry-pick only picks the commits you tell it to. You can give it a list of commits, or you can give it a range of commits.

Git has two primary ways of specifying a range, A..B and A...B.

A..B says to give you all the commits reachable from B which are not reachable from A. So if you want all the commits in your branch, but not the commits merged in from master, you'd use master..my-new-feature.

A...B is the "symmetric difference". It is commits that are reachable from either A or B, but not from both. It's useful if you want to get the commits from both branches, but not from their common ancestor.

For example, after a couple merge updates your repository looks like this.

A - B - C - D - E - F  - G - H - I - J - K [master]
         \           \            \
          1 - 2 - 3 - M4 - 5 - 6 - M7 - 8 - 9 [my-new-feature]

The commits reachable from my-new-feature are...

A - B - C - D - E - F  - G - H - I
         \           \            \
          1 - 2 - 3 - M4 - 5 - 6 - M7 - 8 - 9

And the commits reachable from master are...

A - B - C - D - E - F  - G - H - I - J - K

master..my-new-feature is the commits reachable from my-new-feature minus those reachable from master.

1 - 2 - 3 - M4 - 5 - 6 - M7 - 8 - 9

And master...my-new-feature is the commits reachable from either my-new-feature or master but not both.

J - K

1 - 2 - 3 - M4 - 5 - 6 - M7 - 8 - 9

So git cherry-pick master..my-new-feature should do what you want. git log takes the same set of revisions, so you can check with git log master..my-new-feature.


Note, much of this can be avoided if you rebase instead of merge when updating your branch. git rebase master. Rather than merging changes from master into your branch this will copy your commits on top of the new master. The result is a simpler history.

If you rebased instead of merged, your history would look like this.

A - B - C - D - E - F  - G - H - I - J - K [master]
                                  \
                                   1 - 2 - 3 - M4 - 5 - 6 - M7 - 8 - 9 [my-new-feature]

And if you rebased again, it would look like this.

A - B - C - D - E - F  - G - H - I - J - K [master]
                                          \
                                           1 - 2 - 3 - M4 - 5 - 6 - M7 - 8 - 9 [my-new-feature]

It's as if you'd written my-new-feature on top of the latest version of master all along.

A git rebase master on your branch with all the merges would remove the merges and you'd wind up with the simpler history from above. However rebase introduces some complications of its own so don't try it without someone to guide you.

CodePudding user response:

If you go cherry picking with a friend, point to a tree, and say "Please pick that cherry for me." Your friend will likely respond with "That cherry? Which cherry do you mean?" Git does the same thing. The cherry-pick command requires either a single commit, or a range of commits, specified by you.

git cherry-pick a1b2c3d4 # single commit

# or

git cherry-pick a1b2c3d4..b2c3d4e5 # range of commits

As with most commands in Git, you can substitute a tag or branch name instead of a commit ID, since both are simply pointers to a commit.

Important Note: when you use a range, the first commit listed is the parent of the first commit to pick, and that parent commit will not be picked.

Given this information, if you show the graph of your commits after step 7, it should be fairly straight forward to determine which commit or commits you need to cherry-pick to accomplish your goal.

  • Related