Reputation: 19331
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
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
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
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
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
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