2015-10-21 26 views
5

Ho biforcato un repository e modificato il file A. Ora il file A nel repository upstream è stato spostato in una sottodirectory. Sto cercando di unire il repo upstream alla mia forcella.Git unione dei file spostati

Git pensa che il file A è stato eliminato nella sua posizione originale e ne è stato creato uno nuovo nella nuova sottodirectory (Ciò potrebbe anche essere dovuto al modo in cui hanno spostato il file upstream).

Voglio ottenere le mie modifiche in questo file nella nuova posizione con meno ripercussioni possibili, cronologia w.r.t di commit e roba. Qualcuno può aiutarmi a trovare modi per raggiungere questo obiettivo?

+0

Hai conflitti durante la fusione? Di solito Git è abbastanza intelligente da capire che un file è stato spostato. Cosa succede se si esegue semplicemente "git merge origin/master' (o qualunque sia il nome del ramo upstream)? – knittl

risposta

5

Git rileva sempre i nomi "dopo il fatto", confrontando i due alberi in questione (o un albero e l'indice, per i casi che non includono git merge stesso). (Linus Torvalds considera questa una caratteristica, vedi this SO question per esempio.)

In ogni caso, git merge verrà eseguito diff interno di git con rilevamento merge abilitata e la somiglianza-indice di default del 50%, a meno che non si configura diversamente. Analogamente, git diff ha alcune impostazioni predefinite che sono anche configurabili. Se esegui manualmente git diff --find-renames -M50% tra il merge-base e l'upstream, probabilmente stai bene (ma vedi la nota 1 sulla configurazione).

Se git non rileva, è possibile che sia necessario regolare le soglie di rilevamento del rename e/o aumentare il numero di file che git dovrebbe prendere in considerazione. Il primo di questi è il valore rename-threshold nelle opzioni -X (rename-threshold compare per la prima volta in git 1.7.4). Vedi the documentation per i dettagli.


È possibile impostare merge.renameLimit per il numero di file da considerare in termini di rilevazione Rinomina. Se non lo si imposta, il valore predefinito corrente è 1000 file (ma l'impostazione predefinita è cambiata nel tempo). Inoltre, se non lo imposti, unisci usa diff.renameLimit, quindi puoi impostare solo il secondo di questi e avere sia diff sia unire usa entrambi i valori.

Il modo in cui il rilevamento del rinominare file funziona è un po 'complesso, ma abbastanza semplice da descrivere con l'esempio. Supponiamo che git stia confrontando commit 12345 con commit 67890, e in 12345 ci sono file con nomi di percorso A, B/C e D; ma in 67890 ci sono i nomi di percorso B/gronk, B/C e D. Ciò significa che il percorso A è scomparso, ma è stato visualizzato il nuovo percorso B/gronk.Git ricorderà quindi tali percorsi (fino al valore limite di ridenominazione) e confronterà i contenuti di 12345:A con il contenuto di 67890:B/gronk. Se i file sono "sufficientemente simili", git dichiarerà che 12345:A è stato rinominato in 67890:B/gronk.

Non sono sicuro di come Git decida che un file è del 50%, o del 75%, o simile, simile/diverso. Ho visto che l'indice di similarità è basato su "chunk" piuttosto che su linee (anche se il solito output diff è orientato alla linea), comunque.

1

È necessario utilizzare git mv e non solo mv per spostare il file.

Poiché git acquisisce un'istantanea del contenuto, non interessa il nome file (che è archiviato in un file idx come metadati).

Se si sposta semplicemente il file, git non "capirà" che si desidera spostarlo e lo tratterà come un nuovo file.

è necessario ripristinare le modifiche e quindi utilizzare:

git mv <old path> <new path> 

Ora in git status vedrete lo spostamento del file e non la cancellazione di uno e la creazione di uno nuovo.

+2

Questo non è corretto, o almeno incompleto: git scopre i nomi dei nomi "dopo il fatto" quando si confrontano due alberi o si confrontano un albero e l'indice, in base ai flag forniti al suo codice diff interno. Il comando 'git status' imposta sempre" check per rinomina "ma' git diff' e 'git show' usano' -M', '--find-renames',' --no-renames', e le impostazioni di configurazione ('diff.renames' e' diff.renamelimit') per controllare il macchinario di rilevamento del rinominato. Se hai già rinominato un file, quindi 'git rm --cached' il vecchio percorso e' git add' il nuovo percorso, ottieni lo stesso effetto di come avresti usato 'git mv'. – torek

+0

Non ho spostato manualmente il file. Sto cercando di unire il repo upstream con il mio. Viene spostato nel repository upstream. –