Cómo eliminar la gran cantidad de archivos sin eliminar el contenido

454

Accidentalmente agregué muchos archivos temporales usando git add -A

Logré desestadificar los archivos con los siguientes comandos y logré eliminar el índice sucio.

git ls-files -z | xargs -0 rm -f
git diff --name-only --diff-filter=D -z | xargs -0 git rm --cached

Los comandos anteriores se enumeran en el git help rm. Pero lamentablemente, mis archivos también se eliminaron en la ejecución, a pesar de que había dado la opción de caché. ¿Cómo puedo borrar el índice sin perder el contenido?

También sería útil que alguien pueda explicar cómo funciona esta operación de tubería.

sarat
fuente
8
rm -fno es un comando git y no tiene una --cachedopción. Sus archivos locales se eliminaron antes de ejecutarlos, git rmasí que no creo que pueda culpar legítimamente git rmde nada.
CB Bailey
8
@sarat, considere cambiar la respuesta correcta a la respuesta altamente votada de Ian Maddox , ya git reset --hardque no es la respuesta correcta y, de hecho, eliminará el contenido. Esto confundirá a los usuarios, como a mí.
Marco Pashkov
2
@sarat como dice Marco, continúa. Esta página recibe mucho tráfico.
Ross
@MarcoPashkov & Ross gracias chicos. Hecho.
sarat

Respuestas:

986

git reset

Si todo lo que quiere es deshacer una ejecución excesivamente entusiasta de "git add":

git reset

Sus cambios no estarán organizados y estarán listos para que los vuelva a agregar a su gusto.


No ejecute git reset --hard.

No solo desestabilizará sus archivos agregados, sino que revertirá cualquier cambio que haya realizado en su directorio de trabajo. Sin embargo, si creó archivos nuevos en el directorio de trabajo, no los eliminará.

Ian Maddox
fuente
15
Te debo una pinta Ian
DasBooten
1
A menudo encuentro que tengo que actuar git checkout -- *también
Den-Jason
1
Ahorraste mucho esfuerzo. Gracias hombre
RajnikantDixit
35

Si tiene un repositorio prístino (o HEAD no está configurado) [1] simplemente podría

rm .git/index

Por supuesto, esto requerirá que volver a añadir los archivos que qué desea ser agregado.


[1] Nota (como se explica en los comentarios), esto generalmente solo sucedería cuando el repositorio sea nuevo ("prístino") o si no se han realizado compromisos. Más técnicamente, siempre que no haya pago o árbol de trabajo.

Solo haciéndolo más claro :)

sehe
fuente
Sí, es más como eliminar el índice creado. Lo bueno es que no necesito reiniciar git. ¡Gracias!
sarat
¿Estás seguro de que es una operación segura? Acabo de hacer esto (en realidad moví el índice fuera del camino) y obtuve todos los demás archivos preparados para su eliminación.
Inger
@inger "Si tienes un repositorio prístino". Claramente no tenías eso.
sehe
En realidad, me preguntaba qué querías decir con "repositorio prístino" (no me siento afortunado con Google tampoco). ¿Entonces quisiste decir un repositorio vacío?
Inger
1
@inger De acuerdo. Tuve que suponer que el OP había tenido esta situación exacta; él no lo especifica, pero su descripción deja la posibilidad. De todos modos, solo estoy compartiendo información, y no puedo influir en la votación :(. He agregado una palabra de advertencia al texto de respuesta, en caso de que ayude a otros en el futuro.
Sehe
15

Use git reset HEADpara restablecer el índice sin eliminar archivos. (Si solo desea restablecer un archivo en particular en el índice, puede git reset HEAD -- /path/to/filehacerlo).

El operador de tubería, en una carcasa, toma el stdoutproceso a la izquierda y lo pasa stdinal proceso a la derecha. Es esencialmente el equivalente de:

$ proc1 > proc1.out
$ proc2 < proc1.out
$ rm proc1.out

pero en su lugar $ proc1 | proc2, el segundo proceso puede comenzar a obtener datos antes de que el primero termine de generarlos, y no hay ningún archivo real involucrado.

Ámbar
fuente
pero a cómo usarlo con múltiples archivos. Nunca antes había comprometido estos archivos.
sarat
3
Simplemente escriba git reset HEADsin especificar nada más y restablecerá todo el índice. Luego, puede volver a agregar solo los archivos que desee.
Ámbar
Tuve el siguiente error. Nunca cometí estos artículos antes. $ git reset HEAD fatal: ambiguous argument 'HEAD': unknown revision or path not in the working tree. Use '--' to separate paths from revisions
Sarat
1
Prueba en git resetese momento, sin el HEAD.
Ámbar
Ya intenté que terminé en el siguiente error. $ git reset fatal: Failed to resolve 'HEAD' as a valid ref.
sarat
9
git stash && git stash pop
Bijan
fuente
2
Haría 'git stash && git stash pop' para que el alijo también se elimine. 'aplicar' dejaría el alijo en la lista de alijo.
chitti
8

Si HEAD no está configurado (es decir, aún no tiene confirmaciones, pero no desea simplemente volar .gitporque ya ha configurado otra configuración de repositorio que desea mantener), también puede hacerlo

git rm -rf --cached .

para destrabar todo. Esto es efectivamente lo mismo que la solución de Sehe, pero evita la intrusión con los componentes internos de Git.

jjlin
fuente
esto realmente le dice a Git que elimine todo en el área en caché.
Visionary Software Solutions
1
El caché también se conoce como el área de ensayo, por lo que no estoy seguro de a qué te refieres.
jjlin 01 de
De sehe, rm .git / index es muy peligroso, ¡asegúrese de leer la NOTA que tiene sobre un nuevo repositorio! Esto es mucho más seguro para el otro 99.999% del tiempo. No leí con atención y tuve que volar mi copia de trabajo y volver a clonar después de hacer rm .git / index en mi copia de trabajo.
phpguru
¡NO use este comando! Cambiará TODOS los proyectos al estado sin seguimiento (incluidos los que no se realizaron por etapas). Esta no es una solución a la pregunta original. La solución correcta utilizando el comando 'git rm' es especificar SOLAMENTE los archivos que desea sin clasificar: git rm -rf --cached <archivos que desea eliminar del escenario>.
Monte Creasor
Solo debe usar este comando cuando tenga un nuevo repositorio sin confirmaciones todavía (esto es lo que significa "HEAD no está configurado"), pero no desea simplemente volar .gitporque ha configurado otra configuración de repositorio que querer guardar. He editado para aclarar esto.
jjlin
5

Advertencia: ¡no use el siguiente comando a menos que quiera perder el trabajo no comprometido!

El uso git resetse ha explicado, pero también solicitó una explicación de los comandos canalizados, así que aquí va:

git ls-files -z | xargs -0 rm -f
git diff --name-only --diff-filter=D -z | xargs -0 git rm --cached

El comando git ls-filesenumera todos los archivos que git conoce. La opción les -zimpone un formato específico, el formato esperado por ellos xargs -0, que luego los invoca rm -f, lo que significa eliminarlos sin verificar su aprobación.

En otras palabras, "enumere todos los archivos que Git conoce y elimine su copia local".

Luego llegamos a git diff, que muestra los cambios entre las diferentes versiones de elementos que Git conoce. Esos pueden ser cambios entre diferentes árboles, diferencias entre copias locales y copias remotas, etc.
Tal como se usa aquí, muestra los cambios no organizados; los archivos que ha cambiado pero que aún no ha confirmado. La opción --name-onlysignifica que solo desea los nombres de archivo (completos) y --diff-filter=Dsignifica que solo está interesado en los archivos eliminados. (Oye, ¿no acabamos de eliminar un montón de cosas?) Esto luego se canaliza a lo xargs -0que vimos antes, lo que invoca git rm --cacheden ellas, lo que significa que se eliminan del caché, mientras que el árbol de trabajo debe dejarse solo, excepto que acaba de eliminar todos los archivos de su árbol de trabajo. Ahora también se eliminan de su índice.

En otras palabras, todos los cambios, realizados o no, han desaparecido y su árbol de trabajo está vacío. Llora, revisa tus archivos desde el origen o de forma remota, y vuelve a hacer tu trabajo. Maldice al sádico que escribió estas líneas infernales; No tengo idea de por qué alguien querría hacer esto.


TL; DR: acabas de limpiar todo; comenzar de nuevo y usar git resetde ahora en adelante.

SQB
fuente
2

Me temo que la primera de esas líneas de comando eliminó incondicionalmente de la copia de trabajo todos los archivos que están en el área de preparación de git. El segundo eliminó todos los archivos que se rastrearon pero que ahora se han eliminado. Desafortunadamente, esto significa que habrá perdido cualquier modificación no confirmada de esos archivos.

Si desea que su copia de trabajo e índice vuelvan a estar como estaban en la última confirmación , puede ( cuidadosamente ) usar el siguiente comando:

git reset --hard

Digo "cuidadosamente", ya git reset --hard que eliminará los cambios no confirmados en su copia de trabajo e índice. Sin embargo, en esta situación parece que solo desea volver al estado en su última confirmación, y los cambios no confirmados se han perdido de todos modos.

Actualización: según sus comentarios sobre la respuesta de Amber, todavía no ha creado ninguna confirmación (ya que HEAD no se puede resolver), por lo que esto no ayudará, me temo.

En cuanto a cómo funcionan esas canalizaciones: git ls-files -zy git diff --name-only --diff-filter=D -zambas generan una lista de nombres de archivo separados con el byte 0. (Esto es útil, ya que, a diferencia de las nuevas líneas, 0se garantiza que los bytes no aparezcan en los nombres de archivo en sistemas similares a Unix). El programa xargsesencialmente construye líneas de comando a partir de su entrada estándar, de forma predeterminada al tomar líneas de entrada estándar y agregarlas al final de la línea de comando. La -0opción dice esperar entrada estándar a separada por 0bytes. xargspuede invocar el comando varias veces para usar todos los parámetros de la entrada estándar, asegurándose de que la línea de comando nunca sea demasiado larga.

Como ejemplo simple, si tiene un archivo llamado test.txt, con los siguientes contenidos:

hello
goodbye
hello again

... entonces el comando xargs echo whatever < test.txtinvocará el comando:

echo whatever hello goodbye hello again
Mark Longair
fuente
Nunca hice ninguna confirmación, por lo que dirá que no puedo resolver HEAD. Lo que hacemos en tales situaciones. Muchas gracias por explicar la tubería en detalle.
sarat
8
Si acabas de cambiar tu git ignore y agregaste git --todos para incluir una gran cantidad de archivos, NO ejecutes git reset-- duro para desestabilizarlos. ¡SERÁN BORRADOS!
Disfruta
55
Uwaaahh !! Tal vez necesite resaltar la palabra "cuidadosamente" . Acabo de ver estas tres palabras "git reset --hard" y todos mis archivos no organizados son ... ¡fufff! ¡¡¡¡¡ido!!!!!
Vineeth Chitteti
1

Si desea eliminar todos los cambios, use el siguiente comando,

git reset --soft HEAD

En el caso de que desee eliminar los cambios del escenario y revertirlos desde el directorio de trabajo,

git reset --hard HEAD
027
fuente