Reputation: 7940
I'm afraid this must have been asked thousands of times but I haven't found it anywhere and it happens to me all the time.
At work, when I try to pull the latest commits on the branch that I currently have checked out, I get conflict errors. This happens to me even if I haven't made any changes to the branch.
So I end up deleting my local branch and fetching the branch as if it were brand new.
This is an example of what I'm describing:
➜ my_project git:(foo_branch) ✗ git pull
From github.com:Blabla/my_project
+ c6a6ccf...39052a7 foo_branch -> origin/foo_branch (forced update)
+ aa9d3a9...22cdf8c development -> origin/development (forced update)
* [new branch] docs/DE3802 -> origin/docs/DE3802
0b2ed86..1256c5c docs/US16862 -> origin/docs/US16862
15a755b..8a3ebdd master -> origin/master
Auto-merging cloudformation/appsync/schema.graphql
CONFLICT (add/add): Merge conflict in my_project/media/clients/foo/file_1
Auto-merging my_project/media/clients/foo/policy_coverages
Auto-merging my_project/apps/engine/tests/test_functions.py
CONFLICT (content): Merge conflict in my_project/apps/engine/tests/test_functions.py
Auto-merging my_project/apps/engine/functions.py
CONFLICT (content): Merge conflict in my_project/apps/engine/functions.py
Auto-merging my_project/apps/engine/defaults.py
CONFLICT (content): Merge conflict in my_project/apps/engine/defaults.py
Automatic merge failed; fix conflicts and then commit the result.
How can I just pull the latest changes in the branch and make them overwrite the older version I have?
Upvotes: 1
Views: 1450
Reputation: 165218
Someone has been altering history and force pushing their branches.
tl;dr: Don't make local branches unless you need to make changes. Instead of creating and checking out foo_branch
, checkout origin/foo_branch
.
tl;dr: Use git pull --rebase
to replay your local changes on top of the remote branch. I recommend rebasing all pulls. It is safe. You can do so by adding this to your .gitconfig
.
[pull]
rebase = merges
A git pull
is a git fetch
plus a git merge
. The first portion of the git pull
is a record of the git fetch
portion to update your remote tracking branches.
From github.com:Blabla/my_project
+ c6a6ccf...39052a7 foo_branch -> origin/foo_branch (forced update)
+ aa9d3a9...22cdf8c development -> origin/development (forced update)
* [new branch] docs/DE3802 -> origin/docs/DE3802
0b2ed86..1256c5c docs/US16862 -> origin/docs/US16862
15a755b..8a3ebdd master -> origin/master
Let's focus on just foo_branch
.
+ c6a6ccf...39052a7 foo_branch -> origin/foo_branch (forced update)
This says that the remote branch foo_branch
is being tracked locally in origin/foo_branch
. You had origin/foo_branch
at c6a6ccf
. The fetch moved it to 39052a7
. +
, (forced_update)
and ...
indicate it was not a "fast-forward".
A "fast-forward" is when a branch can be updated with no merge. For example...
A - B - C [master]
\
D - E [feature]
If we git merge feature
into master there is no need for a merge, Git will simply move the master
label to the same commit as feature
.
$ git merge feature
# Fast forward master from C to E.
A - B - C - D - E [master]
[feature]
OTOH if master had changes, a merge would be necessary to combine both the changes in feature with the new changes in master.
A - B - C - F [master]
\
D - E [feature]
$ git merge feature
A - B - C - F - G [master]
\ /
D - E [feature]
Normally, git fetch
is a fast forward. origin/foo_branch
is a snapshot of your last git fetch
. You should have no additional changes to origin/foo_branch
so any new changes can be fast forwarded. Here's what that might look like. Remember, a git pull origin foo_branch
is a git fetch origin
and git merge foo_branch origin/foo_branch
.
origin
A - B - C - D - E [foo_branch]
local
A - B - C [foo_branch]
[origin/foo_branch]
$ git fetch origin
local
A - B - C [foo_branch]
\
D - E [origin/foo_branch]
$ git merge foo_branch origin/foo_branch
# Fast-forward foo_branch from C to E.
A - B - C - D - E [origin/foo_branch]
But what happens if someone rebases foo_branch
and does a force push?
origin
A - B1 - C1 - D - E [foo_branch]
local
A - B - C [foo_branch]
[origin/foo_branch]
$ git fetch origin
local
A - B1 - C1 - D - E [origin/foo_branch]
\
B - C [foo_branch]
B1 and C1 represent rebased commits. After the fetch foo_branch
and origin/foo_branch
have "diverged". The next part of git pull
cannot fast-forward and requires a merge.
$ git merge foo_branch origin/foo_branch
local
A - B1 - C1 - D - E [origin/foo_branch]
\ \
B - C ------------ M [foo_branch]
Even though there were no local changes to foo_branch
, there are likely to be conflicts between B and B1 and C and C1.
So, what to do about it.
First, don't make local branches if you don't need to make local changes. Instead of making a local foo_branch
, reference origin/foo_branch
. Then there is no local branch to fall out of sync.
Second, change git pull
so it does a rebase instead of a merge. You can do this individually with git pull --rebase
and globally by setting pull.rebase
to merges
.
Going back to our example above where foo_branch
and origin/foo_branch
have diverged after foo_branch
was remotely rebased...
origin
A - B1 - C1 - D - E [foo_branch]
local
A - B - C [foo_branch]
[origin/foo_branch]
git pull --rebase
will not attempt a merge. It will instead rebase your local changes to foo_branch
on top of the new origin/foo_branch
. There are no local changes, so foo_branch
is simply brought up to date with the new origin/foo_branch
.
local
A - B1 - C1 - D - E [foo_branch]
[origin/foo_branch]
If you did have changes, they would be replayed on top of the new origin/foo_branch
.
origin
A - B1 - C1 - D - E [foo_branch]
local
A - B - C [origin/foo_branch]
\
F - G [foo_branch]
$ git pull --rebase
local
A - B1 - C1 - D - E [origin/foo_branch]
\
F - G [foo_branch]
Third, discuss procedures around forced pushes with other members of your project.
Upvotes: 3