Wie wähle ich eine Zusammenführungsstrategie für eine Git-Rebase aus?

147

git-rebaseManpage-Erwähnungen -X<option>können an übergeben werden git-merge. Wann / wie genau?

Ich mag durch Einspielen von Patches mit rebase rekursive Strategie und ihrer Option (anzuwenden , ohne Stöcke, anstatt ganze widersprüchliche Commits Skipping). Ich möchte nicht zusammenführen, ich möchte die Geschichte linear machen.

Ich habe es versucht:

git rebase -Xtheirs

und

git rebase -s 'recursive -Xtheirs'

aber git lehnt -Xin beiden fällen ab .


git rebase -Xtheirsfunktioniert in neueren Versionen, außer dass Baumkonflikte manuell gelöst werden müssen. Sie müssen git rebase -Xtheirs --continue(mit -Xwiederholten) ausführen, nachdem Sie diese Konflikte gelöst haben.

Kornel
quelle
Hinweis: Dies funktioniert jetzt auch mit git rebase --interactive. Siehe meine [aktualisierte Antwort unten ( stackoverflow.com/a/2945367/6309 ).
VonC

Antworten:

229

Sie können dies mit Git v1.7.3 oder höheren Versionen verwenden.

git rebase --strategy-option theirs ${branch} # Long option
git rebase -X theirs ${branch} # Short option

(Dies ist eine Abkürzung für, git rebase --strategy recursive --strategy-option theirs ${branch}wie in der Dokumentation angegeben )

Von Git v1.7.3 Versionshinweise:

git rebase --strategy <s>lernte die Option --strategy-option/ -X, um zusätzliche Optionen zu übergeben, die von der gewählten Zusammenführungsstrategie verstanden werden.

NB: "Unsere" und "ihre" bedeuten das Gegenteil von dem, was sie während einer direkten Zusammenführung tun. Mit anderen Worten, "ihre" begünstigen die Commits für den aktuellen Zweig.

iCrazy
quelle
6
zur Verdeutlichung: $ git Rebase - Strategie rekursiv -X ihre
Gregg Lind
28
Wenn ich das versuche, ist die Bedeutung von oursund theirsscheint das Gegenteil von dem zu sein, was ich erwarte. Ich muss verwenden, theirsum meine aktuelle Niederlassung zu bevorzugen.
Craig McQueen
19
@CraigMcQueen Wenn Sie rebase verwenden, werden Ihre unveröffentlichten (nicht gepushten) Commits beiseite gelegt, die Verzweigung wird an der Fernbedienung ausgerichtet (schneller Vorlauf) und Ihre Commits werden über Ihrer Verzweigung wiedergegeben. . Ihre Commits gehören je nach Zusammenführungsvorgang "ihnen", und der aktuelle (schnell vorgeleitete) Status der lokalen Niederlassung ist "unser". Mag kontraintuitiv erscheinen, aber sobald Sie erkennen, was tatsächlich passiert, macht es Sinn.
Patrikbeno
6
@patrikbeno: Um Obi-Wan Kenobi zu zitieren: "Also, was ich dir gesagt habe, war wahr ... von einem bestimmten Standpunkt aus."
Craig McQueen
5
Ich bin mir nicht sicher, ob es sich lohnt, etwas hinzuzufügen, aber zumindest in relativ aktuellen Versionen -Ximpliziert das Vorhandensein von -s recursive, so dass Sie jetzt nur verwenden können git rebase ${branch} -X theirs. (Quelle git-scm.com/docs/git-rebase#git-rebase--Xltstrategy-optiongt )
Matt Passell
20

Dies gilt für Zusammenführungsstrategien, die über eigene Optionen verfügen

git rebase <branch> -s recursive -X theirs

sollte funktionieren, obwohl dieser Patch erwähnt (Februar 2010):

Die Manpage sagt, dass git-rebaseZusammenführungsstrategien unterstützt werden, aber der Befehl rebase weiß nichts darüber -Xund gibt die Verwendung an, wenn er angezeigt wird .

Wenn es also immer noch nicht funktioniert, wird es gerade diskutiert!
(unterstützt im letzten Git)


Update von Commit db2b3b820e2b28da268cc88adff076b396392dfe (Juli 2013, Git 1.8.4+),

Ignorieren Sie die Zusammenführungsoptionen in der interaktiven Rebase nicht

Die Zusammenführungsstrategie und ihre Optionen können in angegeben werden git rebase, mit -- interactivewurden sie jedoch vollständig ignoriert.

Unterzeichnet von: Arnaud Fontaine

Das bedeutet, dass -XStrategie und Strategie jetzt sowohl mit interaktiver als auch mit einfacher Rebase funktionieren.

VonC
quelle
1
@porneL: Das dachte ich mir. Daher mein Link zum Patch-Vorschlag.
VonC
@porneL: Ja, ich habe diesen Fehler auch bemerkt - ich gehe davon aus, dass er in Kürze behoben wird, ob mit diesem Patch oder auf andere Weise, da alle grundlegenden Funktionen vorhanden sind. Sie müssen nur genau entscheiden, wie sie von Rebase bis Merge kommunizieren.
Cascabel
@porneL: Es war in Git 1.7.3 enthalten. Wenn Sie immer noch ein 1.7.1-Benutzer wie ich sind, gibt es eine einfache Lösung. Überprüfen Sie meine Antwort unten
MestreLion
7

Wie iCrazy sagte, ist diese Funktion nur für Git 1.7.3 verfügbar. Für die armen Seelen (wie ich), die immer noch 1.7.1 verwenden, präsentiere ich eine Lösung, die ich selbst gemacht habe:

Git-Rebase-ihre

Es ist ein sehr ausgefeiltes (und damit langes) Skript, das für die Verwendung in der Produktion gedacht ist: UI-Optionen, verarbeitet mehrere Dateien, prüft, ob die Datei tatsächlich Konfliktmarkierungen enthält usw. Der "Kern" kann jedoch in zwei Zeilen zusammengefasst werden:

cp file file.bak
awk '/^<+ HEAD$/,/^=+$/{next} /^>+ /{next} 1' file.bak > file

Und hier ist das vollständige Skript:

#!/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
MestreLion
quelle
Danke @VonC! Ich bin mir nur nicht sicher, warum SO das Bash-Skript nicht farbcodiert hat. Ein großes Skript wie dieses ist an sich immer hässlich ... aber eine riesige Menge schwarzen Textes macht es noch hässlicher: P
MestreLion
Dies wird unter stackoverflow.com/editing-help#syntax-highlighting erläutert . Ich habe den entsprechenden Prettify-Sprachcode vor Ihrem Codeblock hinzugefügt. Es sollte jetzt besser aussehen.
VonC
Danke @VonC! Die Syntaxhervorhebung von SO ist wirklich unterdurchschnittlich, aber es ist besser als nichts. Und du bist sehr nachdenklich! Und als DIE Git-Autorität in SO könnten Sie an einem weiteren Hilfsskript interessiert sein: stackoverflow.com/a/10220276/624066 . Das und mein Github-Account haben Tools, die Ihnen gefallen können.
MestreLion
Für 1.7.1 scheint dies für mich zu funktionieren; Das obige Skript ist nicht erforderlich. git rebase --strategy="recursive --theirs" master
Papadeltasierra
Tut mir leid, dass ich ein Git-Neuling bin, aber wie benutzt man das oben angegebene Git-Rebase-Heres-Skript? Ist es eine Option, die irgendwie an git-rebase übergeben wurde, oder reduziert sie nur die Zeit, die zum manuellen Lösen von Konflikten erforderlich ist?
Papadeltasierra