4

I created a branch to develop a new feature. Since this new feature was develop entirely as a new project, the only possible source of conflict would be in the solution file.

As the feature was developed, the master branch was updated several times. When I completed my development and testing, I did:

git checkout master
git fetch
git pull
git checkout myFeature
git rebase master

The rebase (and all other commands) went fine and no conflicts/errors/problems were reported. My next step was to git status and the result was:

On branch myFeature
Your branch and 'origin/myFeature' have diverged, and have 7 and 5 different commits each, respectively. (use "git pull" to merge the remote branch into yours)

When I git pull a merge was open and looking at the history, my commits were duplicated. This duplication, in my point of view was not supposed to happen. I was expecting that my commits were supposed to be re-applied AFTER the last (currently) commit on the master.

Am I doing something wrong or my expectation is wrong?

Julian
  • 33,915
  • 22
  • 119
  • 174
Leonardo
  • 10,737
  • 10
  • 62
  • 155

3 Answers3

10

Why is there a merge commit

When you do a rebase, you're changing Git history. When you do a pull again, Git tries to combine both histories again. As by default git pull is a git fetch + git merge, this will lead to a merge commit.

This isn't what you want after changing history as it will (partly) reverts you history changes. Unfortunately the hint of git status is a bit misleading...

What should you do after a rebase / changing history

After changing history (e.g. rebase), you need a force push so you will get that history also on the remote. You're telling git then "the history is different, but trust me, that's intended".

It's recommend to use a "force push with lease": git push --force-with-lease - see git push --force-with-lease vs. --force.

Steps to fix the current state

Luckily you could go back before the git pull by using the Git reflog!

This will fix the wrong pull and there won't be any conflicts to solve :)

So steps to do:

  1. Find correct commit in the reflog git reflog, so before the git pull (note: you could quit the reflog by typing q)
  2. Git reset to that commit, e.g. git reset 327fb961e --hard
  3. Double check and do a git push --force-with-lease.

Note: if you are making a mistake with git reset, you could use the git reflog again :)

Note 2: the reflog is only on your local machine

Julian
  • 33,915
  • 22
  • 119
  • 174
  • 1
    so after `git rebase master` I do a `git push --force-with-lease` instead of `git pull`? – Leonardo Oct 24 '19 at 19:16
  • 1
    Yes indeed! You get it :) – Julian Nov 30 '20 at 18:18
  • I've seen a ton of answers explaining how to _avoid_ getting into this situation, but this is the first one I've seen that clearly explained how to recover if you've _already_ gotten into this situation -- huge life saver, thank you @Julian!! – Seth Aug 22 '22 at 15:39
  • FYI, this answer assumes that you've performed the rebase on your local branch first. However, for folks like me who've performed the rebase on the _remote_ branch first (eg. via GitHub), this is the sequence of steps I needed to follow to avoid this situation: Do NOT pull changes from rebased remote branch to local branch -- that's what causes the merge+duplicate commits! Instead, simply force-delete the local branch, then re-checkout the rebased remote branch to create a new local branch. At this point, both your remote and local branches are rebased and in sync with each other. – Seth Aug 22 '22 at 15:40
3

The previous answer looks great. Just trying to illustrate visually what's going, in case that's helpful:

Since git rebase modifies history, you branch after rebasing looks different from the one you have on origin.

origin/master:

A -> B -> C -> D -> E

yourbranch, origin/yourbranch:

A -> B -> F -> G -> H

After rebasing, yourbranch would look like:

A -> B -> C -> D -> E -> F -> G -> H

Then, when you pull origin/yourbranch, you would have:

A -> B -> C -> D -> E -> F -> G -> H - I (merge commit)
      \                              /
        -> F -> G -> H -------------

Since the histories are different, it becomes a normal, non-fast-forward merge. Effectively, your remote and local branches have become different branches.

kid_x
  • 1,415
  • 1
  • 11
  • 31
1

This part was enough for rebasing with master branch.

git checkout master
git fetch
git pull
git checkout myFeature
git rebase master

However, you can just use the following command instead of all the above command to do the same thing.

$ git pull origin master --rebase

After this all the commit hash will be rewritten that's why git status showed that your branch has diverged.

Ignoring this, you could run the following command to push the rebased code to the remote branch.

$ git push origin HEAD -f

While rebasing if you face conflicts and you are not willing to continue the rebase, you can just run git rebase --abort to abort the rebasing.

In any case, if you find yourself in the middle of some unwanted commit related hazard, you can follow the following steps.

  • git reflog - to find the last perfect commit & note its commit hash
  • git reset --hard <commit-hash> - provide the last perfect commit hash

It will take you to the last perfect code of the repo.

Masudur Rahman
  • 1,585
  • 8
  • 16