Comment sélectionner une stratégie de fusion pour un rebase git?

147

git-rebaseles mentions de page de manuel -X<option>peuvent être transmises git-merge. Quand / comment exactement?

Je voudrais rebase en appliquant des correctifs avec une stratégie récursive et leur option (appliquez n'importe quel bâton, plutôt que de sauter des commits entiers en conflit). Je ne veux pas de fusion, je veux rendre l'histoire linéaire.

J'ai essayé:

git rebase -Xtheirs

et

git rebase -s 'recursive -Xtheirs'

mais git rejette -Xdans les deux cas.


git rebase -Xtheirsfonctionne dans les versions récentes, sauf que les conflits d'arborescence doivent être résolus manuellement. Vous devez exécuter git rebase -Xtheirs --continue(avec -Xrépété) après avoir résolu ces conflits.

Kornel
la source
Remarque: cela fonctionne maintenant git rebase --interactiveaussi avec . Voir ma [réponse mise à jour ci-dessous ( stackoverflow.com/a/2945367/6309 ).
VonC le

Réponses:

231

Vous pouvez l'utiliser avec Git v1.7.3 ou versions ultérieures.

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

(qui est un court pour git rebase --strategy recursive --strategy-option theirs ${branch}comme indiqué par la documentation )

À partir des notes de version de Git v1.7.3:

git rebase --strategy <s>appris l' option --strategy-option/ -Xpour passer des options supplémentaires qui sont comprises par la stratégie de fusion choisie.

NB: «Les nôtres» et «les leurs» signifient le contraire de ce qu'ils font lors d'une fusion directe. En d'autres termes, "leur" favorise les commits sur la branche courante .

je suis fou
la source
6
pour clarifier: $ git rebase --strategy recursive -X theirs
Gregg Lind
28
Quand j'essaye ceci, la signification de ourset theirssemble être le contraire de ce que j'attends. Je dois utiliser theirspour favoriser ma branche actuelle.
Craig McQueen
19
@CraigMcQueen, lorsque vous utilisez rebase, vos commits non publiés (non repoussés) sont mis de côté, la branche est alignée sur remote (avance rapide) et vos commits sont rejoués au-dessus de votre branche. . Vos commits sont "les leurs" selon l'opération de fusion, et l'état actuel (avance rapide) de la branche locale est "le nôtre". Cela peut sembler contre-intuitif, mais une fois que vous réalisez ce qui se passe réellement, cela a du sens.
patrikbeno
6
@patrikbeno: Pour citer Obi-Wan Kenobi, "Donc ce que je vous ai dit était vrai ... d'un certain point de vue."
Craig McQueen
5
Je ne suis pas sûr que cela vaille la peine d'être ajouté, mais au moins dans les versions relativement récentes, la présence de -Ximplique -s recursive, donc vous pouvez maintenant utiliser juste git rebase ${branch} -X theirs. (source git-scm.com/docs/git-rebase#git-rebase--Xltstrategy-optiongt )
Matt Passell
20

Ceci est pour les stratégies de fusion qui viennent avec leur propre ensemble d'options

git rebase <branch> -s recursive -X theirs

devrait fonctionner, bien que ce patch mentionne (février 2010):

La page de manuel indique que git-rebaseprend en charge les stratégies de fusion, mais la commande rebase ne le sait pas -Xet donne l'utilisation lorsqu'elle est présentée.

Donc si ça ne marche toujours pas, ça fait débat en ce moment!
(pris en charge dans git récent)


Mise à jour du commit db2b3b820e2b28da268cc88adff076b396392dfe (juillet 2013, git 1.8.4+),

N'ignorez pas les options de fusion dans le rebase interactif

La stratégie de fusion et ses options peuvent être spécifiées dans git rebase, mais avec -- interactive, elles ont été complètement ignorées.

Signé par: Arnaud Fontaine

Cela signifie -Xque la stratégie fonctionne désormais avec le rebase interactif, ainsi que le rebase simple.

VonC
la source
1
@porneL: Je le pensais. D'où mon lien vers la proposition de patch.
VonC
@porneL: Ouais, j'ai aussi remarqué ce bogue - je pense qu'il sera bientôt résolu, que ce soit avec ce patch ou autrement, puisque toutes les installations de base sont là; il leur suffit de décider exactement comment ils vont communiquer de rebase à fusion.
Cascabel
@porneL: il a été inclus dans git 1.7.3. Si vous êtes toujours un utilisateur 1.7.1 comme moi, il existe une solution simple, vérifiez ma réponse ci
MestreLion
7

Comme l'a dit iCrazy , cette fonctionnalité n'est disponible qu'à partir de git 1.7.3. Donc, pour les pauvres âmes (comme moi) utilisant toujours 1.7.1, je présente une solution que j'ai faite moi-même:

git-rebase-leur

C'est un script très soigné (et donc long), destiné à une utilisation en production: options d'interface utilisateur, gère plusieurs fichiers, vérifie si le fichier a réellement des marqueurs de conflit, etc., mais le "noyau" peut être résumé en 2 lignes:

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

Et voici le script complet:

#!/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
la source
Merci @VonC! Je ne sais pas pourquoi SO n'a pas codé en couleur le script bash. Un gros script comme celui-ci est toujours moche en soi ... mais être une énorme masse de texte noir le rend encore plus laid: P
MestreLion
Cela est expliqué dans stackoverflow.com/editing-help#syntax-highlighting . J'ai ajouté le code de langue prettify approprié avant votre bloc de code. Ça devrait être mieux maintenant.
VonC
Merci @VonC! La coloration syntaxique de SO est vraiment médiocre, mais c'est mieux que rien. Et vous êtes extrêmement attentionné! Et, étant LA autorité git dans SO, vous pourriez être intéressé par un autre script d'aide: stackoverflow.com/a/10220276/624066 . Cela et mon compte github ont des outils dont vous pouvez profiter.
MestreLion
Pour 1.7.1, cela semble fonctionner pour moi; pas besoin du script ci-dessus. git rebase --strategy="recursive --theirs" master
Papadeltasierra
Désolé d'être un novice git, mais comment utiliser le script git-rebase-theirs donné ci-dessus? Est-ce une option passée en quelque sorte à git-rebase ou cela réduit-il simplement le temps nécessaire pour résoudre manuellement les conflits?
Papadeltasierra