Just like git push --force allows overwriting remote branches, git fetch --force (or git pull --force ) allows overwriting local branches.
Usually git does not overwrite anything during merge.
You can use the git reset --merge command. You can also use the git merge --abort command. As always, make sure you have no uncommitted changes before you start a merge.
Not really related to this answer, but I'd ditch git pull
, which just runs git fetch
followed by git merge
. You are doing three merges, which is going to make your Git run three fetch operations, when one fetch is all you will need. Hence:
git fetch origin # update all our origin/* remote-tracking branches
git checkout demo # if needed -- your example assumes you're on it
git merge origin/demo # if needed -- see below
git checkout master
git merge origin/master
git merge -X theirs demo # but see below
git push origin master # again, see below
The most interesting part here is git merge -X theirs
. As root545 noted, the -X
options are passed on to the merge strategy, and both the default recursive
strategy and the alternative resolve
strategy take -X ours
or -X theirs
(one or the other, but not both). To understand what they do, though, you need to know how Git finds, and treats, merge conflicts.
A merge conflict can occur within some file1 when the base version differs from both the current (also called local, HEAD, or --ours
) version and the other (also called remote or --theirs
) version of that same file. That is, the merge has identified three revisions (three commits): base, ours, and theirs. The "base" version is from the merge base between our commit and their commit, as found in the commit graph (for much more on this, see other StackOverflow postings). Git has then found two sets of changes: "what we did" and "what they did". These changes are (in general) found on a line-by-line, purely textual basis. Git has no real understanding of file contents; it is merely comparing each line of text.
These changes are what you see in git diff
output, and as always, they have context as well. It's possible that things we changed are on different lines from things they changed, so that the changes seem like they would not collide, but the context has also changed (e.g., due to our change being close to the top or bottom of the file, so that the file runs out in our version, but in theirs, they have also added more text at the top or bottom).
If the changes happen on different lines—for instance, we change color
to colour
on line 17 and they change fred
to barney
on line 71—then there is no conflict: Git simply takes both changes. If the changes happen on the same lines, but are identical changes, Git takes one copy of the change. Only if the changes are on the same lines, but are different changes, or that special case of interfering context, do you get a modify/modify conflict.
The -X ours
and -X theirs
options tell Git how to resolve this conflict, by picking just one of the two changes: ours, or theirs. Since you said you are merging demo
(theirs) into master
(ours) and want the changes from demo
, you would want -X theirs
.
Blindly applying -X
, however, is dangerous. Just because our changes did not conflict on a line-by-line basis does not mean our changes do not actually conflict! One classic example occurs in languages with variable declarations. The base version might declare an unused variable:
int i;
In our version, we delete the unused variable to make a compiler warning go away—and in their version, they add a loop some lines later, using i
as the loop counter. If we combine the two changes, the resulting code no longer compiles. The -X
option is no help here since the changes are on different lines.
If you have an automated test suite, the most important thing to do is to run the tests after merging. You can do this after committing, and fix things up later if needed; or you can do it before committing, by adding --no-commit
to the git merge
command. We'll leave the details for all of this to other postings.
1You can also get conflicts with respect to "file-wide" operations, e.g., perhaps we fix the spelling of a word in a file (so that we have a change), and they delete the entire file (so that they have a delete). Git will not resolve these conflicts on its own, regardless of -X
arguments.
There are three merges in both of our command sequences. The first is to bring origin/demo
into the local demo
(yours uses git pull
which, if your Git is very old, will fail to update origin/demo
but will produce the same end result). The second is to bring origin/master
into master
.
It's not clear to me who is updating demo
and/or master
. If you write your own code on your own demo
branch, and others are writing code and pushing it to the demo
branch on origin
, then this first-step merge can have conflicts, or produce a real merge. More often than not, it's better to use rebase, rather than merge, to combine work (admittedly, this is a matter of taste and opinion). If so, you might want to use git rebase
instead. On the other hand, if you never do any of your own commits on demo
, you don't even need a demo
branch. Alternatively, if you want to automate a lot of this, but be able to check carefully when there are commits that both you and others, made, you might want to use git merge --ff-only origin/demo
: this will fast-forward your demo
to match the updated origin/demo
if possible, and simply outright fail if not (at which point you can inspect the two sets of changes, and choose a real merge or a rebase as appropriate).
This same logic applies to master
, although you are doing the merge on master
, so you definitely do need a master
. It is, however, even likelier that you would want the merge to fail if it cannot be done as a fast-forward non-merge, so this probably also should be git merge --ff-only origin/master
.
Let's say that you never do your own commits on demo
. In this case we can ditch the name demo
entirely:
git fetch origin # update origin/*
git checkout master
git merge --ff-only origin/master || die "cannot fast-forward our master"
git merge -X theirs origin/demo || die "complex merge conflict"
git push origin master
If you are doing your own demo
branch commits, this is not helpful; you might as well keep the existing merge (but maybe add --ff-only
depending on what behavior you want), or switch it to doing a rebase. Note that all three methods may fail: merge may fail with a conflict, merge with --ff-only
may not be able to fast-forward, and rebase may fail with a conflict (rebase works by, in essence, cherry-picking commits, which uses the merge machinery and hence can get a merge conflict).
I had a similar issue, where I needed to effectively replace any file that had changes / conflicts with a different branch.
The solution I found was to use git merge -s ours branch
.
Note that the option is -s
and not -X
. -s
denotes the use of ours
as a top level merge strategy, -X
would be applying the ours
option to the recursive
merge strategy, which is not what I (or we) want in this case.
Steps, where oldbranch
is the branch you want to overwrite with newbranch
.
git checkout newbranch
checks out the branch you want to keepgit merge -s ours oldbranch
merges in the old branch, but keeps all of our files.git checkout oldbranch
checks out the branch that you want to overwriteget merge newbranch
merges in the new branch, overwriting the old branchThis merge approach will add one commit on top of master
which pastes in whatever is in feature
, without complaining about conflicts or other crap.
git stash
git status # if anything shows up here, move it to your desktop
git checkout master
git pull # if there is a problem in this step, it is outside the scope of this answer
feature
all dressed upgit checkout feature
git merge --strategy=ours master
git checkout master
git merge --no-ff feature
You can try "ours" option in git merge,
git merge branch -X ours
This option forces conflicting hunks to be auto-resolved cleanly by favoring our version. Changes from the other tree that do not conflict with our side are reflected to the merge result. For a binary file, the entire contents are taken from our side.
demo
branch into master
git fetch --all
demo
branch on localgit pull origin demo
master
branch. This branch will be completely changed with the code on demo
branchgit checkout master
master
branch and run this command.git reset --hard origin/demo
reset
means you will be resetting current branch
--hard
is a flag that means it will be reset without raising any merge conflict
origin/demo
will be the branch that will be considered to be the code that will forcefully overwrite current master
branch
The output of the above command will show you your last commit message on origin/demo
or demo
branch
Then, in the end, force push the code on the master
branch to your remote repo.
git push --force
When I tried using -X theirs
and other related command switches I kept getting a merge commit. I probably wasn't understanding it correctly. One easy to understand alternative is just to delete the branch then track it again.
git branch -D <branch-name>
git branch --track <branch-name> origin/<branch-name>
This isn't exactly a "merge", but this is what I was looking for when I came across this question. In my case I wanted to pull changes from a remote branch that were force pushed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With