Come unire le modifiche a un singolo file anziché unire i commit?


383

Ho due rami (A e B) e voglio unire un singolo file dal ramo A con un singolo file corrispondente dal ramo B.



27
La maggior parte delle risposte a quell'altro post riguarda il modo in cui unire selettivamente i commit , non i file . Questo rende la risposta selezionata errata. La domanda rimane senza risposta.


Questa risposta è la strada da percorrere, IMO. git diff branch_name > patch git apply patch. stackoverflow.com/a/9473543/1091853
blamb

Risposte:


631

Mi sono imbattuto nello stesso problema. Per essere precisi, ho due rami Ae Bcon gli stessi file ma una diversa interfaccia di programmazione in alcuni file. Ora i metodi di file f, che sono indipendenti dalle differenze di interfaccia tra i due rami, sono stati cambiati in ramo B, ma la modifica è importante per entrambi i rami. Quindi, ho bisogno di unire solo il file fdel ramo Bnel file fdel ramo A.

Un semplice comando ha già risolto il problema per me se presumo che tutte le modifiche vengano eseguite in entrambi i rami Ae B:

git checkout A

git checkout --patch B f

Il primo comando passa al ramo A, nel punto in cui voglio unire Bla versione del file f. Il secondo comando corregge il file fcon fof HEADof B. È anche possibile accettare / scartare singole parti della patch. Invece di Bte puoi specificare qualsiasi commit qui, non deve essere HEAD.

Modifica comunità : se il file fsu Bnon esiste Aancora, ometti l' --patchopzione. Altrimenti, otterrai un "Nessun cambiamento". Messaggio.


10
Funziona solo se si desidera aggiornare un file. Cosa succede se desidero aggiungere un nuovo file dal ramo B al ramo A?
Umair A.

25
@UmairAshraf dovresti essere in grado di aggiungere un nuovo file da B ad A rimuovendo l'opzione --patch.
bbak,

9
Hmmm ... quando provo questo ricevo il messaggio "nessuna modifica", ma chiaramente ci sono delle modifiche. OK, dovevo trovarmi nella cartella in cui si trovava il file pertinente. Modifica: questa potrebbe probabilmente essere la mia soluzione preferita a un problema che ho visto su StackOverflow :-D
bot_bot

2
Ho dovuto usare git checkout --patch B -- fper farlo funzionare.
user545424,

8
Devi solo aggiungere che se hai più modifiche (hunk) nel file e vuoi metterle in scena tutte , puoi premere adurante la fase interattiva, invece di premere yogni volta. O usa git checkout B -- finvece il comando.
Dmitry Gonchar,

17

Ecco cosa faccio in queste situazioni. È un kludge ma funziona bene per me.

  1. Crea un altro ramo in base al tuo ramo di lavoro.
  2. git pull / git unisce la revisione (SHA1) che contiene il file che si desidera copiare. Quindi questo unirà tutte le tue modifiche, ma stiamo usando questo ramo solo per prendere un file.
  3. Risolvi eventuali conflitti, ecc. Esamina il tuo file.
  4. controlla la tua filiale di lavoro
  5. Verifica il file eseguito il commit dalla tua unione.
  6. Commettilo.

Ho provato a patchare e la mia situazione era troppo brutta per questo. Quindi in breve sembrerebbe così:

Ramo di lavoro: A Ramo sperimentale: B (contiene file.txt con le modifiche che voglio piegare.)

git checkout A

Crea un nuovo ramo basato su A:

git checkout -b tempAB

Unisci B in tempAB

git merge B

Copia l'hash sha1 dell'unione:

git log

commit 8dad944210dfb901695975886737dc35614fa94e
Merge: ea3aec1 0f76e61
Author: matthewe <matthewe@matthewe.com>
Date:   Wed Oct 3 15:13:24 2012 -0700

Merge branch 'B' into tempAB

Dai un'occhiata al tuo ramo di lavoro:

git checkout A

Guarda il tuo file fisso:

git checkout 7e65b5a52e5f8b1979d75dffbbe4f7ee7dad5017 file.txt

E lì dovresti averlo. Commetti il ​​tuo risultato.


3
Quindi dobbiamo fare tutto questo solo per unire un singolo file? Non sarebbe solo più semplice copiare e incollare il file nell'altro ramo
Robin

1
@Robin probabilmente no, poiché l'unione mantiene le modifiche sul file, che differiscono tra il ramo A e B. la copia del file sovrascriverà eventuali differenze aggiuntive tra il ramo operativo A e ciò che si desidera portare da B, che potrebbe non contenere quelle entrate / modifiche. ad esempio, il sospetto si Aè spostato Bdall'inizio, in altri modi. La copia sovrascriverà quelle differenze.
blamb

14

Questo utilizza il difftool interno di git. Forse un po 'di lavoro da fare ma diretto.

#First checkout the branch you want to merge into
git checkout <branch_to_merge_into>

#Then checkout the file from the branch you want to merge from
git checkout <branch_to_merge_from> -- <file> 

#Then you have to unstage that file to be able to use difftool
git reset HEAD <file> 

#Now use difftool to chose which lines to keep. Click on the mergebutton in difftool
git difftool

#Save the file in difftool and you should be done.

1
Per chiarire l'uso di --(etichetta argomento vuota), git checkout docs: ARGUMENT DISAMBIGUATION dire: "usa git checkout -- <pathspec>se vuoi controllare questi percorsi fuori dall'indice". Questo perché potresti avere sia un ramo che un file / percorso con lo stesso nome. In questi casi, invece di chiederti di non chiarire se il ramo o il percorso debbano essere estratti quando entrambi esistono, git sceglierà di controllare il ramo per impostazione predefinita. Tuttavia, se --precede, git verificherà invece il file / percorso.
SherylHohman,

8

Ho trovato questo approccio semplice e utile: come "unire" file specifici da un altro ramo

A quanto pare, ci stiamo sforzando troppo. Il nostro buon amico Git Checkout è lo strumento giusto per il lavoro.

git checkout source_branch <paths>...

Possiamo semplicemente dare a git checkout il nome del ramo della caratteristica A e i percorsi dei file specifici che vogliamo aggiungere al nostro ramo principale.

Si prega di leggere l'intero articolo per una maggiore comprensione


2
Questo sovrascrive i file, non li unisce
Alex G,

Per te potrebbe, dipende da cosa stai facendo e cosa stai cercando di ottenere. L'idea qui è il ramo B è il fork di A, si modificano 4 file in B, ma si desidera unire solo 2 da B ad A. L'unione regolare unirebbe tutti i 4, qui è possibile selezionare. Potrebbe sembrare che siano stati sostituiti perché B contiene essenzialmente file più recenti. Devi supportare la tua esperienza con alcune prove.
Pawel Cioch,

Sono d'accordo che sovrascrive. penso che intendevi usare l' -popzione in quel comando. Che quindi, sovrascrive tutte le parti del tuo file di worktree che in precedenza hanno deviato dal ramo da cui stai estraendo, prima delle modifiche della patch, sfortunatamente.
blamb

Beh, l'idea era del 2009, è probabile che la nuova versione di git si comporti in modo diverso e abbia bisogno di -p o qualsiasi altra cosa, ma quando lo stavo pubblicando stava funzionando per me, ma forse non mi importava che i file fossero sovrascritti, come l'ultima versione era ciò di cui avevo bisogno
Pawel Cioch,


3

Il seguente comando confronterà (1) il file del ramo corretto, con master (2) ti chiederà in modo interattivo quali modifiche applicare.

git checkout --patch master


0

La mia modifica è stata respinta, quindi allego come gestire qui l'unione delle modifiche da un ramo remoto.

Se devi farlo dopo un'unione errata, puoi fare qualcosa del genere:

# If you did a git pull and it broke something, do this first
# Find the one before the merge, copy the SHA1
git reflog
git reset --hard <sha1>

# Get remote updates but DONT auto merge it
git fetch github 

# Checkout to your mainline so your branch is correct.
git checkout develop 

# Make a new branch where you'll be applying matches
git checkout -b manual-merge-github-develop

# Apply your patches
git checkout --patch github/develop path/to/file
...

# Merge changes back in
git checkout develop
git merge manual-merge-github-develop # optionally add --no-ff

# You'll probably have to
git push -f # make sure you know what you're doing.

0

Supponendo che B sia l'attuale ramo:

$ git diff A <file-path> > patch.tmp
$ git apply patch.tmp -R

Si noti che ciò applica solo le modifiche al file locale. Dovrai impegnarti in seguito.


Per me questo genera unerror: <file-path>: already exists in working directory
kontur il

È necessario specificare il file o il percorso del file nella directory corrente. Sto usandogit diff Branch_A <file-path, filename> -- hash_commit > file_name.temp
R.Chatsiri il

0

Puoi verificare la vecchia versione del file da unire, salvandola con un nome diverso, quindi eseguire qualunque sia il tuo strumento di unione sui due file.

per esempio.

git show B:src/common/store.ts > /tmp/store.ts (dove B è il nome della filiale / commit / tag)

meld src/common/store.ts /tmp/store.ts


0

Lo farò come

git format-patch branch_old..branch_new file

questo produrrà una patch per il file.

Applica patch sul target branch_old

git am blahblah.patch


Puoi facilmente esaminare la patch per una maggiore sicurezza?
XavierStuvw,
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.