Es bien sabido que la interfaz de línea de comandos de Git es confusa. Por ejemplo,git checkout
tiene distintos comportamientos no demasiado relacionados entre sí.
El primero es cambiar a una rama ya existente:
git checkout mirama
También podemos crear una nueva rama local y cambiarnos a ella:
git checkout -b mineuvaramalocal
O bajarnos una rama de un remote y comenzar a seguirla:
git checkout -b unarama --track origin/unarama
Si en vez de pasarle una rama le pasamos el hash de un commit, checkout
nos pondrá en el (innecesariamente) temido estado de "detached HEAD":
git checkout f4f031d
"detached HEAD", significa que HEAD no está apuntando a una rama que a su vez apunta a un commit, sino que apunta directamente a un commit.
Por otra parte, checkout
también puede utilizarse para descartar los cambios para un archivo concreto en el worktree, sobreescribiéndolos con los contenidos del índice:
git checkout -- /path/to/archive.txt
Si estamos en medio de un merge, podemos usar esta variante de checkout
para quedarnos o bien con los cambios de la versión local de un archivo, o con los cambios de la rama que estamos mergeando:
git checkout --ours -- /path/to/archive.txt
git checkout --theirs -- /path/to/archive.txt
Esto funciona porque, cuando hay un merge en curso, el índice almacena tanto la versión local (--ours
) como la de la rama que mergeamos (--theirs
) de los archivos en conflicto.
checkout
no solo nos deja sobreescribir un archivo en el worktree desde el índice. También nos deja sobreescribir un archivo tanto en el worktree como en el índice con una versión del archivo traída de cualquier otra rama o commit:
git checkout f4f031d -- /path/to/archive.txt
Como esta variante del comando (al contrario que la anterior) también sobreescribe el índice, no solo el worktree, hay que hacer git diff --staged
para ver los cambios. Ojo, esto no es un cherry-pick, ya que no crea un commit nuevo.
Si solo estamos interesados en traernos parte de los cambios ("hunks") para el archivo desde el otro commit, podemos usar --patch
para elegirlos de manera interactiva:
git checkout --patch f4f031d -- /path/to/archive.txt
Como hemos visto, a veces checkout
cambia de rama, y a veces modifica archivos en el worktree (y quizás en el índice) sin cambiar de rama.
Desde la versión 2.23.0 de Git, se han añadido dos nuevos (y todavía experimentales en 2.29.1) comandos a Git: git switch y git restore. Entre los dos se reparten la funcionalidad de git checkout
.
git switch
abarca la funcionalidad de git checkout
relacionada con cambios de rama, mientras que git restore
abarca la funcionalidad de manipulación de worktree e índice.
Idealmente, una vez que estos dos nuevos comandos se estabilicen en alguna versión futura de Git, podrían usarse en vez de git checkout
, el cual quedaría obsoleto.
What's the difference between git switch and git checkout
What is the git restore
command and what is the difference between git restore
and git reset
?