2015-08-19 42 views
7

Supponiamo di avere un file a.txt. Un giorno, l'ho cancellato, commesso e spinto.Git ripristina il file cancellato e conserva la cronologia dei file

Il giorno successivo, volevo annullare l'ultimo commit, riportando a.txt. Ho provato a utilizzare git revert, ma quando ho fatto git blame, tutte le linee stanno mostrando l'annullamento del commit hash. La storia della colpa originale è persa.

Posso recuperare il file e conservare la cronologia dei file, ad esempio, come se il file non fosse stato eliminato prima? Si noti che non è necessario modificare la cronologia poiché il commit è stato eseguito.

Grazie!

+0

Intendi dire che non è possibile eseguire un push forzato a monte? – shengy

+2

Git non traccia la cronologia dei file; tiene traccia solo della cronologia dell'intera directory radice. Quindi ricostruire la cronologia dei file è un problema quando si richiede di visualizzare la cronologia, non quando si ripristina il file. – Nayuki

+0

@shengy No, non riesco a – fushar

risposta

0

È possibile farlo utilizzando git reset anziché git revert. git reset rilascia il nuovo commit e verifica un commit precedente. Questo non è raccomandato se hai già spinto a monte.

NAME 
     git-reset - Reset current HEAD to the specified state 

SYNOPSIS 
     git reset [-q] [<tree-ish>] [--] <paths>... 
     git reset (--patch | -p) [<tree-ish>] [--] [<paths>...] 
     git reset [--soft | --mixed | --hard | --merge | --keep] [-q] [<commit>] 

DESCRIPTION 
     In the first and second form, copy entries from <tree-ish> to the index. In the third form, set the 
     current branch head (HEAD) to <commit>, optionally modifying index and working tree to match. The 
     <tree-ish>/<commit> defaults to HEAD in all forms. 

Dal momento che avete già preme:

  • Se non si hanno collaboratori attivi che trainavano quel giorno, utilizzare git reset e forzare la spinta git push -f.
+0

Ha già cancellato il file e spinto verso l'alto, 'git reset' a questo punto non funziona per lui. – shengy

1

Run git colpa con l'opzione -C specificata tre volte:

git blame -C -C -C 

Questo fa sì che git blame a cercare i contenuti copiati dai file di commit precedenti.

Da the documentation for git blame:

-C|<num>|

Oltre a -M, rilevare linee spostati o copiati da altri file che sono stati modificati nella stessa commit. Ciò è utile quando riorganizzi il tuo programma e trasferisci il codice tra i file. Quando questa opzione è assegnata due volte, il comando cerca anche copie da altri file nel commit che crea il file. Quando questa opzione viene data per tre volte , il comando cerca anche copie da altri file in qualsiasi commit.

<num> è facoltativo ma è il limite inferiore del numero di caratteri alfanumerici che Git deve rilevare come spostamento/copia tra file per poter associare quelle linee con il genitore commettere. E il valore predefinito è 40. Se sono disponibili più di una delle opzioni -C, l'argomento <num> dell'ultimo -C avrà effetto.

+0

Sei sicuro che funzioni? Ho provato qualcosa come 'git init'' echo "test"> a.txt "' 'git add a.txt'' git commit -m "Commit 1" '' echo "foobar" >> a.txt' 'git add a.txt' 'git commit -m" Commit 2 "' 'git rm a.txt'' git commit -m "Commit 3" '' git revert HEAD' 'git blame -C -C -C a.txt' e entrambe le righe mostrano il commit di annullamento ... – fushar

+0

@fushar Sono abbastanza sicuro che hai bisogno di più di una parola per git per registrare che hai spostato qualcosa I documenti dicono che 40 caratteri sono il minimo Ho modificato la citazione nella mia risposta per essere più completo – Ajedi32

+0

Volevo solo dimostrare che la tua soluzione non funziona, nell'esempio più semplice: in realtà non funziona sul mio progetto reale (il mio contenuto del file cancellato è molto più grande di 40 ovviamente). - 'git blame -C1 -C1 -C1 a.txt' sfortunatamente non funziona anche per l'esempio' a.txt'. – fushar

2

È CAN fare questo!Ecco come:

  1. Avviare un nuovo ramo dal commit che precede l'eliminazione che si desidera annullare.
  2. Unire la modifica all'origine di errore con git merge <sha> -s ours.
  3. Se le modifiche commettere avuto oltre l'eliminazione che si desidera conservare:
    1. riapplicare le modifiche alla vostra copia di lavoro con git diff <sha>^..<sha> | git apply.
    2. Ignora le eliminazioni (sono disponibili molte tecniche: git checkout -p potrebbe funzionare bene per te).
  4. Unire questo ramo nuovamente al ramo principale (ad es. Master).

Questo produce una cronologia con due rami; uno in cui il file è stato cancellato e uno in cui non è mai stato eliminato. Di conseguenza, git è in grado di tracciare la cronologia dei file senza ricorrere a eroismi come -C -C -C. (In effetti, anche con -C -C -C, il file non viene "ripristinato", poiché ciò che git vede è che un nuovo file è stato creato come una copia di un file esistente. Con questa tecnica, stai reintroducendo lo stesso file al repository.)

+0

Funziona come un piacere e ho imparato qualcosa ora, grazie @Matthew! Il mio caso era abbastanza complesso e avevo bisogno di leggere un po 'in git checkout -p', ma anche su un commit parzialmente offensivo con modifiche miste questo approccio ha finito per funzionare esattamente come ne avevo bisogno. – bossi