¿Git te obliga a realizar cambios en la punta? ¿Su inserción incluye esos files?

Con Mercurial, si intentas presionar y hubo confirmaciones hechas para el repository principal, te ves obligado a tirar y fusionar.

El problema es que, cuando va a confirmar los cambios, el set de cambios que inserta contiene files que se vio obligado a fusionar.

No tocaste estos files, pero el historial muestra cómo modificarlos.

¿Git tiene este mismo comportamiento? ¿O es lo suficientemente inteligente como para saber que no modificó esos files, por lo que no tiene sentido tener su historial?

Con Mercurial, si intentas presionar y hubo confirmaciones hechas para el repository principal, te ves obligado a tirar y fusionar.

Tanto Git como Mercurial funcionan esencialmente de la misma manera aquí. Cuando se hayan realizado nuevas confirmaciones en el repository remoto, git push abortará con:

 $ git push To /home/mg/tmp/git/repo-1 ! [rejected] master -> master (non-fast-forward) error: failed to push some refs to '/home/mg/tmp/git/repo-1' To prevent you from losing history, non-fast-forward updates were rejected Merge the remote changes (eg 'git pull') before pushing again. See the 'Note about fast-forwards' section of 'git push --help' for details. 

Mercurial también aborta en esta situación:

 $ hg push pushing to /home/mg/tmp/hg/repo-1 searching for changes abort: push creates new remote head 436b0ce25d42! (you should pull and merge or use push -f to force) 

Hasta aquí todo bien. En Git, ahora ejecutarás git pull y en Mercurial puedes ejecutar hg fetch . Esto recuperará y fusionará los nuevos sets de cambios y funcionará igual en ambos sistemas.

El problema es que, cuando va a confirmar los cambios, el set de cambios que inserta contiene files que se vio obligado a fusionar.

No tocaste estos files, pero el historial muestra cómo modificarlos.

Creo que estás malinterpretando lo que Mercurial te está mostrando. Ambos sistemas trabajan en instantáneas del repository completo, por lo que ambos sistemas lo obligarán a realizar cambios en los files que no tocó en la fusión. Una confirmación de fusión de Git también "contendrá" todos los files que no se modificaron; se hace reference a ellos a través del object de tree al que hace reference la confirmación.

Debido a que ambos sistemas usan instantáneas, la pregunta "¿quién modificó qué?" solo tiene sentido cuando se comparan dos instantáneas. Para un set de cambios de combinación, hay dos comparaciones interesantes: contra el primer padre y contra el segundo padre.

La diferencia entre Mercurial y Git es que no se muestra ningún parche para un set de cambios de combinación:

 $ git log -p -1 commit 8cdbbef1b6f0fc8e01997f6842b7f249d066a30c Merge: b77058e e99e303 Author: Martin Geisler <mg@aragost.com> Date: Mon Jan 23 14:09:09 2012 +0100 Merge branch 'master' of /home/mg/tmp/git/repo-1 

mientras que Mercurial siempre muestra un parche contra el primer padre:

 $ hg log -p -l 1 changeset: 3:94060588f0a5 tag: tip parent: 2:06d00ad5063b parent: 1:436b0ce25d42 user: Martin Geisler <mg@aragost.com> date: Mon Jan 23 14:01:25 2012 +0100 summary: Automated merge with file:///home/mg/tmp/hg/repo-1 diff --git a/bb/b new file mode 100644 --- /dev/null +++ b/b @@ -0,0 +1,1 @@ +b 

Esto muestra que el file b no estaba presente en el primer padre de la combinación. En otras palabras: probablemente proviene del segundo padre. Use hg diff -r "p2(3):3" o hg diff -r "3^2:3" para verificar esto. En Git git diff "8cdbbef^2" 8cdbbef para compararlo con el segundo padre.

Observe que ambos sistemas muestran lo mismo para git log b y hg log b : el set de cambios de fusión no está en el logging del file a less que el file haya sido modificado como parte del set de cambios de combinación. Los files se modifican normalmente en sets de cambios de combinación porque los conflictos deben resolverse antes de confirmar la fusión.

Es lo suficientemente inteligente como para saber. Sus confirmaciones son independientes de las confirmaciones fusionadas.

Git no mostrará esos en una vista de parche. Esto significa que los fusionó porque tenía que hacerlo, pero las confirmaciones que no son de fusión no mostrarán cambios en esos files. De hecho, git log -p que mostrará los commits y los parches para cada uno, no mostrará la fusión a less que haya conflictos.

Esta respuesta ha sido sustancialmente revisada después de una discusión detallada con @LaurensHolst.


Puede elegir include asignaciones de fusión o no. El valor pnetworkingeterminado para git es include las asignaciones de fusión. También puede configurar pull para utilizar rebase, que creará un historial lineal sin fusiones.

Las sucursales remotas se pueden configurar para volver a establecer la base en lugar de combinarlas:

 git config branch.<branch-name>.rebase true 

git puede configurar esto automáticamente usando

 git config [--global] branch.autosetuprebase always 

El uso de rebase para las asignaciones de fusión hace que las confirmaciones locales se realicen después de las confirmaciones remotas sin necesidad de una confirmación adicional. Esto proporciona una versión lineal de la historia. git le permite elegir qué historial prefiere.

Una respuesta y explicación similar se puede encontrar en los resultados de extracción de Git en posts extraños "Merge branch" en el logging de commit .

Si no tocó los files que se han modificado en el control remoto, entonces git no los mostrará como conflictos y no tendrá que fusionarlos. Entonces, no, no se mostrará como si hubieras tocado esos files si no lo has hecho.

Además, si no desea que la fusión se muestre en su historial, puede usar la opción --rebase cuando lo --rebase desde un control remoto (consulte man git-pull ).