Given a git repo with two branches master
and feature
. When rebasing the feature branch on top of master using rebase master
lets say that file a.txt
contains a conflict that needs to be resolved before the rebase can continue.
I know that I can resolve the conflict in three steps:
a.txt
in my editor manually resolve the conflictgit add a.txt
to tell git I have manually resolved the conflict git rebase --continue
move the rebase forwardIs there a way to avoid step 1 by telling git that I want the version of the file from the master branch or I want the version of the file from feature branch without having to do steps 1 and 2 above.
Yes. In fact, there's more than one way to do it.
The rebase and merge (and cherry-pick, for that matter) commands all take the same strategy
and -X
flags to pass to the underlying git merge machinery. For the recursive
strategy, -Xours
and -Xtheirs
choose one or the other "sides" of files in the case of a file modified in both branches being merged.
Or—this is quite different—in the cases when merge stops with a conflict, you can use git checkout
with the --ours
or --theirs
flags, to pick the version from one side or the other. (You can do this with other commands; here, I'll stick with --ours
and --theirs
as these match the arguments to the commands that use the merge machinery.)
This is of course different because you can switch up the choices:
$ git checkout main
Switched to branch 'main'
$ git merge branch
... conflicts in files A and B ...
$ git checkout --ours -- A # takes main:A
$ git checkout --theirs -- B # takes branch:B
Note that this is quite different from the "ours strategy" (the above shows the "recursive
strategy with the ours
option"). With the "ours strategy", something completely different occurs. Let's start without it, doing the same merge again:
$ git checkout main && git merge branch
... conflicts ...
$ git checkout --ours -- A B # take main:A and main:B
Let's say there's a third file, C
, that git can merge on its own. When you do the above, git merges C
and you take main:A
and main:B
. If you were to use git merge --strategy=ours branch
, though, git would take main:A
, main:B
, and main:C
. It would discard the branch:C
changes rather than automatically merging them.
I've used git merge
above because it makes the "ours" and "theirs" stuff "work right". I dislike the way git names these, though, because when you're doing a rebase, the ours/theirs version get swapped around, because rebase works by changing to the "other" branch and doing a series of cherry-picks. That is:
$ git checkout mine; git rebase theirs
works underneath by doing the (very) rough equivalent of:
$ git checkout theirs; git cherry-pick theirs..mine
and then afterward, shuffling the branch labels around so that branch theirs
does not actually move. (It's not nearly that bad internally :-) but it does manage to make --ours
mean "theirs" and --theirs
mean "ours", which is pretty bad externally.)
You can use:
git checkout --ours -- path/to/file
Or:
git checkout --theirs -- path/to/file
...during a merge or rebase to choose a particular version of a conflicting file; because rebasing is a little strange, --theirs
in this case would be feature
's version, --ours
would be master
's.
I believe that what you are looking for, which will get rid of all three steps, is
git rebase master -X theirs
which will automatically resolve conflicts in favour of feature
(the currently checked out branch), or
git rebase master -X ours
The sense of ours
and theirs
is counterintuitive as arguments to rebase, as noted in the description of the option at http://git-scm.com/docs/git-rebase
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