¿Deshacer modificaciones de copia de trabajo de un archivo en Git?

1634

Después de la última confirmación, modifiqué un montón de archivos en mi copia de trabajo, pero quiero deshacer los cambios en uno de esos archivos, como en restablecerlo al mismo estado que la confirmación más reciente.

Sin embargo, solo quiero deshacer los cambios de la copia de trabajo solo de ese archivo, nada más con él.

¿Cómo puedo hacer eso?

Hasen
fuente

Respuestas:

2215

Puedes usar

git checkout -- file

Puede hacerlo sin el --(como lo sugiere nimrodm), pero si el nombre de archivo parece una rama o etiqueta (u otro identificador de revisión), puede confundirse, por lo que --es mejor usarlo .

También puede consultar una versión particular de un archivo:

git checkout v1.2.3 -- file         # tag v1.2.3
git checkout stable -- file         # stable branch
git checkout origin/master -- file  # upstream master
git checkout HEAD -- file           # the version from the most recent commit
git checkout HEAD^ -- file          # the version before the most recent commit
Brian Campbell
fuente
34
¿Cuál es la diferencia entre HEAD y HEAD ^?
hasen
62
HEAD es la confirmación más reciente en la rama actual, y HEAD ^ es la confirmación anterior en la rama actual. Para la situación que describe, puede usar git checkout HEAD - nombre de archivo.
Paul
16
En resumen "git checkout sha-reference - filename" donde la referencia sha es una referencia al sha de un commit, en cualquier forma (rama, etiqueta, padre, etc.)
Lakshman Prasad
29
NOTA: Si el archivo ya está preparado, primero debe restablecerlo. git reset HEAD <filename> ; git checkout -- <filename>
Olie
14
@gwho Sí, puede hacer HEAD^^2 confirmaciones de la más reciente o HEAD^^^3 confirmaciones de vuelta. También puede usar HEAD~2, o HEAD~3, que se vuelve más conveniente si desea volver más confirmaciones, mientras que HEAD^2significa "el segundo padre de esta confirmación"; debido a las confirmaciones de fusión, una confirmación puede tener más de una confirmación previa, por lo que con HEAD^un número se selecciona cuál de esos padres, mientras que con HEAD~un número siempre se selecciona el primer elemento primario pero ese número de confirmaciones se devuelve. Ver git help rev-parsepara más detalles.
Brian Campbell
139

Solo usa

git checkout filename

Esto reemplazará el nombre del archivo con la última versión de la rama actual.

ADVERTENCIA: sus cambios serán descartados, no se guarda ninguna copia de seguridad.

nimrodm
fuente
22
@duckx es desambiguar los nombres de las ramas de los nombres de archivo. Si dice que git checkout xx es un nombre de rama así como un nombre de archivo, no estoy seguro de cuál es el comportamiento predeterminado, pero creo que git asumirá que desea cambiar a la rama x. Cuando usas --estás diciendo que lo que sigue son los nombres de los archivos.
hasen
1
ic gracias por aclarar eso. todos asumen que sabes qué significa cuando te muestran ejemplos. y no es algo que también puedas googlear fácilmente.
Patoshi パ ト シ
1
Parece que la respuesta fue editada para eliminarla --. Si bien sigue siendo correcto, como señala @hasen, si existe una ambigüedad entre el nombre del archivo y los nombres de las ramas, ¡aquí puede terminar con un comportamiento muy indeseable!
BrainSlugs83
2
Me gusta como es, sin --, agradable y fácil. Cuando nombras ramas usando nombres de archivos, debe haber un mal pensamiento en alguna parte ...
Marco Faustinelli
133
git checkout <commit> <filename>

Utilicé esto hoy porque me di cuenta de que mi favicon había sido sobrescrito hace algunos commits cuando actualicé a drupal 6.10, así que tuve que recuperarlo. Aquí esta lo que hice:

git checkout 088ecd favicon.ico
neoneye
fuente
1
¿Cómo obtengo el commit (de un archivo eliminado anteriormente) excepto el desplazamiento que arroja toneladas de salida "git log --stat"?
Alex
44
OMI es un poco difícil a través de la línea de comandos para escanear a través de gits log y encontrar el archivo correcto. Es mucho más fácil con una aplicación GUI, como sourcetreeapp.com
neoneye
66
git log --oneline <filename>le dará un registro más compacto y solo incluirá cambios en el archivo específico
rjmunro
1
alternativamente, puede usargit reflog <filename>
ygesher
70

Si su archivo ya está preparado (sucede cuando hace un git add, etc. después de editar el archivo) para desestabilizar sus cambios.

Utilizar

git reset HEAD <file>

Entonces

git checkout <file>

Si aún no está en escena, solo use

git checkout <file>
Thanikkal
fuente
2
Esto ha sido más útil que el aceptado jaja. Es fácil olvidar qué cambios se han realizado y qué no, por lo que restablecer ayudó. Aunque también probé "git reset --hard" antes, no hizo lo que hizo "git reset HEAD". ¿Me pregunto porque?
Arman Bimatov
20

Si solo desea deshacer los cambios del commit anterior en ese archivo, puede intentar esto:

git checkout branchname^ filename

Esto revisará el archivo como estaba antes de la última confirmación. Si desea regresar algunas confirmaciones más, use la branchname~nnotación.

sykora
fuente
Esto no eliminará los cambios del commit, solo aplicará el diff a la versión en HEAD.
FernandoEscher
2
Si bien es cierto, el póster original solo quería revertir sus modificaciones de la copia de trabajo (creo), no revertir los cambios desde el último commit. La pregunta del póster original era un poco confusa, por lo que puedo entender la confusión.
tal vez no sea el uso de OP, pero estaba buscando cómo sobrescribir mi rama con la copia maestra; esto funciona bastante bien cuando se reemplazabranchname^
Alex
15

He hecho a través de git bash:

(use "git checkout -- <file>..." to discard changes in working directory)

  1. Estado de Git. [Entonces, hemos visto un archivo modificado.
  2. git checkout - index.html [he cambiado en el archivo index.html:
  3. estado de git [ahora se eliminaron esos cambios]

ingrese la descripción de la imagen aquí

Shiva
fuente
8

Siempre me confundo con esto, así que aquí hay un caso de prueba recordatorio; Digamos que tenemos este bashscript para probar git:

set -x
rm -rf test
mkdir test
cd test
git init
git config user.name test
git config user.email [email protected]
echo 1 > a.txt
echo 1 > b.txt
git add *
git commit -m "initial commit"
echo 2 >> b.txt
git add b.txt
git commit -m "second commit"
echo 3 >> b.txt

En este punto, el cambio no está organizado en la memoria caché, por lo que git statuses:

$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   b.txt

no changes added to commit (use "git add" and/or "git commit -a")

Si desde este punto, lo hacemos git checkout, el resultado es este:

$ git checkout HEAD -- b.txt
$ git status
On branch master
nothing to commit, working directory clean

Si en cambio lo hacemos git reset, el resultado es:

$ git reset HEAD -- b.txt
Unstaged changes after reset:
M   b.txt
$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   b.txt

no changes added to commit (use "git add" and/or "git commit -a")

Entonces, en este caso, si los cambios no están organizados, git resetno hay diferencia, mientras que los git checkoutsobrescribe.


Ahora, digamos que el último cambio del script anterior es en etapas / en caché, es decir, también lo hicimos git add b.txtal final.

En este caso, git statusen este punto es:

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    modified:   b.txt

Si desde este punto, lo hacemos git checkout, el resultado es este:

$ git checkout HEAD -- b.txt
$ git status
On branch master
nothing to commit, working directory clean

Si en cambio lo hacemos git reset, el resultado es:

$ git reset HEAD -- b.txt
Unstaged changes after reset:
M   b.txt
$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   b.txt

no changes added to commit (use "git add" and/or "git commit -a")

Por lo tanto, en este caso, si los cambios se organizan, git resetbásicamente se convertirán en cambios no organizados, mientras git checkoutque los sobrescribirá por completo.

sdaau
fuente
7

Esta respuesta es para el comando necesario para deshacer los cambios locales que se encuentran en múltiples archivos específicos en la misma o múltiples carpetas (o directorios). Esta respuesta aborda específicamente la pregunta en la que un usuario tiene más de un archivo pero no quiere deshacer todos los cambios locales:

si tiene uno o más archivos, puede aplicar el mismo comando ( git checkout -- file) a cada uno de esos archivos enumerando cada una de sus ubicaciones separadas por espacio como en:

git checkout -- name1/name2/fileOne.ext nameA/subFolder/fileTwo.ext

tenga en cuenta el espacio anterior entre name1 / name2 / fileOne.ext nameA / subFolder / fileTwo.ext

Para múltiples archivos en la misma carpeta:

Si tiene que descartar los cambios para todos los archivos en un determinado directorio, use la comprobación git de la siguiente manera:

git checkout -- name1/name2/*

El asterisco en lo anterior hace el truco de deshacer todos los archivos en esa ubicación bajo nombre1 / nombre2.

Y, de manera similar, lo siguiente puede deshacer los cambios en todos los archivos para varias carpetas:

git checkout -- name1/name2/* nameA/subFolder/*

nuevamente, tenga en cuenta el espacio entre name1 / name2 / * nameA / subFolder / * en lo anterior.

Nota: nombre1, nombre2, nombreA, subcarpeta: todos estos nombres de carpeta de ejemplo indican la carpeta o paquete donde pueden residir los archivos en cuestión.

Nirmal
fuente
5

Restauro mis archivos usando la identificación SHA, lo que hago es git checkout <sha hash id> <file name>

Beto
fuente
3

Para mí solo este funcionó

git checkout -p filename

ingrese la descripción de la imagen aquí

Ramesh Bhupathi
fuente
2

Si aún no ha empujado o compartido su compromiso:

git diff --stat HEAD^...HEAD | \
fgrep filename_snippet_to_revert | cut -d' ' -f2 | xargs git checkout HEAD^ --
git commit -a --amend
Jesse Glick
fuente
0

Si ya está confirmado, puede revertir el cambio para el archivo y confirmar nuevamente, luego aplastar la nueva confirmación con la última confirmación.

Gina
fuente
1
Agregar comandos específicos para usar ayudaría al póster original y a los futuros visitantes.
Adrian
0

No sé por qué, pero cuando intento ingresar mi código, aparece como una imagen.

ingrese la descripción de la imagen aquí

Gene
fuente