2

I want to select particular set of commits to be cherry-picked to a new branch.

main-branch
* commit8
* commit7
* commit6
* commit5
* commit4
* commit3
* commit2
* commit1

I just want to create a release-branch with selected commits.

release-branch
* commit7
* commit6
* commit4
* commit2
* commit1

Is it possible to associate a tag for needed commits and write a script to cherry-pick commits with the particular tag?

Gopalki
  • 47
  • 6

1 Answers1

5

tl;dr: probably better to use git rebase -i


I don't guess I see what you expect to get out of tagging. To avoid saying

git cherry-pick commit

for each commit you would instead say

git tag my_tag commit

and then still have to actually run the script to copy the commits... it's more work than just doing it manually. (Plus, the above tag commands wouldn't work as you want, because a given tag points to exactly one object; so you'd have to use many tags, and have your cherry-pick script find all of them...)

That's not to say manual cherry-picking is the best way. The point of cherry-pick is to grab "that one change I need"; if you need to process an entire branch, it's probably easier to use git rebase. The rebase operation is often misunderstood; it copies commits, much like cherry-pick. (People often seem to think that it "replaces" commits, removing the originals; this is not exactly true. It can change the history of a ref, but that's the extent of that.)

So for example, if you start with

A -- B -- C -- D -- E -- F -- G -- H <--(main-branch)

you could

git checkout main-branch
git checkout -b release-branch
git rebase -i master~6

(I've used master~6 because it's an expression that refers to B; B's object ID (hash) would also work. I chose B because C is the first commit you don't want to retain - so rewriting starts after B. If you wanted to remove A, you could use an expression that resolves to A's parent if A has a parent, or use --root if A does not have a parent.)

Now git will open an editor and show you a "todo" list, with one line for each commit in your branch back to (but not including) B. For the commits you want to remove, change the first word on that commit's line from pick to drop (or just delete the line).

When you exit the editor, the rebase operation will begin "copying" commits (i.e. making new commits that apply the same changes on the new base). At each step, there could be conflicts (if a change in a later commit depends on a change in an earlier commit you removed); you'll be prompted to resolve those and continue the rebase operation.

When it's done you will have

A -- B -- C -- D -- E -- F -- G -- H <--(main-branch)
      \
       D' -- F' -- G' <--(release-branch)

where D' applies the same changes as D, etc.

This is not without potential drawbacks (though the drawbacks are the same for rebase as they would've been for cherry-pick); it really depends what you'll do with the branches from here. If release-branch is just a terminal state that you'll release and forget, it's probably fine. If you might need to hotfix the release, you'll find that merging between release-branch and main-branch could be difficult; so then you might have to use cherry-pick or rebase to share the fix between the release and your main development line.

Mark Adelsberger
  • 42,148
  • 4
  • 35
  • 52