Come applicare una patch Git a un file con un nome e un percorso diversi?


100

Ho due repository. In uno, apporto modifiche al file ./hello.test. Eseguo le modifiche e creo una patch da quel commit con git format-patch -1 HEAD. Ora, ho un secondo repository che contiene un file che ha lo stesso contenuto come hello.test ma viene messo in una directory diversa con un nome diverso: ./blue/red/hi.test. Come posso applicare la suddetta patch al hi.testfile? Ho provato git am --directory='blue/red' < patch_filema questo ovviamente si lamenta che i file non hanno lo stesso nome (cosa che pensavo non interessasse a Git?). So che probabilmente potrei modificare il diff per applicarlo a quel file specifico, ma sto cercando una soluzione di comando.


Risposte:


97

Puoi creare la patch usando git diffe poi applicarla usando l' patchutility, che ti permette di specificare il file a cui vuoi applicare il diff.

Per esempio:

cd first-repo
git diff HEAD^ -- hello.test > ~/patch_file

cd ../second-repo
patch -p1 blue/red/hi.test ~/patch_file

7
Ah, bello, non ci ho pensato. Tuttavia, esiste un modo per farlo con i comandi Git in modo che i dati di commit (data e ora, autore del commit, messaggio di commit) siano mantenuti gli stessi?
martedì

2
È possibile che ci sia qualcosa che puoi fare con amo apply, ma non riesco a trovarlo. Se ti ritrovi a duplicare molto le modifiche, potrebbe esserci una soluzione migliore usando i sottomoduli, o qualunque sia la tua lingua preferita per condividere il codice (ad esempio in Ruby potresti estrarre il codice duplicato come una gemma).
georgebrock

1
Questo è in realtà correlato alla documentazione (i file di origine sono XML). I sottomoduli non sono davvero un'opzione in quanto dovrei difenderli con forza nella nostra infrastruttura esistente.
martedì

52

Esiste una soluzione semplice che non comporta la modifica manuale delle patch né script esterni.

Nel primo repository (questo può anche esportare un intervallo di commit, utilizzare -1se si desidera selezionare solo un commit):

git format-patch --relative <committish> --stdout > ~/patch

Nel secondo repository:

git am --directory blue/red/ ~/patch

Invece di usare --relativein git format-patch, un'altra soluzione è usare l' -p<n>opzione in git amper rimuovere le ndirectory dal percorso delle patch, come menzionato in una risposta a una domanda simile .

È anche possibile eseguire git format-patch --relative <committish>senza --stdout, e genererà un set di .patchfile. Questi file possono quindi essere inviati direttamente a git amcon git am --directory blue/red/ path/to/*.patch.


9
Questo si basa ancora sul fatto che i nomi dei file sono gli stessi, giusto?
martedì

3
Va notato che l' --directoryopzione sembra richiedere di specificare il percorso completo della directory relativo alla radice del repository; qualcosa come --directory=./while chdir'd in una sottodirectory nel repository non funzionerà.
Reid

1
L'utilizzo di --3wayaiuti con does not exist in index:git am --3way --directory (relative-path) (patch)
Brent Bradburn

Usa il -ktasto in entrambi i comandi per non eliminare la prima riga del messaggio di commit.
ruvim

L'uso --3waynon solo aiuta con gli errori "non esiste nell'indice" (come sottolineato da @nobar), ma consente anche di gestire in modo pulito i conflitti di unione. Invece di lasciare intatti i file in conflitto, viene aggiunto un blocco di conflitto che può essere risolto.
Daniel Wolf

11

Rispondendo alla mia domanda con uno script che fa proprio questo: https://github.com/mprpic/apply-patch-to-file

Invece di modificare manualmente il file della patch, richiede all'utente il file di destinazione, modifica la patch e la applica al repository in cui ci si trova attualmente.


5

Basandosi sulla risposta di @georgebrock, ecco una soluzione che ho usato:

Per prima cosa, crea i file di patch come al solito (es. git format-patch commitA..commitB).

Quindi assicurati che il tuo repository di destinazione sia pulito (non dovrebbero esserci file modificati o non tracciati) e applica le patch in questo modo:

cd second-repo
git am ~/00*.patch

Per ogni file di patch verrà visualizzato un errore del tipo "errore: XYZ non esiste nell'indice". È ora possibile applicare manualmente questo file di patch:

patch --directory blue/red < ~/0001-*.patch
git add -a
git am --continue

È necessario eseguire questi tre passaggi per ogni file di patch.

Ciò manterrà il messaggio di commit originale ecc. Senza richiedere alcun git format-patchcomando speciale o modificare i file di patch.


1
Buona risposta, penso che questa sia la base migliore per qualsiasi tipo di manipolazione di patch "non standard". Lo faccio in 3 passaggi. (1) Impegnarsi a scrivere - git format-patch -1 commitA --stdout > thing.diff; (2) Modifica il file della patch finché non farà quello che mi serve; (3) Testo per il commit git am --3way thing.diff che ha il vantaggio di poter accettare le parti della patch che si applicano in modo pulito e utilizzare gitil processo di risoluzione dei conflitti standard di per le parti che non lo fanno.
Siamo tutti Monica

2

Capisco che i due file sono esattamente gli stessi nella tua situazione, quindi è probabile che la patch abbia successo.

Tuttavia, nel caso in cui si desideri applicare una patch a un file simile, ma non esattamente lo stesso, o si desideri eseguire una patch interattiva, si utilizzerà l'unione a tre vie.

Supponiamo che tu abbia modificato File A, denotiamo A~1come versione precedente e desideri applicare la differenza tra A~1a Aa File B.

Apri uno strumento di unione a tre vie, ad esempio Oltre il confronto, il percorso del pannello di sinistra è A, il pannello centrale è l'antenato comune quindi il percorso è A~1, il percorso del pannello di destra è B. Quindi, il pannello inferiore mostra il risultato dell'applicazione della differenza tra A~1a Aa File B.

La figura seguente illustra l'idea.

inserisci qui la descrizione dell'immagine


0

FYI: Recentemente ho avuto problemi a scaricare una patch da Github e ad applicarla a un file locale (che era un "override" in una nuova posizione).

git amnon applicherebbe la patch né perché il file era "non nell'indice" o "sporco". Ma ho scoperto che il semplice patchcomando potrebbe applicare la patch. Mi ha chiesto di correggere il nome del file.

Ho fatto il lavoro, comunque ...

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.