tool portable online mac configurar git meld

portable - Git Rebase Conflict: ¿Quién es HEAD?



meld portable windows (2)

Definiciones

En esta sección vamos a ver las deficiones que nos piden en respuesta:

¿Quién es HEAD?

HEAD : el compromiso actual tu repo está activado . La mayoría de las veces, HEAD apunta al último compromiso en su sucursal, pero ese no es el caso. HEAD realmente solo significa "a qué apunta mi repo actualmente".

En el caso de que se HEAD referencia a la HEAD confirmación no es la punta de ninguna rama, esto se denomina " detached head ".

¿Es la CABEZA de la rama del desarrollo?

En el momento en que se realiza una fusión o rebase, el HEAD pasa inmediatamente a la confirmación creada o refactorizada y, por lo tanto, apunta a la rama de desarrollo .

En git bash podemos ver la situación de HEAD , listando commit:

# Normal commit list git log # List of commit in a single line git log --oneline # All commits graphically-linear (Recommended as alias) git log --all --graph --decorate --oneline

Práctica

En esta sección veremos el _how_ trabaja algunas acciones realizadas por el usuario.

Cuando el usuario procede a:

# Command to change from the branch to the current one to experimentalbranch git checkout experimentalbranch # Command that traverses the typical workflow to synchronize its local repository with the main branch of the central repository (remoterepo) git fetch remoterepo # git fetch origin # git fetch origin branch:branch # With the command git rebase, you can take all the changes confirmed in one branch (remoterepo), and reapply them over another developmentbranch git rebase remoterepo/developmentbranch

En este momento, llego a los conflictos. Sin embargo, no estoy familiarizado con ninguno de estos cambios (estoy reajustando semanas en cambios, porque no fusionaron mis cambios inmediatamente). Además, es mi primera vez haciendo rebase. Estoy más acostumbrado a fusionarme.

La unión de ramas se realiza de dos maneras:

  • git merge

  • git rebase.

Nota :

Para los ejemplos usaremos el siguiente árbol :

* a122f6d (HEAD -> remoterepo) Commit END * 9667bfb Commit MASTER | * b9bcaf0 (origin/experimentalbranch, experimentalbranch) Commit 3 | * 110b2fb Commit 2 | * e597c60 Commit 1 |/ * 0e834f4 (origin/remoterepo) First commit

git merge

La forma más conocida es git merge , que realiza una fusión de tres bandas entre las dos últimas instantáneas de cada rama y el ancestro común de ambas, creando una nueva confirmación con cambios mixtos.

Por ejemplo :

git checkout remoterepo git merge experimentalbranch

Nos produciría:

* 003e576 (HEAD -> remoterepo) Merge branch ''experimentalbranch'' in remoterepo |/ | * b9bcaf0 (origin/experimentalbranch, experimentalbranch) Commit 3 | * 110b2fb Commit 2 | * e597c60 Commit 1 * | a122f6d Commit END * | 9667bfb Commit MASTER |/ * 0e834f4 (origin/remoterepo) First commit

git rebase

git rebase básicamente lo que hace es recopilar uno por uno los cambios confirmados en una rama y volver a aplicarlos en otra .

El uso de rebase puede ayudarnos a evitar conflictos siempre que se aplique a confirmaciones locales que no se hayan cargado en ningún repositorio remoto . Si no es cuidadoso con este último y un compañero usa los cambios afectados, asegúrese de que tendrá problemas, ya que estos tipos de conflictos suelen ser difíciles de reparar .

Por ejemplo :

git checkout remoterepo git rebase experimentalbranch * f8a74be (HEAD -> remoterepo) Commit END * 4293e9d Commit MASTER * b9bcaf0 (origin/experimentalbranch, experimentalbranch) Commit 3 * 110b2fb Commit 2 * e597c60 Commit 1 * 0e834f4 (origin/remoterepo) First commit

¿Qué es el origen?

origin : el nombre predeterminado que git le da a su repositorio remoto principal . Su caja tiene su propio repo, y lo más probable es que se empuja hacia algún repo remoto al que usted y todos sus compañeros de trabajo presionan. Ese repo remoto casi siempre se llama origen, pero no tiene que serlo.

Tengo este proyecto donde el repositorio remoto tiene la rama de desarrollo principal y tengo una bifurcación que contiene la rama experimental. Debo rebase cambios de la rama de desarrollo a mi rama experimental antes de empujar a mi bifurcación. Así que va como:

git checkout experimentalbranch git fetch remoterepo git rebase remoterepo/developmentbranch

En este momento, llego a los conflictos. Sin embargo, no estoy familiarizado con ninguno de estos cambios (estoy reajustando semanas en cambios, porque no fusionaron mis cambios inmediatamente). Además, es mi primera vez haciendo rebase . Estoy más acostumbrado a merge .

En meld, por lo general es como <<LOCAL||REMOTE>> para merge , lo que suena muy intuitivo. Pero en rebase , es <<HEAD||COMMIT MESSAGE>> . ¿Quién es HEAD ? ¿Es la HEAD de la rama del desarrollo? ¿Es el último código en la rama de desarrollo o en otro lugar?


TL; DR (agregado en mayo de 2018)

Todo esto es fundamentalmente al menos un poco confuso porque Git permite que su funcionamiento interno se muestre a través de usted.

Tenga en cuenta que los casos que nos preocupan aquí ocurren cuando ejecuta:

git checkout somebranch; git rebase origin/their-branch

o similar. La reorganización se detuvo temporalmente para obligarlo a resolver un conflicto de fusión, después de lo cual se supone que debe git add el conflicto resuelto y ejecutar git rebase --continue . (Si usa alguna herramienta de combinación con git mergetool , o una interfaz GUI elegante, esa interfaz puede hacer todo o parte de esto por usted de otra manera, pero debajo, es git add los archivos resueltos y ejecutar git rebase --continue . )

Al comienzo, el compromiso HEAD es su rama, de modo que si utiliza git checkout --ours o git checkout --theirs , --ours significa suya - la confirmación final de origin/their-branch mientras que --theirs significa Tuyo , el primer commit que estás rebasando. Este es el tipo normal de confusión de Git (vea ¿Cuál es el significado preciso de "nuestro" y "de ellos" en git? ) Y no es lo que llevó a la pregunta original.

Más tarde, sin embargo, el HEAD commit es en realidad una especie de mezcla . Es el resultado de copiar algunos de sus compromisos sobre su último compromiso . Ahora está teniendo un conflicto entre su propia serie de compromisos parcialmente construida y sus propios compromisos originales . La fuente de este conflicto suele ser algo que "ellos" hicieron (algo que cambió en el camino en el origin/their-branch ). Todavía tienes que resolver este conflicto. Cuando lo haga, puede ver que el mismo conflicto se repite en las confirmaciones posteriores.

Nuevamente, HEAD o local o --ours es un compromiso que se ha creado mediante la combinación de sus cambios y sus cambios , y el otro compromiso ( remote o >>>>>>> o - --theirs ) es su propio compromiso, que se vuelve a generar. está intentando copiar encima de HEAD .

Más

Al fusionar (incluido el reajuste de bases, que es un caso especial de "fusión" repetida internamente), hay dos "cabezas" (dos puntas de rama específicas) involucradas. Llamemos a estos your-branch y origin/their-branch :

G - H -------- <-- HEAD=your-branch / / ... - E - F M <-- desired merge commit [requires manual merge] / / I - J - K - L <-- origin/their-branch

Este punto es comúnmente confuso (y no es sorprendente), aunque cuando se lo etiqueta así, es lo suficientemente claro.

Sin embargo, para empeorar las cosas, git usa --ours y --theirs para referirse a los dos compromisos de la cabeza durante una fusión, siendo "nuestro" el que estaba en (cometer H ) cuando ejecutó git merge , y "suyo" siendo, bueno, de ellos (cometer L ). Pero cuando estás haciendo un rebase, las dos cabezas se invierten, de modo que "nuestro" es el jefe al que estás rebasando, es decir, su código actualizado, y "suya" es el compromiso al que estás rebasando actualmente, Es decir, tu propio código.

Esto se debe a que rebase utiliza en realidad una serie de operaciones de selección selectiva. Comienzas con casi la misma imagen:

G - H <-- HEAD=your-branch / ... - E - F / I - J - K - L <-- origin/their-branch

Lo que git debe hacer aquí es copiar el efecto de los compromisos G y H , es decir, git cherry-pick commit G , y luego hacerlo de nuevo con commit H Pero para hacer eso, git tiene que cambiar para cometer L primero, internamente (usando el modo "HEAD desasociado"):

G - H <-- your-branch / ... - E - F / I - J - K - L <-- HEAD, origin/their-branch

Ahora puede iniciar la operación de rebase comparando los árboles para los compromisos F y G (para ver lo que cambió), luego comparando F vs L (para ver si parte de su trabajo ya está en L ) y tomando cualquier cambio que no esté en L y añadirlo. Esta es una operación de "fusión", internamente.

G - H <-- your-branch / ... - E - F G'' <-- HEAD / / I - J - K - L <-- origin/their-branch

Si la fusión no va bien, HEAD aún se deja en el compromiso L (porque el compromiso G'' todavía no existe). Por lo tanto, sí, HEAD es el jefe de su rama de desarrollo; al menos, es ahora.

Sin embargo, una vez que existe la copia de G , HEAD mueve a G'' y git intenta copiar los cambios de H , de la misma manera (diff G vs H , luego diff F vs G'' , y fusiona los resultados):

G - H <-- your-branch / ... - E - F G'' - H'' <-- HEAD / / I - J - K - L <-- origin/their-branch

Nuevamente, si la combinación falla y necesita ayuda, te quedas con HEAD apuntando a G'' lugar de H'' ya que H'' aún no existe.

Una vez que se fusionan, todos los éxitos y las confirmaciones G'' y H'' existen, git elimina la etiqueta que your-branch comete de la confirmación H , y hace que apunte a la confirmación H'' lugar:

G - H / ... - E - F G'' - H'' <-- HEAD=your-branch / / I - J - K - L <-- origin/their-branch

y ahora estás rediseñado y HEAD es una vez más lo que esperas. Pero durante la rebase, HEAD es su punta de rama (cometer L ) o uno de los nuevos compromisos copiados y anexados más allá de su punta de rama; y --ours significa que la rama se está cultivando al final de L mientras que --theirs significa que el commit se está copiando desde ( G o H arriba).

(Esto es básicamente git exponiendo el mecanismo en bruto de cómo hace lo que hace, lo que sucede bastante en git).