How do I select a merge strategy for a git rebase?
Solution 1
You can use this with Git v1.7.3 or later versions.
git rebase --strategy-option theirs ${branch} # Long option
git rebase -X theirs ${branch} # Short option
(which is a short for git rebase --strategy recursive --strategy-option theirs ${branch}
as stated by the documentation)
From Git v1.7.3 Release Notes:
git rebase --strategy <s>
learned the --strategy-option
/-X
option to pass extra options that are understood by the chosen merge strategy.
NB: "Ours" and "theirs" mean the opposite of what they do during a straight merge. In other words, "theirs" favors the commits on the current branch.
Solution 2
This is for merge strategies that come with their own set of options
git rebase <branch> -s recursive -X theirs
should work, although this patch mentions (February 2010):
The manpage says that
git-rebase
supports merge strategies, but the rebase command doesn't know about-X
, and gives the usage when presented with it.
So if it still doesn't work, it is being debated right now!
(supported in recent git)
Update from commit db2b3b820e2b28da268cc88adff076b396392dfe (July 2013, git 1.8.4+),
Do not ignore merge options in interactive rebase
Merge strategy and its options can be specified in
git rebase
, but with-- interactive
, they were completely ignored.Signed-off-by: Arnaud Fontaine
That means -X
and strategy now work with interactive rebase, as well as plain rebase.
Solution 3
As iCrazy said, this feature is only available for git 1.7.3 onwards. So, for the poor souls (like me) still using 1.7.1, I present a solution I did myself:
It is a very well-polished (and thus long) script, meant for production use: ui options, handles multiple files, check if file actually has conflict markers, etc, but the "core" could be summarized in 2 lines:
cp file file.bak
awk '/^<+ HEAD$/,/^=+$/{next} /^>+ /{next} 1' file.bak > file
And here is the full script:
#!/bin/bash
#
# git-rebase-theirs - Resolve rebase conflicts by favoring 'theirs' version
#
# Copyright (C) 2012 Rodrigo Silva (MestreLion) <[email protected]>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not see <http://www.gnu.org/licenses/gpl.html>
#Defaults:
verbose=0
backup=1
inplace=0
ext=".bak"
message() { printf "%s\n" "$1" >&2 ; }
skip() { message "skipping ${2:-$file}${1:+: $1}"; continue ; }
argerr() { printf "%s: %s\n" "$myname" "${1:-error}" >&2 ; usage 1 ; }
invalid() { argerr "invalid option: $1" ; }
missing() { argerr "missing${1:+ $1} operand." ; }
usage() {
cat <<- USAGE
Usage: $myname [options] [--] FILE...
USAGE
if [[ "$1" ]] ; then
cat >&2 <<- USAGE
Try '$myname --help' for more information.
USAGE
exit 1
fi
cat <<-USAGE
Resolve git rebase conflicts in FILE(s) by favoring 'theirs' version
When using git rebase, conflicts are usually wanted to be resolved
by favoring the <working branch> version (the branch being rebased,
'theirs' side in a rebase), instead of the <upstream> version (the
base branch, 'ours' side)
But git rebase --strategy -X theirs is only available from git 1.7.3
For older versions, $myname is the solution.
It works by discarding all lines between '<<<<<<< HEAD' and '========'
inclusive, and also the the '>>>>>> commit' marker.
By default it outputs to stdout, but files can be edited in-place
using --in-place, which, unlike sed, creates a backup by default.
Options:
-h|--help show this page.
-v|--verbose print more details in stderr.
--in-place[=SUFFIX] edit files in place, creating a backup with
SUFFIX extension. Default if blank is ""$ext"
--no-backup disables backup
Copyright (C) 2012 Rodrigo Silva (MestreLion) <[email protected]>
License: GPLv3 or later. See <http://www.gnu.org/licenses/gpl.html>
USAGE
exit 0
}
myname="${0##*/}"
# Option handling
files=()
while (( $# )); do
case "$1" in
-h|--help ) usage ;;
-v|--verbose ) verbose=1 ;;
--no-backup ) backup=0 ;;
--in-place ) inplace=1 ;;
--in-place=* ) inplace=1
suffix="${1#*=}" ;;
-* ) invalid "$1" ;;
-- ) shift ; break ;;
* ) files+=( "$1" ) ;;
esac
shift
done
files+=( "$@" )
(( "${#files[@]}" )) || missing "FILE"
ext=${suffix:-$ext}
for file in "${files[@]}"; do
[[ -f "$file" ]] || skip "not a valid file"
if ((inplace)); then
outfile=$(tempfile) || skip "could not create temporary file"
trap 'rm -f -- "$outfile"' EXIT
cp "$file" "$outfile" || skip
exec 3>"$outfile"
else
exec 3>&1
fi
# Do the magic :)
awk '/^<+ HEAD$/,/^=+$/{next} /^>+ /{next} 1' "$file" >&3
exec 3>&-
((inplace)) || continue
diff "$file" "$outfile" >/dev/null && skip "no conflict markers found"
((backup)) && { cp "$file" "$file$ext" || skip "could not backup" ; }
cp "$outfile" "$file" || skip "could not edit in-place"
((verbose)) && message "resolved ${file}"
done
Related videos on Youtube
Kornel
Mainly doing image compression R&D & web app development. Specialising in webby stuff (full stack), plus C and Rust. Developer of pngquant2, ImageOptim. Maintainer of MozJPEG, Sparkle, superagent. Has a GitHub. Really bad at filling bios.
Updated on October 19, 2020Comments
-
Kornel over 3 years
git-rebase
man page mentions-X<option>
can be passed togit-merge
. When/how exactly?I'd like to rebase by applying patches with recursive strategy and theirs option (apply whatever sticks, rather than skipping entire conflicting commits). I don't want merge, I want to make history linear.
I've tried:
git rebase -Xtheirs
and
git rebase -s 'recursive -Xtheirs'
but git rejects
-X
in both cases.
git rebase -Xtheirs
works in recent versions, except tree conflicts need to be resolved manually. You need to rungit rebase -Xtheirs --continue
(with-X
repeated) after resolving those conflicts.-
VonC almost 11 yearsNote: this now works with
git rebase --interactive
too. See my [updated answer below(stackoverflow.com/a/2945367/6309).
-
-
VonC about 14 years@porneL: I thought so. Hence my link to the patch proposal.
-
Cascabel about 14 years@porneL: Yeah, I've noticed this bug too - I expect it'll get addressed before long though, whether with that patch or otherwise, since all the basic facilities are there; they just have to decide exactly how they're going to communicate from rebase to merge.
-
Sakie about 13 yearsto clarify: $ git rebase --strategy recursive -X theirs
-
MestreLion about 12 years@iCrazy: so, is it
-X theirs
or-Xtheirs
? Usually arguments of 1-letter options are concatenated to the option itself.. is git different in this regard? -
MestreLion about 12 yearsAlso, for unfortunate git 1.7.1 users, check my answer for a solution
-
MestreLion about 12 years@porneL: it was included in git 1.7.3. If you're still a 1.7.1 user like me, there is an easy solution, check my answer below
-
MestreLion about 12 yearsThanks @VonC ! I'm just not sure why SO didn't color-coded the bash script. A big script like this is always ugly by itself... but being a huge mass of black text makes it even uglier :P
-
VonC about 12 yearsIt is explained in stackoverflow.com/editing-help#syntax-highlighting. I have added the appropriate prettify language code before your code block. It should look better now.
-
MestreLion about 12 yearsThanks @VonC! SO's syntax highlighting is really subpar, but it's waaaay better than nothing. And you are extremely thoughtful! And, being THE git authorithy in SO, you may be interested in yet another helper script: stackoverflow.com/a/10220276/624066 . That and my github account have tools you may enjoy.
-
Exectron about 9 yearsWhen I try this, the meaning of
ours
andtheirs
seems to be the opposite of what I expect. I need to usetheirs
to favour my current branch. -
patrikbeno over 8 years@CraigMcQueen, when using rebase, your unpublished (unpushed) commits are put aside, branch is aligned with remote (fast-forwarded), and your commits are being replayed on top of your branch. . Your commits are "theirs" according to merge operation, and current (fast-forwarded) state of local branch is "ours". May seem counterintuitive, but once you realize what is actually happening, it makes sense.
-
Exectron over 8 years@patrikbeno: To quote Obi-Wan Kenobi, "So what I told you was true... from a certain point of view."
-
Papadeltasierra over 8 yearsFor 1.7.1, this seems to work for me; no need for the script above.
git rebase --strategy="recursive --theirs" master
-
Papadeltasierra over 8 yearsSorry for being a git novice, but how does one use the git-rebase-theirs script given above? Is it an option somehow passed to git-rebase or does it just reduce the time required to manually resolve conflicts?
-
MestreLion over 8 years@Papadeltasierra : it just resolve the conflicts by automatically finding and replacing the conflict markers. Please note that this script was only useful for the now ancient git versions prior to 1.7.3. From 1.7.3 onwards you can simply use
git rebase -s recursive -X theirs <branch>
as iCrazy answered -
Matt Passell about 6 yearsI'm not sure that it's worth adding, but at least in relatively current versions, the presence of
-X
implies-s recursive
, so you can now use justgit rebase ${branch} -X theirs
. (source git-scm.com/docs/git-rebase#git-rebase--Xltstrategy-optiongt ) -
Alexandros about 5 yearsIs it possible to perform this action (resolve using theirs) in the middle of a rebase? i.e. I did "git rebase master", got some conflicts, do I need to abort and retry or can I "git resolve -Xtheirs" or something like that?
-
soMuchToLearnAndShare almost 4 years@CraigMcQueen, the reason the
"ours"
,"theirs"
appear to be opposite to what you expect, it is because, during rebase, git, under the hood, checkout the target branch, so that becomes'local/ours
' and your branch becomes'remote/theirs'
.