¿Cómo selecciono una estrategia de fusión para un git rebase?

147

git-rebase-X<option>Se pueden pasar las menciones de la página man git-merge. ¿Cuándo / cómo exactamente?

Me gustaría volver a crear la base aplicando parches con una estrategia recursiva y su opción (aplique cualquier cosa, en lugar de omitir confirmaciones conflictivas completas). No quiero fusionarme, quiero hacer que la historia sea lineal.

He intentado:

git rebase -Xtheirs

y

git rebase -s 'recursive -Xtheirs'

pero git rechaza -Xen ambos casos.


git rebase -Xtheirsfunciona en versiones recientes, excepto que los conflictos de árbol deben resolverse manualmente. Debe ejecutar git rebase -Xtheirs --continue(con -Xrepetición) después de resolver esos conflictos.

Kornel
fuente
Nota: esto ahora funciona git rebase --interactivetambién con . Vea mi [respuesta actualizada a continuación ( stackoverflow.com/a/2945367/6309 ).
VonC

Respuestas:

231

Puede usar esto con Git v1.7.3 o versiones posteriores.

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

(que es una abreviatura de git rebase --strategy recursive --strategy-option theirs ${branch}lo indicado en la documentación )

Desde Git v1.7.3 Notas de la versión:

git rebase --strategy <s>aprendió la opción --strategy-option/ -Xpara pasar opciones adicionales que se entienden por la estrategia de fusión elegida.

NB: "Nuestro" y "suyo" significan lo contrario de lo que hacen durante una fusión directa. En otras palabras, "el suyo" favorece los commits en la rama actual .

Estoy loco
fuente
66
para aclarar: $ git rebase --estrategia recursiva -X de ellos
Gregg Lind
28
Cuando intento esto, el significado de oursy theirsparece ser lo contrario de lo que espero. Necesito usar theirspara favorecer mi rama actual.
Craig McQueen
19
@CraigMcQueen, cuando usa rebase, sus confirmaciones no publicadas (no eliminadas) se dejan de lado, la rama se alinea con la remota (reenvío rápido) y sus confirmaciones se reproducen en la parte superior de su rama. . Sus confirmaciones son "suyas" de acuerdo con la operación de fusión, y el estado actual (rápido) de la sucursal local es "nuestro". Puede parecer contradictorio, pero una vez que te das cuenta de lo que realmente está sucediendo, tiene sentido.
patrikbeno
66
@patrikbeno: Citando a Obi-Wan Kenobi, "Entonces, lo que te dije era cierto ... desde cierto punto de vista".
Craig McQueen
55
No estoy seguro de que valga la pena agregar, pero al menos en versiones relativamente actuales, la presencia de -Ximplica -s recursive, por lo que ahora puede usar solo git rebase ${branch} -X theirs. (fuente git-scm.com/docs/git-rebase#git-rebase--Xltstrategy-optiongt )
Matt Passell
20

Esto es para combinar estrategias que vienen con su propio conjunto de opciones

git rebase <branch> -s recursive -X theirs

debería funcionar, aunque este parche menciona (febrero de 2010):

La página de manual dice que git-rebaseadmite estrategias de fusión, pero el comando rebase no lo sabe -Xy proporciona el uso cuando se le presenta.

Entonces, si aún no funciona, ¡se está debatiendo ahora mismo!
(compatible con git reciente)


Actualización de commit db2b3b820e2b28da268cc88adff076b396392dfe (julio de 2013, git 1.8.4+),

No ignore las opciones de fusión en el rebase interactivo

La estrategia de fusión y sus opciones se pueden especificar en git rebase, pero con -- interactive, se ignoraron por completo.

Firmado por: Arnaud Fontaine

Eso significa que la -Xestrategia ahora funciona con rebase interactivo, así como rebase simple.

VonC
fuente
1
@porneL: eso pensé. De ahí mi enlace a la propuesta de parche.
VonC
@porneL: Sí, también he notado este error; espero que se solucione pronto, ya sea con ese parche o de otro modo, ya que todas las instalaciones básicas están ahí; solo tienen que decidir exactamente cómo se van a comunicar desde el rebase hasta la fusión.
Cascabel
@porneL: se incluyó en git 1.7.3. Si todavía eres un usuario de 1.7.1 como yo, hay una solución fácil,
mira
7

Como dijo iCrazy , esta función solo está disponible para git 1.7.3 en adelante. Entonces, para las almas pobres (como yo) que todavía usan 1.7.1, presento una solución que hice yo mismo:

git-rebase-suyo

Es un script muy bien pulido (y, por lo tanto, largo), destinado al uso de producción: opciones de interfaz de usuario, maneja múltiples archivos, verifica si el archivo realmente tiene marcadores de conflicto, etc., pero el "núcleo" podría resumirse en 2 líneas:

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

Y aquí está el guión completo:

#!/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
fuente
Gracias @VonC! No estoy seguro de por qué SO no codificó por colores el script bash. Un gran guión como este siempre es feo en sí mismo ... pero ser una gran masa de texto negro lo hace aún más feo: P
MestreLion
Se explica en stackoverflow.com/editing-help#syntax-highlighting . He agregado el código de idioma de prettify apropiado antes de su bloque de código. Debería verse mejor ahora.
VonC
Gracias @VonC! El resaltado de sintaxis de SO es realmente deficiente, pero es mucho mejor que nada. ¡Y eres extremadamente atento! Y, al ser LA autoridad de git en SO, puede interesarle otro script de ayuda: stackoverflow.com/a/10220276/624066 . Eso y mi cuenta de Github tienen herramientas que puedes disfrutar.
MestreLion
Para 1.7.1, esto parece funcionar para mí; No es necesario el script anterior. git rebase --strategy="recursive --theirs" master
Papadeltasierra
Perdón por ser un novato git, pero ¿cómo se usa el script git-rebase-theirs que se proporciona anteriormente? ¿Es una opción pasada de alguna manera a git-rebase o simplemente reduce el tiempo requerido para resolver conflictos manualmente?
Papadeltasierra