12

In merging my changes against an upstream master, I frequently find myself doing the following:

git checkout somefeature
git checkout -b integration
git rebase master # resolving conflicts along the way
git checkout somefeature
git merge integration # or rebase, doesn't matter in this example

I'll often find that merging the integration branch back into my feature branch fails do to some conflicts. The first question I have is, "why is this happening if my integration branch is a descendent of somefeature and I've already resolved conflicts against the upstream master?"

If you're wondering why I'm using an integration branch to begin with, it's to prevent polluting my current branch with a half-failed merge.

My current workaround is to do this:

git checkout integration
git branch -f somefeature # overwrite the branch

The problem now is that I can't push my changes back to a remote branch:

git push origin somefeature
! [rejected]        somefeature -> somefeature (non-fast forward)

So now I have to remove the remote branch and re-push my changes. This can't be the optimal way to do this, so I'm wondering, "what's the best way to overwrite a branch and push the changes to a remote branch?"

tmountain
  • 179
  • 1
  • 1
  • 9

4 Answers4

15

The problem is caused because git rebase generates a new series of commits that aren't descended from the somefeature branch, then when you try and merge them back into somefeature the conflict resolution done during the rebase doesn't apply. If you were to just merge instead of rebase then this would work as the merge commit would descend from the somefeature branch.

In terms of pushing to the remote branch you can just use --force to make the push succeed, that will cause problems for anyone else that has a copy of it though.

Nemo157
  • 3,559
  • 19
  • 27
  • 3
    Note though that you should never change already published commits, as others working with you will run into the same problems as you do, that they have duplicated yet incompatible commits already in their repository. Rebasing is fine as long as it's just local, but rebasing commits and republishing them is evil – hence the *“rejected”* error by Git (it is smart and notices that you are probably doing something wrong). – poke Jan 19 '11 at 21:48
  • Ah, I was using merge for the convenience of step by step conflict resolution without considering that the commits wouldn't be descendants of the somefeature branch. Accepting this as the true answer to my question. Thanks so much! – tmountain Jan 19 '11 at 21:49
4

You could use git merge -s recursive -Xtheirs, which will auto-resolve conflicts in favor of the integration branch. However, that still does a merge and may not play well with files moving around and such.

However, since your branch is pushed, you have a reason to want to keep its history around. To get the ideal behavior you want, you could use the 'ours' strategy in the integration branch.

git checkout somefeature
git checkout -b integration
git rebase master # resolving conflicts along the way
git merge -s ours somefeature # mark integration as superseding the somefeature branch
git checkout somefeature
git merge integration # this is now a fast-forward, no conflicts
Walter Mundt
  • 24,753
  • 5
  • 53
  • 61
  • However, in general, Nemo157's solution is better - just use merge instead of rebase from the beginning for feature branches that are published in a non-local repo. That's how git's designed to work. – Walter Mundt Jan 19 '11 at 21:45
  • I was unaware of the 'ours' merge strategy. This looks like the solution I've been seeking. Thank you! – tmountain Jan 19 '11 at 21:48
0

You could make sure your final merge overwrite the destination branch with a merge driver:
See "Can I tell git pull to overwrite instead of merge?" for example.

The idea is to have a custom merge driver with a "keepTheir" script.

Community
  • 1
  • 1
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
0

Your first bit of operations is very strange. You make a copy of somefeature. You rebase that against master. Then you go back to that feature and merge it with the rebased equivelant of itself. This is not the way to do things.

Don't over complicate things. If you want the feature branch to start somewhere else instead (like the latest master), just rebase it.

Then push it with --force (or -f). Tell anyone else that was using that feature branch that they have to fetch the changes and adjust anything that they had locally that they didn't push yet.

Merge is better in the case when others have been working on it.

Hope this helps.

Adam Dymitruk
  • 124,556
  • 26
  • 146
  • 141
  • 1
    Eh, was under the impression that making a copy of somefeature and then merging that against master would be an easy way to merge two branches without mucking about with either of the originals. I suppose it is better just to do a standard rebase. Thanks. – tmountain Jan 19 '11 at 21:44
  • you can merge it instead. You were trying to do both. That was the issue. It's up to you if you want to merge to master or rebase to master. One produces a linear history, the other preserves the point at which you branched. Your choice. You will have potentially more conflicts to resolve if you take the rebase route in addition to "moving someone's cheese" potentially. – Adam Dymitruk Jan 19 '11 at 21:48