1303

Somehow my master and my origin/master branch have diverged.
I actually don't want them to diverge.

How can I view these differences and merge them?

ᴍᴇʜᴏᴠ
  • 4,804
  • 4
  • 44
  • 57
Frank
  • 18,432
  • 9
  • 30
  • 30
  • 4
    what do you mean by diverging? do you rebase your master *after* pushing it? – hasen Mar 16 '10 at 06:24
  • 42
    I get a message saying "Your branch and 'origin/master' have diverged, # and have 1 and 1 different commit(s) each, respectively." – Frank Mar 16 '10 at 15:27
  • I have updated my answer to reflect that "diverged" warning message. – VonC Mar 16 '10 at 15:49
  • The accepted answer to another question may also be helpful in resolving certain cases where this might come into play (e.g. you're trying to move your master around, but it already had been pushed): http://stackoverflow.com/questions/2862590/how-to-replace-master-branch-in-git-entirely-from-another-branch – lindes Jun 01 '12 at 23:10
  • 13
    The explanation at this blog helped me infinitely more than any answer below: http://sebgoo.blogspot.com/2012/02/git-your-branch-and-originxxx-have.html –  Mar 30 '13 at 20:18
  • The word you are looking for is 'converge' by the way. – Andreas Hartmann Sep 30 '16 at 09:03
  • 6
    To undo all changes to my own local branch after it had 'diverged' (needed push and pull, when I made no changes I can remember): git reset --hard origin/my-branch . Only do this if you know you did not make any local changes that you want to keep. – Dean Dec 04 '18 at 20:13
  • I had a hard time figuring this out and finally just ran `git branch -D offending_branch && git fetch && git checkout offending_branch` and it fixed the issue – Neil C. Obremski May 13 '21 at 16:11
  • 1
    @user711807 Archived version https://web.archive.org/web/20150213051658/https://serebrov.github.io/html/2012-02-13-git-branches-have-diverged.html – Iceland_jack Jun 26 '23 at 09:10
  • Non-archived version: https://serebrov.github.io/html/2012-02-10-git-checkout-and-track-remote-branch.html – Teepeemm Jul 22 '23 at 18:05

20 Answers20

1297

You can review the differences with a:

git log HEAD..origin/main

# old repositories
git log HEAD..origin/master

before pulling it (fetch + merge) (see also "How do you get git to always pull from a specific branch?")

Note: since Git 2.28 (Q3 2020), the default branch is configurable, and now (2021+) set to main, no longer master.
The rest of the answer reflects that more recent convention.


When you have a message like:

"Your branch and 'origin/main' have diverged, # and have 1 and 1 different commit(s) each, respectively."

Check if you need to update origin.
If origin is up-to-date, then some commits have been pushed to origin from another repo while you made your own commits locally.

... o ---- o ---- A ---- B  origin/main (upstream work)
                   \
                    C  main(your work)

You based commit C on commit A because that was the latest work you had fetched from upstream at the time.

However, before you tried to push back to origin, someone else pushed the commit B.
Development history has diverged into separate paths.

You can then merge or rebase. See Pro Git: Git Branching - Rebasing for details.

Merge

Use the git merge command:

$ git merge origin/main

# old repositories
$ git merge origin/master

This tells Git to integrate the changes from origin/main into your work and create a merge commit.
The graph of history now looks like this:

... o ---- o ---- A ---- B  origin/main (upstream work)
                   \      \
                    C ---- M  main (your work)

The new merge, commit M, has two parents, each representing one path of development that led to the content stored in that commit.

Note that the history behind M is now non-linear.

Rebase

Use the git rebase command:

$ git rebase origin/main

# old repositories
$ git rebase origin/master

This tells Git to replay commit C (your work) as if you had based it on commit B instead of A.
CVS and Subversion users routinely rebase their local changes on top of upstream work when they update before commit.
Git just adds explicit separation between the commit and rebase steps.

The graph of history now looks like this:

... o ---- o ---- A ---- B  origin/main (upstream work)
                          \
                           C'  main (your work)

Commit C' is a new commit created by the git rebase command.
It is different from C in two ways:

  1. It has a different history: B instead of A.
  2. Its content accounts for changes in both B and C; it is the same as M from the merge example.

Note that the history behind C' is still linear.
We have chosen (for now) to allow only linear history in cmake.org/cmake.git.
This approach preserves the CVS-based workflow used previously and may ease the transition.
An attempt to push C' into our repository will work (assuming you have permissions and no one has pushed while you were rebasing).

The git pull command provides a shorthand way to fetch from origin and rebase local work on it:

$ git pull --rebase

This combines the above fetch and rebase steps into one command.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • 7
    I found this while looking up the same problem, can you explain why 'git reset --hard HEAD' didn't fix the problem? – Neth Nov 26 '10 at 14:19
  • 20
    @Neth: because it is not about staged modifications (i.e. modifications present in the index but not yet committed), but about *local commits* (which differs from commits present on the remote). `git reset --hard HEAD` would only remove any local indexed non-committed modification, and would do nothing to reconcile the differences between local and remote *commits*. Only a merge or a rebase will bring the two set of commits (the local one and the remote one) together. – VonC Nov 26 '10 at 16:48
  • 4
    Wow, thanks for this awesome response. We had accidentally done a "git pull" without "--rebase", and "git rebase origin/master" was just the fix! – mrooney May 09 '11 at 21:50
  • 7
    How about - I just want to ignore/dump my local changes and be with my local branch where the remote is? In other words, I want `master` to point to `B` at your example. – CygnusX1 Apr 29 '12 at 10:32
  • 36
    @CygnusX1 that would be a `git reset --hard origin/master` as mentioned in the answer just below: http://stackoverflow.com/a/8476004/6309 – VonC Apr 30 '12 at 06:01
  • Yes, I see it now. Somehow I didn't see it yesterday :( – CygnusX1 Apr 30 '12 at 07:34
  • Great answer, I'd only add that if you're stuck in the middle of a merge you can 'git merge --abort' then choose the merge or rebase options. – Joe Cairns Nov 05 '12 at 17:47
  • 2
    This might help someone else also; a lot of commands I thought should start with `git` were just me editing text files. So if you're confused, you might need to go in an edit with `nano`, `emacs`, `pico`, `vim`, or whatever GUI editor you use – Nathan majicvr.com May 05 '20 at 23:44
  • 1
    This help me resolved my issue. Great explanation!! Makes it easier to understand – Neo Apr 16 '22 at 18:09
  • Just a note: if you rapidly copy and paste and the command fails, you'd probably need to change `git log HEAD..origin/master` to the new default `git log HEAD..origin/main` (as I did ¯\_(ツ)_/¯). Bottom line: great answer, helped a lot. – HynekS Sep 18 '22 at 23:03
  • 1
    @HynekS Thank you for your feedback. I have edited this 2010 answer to reflect the more recent default branch naming convention. – VonC Sep 19 '22 at 06:44
  • git pull --rebase worked for me – cem çetin Feb 16 '23 at 09:10
  • Could I know why the commands above and below `# old repositories` are same? – Zhou Haibo Apr 24 '23 at 01:15
  • @ZhouHaibo Good point. It was because of [edit #7](https://stackoverflow.com/posts/2452610/revisions), which I just rolled back. – VonC Apr 24 '23 at 05:27
  • 1
    git merge helped – Spartan Apr 25 '23 at 05:58
  • “Note: since Git 2.28 (Q3 2020), the default branch is configurable, and now (2021+) set to main, no longer master.” This is confusing to me. The default `git init` branch name is still `master` for me on Git 2.40.0. Your link brings up both the config in git(1) from 2.28 (correct) and then mentions GitHub’s change to `main`. That must be what you are referring to by “default main”. But I find that to be confusing in this context (this answer), since the surrounding context (like “since 2.28”) is about Git and not about GitHub. – Guildenstern Apr 26 '23 at 20:08
  • @Guildenstern "The default `git init` branch name is still `master` for me on Git 2.40.0."? It is main. `git config --system init.defaultbranch` should be main. That is the case at least for Git for Windows. – VonC Apr 26 '23 at 20:28
  • `git config --system init.defaultbranch` gives no output for me on Linux—it has no default value. On `git init` I get `master` and [this](https://pastebin.com/644jBjC4) “hint” is displayed. – Guildenstern Apr 26 '23 at 20:39
  • @Guildenstern OK, that might be specific to Git for Windows then. – VonC Apr 26 '23 at 21:31
1101

I had this and am mystified as to what has caused it, even after reading the above responses. My solution was to do

git reset --hard origin/main

Then that just resets my (local) copy of main (which I assume is screwed up) to the correct point, as represented by (remote) origin/main.

WARNING: You will lose all changes not yet pushed to origin/main.

zero_cool
  • 3,960
  • 5
  • 39
  • 54
skiphoppy
  • 97,646
  • 72
  • 174
  • 218
  • 41
    yes, it feels a bit like the dummies option, but if there's no real danger and you're here for a quick fix - this works (for me anyway) – PandaWood Apr 11 '12 at 06:34
  • 12
    This requires to be on the master branch before ("git checkout master"). – blueyed Apr 11 '13 at 09:42
  • Hi skiphoppy, thanks for the tip. I agree with PandaWood (no offence meant) that it seems like a bit of a dummies option. But in saying that, I'm not that experienced with the more advanced aspects of Git. – Matthew Setter Jun 30 '13 at 08:18
  • The `origin/master` bit is what I needed -- somehow I just got out of sorts locally and really wanted to revert to origin, but resetting without the explicit remote name was not working. Thanks! – Brian Moeskau Apr 13 '14 at 20:04
  • 8
    @PedroLoureiro Commits are note really lost, you can still find the commits with `git reflog` or see them in `gitk --all`. But yet, of course the hard reset is another thing than a rebase. – sebkraemer Mar 11 '16 at 09:51
  • I always forget to squash and later while doing it with git rebase end up messing. Your solution helped thanks a ton. – vikramvi Nov 14 '16 at 11:15
  • @skiphoppy, what if I want to do the reverse. As in (reset) my remote copy instead ?? – steven7mwesigwa Dec 18 '19 at 11:47
  • safe when it is a feature branch because no conflict since you are alone in that branch. – King Jherold Feb 20 '20 at 06:14
  • It seems this `git branch -f master origin/master` also works, providing that my current branch is not master. – bruin Apr 29 '20 at 02:33
  • This is kind of the "when in doubt, reboot" solution. But hey, if you can't figure out how to resolve the issue, then this is basically the best solution – u84six Nov 10 '20 at 17:47
  • or `git reset origin/main` – Caleb Stanford Jul 19 '22 at 12:10
  • I think I got into this situation when i did `git reset --soft HEAD~1` – Kilmazing Aug 24 '22 at 23:53
71
git pull --rebase origin/main 

is a single command that can help you most of the time.

Edit: Pulls the commits from the origin/main and applies your changes upon the newly pulled branch history.

zero_cool
  • 3,960
  • 5
  • 39
  • 54
asitmoharna
  • 1,484
  • 11
  • 15
  • 121
    please mention what the command does, else people might run it and end up screwing up – Baz1nga Dec 18 '12 at 04:43
  • 3
    If there is no problem, you should end up with your master containing all the changes origin/master plus all your local commits will be replayed on top of it. Seems good to me. – Philipp Claßen Jan 17 '13 at 13:32
  • 8
    Except when there are real differences and it leaves you in an aborted rebase. – ffledgling Nov 25 '15 at 11:39
  • This yields an error: **error: Failed to merge in the changes. Patch failed at 0024 Request and Response models** – IgorGanapolsky Aug 22 '18 at 15:07
53

I believe this should have helped me:

git reset --hard origin/main

But it didn't. Somehow I was getting the same message & as soon as I pulled the changes from the remote branch, the conflicts were happening. Since I was sure that I didn't need my existing local branch at all & I just needed a replica of the main branch from remote, hence I came up with this solution:

  • Checkout to a new branch, for instance, git checkout -b placeholder-branch. Note: This branch can be deleted later.
  • git branch -D main, I did this as I was sure my local branch was screwed up & I didn't need this. I need a fresh copy from the remote instance.
  • git checkout --track origin/main & you're done; now you can delete the placeholder-branch using git branch -D
zero_cool
  • 3,960
  • 5
  • 39
  • 54
Rishi Kulshreshtha
  • 1,748
  • 1
  • 24
  • 35
39

I found myself in this situation when I tried to rebase a branch that was tracking a remote branch, and I was trying to rebase it on main. In this scenario if you try to rebase, you'll most likely find your branch diverged and it can create a mess that isn't for git nubees!

Let's say you are on branch my_remote_tracking_branch, which was branched from main

$ git status

# On branch my_remote_tracking_branch

nothing to commit (working directory clean)

And now you are trying to rebase from master as:

git rebase main

STOP NOW and save yourself some trouble! Instead, use merge as:

git merge main

Yes, you'll end up with extra commits on your branch. But unless you are up for "un-diverging" branches, this will be a much smoother workflow than rebasing. See this blog for a much more detailed explanation.

On the other hand, if your branch is only a local branch (i.e. not yet pushed to any remote) you should definitely do a rebase (and your branch will not diverge in this case).

Now if you are reading this because you already are in a "diverged" scenario due to such rebase, you can get back to the last commit from origin (i.e. in an un-diverged state) by using:

git reset --hard origin/my_remote_tracking_branch

zero_cool
  • 3,960
  • 5
  • 39
  • 54
paneer_tikka
  • 6,232
  • 1
  • 20
  • 17
  • 6
    A rule of thumb is to use `rebase` if the branch you're rebasing has not been published (and used by other people). Otherwise, use `merge`. If you rebase already published (and used) branches, you have to coordinate a conspiracy to rewrite history across every developer that has used your branch. – Mikko Rantalainen May 29 '13 at 05:30
  • 1
    Unfortunately I did not read this message before doing the `git rebase master`... – Vitaly Isaev Jul 08 '14 at 12:26
  • If i do git rebase master while on branch 'foobar' then technically foobar is diverged from origin/foobar until I do a git push -f , right? – relipse May 15 '16 at 20:56
  • http://www.jarrodspillers.com/git/2009/08/19/git-merge-vs-git-rebase-avoiding-rebase-hell.html – akhil_mittal Mar 01 '17 at 11:44
  • 3
    `git reset --hard origin/my_remote_tracking_branch` is what really worked – sgohl Apr 04 '18 at 07:27
  • thanks man.... things were getting dark, but answer came to rescue... :) – mohitesachin217 Oct 10 '19 at 05:33
32

In my case here is what I did to cause the diverged message: I did git push but then did git commit --amend to add something to the commit message. Then I also did another commit.

So in my case that simply meant origin/main was out of date. Because I knew no-one else was touching origin/main, the fix was trivial: git push -f (where -f means force)

zero_cool
  • 3,960
  • 5
  • 39
  • 54
Darren Cook
  • 27,837
  • 13
  • 117
  • 217
  • 9
    +1 for `git push -f` to overwrite the changes previously committed and pushed to origin. I also am sure nobody else touched the repository. – zacharydl Oct 05 '14 at 01:54
  • 5
    Very risky command. Please write a short information regarding risk factor of the command. – J4cK Sep 25 '15 at 20:07
  • 2
    @Trickster: I already had described the risk: "as I knew no-one else was touching origin/master". I believe, in that case, this is not a risky command. – Darren Cook Sep 28 '15 at 06:48
  • 1
    If someone commits on master and then one person run the command git push -f then it is high risk command – J4cK Sep 28 '15 at 14:33
  • Thanks for this answer. My CI had a git commit --amend and would fail because of that. Amending local commits makes sense, in CI if you amend before committing you are technically amending a remote commit thats already been pushed and hence it sees it as a diversion. – Kerry Johnson May 18 '21 at 19:07
19

In my case I have pushed changes to origin/main and then realized I should not have done so :-( This was complicated by the fact that the local changes were in a subtree. So I went back to the last good commit before the "bad" local changes (using SourceTree) and then I got the "divergence message".

After fixing my mess locally (the details are not important here) I wanted to "move back in time" the remote origin/main branch so that it would be in sync with the local main again. The solution in my case was:

git push origin main -f

Note the -f (force) switch. This deleted the "bad changes" that had been pushed to origin/main by mistake and now the local and remote branches are in sync.

Please keep in mind that this is a potentially destructive operation so perform it only if you are 100% sure that "moving back" the remote main in time is OK.

zero_cool
  • 3,960
  • 5
  • 39
  • 54
András Aszódi
  • 8,948
  • 5
  • 48
  • 51
  • Always useful but surely doesn't answer the question. – Thibault D. Jul 20 '16 at 11:24
  • 2
    @ThibaultD. even if it didn't, this is exactly what I was looking for. – Neil Aug 11 '18 at 06:46
  • I'm getting `You are not allowed to force push code to a protected branch on this project.` . I'm trying to push to my fork. – BanAnanas Mar 11 '20 at 22:44
  • I had to remove protection on gitlab repo https://stackoverflow.com/questions/32246503/fix-gitlab-error-you-are-not-allowed-to-push-code-to-protected-branches-on-thi – BanAnanas Mar 11 '20 at 22:54
  • 1
    Yes I had a few commits on master that shouldn't have been there, if you don't care about deleting them, the above or "git push --force" works (REWRITES HISTORY AND DELETES THE DIVERGED REMOTE COMMITS). If you want to keep the commits but not on master then it is possible to move them to another branch. – 00-BBB Apr 22 '21 at 10:36
  • @BanAnanas create a PR based on a new branch and then you'll be able to merge to the protected branch – Máxima Alekz Jul 12 '22 at 22:27
  • 1
    @zero_cool No need to be overly politically correct and edit the `master` branch name to `main`. A "master" branch in a Git repo has absolutely nothing to do with slave-keepers. Or do you refuse to play chess just because there are white and black figures moving on black and white fields? And if you do, then what colours would you propose for a chessboard? :-) – András Aszódi Mar 11 '23 at 09:24
15

I know there are plenty of answers here, but I think git reset --soft HEAD~1 deserves some attention, because it let you keep changes in the last local (not pushed) commit while solving the diverged state. I think this is a more versatile solution than pull with rebase, because the local commit can be reviewed and even moved to another branch.

The key is using --soft, instead of the harsh --hard. If there is more than 1 commit, a variation of HEAD~x should work. So here are all the steps that solved my situation (I had 1 local commit and 8 commits in the remote):

1) git reset --soft HEAD~1 to undo local commit. For the next steps, I've used the interface in SourceTree, but I think the following commands should also work:

2) git stash to stash changes from 1). Now all the changes are safe and there's no divergence anymore.

3) git pull to get the remote changes.

4) git stash pop or git stash apply to apply the last stashed changes, followed by a new commit, if wanted. This step is optional, along with 2), when want to trash the changes in local commit. Also, when want to commit to another branch, this step should be done after switching to the desired one.

Bianca Daniciuc
  • 920
  • 1
  • 13
  • 22
  • 1
    Actually, these days, the `pull --rebase` would stash automatically anyway. https://stackoverflow.com/a/30209750/6309 – VonC Sep 22 '17 at 15:04
6

I have fixed it by moving to commit_sha that last is committed to origin/main.

git reset --hard commit_sha

WARNING: You will lose all that is committed after the 'commit_sha' commit.

zero_cool
  • 3,960
  • 5
  • 39
  • 54
Shohin
  • 519
  • 8
  • 11
4

To view the differences:

git difftool --dir-diff main origin/main

This will display the changes or differences between the two branches. In araxis (My favorite) it displays it in a folder diff style. Showing each of the changed files. I can then click on a file to see the details of the changes in the file.

zero_cool
  • 3,960
  • 5
  • 39
  • 54
C.J.
  • 15,637
  • 9
  • 61
  • 77
4

Replace 123 with number of commits your branch has diverged from origin.

git reset HEAD~123 && git reset && git checkout . && git clean -fd && git pull
dsmith63
  • 199
  • 4
3

In my case this was caused by not committing my conflict resolution.

The problem was caused by running the git pull command. Changes in the origin led to conflicts with my local repo, which I resolved. However, I did not commit them. The solution at this point is to commit the changes (git commit the resolved file)

If you have also modified some files since resolving the conflict, the git status command will show the local modifications as unstaged local modifications and merge resolution as staged local modifications. This can be properly resolved by committing changes from the merge first by git commit, then adding and committing the unstaged changes as usual (e.g. by git commit -a).

Matt Bond
  • 1,402
  • 12
  • 19
3

git reset --soft origin/my_remote_tracking_branch

This way you will not loose your local changes
GPopat
  • 445
  • 4
  • 14
2

I prefer doing it more convenient and safer way.

# copying your commit(s) to separate branch
git checkout <last_sync_commit>
git checkout -b temp
git cherry-pick <last_local_commit>

git checkout main
git reset --soft HEAD~1 # or how many commits you have only on local machine
git stash               # safer, can be avoided using hard resetting on the above line
git pull
git cherry-pick <last_local_commit>

# deleting temporary branch
git branch -D temp
zero_cool
  • 3,960
  • 5
  • 39
  • 54
igronus
  • 486
  • 4
  • 12
2

To more directly answer the original question, you can inspect the actual conflicting differences with:

git diff HEAD..origin/master

and use this information to decide whether to pull the origin's changes into your local repo or push your local changes to the origin.

Hashim Aziz
  • 4,074
  • 5
  • 38
  • 68
1

You may encounter this situation, only pull 1 history from remote:

$ git pull --depth=1
fatal: refusing to merge unrelated histories
$ git status
Your branch and 'origin/main' have diverged,
and have 1 and 1 different commits each, respectively.

According to above answers, it will cause the two branches be diverged to different "line", so Git think it's unrelated histories.

---a---b---main
        \      \
          x x x x   diverged, cannot be merged anymore
          \      \
    ---?---?---?---c(origin/main)

And finally, the simple resolution is: git reset --hard origin/main, if you don't care the local changes, otherwise you will lost all your work.

Or try git pull --depth=2.

LitileXueZha
  • 512
  • 6
  • 11
0

I had same message when I was trying to edit last commit message, of already pushed commit, using: git commit --amend -m "New message" When I pushed the changes using git push --force-with-lease repo_name branch_name there were no issues.

LoveForDroid
  • 1,072
  • 12
  • 25
0

Met this problem when I created a branch based on branch A by

git checkout -b a

and then I set the up stream of branch a to origin branch B by

git branch -u origin/B

Then I got the error message above.

One way to solve this problem for me was,

  • Delete the branch a
  • Create a new branch b by
git checkout -b b origin/B
Shawn Wong
  • 554
  • 6
  • 15
0

Absolute solution to this problem is:

git push -f

This command will push your all changes to origin/your branch. No need to worry because you have all your commits that on the origin in your local branch.

Thank me later...

-1

In my case I got this message when I pushed X ver.1 commit from branch B to its remote-tracking branch remote_B.Then on my local repository I made changes and amend it to same commit ie.X ver.2.

Now we have commit X ver1 on remote repo and commit X ver.2 on local. Then git will show you warning that

Your local branch and remote_ have 1 and 1 different commits each, respectively

to solve this you have two option:

1.pull the changes from remote tracking branch .

git reset --hard HEAD
git checkout --track remoteRepoName/branch_name 

2.force push the amended commit to remote repo. (Only recommended if remote repo is not pulled by anyone after pushing the X ver1 commit)

git push -f remote_repo_name remote_branch_name
S G
  • 1
  • 5
  • couple things wrong here: 1. this would overwrite remote `master` with local `master`, thus erasing forever any collaborative work that hasn't been pulled to local. i think they wanted to re-combine a diverged branch, with multiple changes, not delete one in favour of the other. 2. you'd have to delete the branch for the `git checkout --track` command to work - it gives a warning if the branch already exists. – ChumiestBucket May 20 '22 at 14:56