Git – Comportamiento básico trabajando con sucursales

Trabajando con Git 2.13.5, una pregunta muy simple para verificar si soy yo quien malinterpreta algo o un comportamiento incorrecto al trabajar con sucursales.

Sigue estos pasos:

  1. Situación inicial: tengo un determinado repository con una sola twig ("maestro").
  2. git checkout -b some-changes
  3. Abra some_file.js en el editor favorito y agregue algunos cambios. Cierra el file.
  4. git status (veo el file modificado esperando ser montado (en rojo))
  5. Imagina que tengo un error importante ahora en Producción. Yo hago git checkout master
  6. Cuando abro de nuevo some_file.js , todavía veo los cambios en el file, aunque he cambiado a maestro.
  7. Cuando hago el git status , todavía veo el file modificado esperando ser montado (en rojo)).

¿No están equivocados los pasos 6 y 7? Como cambié a la twig principal, ¿no debería ver el some_file.js original_file_justificado no modificado original y todo up-to-date en el command git status ?

Si bien esto es a menudo muy sorprendente para los nuevos usuarios de Git, en realidad es una cosa fundamentalmente sensata y normal en Git. Todo tiene que ver con el model de Git de cómo se deben hacer los compromisos y cómo se debe trabajar en el tree de trabajo. Además, aunque aquí solo se relacionan tangencialmente, las sucursales no significan tanto en Git como lo hacen en la mayoría de los sistemas de control de versiones.

Archivos comprometidos

Cualquier sistema de control de versiones (VCS) debe tener alguna forma de almacenar los files versionados. En Git, en lugar de almacenar files directamente, Git almacena confirmaciones . Una confirmación representa una instantánea completa de todos sus files. Bueno, deberíamos decir casi todos , o incluso algún subset específico , aquí. Y, por lo general, cada compromiso tiene exactamente una confirmación principal : esa es la confirmación que era la confirmación actual, cuando quien realizaba la nueva confirmación realizaba la nueva confirmación.

El compromiso actual: HEAD o @

En otras palabras, siempre tienes un compromiso actual . Esta confirmación actual, que puede nombrar con @ o con la palabra HEAD , es una instantánea permanente (en su mayoría) inmutable (completamente) de un grupo de files. El nombre HEAD realidad contiene el nombre de la twig actual , y el nombre de la twig se resuelve a la identificación hash de confirmación.

Su tree de trabajo

Son esos files los que ingresó en su tree de trabajo cuando ejecutó git clone para clonar el repository. Pero el tree de trabajo es justo donde haces tu trabajo . Necesita un lugar para hacer esto, porque la confirmación actual, HEAD , no se puede cambiar. (Además, los files almacenados en la confirmación actual se almacenan en un formatting especial, solo Git. Otros progtwigs en su computadora, incluyendo su editor y sus manejadores de files .js , probablemente no puedan manejarlo).

El índice y los files sin seguimiento

Ahora, un file en su tree de trabajo, como some_file.js , es simplemente eso: un file en su tree de trabajo. Puede haber un file correspondiente en la confirmación actual ( HEAD ), o puede que no. Eso es importante; pero aún más importante es si hay otra copy de este file en su índice . El índice tal vez se describa mejor como: Lo que Git colocará en su próximo compromiso.

El índice de Git es misterioso, porque no se puede ver directamente. Lo más cerca que puede llegar es ejecutar git ls-files --stage (que puede producir bastante salida y normalmente no es útil). Este índice, también llamado área de transición y, a veces, la memory caching , comienza con otra copy de cada file que está en la confirmación de HEAD . Esta copy, como la de HEAD , está en un formatting especial solo de Git, comprimido hasta un pequeño número de índice, que en última instancia simplemente dice "igual que la versión HEAD ", por lo que no requiere espacio adicional . Aún así, está ahí .

Si un file está en el índice, Git llama a este file. Si el file no está en el índice, Git lo llama sin seguimiento . Esto es muy importante, pero dado que su file es rastreado, no nos preocuparemos por esto todavía.

Si desea que los contenidos actualizados de su tree de trabajo entren en un nuevo compromiso, debe copyr el file del tree de trabajo al índice:

 git add some-file.js 

Ahora la nueva versión está en el índice, list para comprometerse.

El process de checkout de Git es especialmente complicado

En Git, nombres de twigs como some-changes realmente solo nombran un compromiso específico . Cada confirmación nombra a su propio padre, también, por lo que en este momento, tiene:

 ... <-- o <--o <--o <-- master, some-changes (HEAD) 

Tanto some-changes como el master apuntan a la misma confirmación (la misma gran identificación de hash fea). Así que git checkout master pone el nombre master en HEAD , pero ve que no tiene que tocar el índice o el tree de trabajo, porque en realidad no está cambiando commits . Después del pago, tienes:

 ... <-- o <--o <--o <-- master (HEAD), some-changes 

El índice y el tree de trabajo no se modifican, por lo que el git status -que compara HEAD vs index, y el índice vs work-tree-tampoco se modifica, excepto por el nombre de twig que se imprime cuando dice on branch ...

En el paso 4, tiene cambios locales en el file some_file.js . Git respetará estos cambios y le pedirá que decida explícitamente qué hacer con ellos cuando consulte una sucursal. Por defecto, estos cambios seguirán en su copy de trabajo local. Si los cambios entran en conflicto con los cambios en la sucursal, git se quejará y no le permitirá verificar la sucursal.

Usted tiene varias opciones para administrar esto:

  1. Bote sus cambios con git rest --hard HEAD .

  2. Guarde los cambios en su copy local y trabaje en la nueva sucursal como desee.

  3. Confirme sus cambios antes del paso 5 de la manera habitual.

  4. Guarde temporalmente sus cambios con git stash y vuelva a cargarlos en otro momento con git stash apply o git stash pop .