È possibile selezionare un commit da un altro repository git?


726

Sto lavorando con un repository git che necessita di un commit da un altro repository git che non sa nulla del primo.

Normalmente sceglierei ciliegia usando HEAD@{x}ref nel reflog, ma poiché questo .gitnon sa nulla di questa voce reflog (directory fisica diversa), come posso scegliere ciliegia o posso farlo?

Sto usando git-svn. Il mio primo ramo sta usando git-svnil trunkrepo di Subversion e il ramo successivo sta usando git-svnun ramo Subversion.


2
Questa è la ragione fornita da Ben Lee per aver aperto una generosità a questa domanda: "Assegnerò la generosità alla risposta giusta, piuttosto alla risposta accettata. Devo solo aspettare 24 [ore] per farlo." Tuttavia, non capisco quale di queste dovrebbe essere "la risposta giusta" e perché la risposta accettata non è "giusta".

1
Non è chiaro quale sia la natura del problema. In che modo sono correlati questi diversi repository? Uno è un fork di un altro? O sono in realtà due progetti completamente separati e indipendenti?

@Cupcake, la risposta accettata è buona e chiaramente ha aiutato l'OP, quindi dovrebbe essere accettata. Per "giusto" intendevo davvero "giusto per me" (e a giudicare dai commenti, giusto anche per molte altre persone). Ho solo pensato che quello a cui avevo dato la generosità meritava lo stesso rappresentante della risposta accettata.
Ben Lee,

Risposte:


557

Dovrai aggiungere l'altro repository come telecomando, quindi recuperare le sue modifiche. Da lì vedi il commit e puoi selezionarlo.

Come quello:

git remote add other https://example.link/repository.git
git fetch other

Ora hai tutte le informazioni da fare semplicemente git cherry-pick.

Maggiori informazioni su come lavorare con i telecomandi qui: https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes


1
E se sto usando git-svn? il mio primo ramo sta usando git-svn del trunk e il successivo sta usando git-svn su un ramo (grazie per la rapida risposta)
gitcoder182

1
quando cloni per la prima volta il repository Subversion assicurati di clonare l' intero repository, non solo il trunk. Assicurati anche di usare l' --stdlayoutopzione di git-svn se stai usando il layout standard trunk / branch / tags in Subversion. Quindi il ramo Subversion sarà un semplice ramo git remoto.
Wilhelmtell,

33
Se stai usando Github, puoi estrarre la patch aggiungendo .patch all'URL di commit e quindi applicandolo con git am < d821j8djd2dj812.patch. Al di fuori di GH, concetti simili potrebbero essere fatti come indicato nella risposta alternativa di seguito.
radicand,

2
@radicand quale risposta sotto è quella "alternativa"? Si prega di collegarsi ad esso.


854

La risposta, come indicato, è usare il format-patch ma poiché la domanda era come scegliere una ciliegia da un'altra cartella, ecco un pezzo di codice per fare proprio questo:

$ git --git-dir=../<some_other_repo>/.git \
format-patch -k -1 --stdout <commit SHA> | \
git am -3 -k

(spiegazione da @cong ma )

Il git format-patchcomando crea una patch dal some_other_repocommit specificato dal suo SHA (solo -1per un singolo commit). Questa patch viene convogliata git am, che applica la patch localmente ( -3significa provare l'unione a tre vie se la patch non si applica in modo pulito). Spero che questo spieghi.


18
Questo è perfetto, ma sarebbe bello se qualcuno potesse espandersi su questo - una scomposizione di esattamente quello che sta succedendo (specialmente con quelle bandiere) sarebbe incredibilmente utile.
Nick F,

46
@NickF, il git format-patchcomando crea una patch dal some_other_repocommit specificato dal suo SHA (solo -1per un singolo commit). Questa patch viene convogliata git am, che applica la patch localmente ( -3significa provare l'unione a tre vie se la patch non si applica in modo pulito). Spero che questo spieghi.
Cong Ma,

3
errore: patch fallita: somefile.cs: 85 errore: somefile.cs: patch non applicabile Hai modificato a mano la tua patch? Non si applica ai BLOB registrati nel suo indice. Impossibile tornare all'unione a tre vie. Patch non riuscita a 0001 Aggiunte parti della GUI. La copia della patch non riuscita si trova in: <some_other_repo> /.git/rebase-apply/patch Dopo aver risolto questo problema, eseguire "git am --continue". Se si preferisce saltare questa patch, eseguire invece "git am --skip". Per ripristinare il ramo originale e interrompere le patch, eseguire "git am --abort".
Tom,

8
@Tom prova ad usare --ignore-whitespace. Comando completo: git --git-dir=../<some_other_repo>/.git format-patch -k -1 --stdout <commit SHA> | git am -3 -k --ignore-whitespace
Jake Graham Arnold

7
@BoomShadow Perché è molto più semplice. L'aggiunta del telecomando e il recupero portano tutte le altre modifiche al repository. Questa riga di comando è un'azione singola.
Jonathon Reinhart,

152

Ecco un esempio di remote-fetch-merge.

cd /home/you/projectA
git remote add projectB /home/you/projectB
git fetch projectB

Allora puoi:

git cherry-pick <first_commit>..<last_commit>

o potresti anche unire l'intero ramo

git merge projectB/master

54
git merge projectB/master è molto, molto male , perché non sta applicando le modifiche da un singolo commit (come un cherry-pick sarebbe), si sta effettivamente la fusione in tutti i cambiamenti inprojectB/masterche non sono contenuti nel propriomasterramo.

4
Supponevo che questo fosse l'intento del poster originale. Altrimenti, sì, questa non è l'opzione giusta per loro.
Brian,

5
Funziona perfettamente quando i due repository sono correlati.
Ronny Ager-Wick,

1
Ho creato una copia da un repository git (solo per "giocare" senza interrompere il repository originale) e per mantenerlo aggiornato con la sua fonte, la risposta di Brian è esattamente ciò di cui avevo bisogno, quindi Cupcake, io devo dire, non è "sbagliato", ma un altro caso d'uso. Ma è bello da parte tua segnalare il potenziale disastro: D
ferrari2k,

6
IMO questa deve essere la soluzione accettata. Inoltre, se si desidera eliminare il telecomando dopo aver terminato la selezione, utilizzare git remote rm projectB. Utilizzare anche git tag -d tag-nameper rimuovere tutti i tag recuperati dal repository remoto. I commit remoti non verranno più visualizzati nella cronologia e la potatura li rimuoverà dalla memoria alla fine.
ADTC,

130

Puoi farlo, ma richiede due passaggi. Ecco come:

git fetch <remote-git-url> <branch> && git cherry-pick FETCH_HEAD

Sostituisci <remote-git-url>con l'URL o il percorso del repository da cui vuoi selezionare cherry.

Sostituisci <branch>con il nome del ramo o del tag che desideri selezionare dal repository remoto.

È possibile sostituire FETCH_HEADcon un git SHA dal ramo.

Aggiornato: modificato in base al feedback di @ pkalinow.


8
Funziona con un nome di filiale, ma non con SHA. Se si vuole cherry-pick un commit indicato con il suo hash, utilizzare questo invece: git fetch <repo-url> <branch> && git cherry-pick <sha>.
pkalinow,

Grazie. Questo era proprio ciò di cui avevo bisogno per inserire un numero di commit da un repository all'altro, che ho creato a questo scopo.
Wojciii,

Questo era esattamente ciò di cui avevo bisogno con molte implementazioni personalizzate del nostro codice per diversi client (che ognuno ha i propri repository / fork), avevamo bisogno di un modo per ottenere specifici commit nella nostra base / trunk. GRAZIE!
RedSands

Questa dovrebbe essere la risposta accettata per una scelta di ciliegie one-shot tra i repository. Lo uso sempre quando seleziono tra repository già locali, l'URL remoto è quindi solo un percorso del filesystem locale.
Amedee Van Gasse,

61

Ecco i passaggi per aggiungere un telecomando, recuperare i rami e selezionare un commit

# Cloning our fork
$ git clone git@github.com:ifad/rest-client.git

# Adding (as "endel") the repo from we want to cherry-pick
$ git remote add endel git://github.com/endel/rest-client.git

# Fetch their branches
$ git fetch endel

# List their commits
$ git log endel/master

# Cherry-pick the commit we need
$ git cherry-pick 97fedac

Fonte: https://coderwall.com/p/sgpksw


17

Vedi Come creare e applicare una patch con Git . (Dalla formulazione della tua domanda, ho assunto che questo altro repository sia per una base di codice completamente diversa. Se è un repository per la stessa base di codice, dovresti aggiungerlo come telecomando come suggerito da @CharlesB. Anche se è per un altro base di codice, suppongo che potresti ancora aggiungerlo come telecomando, ma potresti non voler portare l'intero ramo nel tuo repository ...)


11

Puoi farlo in una riga come segue. Spero che tu sia nel repository git che ha bisogno della modifica selezionata in modo accurato e che hai verificato per correggere il ramo.

git fetch ssh://git@stash.mycompany.com:7999/repo_to_get_it_from.git branchToPickFrom && git cherry-pick 02a197e9533
# 

git fetch [URL filiale] [Branch to cherry-pick from] && git cherry-pick [commit ID]


1
Saluti, non ho avuto bisogno della ssh://parte, solo perhttps://
Leo


1

Supponendo che Asia il repository da cui scegliere la ciliegia, ed Bè quello che si desidera selezionare la ciliegia, è possibile farlo aggiungendo </path/to/repo/A/>/.git/objectsa </path/to/repo/B>/.git/objects/info/alternates. Crea questo alternatesfile se non esiste.

Ciò consentirà al repository B di accedere a tutti gli oggetti git dal repository A e consentirà a Cherry-Pick di funzionare.


0

La mia situazione era che ho un repository nudo a cui la squadra spinge e un clone di quello seduto proprio accanto ad esso. Questo insieme di linee in un Makefile funziona correttamente per me:

git reset --hard
git remote update --prune
git pull --rebase --all
git cherry-pick -n remotes/origin/$(BRANCH)

Mantenendo aggiornato il master del repository nudo, siamo in grado di scegliere una modifica proposta pubblicata nel repository nudo. Abbiamo anche un modo (più complicato) di selezionare più brach per una revisione e un test consolidati.

Se "non sa nulla" significa "non può essere usato come telecomando", allora questo non aiuta, ma questa domanda SO è emersa mentre cercavo su Google di elaborare questo flusso di lavoro, quindi ho pensato di contribuire.


-n significa no-commit secondo i documenti git e io cosa molto importante vedere le modifiche prima di effettuare un commit
canbax,

0

Se si desidera selezionare più commit per un determinato file fino a quando non si raggiunge un determinato commit, utilizzare quanto segue.

# Directory from which to cherry-pick
GIT_DIR=...
# Pick changes only for this file
FILE_PATH=...
# Apply changes from this commit
FIST_COMMIT=master
# Apply changes until you reach this commit
LAST_COMMIT=...

for sha in $(git --git-dir=$GIT_DIR log --reverse --topo-order --format=%H $LAST_COMMIT_SHA..master -- $FILE_PATH ) ; do 
  git --git-dir=$GIT_DIR  format-patch -k -1 --stdout $sha -- $FILE_PATH | 
    git am -3 -k
done
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.