Registra l'operazione di copia dei file con Git


141

Quando sposto un file in git usando git-mv lo stato mostra che il file è stato rinominato e anche se modifico alcune porzioni, considera comunque quasi la stessa cosa (il che è positivo perché mi permette di seguirne la cronologia) .

Quando copio un file, il file originale ha un po 'di storia che vorrei associare alla nuova copia.

Ho provato a spostare il file quindi a riprovare a eseguire il checkout nella posizione originale - una volta spostato git non mi consente di effettuare il checkout nella posizione originale.

Ho provato a fare una copia del filesystem e poi ad aggiungere il file - git lo elenca come nuovo file.

C'è un modo per fare in modo che git registri un'operazione di copia di un file in modo simile a come registra un file rinominare / spostare dove la cronologia può essere ricondotta al file originale?

Risposte:


113

Git non rinomina né rintraccia il tracciamento, il che significa che non registra rinominazioni o copie. Quello che fa invece è rinominare e copiare il rilevamento . È possibile richiedere il rilevamento della ridenominazione in git diff(e git show) utilizzando l' -Mopzione, è possibile richiedere il rilevamento di copie aggiuntive nei file modificati utilizzando l' -Copzione ( -Cimplica -M) e si può richiedere un rilevamento di copia più costoso tra tutti i file con --find-copies-hardero -C -C(il che implica -C, il che implica, -M). Vedi la manpage git-diff .

Puoi anche configurare git affinché esegua sempre il rilevamento della ridenominazione impostando diff.renamesun valore vero booleano (ad es. trueO 1), e puoi richiedere a git di fare anche il rilevamento della copia impostandolo su copyo copies. Vedi la manpage git-config .

Controlla anche l' -lopzione git diffe la relativa variabile di configurazione diff.renameLimit.


Nota che git log <pathspec>funziona in modo diverso in Git: qui <pathspec>è impostato un delimitatore di percorso, dove percorso può essere un (sotto) nome di directory. Filtra e semplifica la cronologia prima che entri in gioco il rilevamento della ridenominazione e della copia. Se vuoi seguire i nomi e le copie, usa git log --follow <filename>(che al momento è un po 'limitato e funziona solo per un singolo file).


1
@allyourcode: di cosa sei confuso? Per attivare il rilevamento della copia per impostazione predefinita, impostare diff.renamessu copies(ad es. ' git config diff.renames copies'). Sono d'accordo che è un po 'controintuitivo.
Jakub Narębski,

Una sezione che non riesco ad analizzare è "e puoi richiedere di fare anche rinominare automaticamente il rilevamento". Stai dicendo che ci sono quattro valori che possono essere usati da diff.renames (true, 1, copy, copy) e che fanno tutti la stessa cosa?
allyourcode,

1
@allyourcode: mi dispiace, non l'ho notato. Risolto ora, grazie.
Jakub Narębski,

4
@ peschü: Git utilizza un database di oggetti indirizzato al contenuto come archivio. Il contenuto del file viene archiviato nel contenuto 'BLOB' sotto l'indirizzo che è l'hash SHA-1 del contenuto (bene, digitare + lunghezza + contenuto). Ciò significa che i contenuti forniti vengono memorizzati una sola volta. Nb. questa deduplicazione automatica è stata la ragione alla base della creazione del sistema di backup "bup", usando il formato git pack.
Jakub Narębski,

1
A differenza della soluzione seguente, questo non funziona con il rilevamento delle modifiche in un intervallo. Git log consente un argomento range ( git log -L123,456:file.xyz) che segue correttamente le ridenominazioni, ma non le copie, e non puoi passare - seguire in quel caso; inoltre, AFAICT, questo non funziona con git blame.
Clément il

57

2020-05-19: La seguente soluzione presenta i vantaggi di non modificare il registro del file originale, non creare un conflitto di unione ed essere più breve.

Puoi forzare Git a rilevare la cronologia del file copiato in tre commit:

  • Invece di copiare, passa a un nuovo ramo e sposta il file nella sua nuova posizione lì.
  • Aggiungi nuovamente il file originale lì.
  • Unisci il nuovo ramo al ramo originale con l'opzione di avanzamento rapido --no-ff.

(I crediti vanno a Raymond Chen .)


La prima soluzione aveva quattro commit:

  • Invece di copiare, passa a un nuovo ramo e sposta il file nella sua nuova posizione lì.
  • Passa al ramo originale e rinomina il file.
  • Unisci il nuovo ramo nel ramo originale, risolvendo il banale conflitto mantenendo entrambi i file.
  • Ripristina il nome file originale in un commit separato.

(Soluzione tratta da https://stackoverflow.com/a/44036771/1389680 .)


7
Semplicità, brevità, 100% ... Questa risposta è un servizio pubblico ... valorizza tutto ciò che è in vista
ptim

1
Qual è la differenza tra movee rename?
Vovan,

@vovan Ti riferisci al fatto che in bash useresti mvper entrambe le operazioni? Stavo usando 'move' per il caso che potrebbe comportare la modifica della directory del file e 'rename' per il caso in cui non lo fosse.
Robert Pollak,

2
Ho provato a seguire questa (nuova) ricetta e non ha funzionato. Potrebbe essere utile se mostrassi i comandi effettivi.
Greg Lindahl,

1
@RobertPollak Ho provato varie versioni di questo ma non hanno funzionato. Con "sposta il file", intendi git mv orig new? Con "letto l'originale", intendi cp new orig && git add orig?
ᆼ ᆺ ᆼ
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.