Ist es möglich, ein Commit aus einem anderen Git-Repository auszuwählen?

726

Ich arbeite mit einem Git-Repository, das ein Commit von einem anderen Git-Repository benötigt, das nichts von dem ersten weiß.

Normalerweise würde ich mit dem HEAD@{x}im Reflog auswählen, aber da dieser .gitnichts von diesem Reflog-Eintrag (anderes physisches Verzeichnis) weiß, wie kann ich dies auswählen oder kann ich?

Ich benutze git-svn. Mein erster Zweig verwendet git-svndas trunkeines Subversion-Repos, und der nächste Zweig verwendet git-svneinen Subversion-Zweig.

gitcoder182
quelle
2
Dies ist der Grund, den Ben Lee für die Eröffnung eines Kopfgeldes für diese Frage angegeben hat: "Ich werde das Kopfgeld der richtigen Antwort zuweisen, eher der akzeptierten Antwort. Ich muss nur 24 [Stunden] warten, um dies zu tun." Ich verstehe jedoch nicht, welche davon "die richtige Antwort" sein soll und warum die akzeptierte Antwort nicht "richtig" ist.
1
Es ist nicht klar, wie das Problem beschaffen ist. Wie hängen diese verschiedenen Repos zusammen, wenn überhaupt? Ist einer eine Gabel des anderen? Oder handelt es sich tatsächlich um zwei völlig getrennte und nicht miteinander verbundene Projekte?
@ Cupcake, die akzeptierte Antwort ist gut und hat dem OP eindeutig geholfen, daher sollte sie akzeptiert werden. Mit "richtig" meinte ich wirklich nur "richtig für mich" (und nach den Kommentaren zu urteilen, richtig für einige andere Leute auch). Ich dachte nur, derjenige, dem ich das Kopfgeld gegeben habe, verdient so viel Wiederholung wie die akzeptierte Antwort.
Ben Lee

Antworten:

557

Sie müssen das andere Repository als Remote hinzufügen und dann die Änderungen abrufen. Von dort aus sehen Sie das Commit und können es auswählen.

So wie das:

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

Jetzt haben Sie alle Informationen einfach zu tun git cherry-pick.

Weitere Informationen zum Arbeiten mit Fernbedienungen finden Sie hier: https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes

CharlesB
quelle
1
Was ist, wenn ich git-svn verwende? Mein erster Zweig verwendet Git-SVN des Trunks und der nächste verwendet Git-SVN für einen Zweig (danke für die schnelle Antwort)
Gitcoder182
1
Stellen Sie beim ersten Klonen des Subversion-Repositorys sicher, dass Sie das gesamte Repository und nicht nur den Trunk klonen . Stellen Sie außerdem sicher, dass Sie die --stdlayoutOption git-svn verwenden, wenn Sie das Standardlayout für Amtsleitungen / Zweige / Tags in Subversion verwenden. Dann ist der Subversion-Zweig nur ein entfernter Git-Zweig.
Wilhelmtell
33
Wenn Sie Github verwenden, können Sie den Patch abrufen, indem Sie .patch an die Commit-URL anhängen und dann mit anwenden git am < d821j8djd2dj812.patch. Außerhalb von GH könnten ähnliche Konzepte durchgeführt werden, wie in der nachstehenden alternativen Antwort angegeben.
Radicand
2
@radicand welche Antwort unten ist die "alternative"? Bitte verlinken Sie darauf.
7
Detaillierte Schritte zur Auswahl von Kirschen aus einem anderen Repo: coderwall.com/p/sgpksw/git-cherry-pick-from-another-repository
T. Kim Nguyen
854

Die Antwort lautet, wie angegeben, Format-Patch zu verwenden. Da es sich jedoch um die Frage handelt, wie aus einem anderen Ordner ausgewählt werden kann, finden Sie hier einen Code, um genau das zu tun:

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

(Erklärung von @cong ma )

Der git format-patchBefehl erstellt einen Patch aus some_other_repodem von der SHA angegebenen Commit (nur -1für ein einzelnes Commit). Dieser Patch wird an weitergeleitet git am, wodurch der Patch lokal angewendet wird ( -3dh, Sie versuchen die Drei-Wege-Zusammenführung, wenn der Patch nicht sauber angewendet werden kann). Hoffe das erklärt.

Robert Wahler
quelle
18
Dies ist genau richtig, aber es wäre großartig, wenn jemand darauf eingehen könnte - eine Aufschlüsselung der genauen Vorgänge (insbesondere mit diesen Flags) wäre unglaublich nützlich.
Nick F
46
@NickF, der git format-patchBefehl erstellt einen Patch aus some_other_repodem von seinem SHA angegebenen Commit (nur -1für ein einzelnes Commit). Dieser Patch wird an weitergeleitet git am, wodurch der Patch lokal angewendet wird ( -3dh, Sie versuchen die Drei-Wege-Zusammenführung, wenn der Patch nicht sauber angewendet werden kann). Hoffe das erklärt.
Cong Ma
3
Fehler: Patch fehlgeschlagen: somefile.cs: 85 Fehler: somefile.cs: Patch gilt nicht Haben Sie Ihren Patch von Hand bearbeitet? Dies gilt nicht für in seinem Index aufgezeichnete Blobs. Kann nicht auf Drei-Wege-Zusammenführung zurückgreifen. Patch fehlgeschlagen bei 0001 GUI-Teile hinzugefügt. Die Kopie des fehlgeschlagenen Patches befindet sich in: <some_other_repo> /.git/rebase-apply/patch Wenn Sie dieses Problem behoben haben, führen Sie "git am --continue" aus. Wenn Sie diesen Patch lieber überspringen möchten, führen Sie stattdessen "git am --skip" aus. Führen Sie "git am --abort" aus, um den ursprünglichen Zweig wiederherzustellen und das Patchen zu beenden.
Tom
8
@ Tom versuchen es mit --ignore-whitespace. Voller Befehl: 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 Weil es viel einfacher ist. Durch Hinzufügen der Fernbedienung und Abrufen werden alle Änderungen des anderen Repos übernommen. Diese Befehlszeile ist eine einmalige Aktion.
Jonathon Reinhart
152

Hier ist ein Beispiel für das Remote-Fetch-Merge.

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

Dann kannst du:

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

oder Sie könnten sogar den gesamten Zweig zusammenführen

git merge projectB/master
Brian
quelle
54
git merge projectB/master sehr, sehr falsch ist , weil Sie nicht die Änderungen von einem einzigen begehen (wie eine Kirsche-Pick würde) Anwendung, sind Sie tatsächlich beiZusammenführung aller Änderungen inprojectB/master, die nicht in Ihrem eigenen enthaltenenmasterZweig.
4
Ich ging davon aus, dass dies die Absicht des Originalplakats war. Ansonsten ist dies nicht die richtige Option für sie.
Brian
5
Dies funktioniert hervorragend, wenn die beiden Repositorys miteinander verbunden sind.
Ronny Ager-Wick
1
Ich habe eine Kopie aus einem Git-Repository erstellt (nur um "herumzuspielen", ohne das ursprüngliche Repo zu beschädigen) und um es mit seiner Quelle auf dem neuesten Stand zu halten, ist die Antwort von Brian genau das, was ich brauchte, also Cupcake, ich Ich muss sagen, es ist nicht "falsch", sondern ein anderer Anwendungsfall. Aber es ist schön von Ihnen, auf die mögliche Katastrophe
hinzuweisen
6
IMO muss dies die akzeptierte Lösung sein. Wenn Sie die Fernbedienung löschen möchten, nachdem Sie die Kirschernte abgeschlossen haben, verwenden Sie außerdem git remote rm projectB. Verwenden Sie git tag -d tag-namediese Option auch , um alle vom Remote-Repo abgerufenen Tags zu entfernen. Die Remote-Commits werden in Ihrem Verlauf nicht mehr angezeigt, und durch das Bereinigen werden sie schließlich aus dem Speicher entfernt.
ADTC
130

Sie können es tun, aber es erfordert zwei Schritte. Hier ist wie:

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

Ersetzen Sie <remote-git-url>durch die URL oder den Pfad zu dem Repository, aus dem Sie auswählen möchten.

Ersetzen Sie ihn <branch>durch den Zweig- oder Tag-Namen, den Sie aus dem Remote-Repository auswählen möchten.

Sie können durch FETCH_HEADeinen Git SHA aus der Filiale ersetzen .

Aktualisiert: geändert basierend auf dem Feedback von @ pkalinow.

docwhat
quelle
8
Es funktioniert mit einem Filialnamen, aber nicht mit SHA. Wenn Sie ein Commit auswählen möchten, das durch seinen Hash gekennzeichnet ist, verwenden Sie stattdessen Folgendes : git fetch <repo-url> <branch> && git cherry-pick <sha>.
pkalinow
Vielen Dank. Dies war genau das, was ich brauchte, um eine Reihe von Commits von einem Repository in ein anderes einzufügen, die ich zu diesem Zweck erstellt hatte.
Wojciii
Dies war genau das, was ich mit vielen benutzerdefinierten Implementierungen unseres Codes für verschiedene Clients (die jeweils ihre eigenen Repositorys / Gabeln haben) brauchte. Wir brauchten eine Möglichkeit, um bestimmte Commits in unsere Basis / unseren Trunk zu bekommen. VIELEN DANK!
RedSands
Dies sollte die akzeptierte Antwort für einen One-Shot-Cherry-Pick über Repos sein. Ich benutze es die ganze Zeit, wenn ich zwischen Repos wähle, die bereits lokal sind. Die Remote-URL ist dann nur ein lokaler Dateisystempfad.
Amedee Van Gasse
61

Hier sind die Schritte zum Hinzufügen einer Fernbedienung, zum Abrufen von Zweigen und zum Auswählen eines Commits

# Cloning our fork
$ git clone [email protected]: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

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

jaredwilli
quelle
17

Siehe Erstellen und Anwenden eines Patches mit Git . (Aus dem Wortlaut Ihrer Frage ging ich davon aus, dass dieses andere Repository für eine völlig andere Codebasis bestimmt ist. Wenn es sich um ein Repository für dieselbe Codebasis handelt, sollten Sie es als Remote hinzufügen, wie von @CharlesB vorgeschlagen. Auch wenn es sich um ein anderes handelt Codebasis, ich denke, Sie könnten es immer noch als Remote hinzufügen, aber Sie möchten möglicherweise nicht den gesamten Zweig in Ihr Repository aufnehmen ...)

Aasmund Eldhuset
quelle
11

Sie können dies in einer Zeile wie folgt tun. Ich hoffe, Sie befinden sich im Git-Repository, das die von Kirschen gepflückte Änderung benötigt, und Sie haben den richtigen Zweig ausgecheckt.

git fetch ssh://[email protected]:7999/repo_to_get_it_from.git branchToPickFrom && git cherry-pick 02a197e9533
# 

git fetch [Zweig-URL] [Zweig zum Cherry-Pick von] && git Cherry-Pick [Commit-ID]

Don
quelle
1
Prost, brauchte das ssh://Teil nicht, nur fürhttps://
Leo
5

Ja. Holen Sie sich das Repository und wählen Sie es aus dem Remote-Zweig aus.

wilhelmtell
quelle
1

Angenommen, es Ahandelt sich um das Repo, aus dem Sie Kirschen pflücken möchten, und um das Repo, zu dem Sie Kirschen pflücken Bmöchten, können Sie dies durch Hinzufügen </path/to/repo/A/>/.git/objectszu tun </path/to/repo/B>/.git/objects/info/alternates. Erstellen Sie diese alternatesDateien, wenn sie nicht vorhanden sind.

Dadurch kann Repo B von Repo A aus auf alle Git-Objekte zugreifen und Cherry-Pick für Sie arbeiten.

Pranavk
quelle
0

Meine Situation war, dass ich ein nacktes Repo habe, zu dem das Team drängt, und einen Klon davon, der direkt daneben sitzt. Diese Zeilen in einem Makefile funktionieren für mich korrekt:

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

Indem wir den Meister des Bare Repo auf dem neuesten Stand halten, können wir eine vorgeschlagene Änderung auswählen, die im Bare Repo veröffentlicht wurde. Wir haben auch eine (kompliziertere) Möglichkeit, mehrere Braches für eine konsolidierte Überprüfung und Prüfung auszuwählen.

Wenn "weiß nichts" bedeutet, dass "nicht als Fernbedienung verwendet werden kann", hilft dies nicht, aber diese SO-Frage tauchte auf, als ich herum googelte, um diesen Workflow zu entwickeln, und dachte, ich würde einen Beitrag leisten.

Paul Hulett
quelle
-n bedeutet laut git docs kein Commit und ich
finde es
0

Wenn Sie mehrere Commits für eine bestimmte Datei auswählen möchten, bis Sie ein bestimmtes Commit erreichen, verwenden Sie Folgendes.

# 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
Diomidis Spinellis
quelle