Herramienta sencilla para "aceptar el suyo" o "aceptar el mío" en un archivo completo usando git
No quiero una herramienta de combinación visual y tampoco quiero tener que visualizar el archivo en conflicto y elegir manualmente entre HEAD (mío) y el cambio importado (el de ellos). La mayoría de las veces quiero todos sus cambios o todos los míos. Comúnmente esto se debe a que mi cambio se hizo ascendente y regresa a mí a través de un tirón, pero puede modificarse ligeramente en varios lugares.
¿Existe una herramienta de línea de comando que elimine los marcadores de conflicto y elija todos de una forma u otra según mi elección? O un conjunto de comandos de git a los que puedo asignarles un alias para realizar cada uno de ellos.
# accept mine
alias am="some_sequence;of;commands"
alias at="some_other_sequence;of;commands"
Hacer esto es bastante molesto. Para 'aceptar el mío' he probado:
randy@sabotage ~/linus $ git merge test-branch
Auto-merging Makefile
CONFLICT (content): Merge conflict in Makefile
Automatic merge failed; fix conflicts and then commit the result.
randy@sabotage ~/linus $ git checkout Makefile
error: path 'Makefile' is unmerged
andy@sabotage ~/linus $ git reset --hard HEAD Makefile
fatal: Cannot do hard reset with paths.
¿Cómo se supone que voy a deshacerme de estos marcadores de cambio?
Puedo hacer:
git reset HEAD Makefile; rm Makefile; git checkout Makefile
Pero esto parece bastante indirecto, debe haber una manera mejor. Y en este punto, no estoy seguro de si git piensa siquiera que se produjo la fusión, así que no creo que esto necesariamente funcione.
En el otro sentido, "aceptar lo suyo" es igualmente complicado. La única forma en que puedo resolverlo es haciendo:
git show test-branch:Makefile > Makefile; git add Makefile;
Esto también me da un mensaje de confirmación desordenado, que tiene Conflictos: Makefile dos veces.
¿Alguien puede indicarme cómo realizar las dos acciones anteriores de una manera más sencilla? Gracias
La solución es muy simple. git checkout <filename>
intenta extraer el archivo del índice y, por lo tanto, falla al fusionarlo.
Lo que debe hacer es (es decir, verificar un compromiso ):
Para comprobar su propia versión, puede utilizar una de:
git checkout HEAD -- <filename>
o
git checkout --ours -- <filename>
(¡Advertencia!: Si está cambiando la base --ours
y --theirs
lo intercambian).
o
git show :2:<filename> > <filename> # (stage 2 is ours)
Para pagar la otra versión , puede utilizar una de:
git checkout test-branch -- <filename>
o
git checkout --theirs -- <filename>
o
git show :3:<filename> > <filename> # (stage 3 is theirs)
También necesitarás ejecutar 'agregar' para marcarlo como resuelto:
git add <filename>
Prueba esto:
- Para aceptar sus cambios:
git merge --strategy-option theirs
- Para aceptar sus cambios:
git merge --strategy-option ours
Según la respuesta de Jakub, puede configurar los siguientes alias de git para mayor comodidad:
accept-ours = "!f() { git checkout --ours -- \"${@:-.}\"; git add -u \"${@:-.}\"; }; f"
accept-theirs = "!f() { git checkout --theirs -- \"${@:-.}\"; git add -u \"${@:-.}\"; }; f"
Opcionalmente, toman una o varias rutas de archivos para resolver y, de forma predeterminada, resuelven todo en el directorio actual si no se proporciona ninguna.
Agréguelos a la [alias]
sección de su ~/.gitconfig
o ejecute
git config --global alias.accept-ours '!f() { git checkout --ours -- "${@:-.}"; git add -u "${@:-.}"; }; f'
git config --global alias.accept-theirs '!f() { git checkout --theirs -- "${@:-.}"; git add -u "${@:-.}"; }; f'
Según la respuesta de Kynan, aquí están los mismos alias, modificados para que puedan manejar espacios y guiones iniciales en los nombres de archivos:
accept-ours = "!f() { [ -z \"$@\" ] && set - '.'; git checkout --ours -- \"$@\"; git add -u -- \"$@\"; }; f"
accept-theirs = "!f() { [ -z \"$@\" ] && set - '.'; git checkout --theirs -- \"$@\"; git add -u -- \"$@\"; }; f"
La situación ideal para resolver conflictos es cuando sabes de antemano de qué manera quieres resolverlos y puedes pasar las -Xours
opciones -Xtheirs
de estrategia de fusión recursiva. Fuera de esto puedo ver tres escenarios:
- Solo desea conservar una única versión del archivo (esto probablemente solo debería usarse en archivos binarios no fusionables, ya que de lo contrario, los archivos en conflicto y no en conflicto pueden no estar sincronizados entre sí).
- Simplemente desea decidir todos los conflictos en una dirección particular.
- Debe resolver algunos conflictos manualmente y luego resolver el resto en una dirección particular.
Para abordar estos tres escenarios, puede agregar las siguientes líneas a su .gitconfig
archivo (o equivalente):
[merge]
conflictstyle = diff3
[mergetool.getours]
cmd = git-checkout --ours ${MERGED}
trustExitCode = true
[mergetool.mergeours]
cmd = git-merge-file --ours ${LOCAL} ${BASE} ${REMOTE} -p > ${MERGED}
trustExitCode = true
[mergetool.keepours]
cmd = sed -i '' -e '/^<<<<<<</d' -e '/^|||||||/,/^>>>>>>>/d' ${MERGED}
trustExitCode = true
[mergetool.gettheirs]
cmd = git-checkout --theirs ${MERGED}
trustExitCode = true
[mergetool.mergetheirs]
cmd = git-merge-file --theirs ${LOCAL} ${BASE} ${REMOTE} -p > ${MERGED}
trustExitCode = true
[mergetool.keeptheirs]
cmd = sed -i '' -e '/^<<<<<<</,/^=======/d' -e '/^>>>>>>>/d' ${MERGED}
trustExitCode = true
La get(ours|theirs)
herramienta simplemente mantiene la versión respectiva del archivo y descarta todos los cambios de la otra versión (para que no se produzca ninguna fusión).
La merge(ours|theirs)
herramienta vuelve a realizar la combinación de tres vías desde las versiones local, base y remota del archivo, eligiendo resolver los conflictos en la dirección indicada. Esto tiene algunas advertencias, específicamente: ignora las opciones de diferenciación que se pasaron al comando de combinación (como el algoritmo y el manejo de espacios en blanco); fusiona limpiamente los archivos originales (por lo que se descarta cualquier cambio manual en el archivo, que podría ser bueno o malo); y tiene la ventaja de que no puede confundirse con los marcadores de diferencias que se supone que están en el archivo.
La keep(ours|theirs)
herramienta simplemente edita los marcadores de diferencias y las secciones adjuntas, detectándolas mediante expresiones regulares. Esto tiene la ventaja de que conserva las opciones de diferenciación del comando de combinación y le permite resolver algunos conflictos manualmente y luego resolver automáticamente el resto. Tiene la desventaja de que si hay otros marcadores de conflicto en el archivo podría confundirse.
Todos estos se utilizan al ejecutar git mergetool -t (get|merge|keep)(ours|theirs) [<filename>]
donde, si <filename>
no se proporcionan, procesa todos los archivos en conflicto.
En términos generales, suponiendo que sepa que no hay marcadores de diferencias que confundan la expresión regular, las keep*
variantes del comando son las más poderosas. Si deja la mergetool.keepBackup
opción sin configurar o verdadera, después de la combinación puede comparar el *.orig
archivo con el resultado de la combinación para comprobar que tiene sentido. Como ejemplo, ejecuto lo siguiente después de mergetool
just para inspeccionar los cambios antes de confirmarlos:
for f in `find . -name '*.orig'`; do vimdiff $f ${f%.orig}; done
Nota : Si merge.conflictstyle
no es así diff3
, entonces el /^|||||||/
patrón de la sed
regla debe serlo /^=======/
.