In parte raccogliendo un impegno con Git


501

Sto lavorando su 2 diversi rami: rilascio e sviluppo .

Ho notato che devo ancora integrare alcune modifiche che sono state impegnate nel ramo di rilascio nel ramo di sviluppo .

Il problema è che non ho bisogno di tutto il commit, solo alcuni hunk in alcuni file, quindi un semplice

git cherry-pick bc66559

non fa il trucco.

Quando faccio a

git show bc66559

Riesco a vedere il diff ma non conosco davvero un buon modo di applicarlo parzialmente al mio attuale albero di lavoro.

Risposte:


793

La cosa fondamentale che vorrai qui è git add -p( -pè sinonimo di --patch). Ciò fornisce un modo interattivo per archiviare il contenuto, permettendoti di decidere se ogni hunk dovrebbe entrare e persino di modificare manualmente la patch se necessario.

Per usarlo in combinazione con cherry-pick:

git cherry-pick -n <commit> # get your patch, but don't commit (-n = --no-commit)
git reset                   # unstage the changes from the cherry-picked commit
git add -p                  # make all your choices (add the changes you do want)
git commit                  # make the commit!

(Grazie a Tim Henigan per avermi ricordato che git-cherry-pick ha un'opzione --no-commit, e grazie a Felix Rabe per aver sottolineato che devi resettare! Se vuoi solo lasciare alcune cose fuori dal commit , è possibile utilizzare git reset <path>...per disinstallare solo quei file.)

Ovviamente puoi fornire percorsi specifici a add -p se necessario. Se stai iniziando con una patch, puoi sostituirla cherry-pickcon apply.


Se vuoi davvero un git cherry-pick -p <commit> (quell'opzione non esiste), puoi usare

git checkout -p <commit>

Ciò differirà il commit corrente rispetto al commit specificato e consentirà di applicare singoli blocchi da tale diff singolarmente. Questa opzione può essere più utile se il commit che stai eseguendo ha conflitti di unione in parte del commit che non ti interessa. (Nota, tuttavia, che checkoutdifferisce da cherry-pick: checkouttenta di applicare <commit>del tutto i contenuti, cherry-pickapplica la diff il commit specificato dal suo genitore. Ciò significa che checkoutpuò applicare più di quel semplice commit, che potrebbe essere più di quello che desideri.)


In realtà, se seguo i consigli con git 1.7.5.4, 'git add -p' dice 'Nessuna modifica' perché è già tutto nell'indice. Devo fare un 'git reset HEAD' prima di 'git add' - un modo per evitare quel reset con qualche opzione?
Felix Rabe,

@FelixRabe: Sono davvero sorpreso che a un certo punto a cherry-pick -nquanto pare non ha lasciato in scena le modifiche - la convenzione è sicuramente che le --no-commitopzioni si fermano proprio prima del commit, cioè con tutte le modifiche messe in scena. Aggiungerò il reset nella risposta.
Cascabel,

1
@Blixt Cioè, se i commit che sono sull'altro ramo, ma non la vostra filiale corrente sono ABCDEF, git checkout -p <F>non non solo ottenere i cambiamenti da F, si arriva si ABCDEF tutte schiacciate insieme e consente di risolvere quello che parte di che si desidera . Ridurre a solo alcuni dei cambiamenti da F è un dolore. D'altra parte, git cherry-pick -n <F>ottieni solo le modifiche da F - e se alcune di queste modifiche sono in conflitto, ti dice utilmente in modo che tu possa capire come unire correttamente.
Cascabel,

Ho avuto problemi con questo quando la modifica è stata un'aggiunta di file. Il git reseteliminerebbe il file in scena e add -psarebbe solo dire 'niente da aggiungere'.
Ian Grainger,


36

Supponendo che le modifiche desiderate siano all'inizio del ramo da cui si desidera apportare le modifiche, utilizzare git checkout

per un singolo file:

git checkout branch_that_has_the_changes_you_want path/to/file.rb

per più file solo daisy chain:

git checkout branch_that_has_the_changes_you_want path/to/file.rb path/to/other_file.rb

5
Ciò copia l'intero file: non solo le modifiche.
Jeremy List,

1
Questa risposta, così come qualsiasi altra risposta qui finora, ha un grande svantaggio: non conserva l'autore originale della modifica, ma si impegna a tuo nome. Se un cambiamento è buono, stai rubando il credito di qualcuno, se un cambiamento è cattivo, ti stai mettendo sul fuoco. Sembra che non ci sia modo di avere git cherry-pick -p, e peccato che non sia ancora lì.
pfalcon,

15

Sulla base della risposta di Mike Monkiewicz , puoi anche specificare un singolo o più file da estrarre dal ramo sha1 / fornito.

git checkout -p bc66559 -- path/to/file.java 

Ciò ti consentirà di scegliere in modo interattivo le modifiche che desideri applicare alla versione corrente del file.


5
Ciò è problematico se la versione corrente del file è significativamente diversa da quella versione. Ti verranno richiesti numerosi cambiamenti irrilevanti (che non compaiono nel commit). Inoltre, le modifiche che desideri davvero possono apparire in una "forma mascherata" come una differenza rispetto alla corrente, non alla differenza originale. È possibile che la differenza originale che desideri sia in conflitto e debba essere correttamente unita; non avrai questa opportunità qui.
Kaz,

1

Se si desidera specificare un elenco di file sulla riga di comando e completare l'operazione in un singolo comando atomico, provare:

git apply --3way <(git show -- list-of-files)

--3way: Se una patch non si applica in modo pulito, Git creerà un conflitto di unione in modo da poter eseguire git mergetool. Se si omette --3way, Git rinuncerà alle patch che non si applicano in modo pulito.


0

Se "parzialmente cherry picking" significa "all'interno dei file, scegliendo alcune modifiche ma scartandone altre", si può fare portando git stash:

  1. Fai la scelta completa di ciliegie.
  2. git reset HEAD^ per convertire l'intero commit selezionato dalla ciliegia in modifiche operative non messe in scena.
  3. Ora git stash save --patch: seleziona interattivamente il materiale indesiderato da riporre.
  4. Git ripristina le modifiche nascoste dalla tua copia di lavoro.
  5. git commit
  6. Buttare via la scorta di modifiche indesiderate: git stash drop.

Suggerimento: se dai un nome alla scorta di modifiche indesiderate: git stash save --patch junkse poi ti dimentichi di fare (6) ora, in seguito riconoscerai la scorta per quello che è.


Se scegli solo Cherry, quindi ripristina ... non avrai nulla da nascondere. Come detto sopra, devi fare una scelta ciliegia con --no-commit, o un reset --hard HEAD ~. Nota che stai procedendo negativamente (selezionando ciò che non vuoi). La soluzione sopra accettata consente un approccio positivo o negativo.
Pierre-Olivier Vares,

0

Utilizzare git format-patchper suddividere la parte del commit che ti interessa e git amapplicarla a un altro ramo

git format-patch <sha> -- path/to/file
git checkout other-branch
git am *.patch
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.