git rebase, haciendo un seguimiento de 'local' y 'remoto'

174

Cuando hago un cambio de git, a menudo tengo dificultades para resolver lo que está sucediendo con lo 'local' y 'remoto' al resolver conflictos. A veces tengo la impresión de que intercambian lados de un compromiso a otro.

Esto es probablemente (definitivamente) porque todavía no lo he entendido correctamente.

Al rebasear, ¿quién es 'local' y quién es 'remoto'?

(Uso P4Merge para resolver conflictos)

Benjol
fuente
¿Es posible que leer esto te ayude? El resto del tutorial también es muy útil ...
ivans
Otro excelente recurso git .
Desconocido
¿ Stackoverflow.com/questions/2959443/… ayuda? (no para la parte ' git svn', solo para la parte ' git rebase')
VonC
@VonC, sí, eso es exactamente. Si desea copiar el fragmento relevante de su respuesta aquí, lo marcaré (¡realmente lo haré esta vez, lo prometo!)
Benjol
Muy bien ... Voy a morder;) Extractos relevantes publicados.
VonC

Respuestas:

244

TL; DR;

Para resumir (como comenta Benubird ), cuando:

git checkout A
git rebase   B    # rebase A on top of B
  • locales B(rebase en ),
  • remote es A

Y:

git checkout A
git merge    B    # merge B into A
  • locales A(fusionarse con ),
  • remote es B

Un cambio de base cambia ours(rama actual antes de que comience el rebase) y theirs(la rama sobre la que desea rebase).


kutschkem señala que, en un contexto mergetool GUI :

  • referencias locales las confirmaciones parcialmente modificadas : " ours" (la rama ascendente)
  • control remoto se refiere a los cambios entrantes : " theirs" - la rama actual antes del rebase.

Vea las ilustraciones en la última parte de esta respuesta.


Inversión cuando rebase

La confusión puede estar relacionada con la inversión de oursy theirsdurante un rebase .
(extractos relevantes)

git rebasepágina man :

Tenga en cuenta que una combinación de rebase funciona al reproducir cada confirmación de la rama de trabajo en la parte superior de la <upstream>rama.

Debido a esto, cuando ocurre un conflicto de fusión:

  • el lado reportado como ' ours' es la serie rebase hasta ahora, comenzando con <upstream>,
  • y ' theirs' es la rama de trabajo. En otras palabras, los lados se intercambian.

Inversión ilustrada

En una fusión

x--x--x--x--x(*) <- current branch B ('*'=HEAD)
    \
     \
      \--y--y--y <- other branch to merge

, no cambiamos la rama actual 'B', así que lo que tenemos sigue siendo en lo que estábamos trabajando (y nos fusionamos desde otra rama)

x--x--x--x--x---------o(*)  MERGE, still on branch B
    \       ^        /
     \     ours     /
      \            /
       --y--y--y--/  
               ^
              their

En un rebase:

Pero en un rebase , cambiamos de lado porque lo primero que hace un rebase es verificar la rama aguas arriba. (para reproducir las confirmaciones actuales encima)

x--x--x--x--x(*) <- current branch B
    \
     \
      \--y--y--y <- upstream branch

A git rebase upstreamprimero cambiará HEADde B a la rama aguas arriba HEAD(de ahí el cambio de 'la nuestra' y 'la de ellos' en comparación con la rama de trabajo "actual" anterior).

x--x--x--x--x <- former "current" branch, new "theirs"
    \
     \
      \--y--y--y(*) <- upstream branch with B reset on it,  
                       new "ours", to replay x's on it

, y luego el rebase reproducirá 'sus' confirmaciones en la nueva rama 'nuestra' B:

x--x..x..x..x <- old "theirs" commits, now "ghosts", available through reflogs
    \
     \
      \--y--y--y--x'--x'--x'(*) <-  branch B with HEAD updated ("ours")
               ^
               |
        upstream branch

Nota: la noción "ascendente" es el conjunto referencial de datos (un repositorio completo o, como aquí, una rama, que puede ser una rama local ) desde el que se leen los datos o se añaden / crean nuevos datos.


' local' y ' remote' vs. ' mine' y ' theirs'

Pandawood agrega en los comentarios :

Para mí, la pregunta sigue siendo, que es "local" y quién es "remoto" (ya que los términos "nuestro" y "suyo" no se usan cuando se rebase en git, referirse a ellos simplemente parece hacer una respuesta más confusa) .

GUI git mergetool

kutschkem agrega, y con razón:

Al resolver conflictos, git dirá algo como:

local: modified file and remote: modified file. 

Estoy bastante seguro de que la pregunta apunta a la definición de local y remoto en este punto. En ese punto, me parece por experiencia que:

  • referencias locales las confirmaciones parcialmente modificadas : " ours" (la rama ascendente)
  • control remoto se refiere a los cambios entrantes : " theirs" - la rama actual antes del rebase.

git mergetoolde hecho menciona 'local' y 'remoto' :

Merging:
f.txt

Normal merge conflict for 'f.txt':
  {local}: modified file
  {remote}: modified file
Hit return to start merge resolution tool (kdiff3):

Por ejemplo, KDiff3 sería mostrar la resolución de combinación como tal :

kdiff3

Y meld también lo mostraría :

Difusión de fusión

Lo mismo para VimDiff , que muestra :

Invoque a Vimdiff como mergetool con git mergetool -t gvimdiff. Las versiones recientes de Git invocan a Vimdiff con el siguiente diseño de ventana:

+--------------------------------+
| LOCAL  |     BASE     | REMOTE |
+--------------------------------+
|             MERGED             |
+--------------------------------+
  • LOCAL:
    Un archivo temporal que contiene el contenido del archivo en la rama actual.
  • BASE:
    Un archivo temporal que contiene la base común para la fusión.
  • REMOTE:
    Un archivo temporal que contiene el contenido del archivo que se fusionará.
  • MERGED:
    El archivo que contiene los marcadores de conflicto.

Git ha realizado la mayor resolución de conflictos automática posible y el estado de este archivo es una combinación de ambos LOCALy REMOTEcon marcadores de conflicto que rodean todo lo que Git no pudo resolver por sí mismo.
El mergetooldebe escribir el resultado de la resolución a este archivo.

VonC
fuente
13
Para mí, la pregunta sigue siendo, que es "local" y quién es "remoto" (ya que los términos "nuestro" y "suyo" no se usan cuando se rebase en git, referirse a ellos simplemente parece hacer una respuesta más confusa) . La pregunta es "quién es local y quién es remoto", por lo que una respuesta seguramente requiere mencionar las palabras "local" y "remoto"
PandaWood
@PandaWood: "local" es "rama actual" (que se convierte en "suya"), "remoto" es "rama ascendente" (que se convierte en "nuestra").
VonC
3
Entonces, para resumir: cuando su git checkout A; git rebase Blocal es B, el remoto es A. Todo lo que necesitaba saber ...
Benubird
1
Git es un grupo de usabilidad. esto no tiene sentido: cuando git checkout A; git rebase Blocal es B, a distancia es una . Si checkout Aahora estoy viendo los archivos tal como existen A, ¿cómo es eso de alguna manera el control remoto ? (No digo que Benubird esté equivocado; digo que git tiene una UX estúpida)
Rafa
1
@VonC seguro; mi punto (despotricar) es que no debería tomar la lectura de documentación, mirar diagramas y tener que navegar por StackOverflow. Si solo el comando proporcionara una respuesta clara e inequívoca. Por ejemplo, en lugar de local / remoto / suyo / nuestro / mío / tuyo, solo muestra {branch A}y / {branch B}o similar.
Rafa
45

La línea de fondo

git rebase

  • LOCAL = la base que estés rebase en
  • REMOTO = los commits que estás subiendo arriba

git merge

  • LOCAL = la rama original en la que te estás fusionando
  • REMOTO = la otra rama cuyas confirmaciones estás fusionando

En otras palabras, LOCAL siempre es el original, y REMOTE siempre es el tipo cuyos compromisos no estaban allí antes, porque están fusionados o rebasados ​​en la parte superior

¡Pruébalo!

Ciertamente. ¡No confíes en mi palabra! Aquí hay un experimento fácil que puedes hacer para verlo por ti mismo.

Primero, asegúrese de tener git mergetool configurado correctamente. (Si no lo hiciera, probablemente no estaría leyendo esta pregunta de todos modos). Luego busque un directorio para trabajar.

Configura tu repositorio:

md LocalRemoteTest
cd LocalRemoteTest

Cree una confirmación inicial (con un archivo vacío):

git init
notepad file.txt  (use the text editor of your choice)
  (save the file as an empty file)
git add -A
git commit -m "Initial commit."

Cree una confirmación en una rama que no sea maestra:

git checkout -b notmaster
notepad file.txt
  (add the text: notmaster)
  (save and exit)
git commit -a -m "Add notmaster text."

Cree una confirmación en la rama maestra:

git checkout master
notepad file.txt
  (add the text: master)
  (save and exit)
git commit -a -m "Add master text."

gitk --all

En este punto, su repositorio debería verse así:

Repositorio con un commit base y dos ramas de un commit

Ahora para la prueba de rebase:

git checkout notmaster
git rebase master
  (you'll get a conflict message)
git mergetool
  LOCAL: master
  REMOTE: notmaster

Ahora la prueba de fusión. Cierre su herramienta de combinación sin guardar ningún cambio y luego cancele la nueva versión:

git rebase --abort

Luego:

git checkout master
git merge notmaster
git mergetool
  LOCAL: master
  REMOTE: notmaster
git reset --hard  (cancels the merge)

Sus resultados deben ser los mismos que se muestran arriba.

Ryan Lundy
fuente
1
+1. Eso aclara los aspectos local/ con los remoteque luché en mi propia respuesta anterior (que es más sobre la inversión de oursvs de theirstodos modos)
VonC
3

No entendí su problema exactamente, pero creo que el siguiente diagrama resuelve su problema. (Rebase: repositorio remoto ---> Espacio de trabajo)

http://assets.osteele.com/images/2008/git-transport.png

Fuente: My Git Workflow

Chathuranga Chandrasekara
fuente