¿Cómo deshago 'git add' antes de confirmar?
Agregué archivos por error a Git usando el comando:
git add myfile.txt
Todavía no he corrido git commit
. ¿Cómo deshago esto para que estos cambios no se incluyan en la confirmación?
Para eliminar un archivo específico
git reset <file>
Eso eliminará el archivo del índice actual (la lista "a punto de confirmarse") sin cambiar nada más.
Para eliminar todos los archivos del conjunto de cambios actual:
git reset
En versiones anteriores de Git, los comandos anteriores son equivalentes a git reset HEAD <file>
y git reset HEAD
respectivamente, y fallarán si HEAD
no están definidos (porque aún no has realizado ninguna confirmación en tu repositorio) o son ambiguos (porque creaste una rama llamada HEAD
, lo cual es una estupidez). que no deberías hacer). Sin embargo, esto se cambió en Git 1.8.2 , por lo que en las versiones modernas de Git puedes usar los comandos anteriores incluso antes de realizar tu primera confirmación:
"git reset" (sin opciones ni parámetros) solía generar un error cuando no tienes ninguna confirmación en tu historial, pero ahora te proporciona un índice vacío (para coincidir con una confirmación inexistente en la que ni siquiera estás).
Documentación: git reset
Quieres:
git rm --cached <added_file_to_undo>
Razonamiento:
Cuando era nuevo en esto, lo intenté por primera vez.
git reset .
(para deshacer toda mi adición inicial), solo para recibir este (no tan) mensaje útil:
fatal: Failed to resolve 'HEAD' as a valid ref.
Resulta que esto se debe a que la referencia HEAD (¿rama?) no existe hasta después de la primera confirmación. Es decir, te encontrarás con el mismo problema de principiante que yo si tu flujo de trabajo, como el mío, fuera algo como:
- cd a mi nuevo directorio de proyectos para probar Git, el nuevo atractivo
git init
git add .
git status
... muchos pergaminos de mierda de ...
=> Maldita sea, no quería agregar todo eso.
google "deshacer git add"
=> encontrar desbordamiento de pila - yay
git reset .
=> fatal: No se pudo resolver 'HEAD' como una referencia válida.
Además, resulta que hay un error registrado debido a la inutilidad de esto en la lista de correo.
Y que la solución correcta estaba ahí en la salida de estado de Git (que, sí, pasé por alto como 'basura)
... # Changes to be committed: # (use "git rm --cached <file>..." to unstage) ...
Y la solución es, de hecho, utilizar git rm --cached FILE
.
Tenga en cuenta las advertencias en otros lugares aquí: git rm
elimina su copia de trabajo local del archivo, pero no si usa --cached . Aquí está el resultado de git help rm
:
--cached Utilice esta opción para desagregar y eliminar rutas sólo del índice. Se conservarán los archivos del árbol de trabajo, modificados o no.
procedo a usar
git rm --cached .
para quitar todo y empezar de nuevo. Sin embargo, no funcionó, porque si bien add .
es recursivo, resulta que rm
debe -r
ser recursivo. Suspiro.
git rm -r --cached .
Bien, ahora he vuelto al punto de partida. La próxima vez haré -n
un ensayo y veré qué se agregará:
git add -n .
Cerré todo a un lugar seguro antes de confiar git help rm
en --cached
no destruir nada (y si lo escribí mal).
Si escribes:
git status
Git le dirá qué se prepara, etc., incluidas instrucciones sobre cómo cancelar la preparación:
use "git reset HEAD <file>..." to unstage
Creo que Git hace un buen trabajo al impulsarme a hacer lo correcto en situaciones como esta.
Nota: Las versiones recientes de Git (1.8.4.x) han cambiado este mensaje:
(use "git rm --cached <file>..." to unstage)
Para aclarar: git add
mueve los cambios del directorio de trabajo actual al área de preparación (índice).
Este proceso se llama puesta en escena . Entonces, el comando más natural para preparar los cambios (archivos modificados) es el obvio:
git stage
git add
es simplemente un alias más fácil de escribir paragit stage
Lástima que no hay git unstage
ni git unadd
comandos. El relevante es más difícil de adivinar o recordar, pero es bastante obvio:
git reset HEAD --
Podemos crear fácilmente un alias para esto:
git config --global alias.unadd 'reset HEAD --'
git config --global alias.unstage 'reset HEAD --'
Y por último, tenemos nuevos comandos:
git add file1
git stage file2
git unadd file2
git unstage file1
Personalmente uso alias aún más cortos:
git a # For staging
git u # For unstaging
Además de la respuesta aceptada, si el archivo agregado por error era enorme, probablemente notará que, incluso después de eliminarlo del índice con ' git reset
', todavía parece ocupar espacio en el .git
directorio.
Esto no es nada de qué preocuparse; De hecho, el archivo todavía está en el repositorio, pero sólo como un "objeto suelto". No se copiará a otros repositorios (mediante clonación, inserción) y el espacio eventualmente se recuperará, aunque quizás no muy pronto. Si estás ansioso, puedes ejecutar:
git gc --prune=now
Actualización (lo que sigue es mi intento de aclarar cierta confusión que puede surgir de las respuestas más votadas):
Entonces, ¿cuál es la verdadera ruinagit add
?
git reset HEAD <file>
?
o
git rm --cached <file>
?
En rigor, y si no me equivoco: ninguna .
git add
no se puede deshacer , de forma segura, en general.
Recordemos primero lo que git add <file>
realmente hace:
Si no
<file>
fue rastreado previamente ,git add
lo agrega al caché , con su contenido actual.Si ya
<file>
se realizó un seguimiento , guarda el contenido actual (instantánea, versión) en la memoria caché. En Git, esta acción todavía se llama agregar (no simplemente actualizarla ), porque dos versiones diferentes (instantáneas) de un archivo se consideran dos elementos diferentes: por lo tanto, estamos agregando un nuevo elemento al caché, que eventualmente será agregado. cometido más tarde.git add
En vista de esto, la pregunta es un poco ambigua:
Agregué archivos por error usando el comando...
El escenario del OP parece ser el primero (archivo sin seguimiento), queremos que "deshacer" elimine el archivo (no solo el contenido actual) de los elementos rastreados. Si este es el caso, entonces está bien ejecutarlo git rm --cached <file>
.
Y también podríamos correr git reset HEAD <file>
. En general, esto es preferible, porque funciona en ambos escenarios: también deshace cuando agregamos incorrectamente una versión de un elemento ya rastreado.
Pero hay dos advertencias.
Primero: hay (como se señala en la respuesta) solo un escenario en el que git reset HEAD
no funciona, pero git rm --cached
sí: un nuevo repositorio (sin confirmaciones). Pero, en realidad, éste es un caso prácticamente irrelevante.
Segundo: tenga en cuenta que git reset HEAD
no se puede recuperar mágicamente el contenido del archivo previamente almacenado en caché, simplemente lo resincroniza desde HEAD. Si nuestro error git add
sobrescribió una versión anterior no confirmada, no podremos recuperarla. Por eso, estrictamente hablando, no podemos deshacer [*].
Ejemplo:
$ git init
$ echo "version 1" > file.txt
$ git add file.txt # First add of file.txt
$ git commit -m 'first commit'
$ echo "version 2" > file.txt
$ git add file.txt # Stage (don't commit) "version 2" of file.txt
$ git diff --cached file.txt
-version 1
+version 2
$ echo "version 3" > file.txt
$ git diff file.txt
-version 2
+version 3
$ git add file.txt # Oops we didn't mean this
$ git reset HEAD file.txt # Undo?
$ git diff --cached file.txt # No dif, of course. stage == HEAD
$ git diff file.txt # We have irrevocably lost "version 2"
-version 1
+version 3
Por supuesto, esto no es muy crítico si simplemente seguimos el flujo de trabajo lento habitual de hacer 'git add' solo para agregar nuevos archivos (caso 1) y actualizamos nuevos contenidos mediante el comando commit git commit -a
.
* (Editar: lo anterior es prácticamente correcto, pero aún así puede haber algunas formas un poco complicadas o complicadas para recuperar cambios que se realizaron, pero que no se confirmaron y luego se sobrescribieron; consulte los comentarios de Johannes Matokic e iolsmit)
Deshacer un archivo que ya se ha agregado es bastante fácil usando Git. Para restablecer archivos myfile.txt
que ya se han agregado, use:
git reset HEAD myfile.txt
Explicación:
Después de preparar los archivos no deseados, para deshacerlos, puede hacer git reset
. Head
es el encabezado de su archivo en el local y el último parámetro es el nombre de su archivo.
He creado los pasos en la imagen a continuación con más detalles para usted, incluidos todos los pasos que pueden ocurrir en estos casos: