Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Merge diff between two branches to third branch

Tags:

git

diff

Assume I have two branches, master and new_feature

I was supposed to work on a specific feature, I thought this feature would be part of new_feature so, I checked out specific_feature branch out of the new_feature branch, like so

git checkout -b specific_feature

Now I did a lot development in this specific_feature branch, merged upstream/new_feature into it a couple of times to get the remote changes.

Now, I come to know that my specific_feature should have been branched out of master not new_feature. (new_feature branch is not ready to be pushed)

Is there a way I can take the diff between my specific_feature branch and new_feature branch, and apply those changes to new branch say specific_feature_master (branched out of master)?

like image 827
Optimus Avatar asked Mar 28 '15 08:03

Optimus


2 Answers

That seems a job for git rebase --onto:

git rebase --onto master new_feature specific_feature

That will take only the commits after new_feature up to specific_feature HEAD, and replay them onto master.

Note that you will then have to force push specific_feature to upstream (if you already pushed it before): git push --force specific_feature.

That can be an issue if others have already pulled that branch and are working on it.


davidriod correctly points out that:

I don't think this will work as the OP as merged several times the upstream/new_feature branch in the specific_feature branch

If new_feature was never updated (fetch only, never pull), then it might still work.
If new_feature was updated (pull) and merged into specific_feature, then the rebase --onto would only play the last few commits since the last merge: here, only z' commits would be replayed, not the first z.

x--x--x
       \
        y--y--Y--y--y (new_feature)
            \  \
             z--M--z'--z' (specific_feature)

Instead of cherry-picking, I would:

  • make specific_feature out of master (and mark the specific_feature branch as tmp)
  • merge Y (the last new_feature commit which was merged in specifc_feature) into the new specific_feature branch

That is:

git checkout -b tmp specific_feature
git checkout -B specific_feature master
git merge $(git merge-base tmp new_feature) # that merges Y

        ----------M (specific_feature)
       /         /
x--x--x         /
       \       /
        y--y--Y--y--y (new_feature)
            \  \
             z--M--z'--z' (tmp)

Then the rebase --onto can use that same common ancestor Y as the correct base:

git rebase --onto specific_feature $(git merge-base tmp new_feature) tmp
git branch -D tmp

        ----------M--z''--z'' (specific_feature)
       /         /
x--x--x         /
       \       /
        y--y--Y--y--y (new_feature)
like image 163
VonC Avatar answered Sep 17 '22 22:09

VonC


You may use use the command git cherry to retrieve the commit done on the specific_feature branch and which does not appear on the origin/new_feature branch.

git cherry origin/new_feature specific_feature

You can then create a new branch from master and cherry-pick all these commits. But if you dependencies between your development on specific_feature and origin/new_feature no scm is going to resolve that for you.

git checkout -b specific_feature_master master
git cherry origin/new_feature specific_feature | egrep '^+' | awk '{print $2} | xargs git cherry-pick

Something like that should do starting point for resolving your problem.

like image 35
davidriod Avatar answered Sep 19 '22 22:09

davidriod