Otto
Otto

Reputation: 19331

Is it possible to retroactively turn a set of commits into a branch?

Say I have a git repository and I've been working on master, can I retroactively create a branch. For example:

A - B - C - A1 - D - A2 - E

I want to make it look like this:

A - A1 - A2   
\           \   
B - C - D - E

The specific use case is when I've cherry-picked a bunch of commits into an old version branch and it needs to go into multiple older versions and I don't want to repeat the cherry-pick on all those revision.

Essentially it's something that would have been good as a feature or topic branch in the first place but wasn't created like that.

Upvotes: 57

Views: 11749

Answers (5)

alltom
alltom

Reputation: 3252

If you want all the commits after revision XXX to have happened in a branch, I find this a lot easier than the other proposed methods.

$ git branch fixes       # copies master to new branch
$ git reset --hard XXX   # resets master to XXX

The commits are now only in the "fixes" branch.

This procedure is described in git's help page for reset under "Undo a commit, making it a topic branch".

Upvotes: 127

Adam Dymitruk
Adam Dymitruk

Reputation: 129526

Forget all that cherry-picking. Just rebase -i twice omitting the changes, making a new branch each time and then merging the 2.

Upvotes: 0

Jakub Narębski
Jakub Narębski

Reputation: 323364

What you want to do is to actually rewrite history. The identifiers of commits would change, and in some cases the changeset given by commits would change. So if there is a chance that somebody could have based work on old version of the branch you want to change, better to not do this. But if you didn't publish this branch, feel free.

Let us assume that a branch we want to change is named 'master', and that the point where we want to start new branch is named 'A' (in given example one of names you can use is 'master~6').

First, lets create new branch from commit 'A', let's name it 'fixes'

$ git checkout -b fixes A

This would also make branch 'fixes' current. Because there are only a few commits that we want to un-cherry-pick, we can cherry pick them on branch 'fixes':

$ git cherry-pick A1
$ git cherry-pick A2

Then we want to remove commits 'A1' and 'A2' from branch 'master'. Because there are only a few commits we want to remove, and possibly many more we want to keep, we eould use 'git rebase --interactive' for that:

$ git rebase -i fixes master

An editor will be fired up with all the commits in 'master' after commit 'A' (which is common commit i.e. merge base of branch 'master' and branch 'fixes'). The list would look like this:

pick deadbee B
pick fa1afe1 C
pick a98d4ba A1
...

Remove lines with commits 'A1' and 'A2', save changes, close editor (or otherwise send changes to inetractive rebase) and git would reapply all commits except those that you have deleted.

Then you can finalize with

$ git merge fixes

(git-rebase left us on rewritten branch 'master').

Upvotes: 0

Bombe
Bombe

Reputation: 83847

Of course you can. (With Git there isn’t much than you can’t do anyway. :)

git checkout -b new-branch hash-of-A
git cherry-pick hash-of-A1
git cherry-pick hash-of-A2

This will create a new branch, starting from the commit A. Afterwards you go back to the same commit again, creating another branch:

git checkout -b new-branch2 hash-of-A
git cherry-pick hash-of-B
git cherry-pick hash-of-C
git cherry-pick hash-of-D
git cherry-pick hash-of-E
git merge new-branch

Now you simply have to merge new-branch and new-branch2 to get the structure you want and drop your old branch.

Of course what Dustin said still holds: the hashes of the commits will change so you should only do that if you haven’t published your changes yet.

Upvotes: 25

Dustin
Dustin

Reputation: 90950

You can't do that transparently because the hashes will have to change, but you basically just need to branch HEAD and rebase -i both branches to drop the respective changes.

Upvotes: 5

Related Questions