7

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)?

Optimus
  • 2,716
  • 4
  • 29
  • 49

2 Answers2

7

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)
Community
  • 1
  • 1
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • I don't think this will work as the OP as merged several times the upstream/new_feature branch in the specific_feature branch – davidriod Mar 28 '15 at 11:58
  • @davidriod ok, I have edited the question to propose an alternative merge-based option (instead of cherry-picking, which I tend to avoid because of commit duplication (http://stackoverflow.com/a/2628915/6309) – VonC Mar 28 '15 at 12:24
  • 1
    @VonC I may have badly understood but basically this is a feature rescheduling which can happen in a project and no code at all from the new feature is supposed to be merged in the master branch. Regarding the commit duplication, it's not a real issue if the specific feature is supposed to get ridden off. Basically I think the OP just want to reconstruct the specific_feature **independantly** from the new_feature branch. – davidriod Mar 28 '15 at 13:38
2

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.

davidriod
  • 937
  • 5
  • 14
  • 1
    minor edit to the last line: `git cherry origin/new_feature specific_feature | egrep '^\+' | awk '{print $2}' | xargs git cherry-pick` – Edwin Hoogerbeets Jan 02 '18 at 22:46