Git: ¿Cómo revertir 2 archivos que están obstinadamente atascados en "Cambiado pero no confirmado"?

84

Tengo un repositorio que tiene dos archivos que supuestamente cambié localmente.

Así que estoy atrapado con esto:

$ git status
# On branch master
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   dir1/foo.aspx
#       modified:   dir2/foo.aspx
#
no changes added to commit (use "git add" and/or "git commit -a")

Doing git diffdice que todo el contenido del archivo ha cambiado, a pesar de que parece falso (parece haber rangos de línea comunes que diff parece no ver).

Curiosamente, no recuerdo haber cambiado estos archivos localmente. Este repositorio se usa con un repositorio remoto (privado, en GitHub.com, FWIW).

No importa lo que haya intentado, no puedo descartar estos cambios locales. He probado todos:

$ git checkout -- .
$ git checkout -f
$ git checkout -- dir1/checkout_receipt.aspx
$ git reset --hard HEAD
$ git stash save --keep-index && git stash drop
$ git checkout-index -a -f

En otras palabras, probé todo lo que se describe en ¿Cómo descarto los cambios sin etapas en Git? y mucho más. Pero los 2 archivos permanecen bloqueados como "cambiado pero no confirmado".

¿Qué diablos causaría que dos archivos se atasquen de esta manera y aparentemente "deshagan la tabla de reversión"?

PD En la lista anterior que muestra los comandos que ya había probado, escribí por error git revertcuando quise decir git checkout. Lo siento y gracias a aquellos de ustedes que respondieron que debería intentarlo checkout. Edité la pregunta para corregirla. Definitivamente ya lo intenté checkout.

Greg Hendershott
fuente
¿Hace git diff --ignore-space-changeo git diff --ignore-all-spacehace una diferencia en la salida de git diff?
jdd
@jermiahd ¡Sí! Con cualquier bandera, git diffdice que los archivos son idénticos.
Greg Hendershott
2
Posible duplicado de stackoverflow.com/questions/2016404/… . De todos modos, me gusta más la respuesta aceptada allí, que es establecer en git config --global core.autocrlf falselugar de "verdadero".
Johann
2
La respuesta [aquí] [1] funcionó para mí y para muchos otros. [1]: stackoverflow.com/questions/2016404/…
Mike K
2
Esto también sucede cuando el repositorio que contiene 2 o más archivos en el mismo directorio con mayúsculas y minúsculas se extrae en un sistema de archivos que no distingue entre mayúsculas y minúsculas. Elimine o cambie el nombre de uno de los archivos para resolver el problema.
465544

Respuestas:

33

¿Cuáles son los finales de línea en los archivos? Apuesto a que son CRLF. Si es así, consulte esta guía: http://help.github.com/line-endings/

En resumen, debe asegurarse de que git esté configurado para convertir los finales de línea a LF en la confirmación y luego confirmar esos archivos. Los archivos en el repositorio siempre deben ser LF, los archivos extraídos deben ser nativos del sistema operativo, asumiendo que configuró git correctamente.

Tekkub
fuente
1
Gracias. Ya lo hice git config --global core.autocrlf truey también lo hace la otra parte presionando al repositorio en GitHub.
Greg Hendershott
1
Entonces solo debería necesitar hacer los bits en el último <pre>bloque de esa guía para arreglar los archivos en el repositorio.
Tekkub
5
No estoy de acuerdo en que los finales de línea siempre deben ser LF en el repositorio (especialmente si alguien más ya ha comprometido CRLF) y también que el sistema operativo debe ser siempre nativo. Mi editor y entorno de Windows (principalmente para PHP, HTML, CSS, etc.) se adapta perfectamente a las terminaciones de línea LF.
Simon East
Una respuesta genial, había olvidado que recientemente había usado gitattributes para forzar LF en archivos de repositorio y no esperaba que git cambiara automáticamente el archivo. Tenemos una mezcla de desarrolladores de Windows y Linux y nos estaba volviendo locos ya que los editores de diferentes plataformas cambiaban constantemente los terminadores de línea, una vez que el cambio se haya extendido, todo esto debería desaparecer.
Oliver Dungey
120

Pasé horas tratando de resolver un problema similar: una rama remota que había verificado, que obstinadamente mostraba cuatro archivos como 'Cambiados pero no actualizados', ¡incluso al eliminar todos los archivos y ejecutarlos git checkout -fnuevamente (u otras variaciones de esta publicación)!

Estos cuatro archivos eran necesarios, pero ciertamente yo no los había modificado. Mi solución final: convencer a Git de que no se han cambiado. Lo siguiente funciona para todos los archivos extraídos, mostrando el estado 'modificado' - ¡asegúrese de haber confirmado / escondido alguno que realmente haya sido modificado !:

git ls-files -m | xargs -i git update-index --assume-unchanged "{}"

En Mac OSX, sin embargo, xargs funciona un poco diferente (gracias a Daniel por el comentario):

git ls-files -m | xargs -I {} git update-index --assume-unchanged {}

Agregué esto como un marcador de posición para mí la próxima vez, pero espero que también ayude a alguien más.

-Alabama

Alan Forsyth
fuente
10
Tenía un par de archivos obstinados y ejecuté este comando, el estado de git ahora no tiene cambios, pero cuando trato de cambiar la rama, git todavía me dice que no puedo cambiar la rama porque esos dos archivos tienen cambios locales. No estoy seguro de lo que hice mal, pero parecía que solo cubría el problema en lugar de solucionarlo. Tampoco pude enviar los archivos después de ejecutar ese comando. La solución para mí fue eliminarlos, confirmar e intercambiar ramas.
RodH257
5
¡Gracias! Probé TODOS los trucos mencionados en todas las demás respuestas que pude encontrar, ninguno funcionó. en una mac no se pudo usar la línea tal como está, simplemente ejecuté git update-index --assume-unchanged <filename> en cada archivo y esto hizo que el problema desapareciera.
Yonatan Karni
6
Esto es exactamente lo que necesitaba, aunque xargs en Mac parece funcionar de manera un poco diferente (estoy ejecutando 10.10 Yosemite). Esto finalmente funcionó para mí:git ls-files -m | xargs -I {} git update-index --assume-unchanged {}
Daniel
4
Para revertir el efecto del comando:git ls-files -v|grep '^h' | cut -c3- | xargs -i git update-index --no-assume-unchanged "{}"
Marinos An
3
Esta solución no soluciona el problema. Lo esconde. Hay un par de cosas que no se pueden realizar después assume-unchaged, como en el caso de @ RodH257. Creo que la respuesta correcta la mayor para el caso en comandos como git checkout -- file, git stashy git reset --hard HEADno funcionan es, como ya se ha contestado, la edición.gitattributes
Marinos Un
20

así es como solucioné el mismo problema en mi caso: cambio .gitattributes abierto:

* text=auto

a:

#* text=auto

guardar y cerrar, luego revertir o restablecer, gracias a @Simon East por la pista

Abu Assar
fuente
1
Eliminar la text=autoconfiguración en .gitattributes funcionó para mí, y luego, después de que yo git reset --hard, volví a colocar esa configuración, ¡los archivos ya no se mostraban como modificados!
ErikE
1
Obviamente, hay algo mal en esta text=autoconfiguración. Estoy trabajando en repositorios con confirmaciones de varios sistemas operativos y todavía no he descubierto qué me causa más problemas: mantenerlo o eliminarlo.
Marinos An
1
@MarinosUn sí, específicamente, git te permite dejar los archivos de texto existentes con los finales de línea incorrectos cuando agregas esta configuración por primera vez. Eso está mal y, a menos que recuerde hacerlo usted mismo, eventualmente se encontrará con uno de estos cambios irreversibles.
Roman Starkov
12

Otra posibilidad es que la diferencia (que le impide revertir estos archivos con un comando de pago) es el modo de archivo. Esto es lo que me pasó. En mi versión de git puedes descubrir esto usando

git diff dir1 / foo.aspx

Y le mostrará los cambios de modo de archivo. Sin embargo, todavía no le permitirá revertirlos. Para ese uso ya sea

git config core.filemode false

o cambie su git .config en su editor de texto agregando

[núcleo]

filemode = false

Después de hacer esto, puede usar

git restablecer HEAD dir1 / foo.aspx

y el archivo debería desaparecer.

(Obtuve todo esto de la respuesta a ¿Cómo hago que git ignore los cambios de modo (chmod)? )

Eyal
fuente
1
Si estás en Windows, diagnóstico / solución de Eyal debe ser su primera conjetura
Métrica de Alcubierre
Tenga especial cuidado de no usar cygwin git de cmd.exe. Si desea git en cmd.exe, instale msysgit.
AlcubierreDrive
Solo para confirmar que este era el problema en Windows.
Dejan Marjanović
Para mí en Windows, este no era el problema ( core.filemodeya estaba configurado como falso). En mi caso, la solución / solución alternativa fue la de la respuesta de Alan Forsyth .
Venryx
3

Intente revertir los cambios locales :

git checkout -- dir1/foo.aspx
git checkout -- dir2/foo.aspx
Tadeck
fuente
Tenía "revertir" en el cerebro y tenía la intención de escribir checkout. Ya lo intenté checkout. Gracias de todos modos por tu respuesta. Fue una buena respuesta a mi pregunta original, así que votaré a favor.
Greg Hendershott
3

Tenía algunos archivos modificados fantasma que se mostraban como modificados, pero en realidad eran idénticos.

Ejecutar este comando a veces funciona:
(Desactiva las conversiones de final de línea "inteligentes" pero a menudo inútiles de git)

git config --local core.autocrlf false

Pero en otro caso descubrí que se debía a un .gitattributesarchivo en la raíz que tenía algunas configuraciones de final de línea presentes, que intentaba aplicar autocrlfpara ciertos archivos incluso cuando estaba apagado. Eso no fue realmente útil, así que eliminé .gitattributes, comprometí y el archivo ya no se mostró como modificado.

Simon East
fuente
Eliminar la text=autoconfiguración en .gitattributes funcionó para mí, y luego, después de que yo git reset --hard, volví a colocar esa configuración, ¡los archivos ya no se mostraban como modificados!
ErikE
2
git checkout dir1/foo.aspx
git checkout dir2/foo.aspx
Steve Prentice
fuente
Tenía "revertir" en el cerebro y tenía la intención de escribir checkout. Ya lo intenté checkout. Gracias de todos modos por tu respuesta. Fue una buena respuesta a mi pregunta original, así que votaré a favor.
Greg Hendershott
2

También puede haber tenido un problema relacionado con los directorios que nombran mayúsculas y minúsculas. Algunos de sus colegas podrían haber cambiado el nombre del directorio de, por ejemplo, myHandler a MyHandler . Si luego empujó y extrajo algunos de los archivos del directorio original, habría tenido 2 directorios separados en el repositorio remoto Y solo uno en su máquina local, ya que en Windows solo puede tener uno. Y estás en problemas.

Para verificar si ese es el caso, solo vea si el repositorio remoto tiene una estructura doble.

Para solucionar este problema, haga una copia de seguridad del directorio principal fuera del repositorio, luego elimine el directorio principal y empújelo. Haga un tirón (aquí es cuando el segundo marcado como eliminado debería aparecer en el estado) y presione nuevamente. Después de eso, vuelva a crear toda la estructura a partir de su copia de seguridad y vuelva a introducir los cambios.

smexy
fuente
2

Creo que sería útil proporcionar una pista sobre cómo reproducir el problema para comprender mejor el problema:

$ git init
$ echo "*.txt -text" > .gitattributes
$ echo -e "hello\r\nworld" > 1.txt
$ git add 1.txt 
$ git commit -m "committed as binary"
$ echo "*.txt text" > .gitattributes
$ echo "change.." >> 1.txt

# Ok let's revert now

$ git checkout -- 1.txt
$ git status
 modified:   1.txt

# Oooops, it didn't revert!!


# hm let's diff:

$ git diff
 warning: CRLF will be replaced by LF in 1.txt.
 The file will have its original line endings in your working 
 directory.
 diff --git a/1.txt b/1.txt
 index c78c505..94954ab 100644
 --- a/1.txt
 +++ b/1.txt
 @@ -1,2 +1,2 @@
 -hello
 +hello
  world

# No actual changes. Ahh, let's change the line endings...

$ file 1.txt 
 1.txt: ASCII text, with CRLF line terminators
$ dos2unix 1.txt
 dos2unix: converting file 1.txt to Unix format ...
$ git diff
 git diff 1.txt
 diff --git a/1.txt b/1.txt
 index c78c505..94954ab 100644
 --- a/1.txt
 +++ b/1.txt
 @@ -1,2 +1,2 @@
 -hello
 +hello
  world

# No, it didn't work, file is still considered modified.

# Let's try to revert for once more:
$ git checkout -- 1.txt
$ git status
 modified:   1.txt

# Nothing. Let's use a magic command that prints wrongly committed files.

$ git grep -I --files-with-matches --perl-regexp '\r' HEAD

HEAD:1.txt

Segunda forma de reproducir: En el script anterior, reemplace esta línea:
echo "*.txt -text" > .gitattributes
con
git config core.autocrlf=false
y mantenga el resto de las líneas como está


¿Qué dicen todos los anteriores? Un archivo de texto puede (bajo algunas circunstancias) ser comprometido con CRLF, (por ejemplo, -texten .gitattributes/ o core.autocrlf=false).

Cuando luego queramos tratar el mismo archivo como texto ( -text-> text), será necesario confirmarlo nuevamente.
Por supuesto, puede revertirlo temporalmente (como respondió correctamente Abu Assar ). En nuestro caso:

echo "*.txt -text" > .gitattributes
git checkout -- 1.txt
echo "*.txt text" > .gitattributes

La respuesta es : ¿realmente quieres hacer eso? Porque causará el mismo problema cada vez que cambies el archivo.


Para el registro:

Para verificar qué archivos pueden causar este problema en su repositorio, ejecute el siguiente comando (git debe compilarse con --with-libpcre):

git grep -I --files-with-matches --perl-regexp '\r' HEAD

Al comprometer el (los) archivo (s) (suponiendo que quiera tratarlos como texto), es lo mismo que hacer lo que se propone en este enlace http://help.github.com/line-endings/ para solucionar dichos problemas . Pero, en lugar de eliminar .git/indexy ejecutar reset, puede simplemente cambiar los archivos, luego ejecutar git checkout -- xyz zyfy luego confirmar.

Marinos An
fuente
2

Tuve el mismo problema, con la interesante adición de que los archivos se cambiaron en Windows, pero no al mirarlos desde WSL. Ninguna cantidad de juegos con finales de línea, reinicios, etc. pudo cambiarlo.

Finalmente, encontré una solución en esta respuesta . A continuación se muestra el texto de conveniencia:


He resuelto este problema siguiendo los siguientes pasos

1) Elimina todos los archivos del índice de Git.

git rm --cached -r .

2) Vuelva a escribir el índice de Git para recoger todos los nuevos finales de línea.

git reset --hard

La solución fue parte de los pasos descritos en el sitio de git https://help.github.com/articles/dealing-with-line-endings/

MCO
fuente
1

Para mí, el problema no se trataba de finales de línea. Se trataba de cambiar mayúsculas y minúsculas en el nombre de la carpeta (Reset_password -> Reset_Password). Esta solución me ayudó: https://stackoverflow.com/a/34919019/1328513

Zhenya
fuente
1

Este problema también puede deberse a que git trata las diferencias de mayúsculas como archivos diferentes, pero Windows los trata como el mismo archivo. Si el nombre de un archivo solo cambia las mayúsculas, todos los usuarios de Windows de ese repositorio terminarán en esta situación.

La solución es confirmar que el contenido de los archivos es correcto y luego volver a enviarlo. Tuvimos que fusionar el contenido de los dos archivos ya que eran diferentes. Luego tire y habrá un conflicto de fusión que puede resolver eliminando el archivo duplicado. Vuelva a enviar la resolución de combinación y volverá a un estado estable.

Andrew West
fuente