2

I'm sure I'm doing something wrong, but here's what's happening.

My team has a develop branch from which we branch to create feature branches.

I'm working on one feature and every time I try to pull --rebase from develop I'm met with a bunch of conflicts.

I solve all conflicts and try to push to feature. A message says the tip of my branch is behind feature's and that I should pull from it.

  hint: Updates were rejected because the tip of your current branch is behind
    hint: its remote counterpart. Merge the remote changes (e.g. 'git pull')
    hint: before pushing again.

I pull from it (without rebasing) and am met with MORE conflicts, which I solve.

Now I can push to feature.

At this point it's all synced and working fine. But if I work on some local work and try pull --rebase from develop, I'm met with a ton of conflicts AGAIN, including some I've already solved (I do have rerere on).

Anything I'm messing up here?

Souljacker
  • 595
  • 6
  • 23
  • If you can show us the real Git commands and messages this would be easier to answer. In particular the "*message says my pointer is behind feature's and that I should pull from it*", I believe that's the misstep. – Schwern May 04 '18 at 04:08
  • @Schwern you were right. Updated it with the proper message – Souljacker May 04 '18 at 04:13

2 Answers2

6

When you rebase a branch on another branch, you generally rewrite the history of that branch. As a result, a normal push will fail because Git will think that your branch has diverged from what is on the remote. Instead of doing this:

git push origin feature

you should have done this:

git push --force origin feature

There are potentially bad side effects from a force push, but if you are the only one working on this feature branch then it is OK.

In terms of a diagram, to better understand what is happening here consider the following:

develop: ... A -- B
              \
feature:        C

Since you branched feature from develop you have added a new C commit. Also, someone else (perhaps you as well) has added a B commit to develop. Now, you rebase feature on develop:

develop: ... A -- B
                   \
feature              C'

Compare the new feature against the one before you rebased. Your new C' commit now sits on top of a new base, the B commit, and when you go to push, Git will reject it. Git will see the common A commit ancestor, but it won't know how to apply the new commit, not without a merge, which would defeat the point of a rebase.

Tim Biegeleisen
  • 502,043
  • 27
  • 286
  • 360
  • What about having to solve all conflicts again when rebasing from develop? – Souljacker May 04 '18 at 04:14
  • 2
    @Souljacker Not sure what you are asking. Once you resolve the conflicts in the rebase, you force push `feature` and you are done, there are no more conflicts. – Tim Biegeleisen May 04 '18 at 04:16
  • That's what I thought, but if I edit something and try to rebase from develop, I meet conflicts again. I didn't try with --force, though. Will try and report back – Souljacker May 04 '18 at 04:19
  • Ok, force pushing worked! One think, which would be the solution if I had more people working on this branch? – Souljacker May 04 '18 at 07:00
  • @Souljacker You may simply have everyone else sharing the branch fetch and then reset their branch to whatever rebased version came in (see [the accpeted answer here](https://stackoverflow.com/questions/9589814/how-do-i-force-git-pull-to-overwrite-everything-on-every-pull)). Basically, they have to force update their local branches. Or, they could just delete their local branches, fetch, and checkout fresh copies. – Tim Biegeleisen May 04 '18 at 07:04
1

I'll try to piece together the commands.

  • git checkout feature
  • git pull --rebase origin develop
  • fix conflicts, finish rebase
  • git push

At this point you get something like this.

To github.com:org/repo.git
 ! [rejected]        feature -> feature (non-fast-forward)
error: failed to push some refs to 'git@github.com:org/repo.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

The hint is wrong, a git pull here is the wrong thing. Instead you should git push --force to overwrite the upstream feature with your own. This is because you've rewritten the feature branch and it has diverged with the upstream one.

Here's what's happened in more detail. At the start things looked something like this. Note that the upstream origin/feature and your local feature are at the same commit.

                      [origin/develop]
A - B - C - D - E - F [develop]
            \
             G - H - I [feature]
                       [origin/feature]

After git pull --rebase origin develop and all the conflicts were fixed, your repository looked like this.

                    [origin/develop]
                    [develop]
A - B - C - D - E - F - G1 - H1 - I1 [feature]
            \
             G - H - I [origin/feature]

rebase doesn't rewrite commits. It creates new ones and pretends it was that way all along. Now feature and origin/feature have diverged meaning one is not an ancestor with the other.

When you try to git push your feature Git refuses. It's not a simple matter of moving origin/feature along a few commits, called a "fast-forward". A merge would be required and git push won't do that for safety reasons. Your work appears to have diverged from everyone else's. A push risks blowing over other people's work on the same branch.

That's why the git push --force is necessary. It tells Git to do it anyway, put origin/feature at commit I1. After the git push --force you'll have this.

                    [origin/develop]
                    [develop]
A - B - C - D - E - F - G1 - H1 - I1 [feature]
            \                        [origin/feature]
             G - H - I

Now it's all good. Your feature work is as if it was on top of develop all along.

If you git pull --rebase origin develop again, and there's no new commits on develop, nothing should happen. If there are new commits, you'll only have to deal with those.

Schwern
  • 153,029
  • 25
  • 195
  • 336