Git: Come ripristinare 2 file che sono ostinatamente bloccati su "Modificato ma non confermato"?


84

Ho un repository che ha due file che presumibilmente ho cambiato localmente.

Quindi sono bloccato con questo:

$ 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 che l'intero contenuto del file è cambiato, anche se dall'occhio sembra falso (sembrano esserci intervalli di linee comuni che diff sembra non riuscire a vedere).

È interessante notare che non ricordo di aver cambiato questi file localmente. Questo repository viene utilizzato con un repository remoto (privato, su GitHub.com, FWIW).

Non importa cosa ho provato, non posso annullare queste modifiche locali. Ho provato tutto:

$ 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

In altre parole ho provato tutto quanto descritto in Come faccio a eliminare le modifiche non organizzate in Git? e altro ancora. Ma i 2 file rimangono bloccati come "modificati ma non salvati".

Cosa diavolo potrebbe causare il blocco di due file in questo modo e apparentemente "un-revert-table" ??

PS Nell'elenco sopra che mostra i comandi che avevo già provato, ho scritto erroneamente git revertquando intendevo git checkout. Mi dispiace e grazie a quelli di voi che mi hanno risposto che avrei dovuto provare checkout. Ho modificato la domanda per correggerla. Sicuramente ho già provato checkout.


Fa git diff --ignore-space-changeo git diff --ignore-all-spacefa differenza nell'output di git diff?
jdd

@jermiahd Sì! Con entrambi i flag, git diffdice che i file sono identici.
Greg Hendershott

2
Possibile duplicato di stackoverflow.com/questions/2016404/… . Comunque mi piace di più la risposta accettata, ovvero impostare git config --global core.autocrlf falseinvece di "vero".
Johann

2
La risposta [qui] [1] ha funzionato per me e per molti altri. [1]: stackoverflow.com/questions/2016404/…
Mike K

2
Ciò accade anche quando il repository contenente 2 o più file nella stessa directory con un caso diverso viene estratto in un file system senza distinzione tra maiuscole e minuscole. Rimuovere o rinominare uno dei file per risolvere il problema.

Risposte:


34

Quali sono le terminazioni di riga nei file? Scommetto che sono CRLF. Se lo sono, consulta questa guida: http://help.github.com/line-endings/

In breve, devi assicurarti che git sia impostato per convertire le terminazioni di riga in LF al momento del commit, quindi eseguire il commit di quei file. I file nel repository dovrebbero essere sempre LF, i file estratti dovrebbero essere nativi del sistema operativo, supponendo che tu abbia impostato git correttamente.


1
Grazie. L'ho già fattogit config --global core.autocrlf true e anche l'altra parte spinge al repo su GitHub.
Greg Hendershott

1
Quindi dovresti solo eseguire i bit nell'ultimo <pre>blocco di quella guida per correggere i file nel repository.
Tekkub

5
Non sono d'accordo sul fatto che le terminazioni di riga dovrebbero sempre essere LF nel repo (specialmente se qualcun altro ha già eseguito il commit di CRLF) e anche che il sistema operativo dovrebbe essere sempre nativo. Il mio editor e ambiente Windows (principalmente per PHP, HTML, CSS ecc.) Si adatta perfettamente alle terminazioni di riga LF.
Simon East

Una risposta geniale, avevo dimenticato che di recente avevo usato gitattributes per forzare LF nei file repo e non mi aspettavo che git cambiasse automaticamente il file. Abbiamo un mix di sviluppatori Windows e Linux e ci stava facendo impazzire mentre gli editor su piattaforme diverse continuavano a cambiare i terminatori di riga, una volta che il cambiamento si è diffuso tutto questo dovrebbe andare via.
Oliver Dungey

121

Ho passato ore a cercare di risolvere un problema simile: un ramo remoto che avevo controllato, che mostrava ostinatamente quattro file come "Modificati ma non aggiornati", anche quando cancellavo tutti i file e correvo di git checkout -fnuovo (o altre variazioni da questo post)!

Questi quattro file erano necessari, ma di certo non erano stati modificati da me. La mia soluzione finale: convincere Git che non erano stati modificati. Quanto segue funziona per tutti i file estratti, mostrando lo stato 'modificato': assicurati di aver già eseguito il commit / nascosto di quelli che sono stati realmente modificati!:

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

Su Mac OSX, tuttavia, xargs funziona in modo leggermente diverso (grazie a Daniel per il commento):

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

L'ho aggiunto come segnaposto per me per la prossima volta, ma spero che aiuti anche qualcun altro.

-Al


10
Avevo un paio di file testardi e ho eseguito questo comando, git status ora non cambia, ma quando provo a cambiare ramo git continua a dirmi che non posso cambiare ramo perché quei due file hanno modifiche locali. Non sei sicuro di cosa ho fatto di sbagliato, ma sembrava che avesse semplicemente coperto il problema invece di risolverlo? Inoltre, non ho potuto eseguire il commit dei file dopo aver eseguito quel comando. La soluzione per me era eliminarli, eseguire il commit e scambiare i rami.
RodH257

5
Grazie! Ho provato TUTTI i trucchi menzionati in ogni altra risposta che ho trovato - nessuno ha funzionato. su un Mac non è stato possibile utilizzare la riga così com'è, è sufficiente eseguire git update-index --assume-unchanged <filename> su ogni file e questo ha risolto il problema.
Yonatan Karni

6
Questo è esattamente ciò di cui avevo bisogno, anche se xargs su Mac sembra funzionare in modo leggermente diverso (sto eseguendo 10.10 Yosemite). Alla fine questo ha funzionato per me:git ls-files -m | xargs -I {} git update-index --assume-unchanged {}
Daniel

4
Per annullare l'effetto del comando:git ls-files -v|grep '^h' | cut -c3- | xargs -i git update-index --no-assume-unchanged "{}"
Marinos An

3
Questa soluzione non risolve il problema. Lo nasconde. Ci sono un paio di cose che non possono essere eseguite dopo assume-unchaged, come nel caso di @ RodH257. Credo che la risposta più corretta per il caso in cui i comandi piace git checkout -- file, git stashe git reset --hard HEADnon funzionano è, come già risposto, modificando.gitattributes
Marinos Un

20

ecco come ho risolto lo stesso problema nel mio caso: open .gitattributes change:

* text=auto

per:

#* text=auto

salva e chiudi, quindi ripristina o ripristina, grazie a @Simon East per il suggerimento


1
La rimozione text=autodell'impostazione in .gitattributes ha funzionato per me, quindi dopo git reset --hardaver ripristinato l'impostazione, i file non venivano più visualizzati come modificati!
ErikE

1
Ovviamente c'è qualcosa di sbagliato in questa text=autoimpostazione. Sto lavorando in repository con commit da più OS e non ho ancora capito cosa mi causi più problemi: mantenerlo o lasciarlo cadere.
Marinos An

1
@Marinos Sì, in particolare git ti consente di lasciare i file di testo esistenti con le terminazioni di riga sbagliate quando aggiungi questa impostazione per la prima volta. È semplicemente sbagliato e, a meno che non ti ricordi di farlo da solo, alla fine ti imbatterai in uno di questi cambiamenti irreversibili.
Roman Starkov

12

Un'altra possibilità è che la differenza (che ti impedisce di ripristinare questi file con un comando di checkout) è una modalità file. Questo è quello che mi è successo. Sulla mia versione di git puoi scoprirlo usando

git diff dir1 / foo.aspx

E ti mostrerà le modifiche alla modalità file. Tuttavia, non ti permetterà ancora di ripristinarli. Anche per quell'uso

git config core.filemode false

o cambia il tuo git .config nel tuo editor di testo aggiungendo

[nucleo]

filemode = false

Dopo averlo fatto, puoi usare

git resetta HEAD dir1 / foo.aspx

e il file dovrebbe scomparire.

(Ho ottenuto tutto questo dalla risposta a Come faccio a fare in modo che git ignori le modifiche alla modalità (chmod)? )


1
Se sei su Windows, la diagnosi / soluzione di Eyal dovrebbe essere la tua prima ipotesi
AlcubierreDrive

Prestare particolare attenzione a non utilizzare mai cygwin git da cmd.exe. Se vuoi git in cmd.exe, installa msysgit.
AlcubierreDrive

Solo per confermare che questo era davvero il problema su Windows.
Dejan Marjanović

Per me su Windows, questo non era il problema ( core.filemodeera già impostato su false). Nel mio caso, la soluzione / soluzione alternativa era quella nella risposta di Alan Forsyth .
Venryx

3

Prova a ripristinare le modifiche locali :

git checkout -- dir1/foo.aspx
git checkout -- dir2/foo.aspx

Avevo "ripristinato" il cervello e avevo intenzione di scrivere checkout. Ho già provato checkout. Grazie comunque per la tua risposta. È stata una buona risposta alla mia domanda originale, quindi voterò.
Greg Hendershott

3

Avevo alcuni file modificati fantasma che venivano visualizzati come modificati, ma in realtà erano identici.

L'esecuzione di questo comando a volte funziona:
(disattiva le conversioni "intelligenti" ma spesso inutili di fine riga di git)

git config --local core.autocrlf false

Ma in un altro caso ho scoperto che era dovuto a un .gitattributesfile nella root che aveva alcune impostazioni di fine riga presenti, che stava cercando di applicarsi autocrlfa determinati file anche quando era disattivato. In realtà non è stato utile, quindi ho eliminato .gitattributes, eseguito il commit e il file non è più mostrato come modificato.


La rimozione text=autodell'impostazione in .gitattributes ha funzionato per me, quindi dopo git reset --hardaver ripristinato l'impostazione, i file non venivano più visualizzati come modificati!
ErikE

2
git checkout dir1/foo.aspx
git checkout dir2/foo.aspx

Avevo "ripristinato" il cervello e avevo intenzione di scrivere checkout. Ho già provato checkout. Grazie comunque per la tua risposta. È stata una buona risposta alla mia domanda originale, quindi voterò.
Greg Hendershott

2

Potresti anche aver avuto un problema relativo alla denominazione delle maiuscole nelle directory. Alcuni dei tuoi colleghi potrebbero aver cambiato il nome della directory da, ad esempio, myHandler a MyHandler . Se in seguito hai spinto e estratto alcuni dei file della directory originale, avresti avuto 2 directory separate sul repository remoto E solo una sulla tua macchina locale poiché su Windows puoi averne solo una. E tu sei nei guai.

Per verificare se è così, controlla se il repository remoto ha una doppia struttura.

Per risolvere questo problema, creare una copia di backup della directory principale al di fuori del repository, quindi eliminare la directory principale e inviarla. Fai un pull (qui quando il secondo contrassegnato come cancellato dovrebbe apparire sullo stato) e premi di nuovo. Successivamente, ricrea l'intera struttura dal backup e invia nuovamente le modifiche.


2

Penso che sarebbe utile fornire un suggerimento su come riprodurre il problema , al fine di comprendere meglio il 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

2 ° modo di riprodurre: nello script sopra, sostituire questa riga:
echo "*.txt -text" > .gitattributes
con
git config core.autocrlf=false
e mantenere il resto delle righe così com'è


Cosa dicono tutte le precedenti? Un file di testo può (in alcune circostanze) essere salvato con CRLF, (ad esempio -textin .gitattributes/ o core.autocrlf=false).

Quando in seguito vogliamo trattare lo stesso file come testo (-text -> text), sarà necessario eseguire nuovamente il commit.
Ovviamente puoi ripristinarlo temporaneamente (come correttamente risposto da Abu Assar ). Nel nostro caso:

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

La risposta è : vuoi davvero farlo, perché causerà lo stesso problema ogni volta che cambi il file.


Per il record:

Per verificare quali file possono causare questo problema nel tuo repository, esegui il seguente comando (git dovrebbe essere compilato con --with-libpcre):

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

Salvando i file (supponendo che tu voglia trattarli come testo), è la stessa cosa che fare ciò che viene proposto in questo link http://help.github.com/line-endings/ per risolvere tali problemi . Ma, invece di rimuovere .git/indexed eseguire reset, puoi semplicemente modificare i file, quindi eseguire git checkout -- xyz zyfe quindi eseguire il commit.


2

Ho avuto lo stesso problema, con l'interessante aggiunta che i file sono stati modificati su Windows, ma non quando li guardavo da WSL. Nessun problema con le terminazioni di linea, i ripristini ecc.

Alla fine, ho trovato una soluzione in questa risposta . Di seguito è riportato il testo per convenince:


Ho risolto questo problema utilizzando i seguenti passaggi

1) Rimuovi ogni file dall'indice di Git.

git rm --cached -r .

2) Riscrivi l'indice Git per riprendere tutte le nuove terminazioni di riga.

git reset --hard

La soluzione faceva parte dei passaggi descritti sul sito git https://help.github.com/articles/dealing-with-line-endings/



1

Questo problema può anche essere dovuto al fatto che git tratta le differenze di maiuscole e minuscole come file diversi, ma Windows le tratta come lo stesso file. Se il nome di un file aveva solo la sua maiuscola cambiata, ogni utente Windows di quel repository si ritroverà in questa situazione.

La soluzione è confermare che i contenuti dei file siano corretti e quindi riprovare. Abbiamo dovuto unire i contenuti dei due file insieme poiché erano diversi. Quindi tirare e ci sarà un conflitto di unione che puoi risolvere eliminando il file duplicato. Ripeti la risoluzione dell'unione e torni a uno stato stabile.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.