How do I select a merge strategy for a git rebase?

102,842

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:

git-rebase-theirs

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
Share:
102,842

Related videos on Youtube

Kornel
Author by

Kornel

Mainly doing image compression R&amp;D &amp; 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, 2020

Comments

  • Kornel
    Kornel over 3 years

    git-rebase man page mentions -X<option> can be passed to git-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 run git rebase -Xtheirs --continue (with -X repeated) after resolving those conflicts.

  • VonC
    VonC about 14 years
    @porneL: I thought so. Hence my link to the patch proposal.
  • Cascabel
    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
    Sakie about 13 years
    to clarify: $ git rebase --strategy recursive -X theirs
  • MestreLion
    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
    MestreLion about 12 years
    Also, for unfortunate git 1.7.1 users, check my answer for a solution
  • MestreLion
    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
    MestreLion about 12 years
    Thanks @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
    VonC about 12 years
    It 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
    MestreLion about 12 years
    Thanks @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
    Exectron about 9 years
    When I try this, the meaning of ours and theirs seems to be the opposite of what I expect. I need to use theirs to favour my current branch.
  • patrikbeno
    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
    Exectron over 8 years
    @patrikbeno: To quote Obi-Wan Kenobi, "So what I told you was true... from a certain point of view."
  • Papadeltasierra
    Papadeltasierra over 8 years
    For 1.7.1, this seems to work for me; no need for the script above. git rebase --strategy="recursive --theirs" master
  • Papadeltasierra
    Papadeltasierra over 8 years
    Sorry 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
    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
    Matt Passell about 6 years
    I'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 just git rebase ${branch} -X theirs. (source git-scm.com/docs/git-rebase#git-rebase--Xltstrategy-optiongt )
  • Alexandros
    Alexandros about 5 years
    Is 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
    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'.