In che modo Git tiene traccia della cronologia durante un refactoring?

Comprendo bene come Git può supportare i trasferimenti di file: poiché utilizza l’hash del file, un file “aggiunto” viene facilmente rilevato come uguale a quello “rimosso”.

La mia domanda riguarda il refactoring: considerando Java, la dichiarazione del pacchetto cambia in modo che il contenuto del file NON sia lo stesso. In tal caso, in che modo Git determina che il file “aggiunto” condivide la cronologia con quella “rimossa”? Verifica la presenza di “contenuti più simili” assumendo che io abbia apportato solo modifiche minori o una soluzione non deterministica simile?

Come accennato in Git FAQ , rileverà contenuti simili basati su un’euristica.

Git deve interagire con molti diversi flussi di lavoro, ad esempio alcune modifiche possono provenire da patch, dove le informazioni sulla rinomina potrebbero non essere disponibili. Affidarsi al rintracciamento esplicito del rinominato rende imansible unire due alberi che hanno fatto esattamente la stessa cosa, tranne uno lo ha fatto come una patch (crea / cancella) e l’ha fatto usando un altro euristico.

In una seconda nota, rinominare i tracking è in realtà solo un caso particolare di tracciamento del modo in cui il contenuto si muove nell’albero. In alcuni casi, potresti invece essere interessato a interrogare quando una funzione è stata aggiunta o spostata in un altro file. Basandosi solo sulla possibilità di ricreare queste informazioni quando necessario, Git mira a fornire un modo più flessibile per tenere traccia di come cambia il tuo albero.

Tuttavia, questo non significa che Git non abbia supporto per la rinomina.
Il macchinario diff in Git ha il supporto per il rilevamento automatico della rinomina, questo è triggersto dall’interruttore ‘ -M ‘ alla famiglia di comandi git-diff-* .
Il meccanismo di rilevamento della ridenominazione viene utilizzato da git-log (1) e git-whatchanged (1) , quindi, ad esempio, ‘ git log -M ‘ fornirà la cronologia dei commit con le informazioni sulla rinomina.
Git supporta anche una forma limitata di fusione tra i nomi.
I due strumenti per assegnare la colpa, git-blame(1) e git-annotate(1) utilizzano entrambi il codice di rilevamento automatico del nome per rinominare i nomi.


git log ti fornisce alcuni dettagli su quella euristica:

 -B[][/] 

Break completa riscrive le modifiche in coppie di cancella e crea. Questo ha due scopi:

  • Colpisce il modo in cui un cambiamento che equivale a una riscrittura totale di un file non come una serie di cancellazioni e inserimenti mescolati con poche righe che capita di corrispondere testualmente al contesto, ma come una singola cancellazione di tutto ciò che è vecchio seguito da un singolo inserimento di tutto ciò che è nuovo, e il numero m controlla questo aspetto dell’opzione -B (il valore predefinito è 60%).
    -B / 70% specifica che meno del 30% dell’originale dovrebbe rimanere nel risultato per git per considerarlo una riscrittura totale (altrimenti la patch risultante sarà una serie di cancellazioni e inserimenti mescolati insieme con le linee di contesto).

  • Quando viene utilizzato con -M, anche un file completamente riscritto viene considerato come la fonte di un rinominare (in genere -M considera solo un file che è scomparso come origine di una rinomina) e il numero n controlla questo aspetto dell’opzione -B (predefinito al 50%) .
    -B20% specifica che una modifica con aggiunta e cancellazione rispetto al 20% o più delle dimensioni del file può essere considerata come una ansible fonte di una rinomina in un altro file.

 -M[] 

Se si generano diff, rilevare e segnalare rinomina per ciascun commit. Per i seguenti file durante la rinomina mentre si attraversa la cronologia, vedere – --follow .
Se n è specificato, è a è una soglia sull’indice di similarità (cioè quantità di addizione / cancellazione rispetto alla dimensione del file).
Ad esempio, -M90% significa che git dovrebbe considerare una coppia di eliminazione / aggiunta di essere un rinominare se non è stato modificato più del 90% del file .


Ulteriori riferimenti:

  • L’ultimo post del blog di Linus per lo strumento di tracciamento dei contenuti , di Junio ​​C Hamano, manutentore di Git.
  • Ottenere Git per riconoscere i file precedentemente spostati
  • Come fare a git mark un cancellato e un nuovo file come mossa di un file?
  • In che modo Git risolve il problema della fusione?

Nota: con Git 2.18 (Q2 2018), lo git status dovrebbe ora mostrare i nomi (invece di cancellare / aggiungere file) quando si spostano / rinominano i file.
Vedi ” Come dire a Git che è la stessa directory, solo un nome diverso “.