Rufen Sie ein bestimmtes Commit aus einem Remote-Git-Repository ab


188

Gibt es eine Möglichkeit, nur ein bestimmtes Commit von einem Remote-Git-Repo abzurufen, ohne es auf meinem PC zu klonen? Die Struktur von Remote Repo ist absolut dieselbe wie die von mir und daher gibt es keine Konflikte, aber ich habe keine Ahnung, wie das geht, und ich möchte dieses riesige Repository nicht klonen.

Ich bin neu in Git, gibt es einen Weg?


1
Ist Ihr bestehendes Repo bereits ein Klon des Remote-Repos oder ist es völlig anders?
CharlesB

Nun, das Repo ist eine Linux-Kernel-Quelle, und es ist ziemlich gleich
Varun Chitre

Also ist es ein Klon oder nein?
CharlesB

1
Nicht genau. Bedenken Sie Folgendes: Lassen Sie das Remote-Repo am Kopf D sein und mein Repo am Kopf A und hinter B, C, D-Commits. Ich möchte Commit B von einem Repo und C von einem anderen und D von einem anderen zusammenführen, da die B, C, D Commits in diesen Repos mit ihren eigenen Spezialitäten unterschiedlich sind
Varun Chitre

1
@ VarunChitre Kannst du die andere Antwort von VonC akzeptieren?
CharlesB

Antworten:


107

Ab Git Version 2.5+ (Q2 2015) ist das Abrufen eines einzelnen Commits (ohne das vollständige Repo zu klonen) tatsächlich möglich.

Siehe Commit 68ee628 von Fredrik Medley ( moroten) , 21. Mai 2015.
(Zusammengeführt von Junio ​​C Hamano - gitster- in Commit a9d3493 , 01. Juni 2015)

Sie haben jetzt eine neue Konfiguration (auf der Serverseite)

uploadpack.allowReachableSHA1InWant

Erlauben Sie upload-pack, eine Abrufanforderung zu akzeptieren, die nach einem Objekt fragt, das von jedem Referenztipp aus erreichbar ist. Beachten Sie jedoch, dass die Berechnung der Erreichbarkeit von Objekten rechenintensiv ist.
Der Standardwert ist false.

Wenn Sie diese serverseitige Konfiguration mit einem flachen Klon ( git fetch --depth=1) kombinieren, können Sie ein einzelnes Commit anfordern (siehe t/t5516-fetch-push.sh:

git fetch --depth=1 ../testrepo/.git $SHA1

Mit dem git cat-fileBefehl können Sie feststellen , dass das Commit abgerufen wurde:

git cat-file commit $SHA1

" git upload-pack" das dient " git fetch" kann angewiesen werden, Commits zu bedienen, die sich nicht an der Spitze eines Refs befinden, solange sie von einem Ref aus mit einer uploadpack.allowReachableSHA1InWant Konfigurationsvariablen erreichbar sind.


Die vollständige Dokumentation lautet:

upload-pack: Ermöglicht optional das Abrufen von erreichbarem sha1

Wenn die uploadpack.allowReachableSHA1InWantKonfigurationsoption auf der Serverseite festgelegt ist, kann " git fetch" eine Anforderung mit einer "Such" -Zeile stellen, die ein Objekt benennt, das nicht angekündigt wurde (wahrscheinlich außerhalb des Bandes oder von einem Submodulzeiger abgerufen wurde).
Es werden nur Objekte verarbeitet, die über die Zweigspitzen erreichbar sind, dh die Vereinigung der beworbenen Zweige und der von ausgeblendeten Zweige transfer.hideRefs.
Beachten Sie, dass das Zurückgehen des Verlaufs zur Überprüfung der Erreichbarkeit mit Kosten verbunden ist.

Diese Funktion kann verwendet werden, wenn der Inhalt eines bestimmten Commits abgerufen wird, für den sha1 bekannt ist, ohne dass das gesamte Repository geklont werden muss, insbesondere wenn ein flacher Abruf verwendet wird .

Nützliche Fälle sind z

  • Repositorys mit großen Dateien im Verlauf,
  • nur die benötigten Daten für eine Submodul-Prüfung abrufen,
  • Wenn Sie einen sha1 teilen, ohne zu sagen, zu welchem ​​Zweig er gehört, und in Gerrit, wenn Sie in Commits denken, anstatt Zahlen zu ändern.
    (Der Gerrit-Fall wurde bereits gelöst, allowTipSHA1InWantda jede Gerrit-Änderung eine Referenz hat.)

Git 2.6 (Q3 2015) wird dieses Modell verbessern.
Siehe Commit 2bc31d1 , Commit cc118a6 (28. Juli 2015) von Jeff King ( peff) .
(Zusammengeführt von Junio ​​C Hamano - gitster- in Commit 824a0be , 19. August 2015)

refs: negativ unterstützen transfer.hideRefs

Wenn Sie eine Hierarchie von Refs mithilfe der transfer.hideRefsKonfiguration ausblenden, können Sie diese Konfiguration später nicht überschreiben, um sie "einzublenden".
Dieser Patch implementiert ein "negatives" Verstecken, wodurch Übereinstimmungen sofort als nicht ausgeblendet markiert werden, selbst wenn eine andere Übereinstimmung sie ausblenden würde.
Wir achten darauf, die Übereinstimmungen in umgekehrter Reihenfolge anzuwenden, wie sie uns von der Konfigurationsmaschinerie zugeführt werden, da dadurch unsere übliche Konfigurationsrangfolge "Letzter gewinnt" funktioniert (und Einträge in .git/configbeispielsweise überschreiben /etc/gitconfig).

So können Sie jetzt tun:

git config --system transfer.hideRefs refs/secret
git config transfer.hideRefs '!refs/secret/not-so-secret'

refs/secretin allen Repos zu verstecken , außer einem öffentlichen Bit in einem bestimmten Repo.


Git 2.7 (Nov / Dec 2015) wird sich wieder verbessern:

Siehe Commit 948bfa2 , Commit 00b293e (05. November 2015), Commit 78a766a , Commit 92cab49 , Commit 92cab49 , Commit 92cab49 (03. November 2015), Commit 00b293e , Commit 00b293e (05. November 2015) und Commit 92cab49 , Commit 92cab49 , Commit 92cab49 , Commit 92cab49 (03. November 2015) von Lukas Fleischer ( lfos) .
Mit freundlicher Unterstützung von Eric Sunshine ( sunshineco) .
(Zusammengeführt von Jeff King - peff- in Commit dbba85e , 20. November 2015)

config.txt: Dokumentieren Sie die Semantik von hideRefsmit Namespaces

Derzeit gibt es keine klare Definition, wie transfer.hideRefssich ein Namespace verhalten soll.
Erklären Sie, dass hideRefsPräfixe in diesem Fall mit entfernten Namen übereinstimmen. So werden hideRefsMuster derzeit im Empfangspaket behandelt.

hideRefs: Unterstützung für übereinstimmende vollständige Refs hinzufügen

Zusätzlich zum Abgleichen von gestrippten Refs können jetzt hideRefsMuster hinzugefügt werden, mit denen der vollständige (nicht gestrippte) Ref abgeglichen wird.
Um zwischen gestrippten und vollständigen Übereinstimmungen zu unterscheiden, muss diesen neuen Mustern ein Zirkumflex ( ^) vorangestellt werden .

Daher die neue Dokumentation :

transfer.hideRefs:

Wenn ein Namespace verwendet wird, wird das Namespace-Präfix von jeder Referenz entfernt, bevor es mit transfer.hiderefsMustern abgeglichen wird .
Wenn beispielsweise refs/heads/masterangegeben in transfer.hideRefsund der aktuellen Namensraum ist foo, dann refs/namespaces/foo/refs/heads/master wird aus der Werbung verzichtet aber refs/heads/masterund refs/namespaces/bar/refs/heads/masterwerden immer noch als so genannte „haben“ Linien ausgeschrieben.
Um die Refs vor dem Strippen abzugleichen, fügen Sie ^vor dem Ref-Namen ein hinzu. Wenn Sie !und kombinieren ^, !muss zuerst angegeben werden.


R .. erwähnt in den Kommentaren die Konfiguration uploadpack.allowAnySHA1InWant, die es ermöglicht upload-pack, eine fetchAnfrage zu akzeptieren , die überhaupt nach einem Objekt fragt. (Standardmäßig false).

Siehe Commit f8edeaa (Nov. 2016, Git v2.11.1) von David "novalis" Turner ( novalis) :

upload-pack: Ermöglicht optional das Abrufen von sha1

Es erscheint ein wenig albern, eine Erreichbarkeitsprüfung durchzuführen, wenn wir dem Benutzer vertrauen, dass er auf absolut alles im Repository zugreift.

Außerdem ist es in einem verteilten System rassig - vielleicht kündigt ein Server eine Referenz an, aber ein anderer hat seitdem einen Force-Push für diese Referenz erhalten, und möglicherweise werden die beiden HTTP-Anforderungen an diese verschiedenen Server weitergeleitet.


4
Können Sie ein vollständigeres Beispiel dafür geben, wie Sie mit nur diesem einzigen Commit einen Repo-Klon erstellen? Ich habe es versucht, bin aber gescheitert. Danke!
Lars Bilke

1
Ich möchte zu GitHub pushen. Vielleicht erlauben sie das nicht.
Lars Bilke

2
@LarsBilke wir reden hier über Klonen oder Ziehen, nicht drücken. Und ich bin mir ziemlich sicher, dass GitHub Git 2.5 noch nicht auf der Serverseite hat.
VonC

2
Jetzt noch besser, es gibt uploadpack.allowAnySHA1InWantohne die Erreichbarkeitsberechnungsstrafe (und den DoS-Vektor).
R .. GitHub STOP HELPING ICE

1
Vielen Dank! Ich finde es lustig, dass sie es als "dem Benutzer vertrauen, um darauf zuzugreifen" beschreiben, anstatt "den Repo-Autoren vertrauen, dass sie keinen zufälligen Mist pushen, den sie nicht veröffentlichen wollen".
R .. GitHub STOP HELPING ICE

97

Sie klonen nur einmal. Wenn Sie also bereits einen Klon des Remote-Repositorys haben, wird durch Abrufen nicht alles erneut heruntergeladen. Geben Sie einfach an, welchen Zweig Sie abrufen möchten, oder rufen Sie die Änderungen ab und überprüfen Sie das gewünschte Commit.

Das Abrufen aus einem neuen Repository ist sehr kostengünstig, da nur die Änderungen heruntergeladen werden, die Sie nicht haben. Denken Sie daran, dass Git mit minimaler Belastung das Richtige macht.

Git speichert alles im .gitOrdner. Ein Commit kann nicht isoliert abgerufen und gespeichert werden, es benötigt alle seine Vorfahren. Sie sind miteinander verbunden .


Um die Downloadgröße zu verringern, können Sie git jedoch bitten, nur Objekte abzurufen, die sich auf einen bestimmten Zweig oder ein bestimmtes Commit beziehen:

git fetch origin refs/heads/branch:refs/remotes/origin/branch

Dadurch werden nur Commits heruntergeladen, die in der Remote-Verzweigung enthalten sind branch (und nur die, die Sie verpassen) , und in gespeichertorigin/branch . Sie können dann zusammenführen oder auschecken.

Sie können auch nur ein SHA1-Commit angeben:

git fetch origin 96de5297df870:refs/remotes/origin/foo-commit

Dadurch wird nur das Commit des angegebenen SHA-1 96de5297df870 (und seiner Vorfahren, die Sie vermissen) heruntergeladen und als (nicht vorhandener) Remote-Zweig gespeichert origin/foo-commit.


3
Sieht so aus, als würden Sie sich nicht sicher sein, was Klon bedeutet. Wenn Sie Änderungen von einem Remote-Repo abrufen, klonen Sie es nicht, sondern erhalten nur die Commits in Ihrem Verlauf. Dann wählen Sie aus, welches Commit Sie
auschecken

1
Es werden immer noch viele Daten (430 MB) mit Git Fetch heruntergeladen. Das erforderliche Commit beträgt nur wenige kbs. Es gibt keinen speziellen Befehl, um dies wirklich zu tun? Und was ist, wenn ich das Repo "Git Fetched" entfernen möchte? wo ist es gespeichert?
Varun Chitre

9
Dies ist jetzt ziemlich veraltet. Wir haben sowohl die Möglichkeit, einen flachen Klon auszuführen als auch ein einzelnes Commit abzurufen . Flache Klone können jetzt normal pushen und abrufen, ohne den vollständigen Verlauf des Projekts kennen zu müssen. Daher ist es nicht mehr richtig zu sagen, dass ein Commit ohne seine Vorfahren nicht alleine existieren kann. Was Sie über das Abrufen nach dem ersten Klon sagen, ist sehr wahr, aber wir haben auch noch billigere Optionen.
Theodore Murdock

6
Der letzte Befehl (mit SHA1-Commit) funktioniert bei mir nicht. Der Befehl macht für eine Weile still "etwas" und wird dann ohne Meldung oder offensichtliche Nebenwirkung beendet.
HRJ

1
@HRJ Ja, das habe ich auch unter Ubuntu 16.04 mit Git erlebt 2.7.4-0ubuntu1.3. Bei Verwendung 2.16.2-0ppa1~ubuntu16.04.1von Git-Core-PPA funktioniert dies jedoch ordnungsgemäß. Klingt nach einem Fehler, der behoben wurde. Bei einer Schnellsuche konnte kein Hinweis darauf gefunden werden. Wenn mir jemand einen Hinweis darauf geben kann, würde ich dieses Update gerne zurückportieren lassen.
Gertvdijk

62

Ich habe an meinem Git Repo gezogen:

git pull --rebase <repo> <branch>

Erlaubte git, den gesamten Code für den Zweig einzuziehen, und dann machte ich einen Reset zu dem Commit, das mich interessierte.

git reset --hard <commit-hash>

Hoffe das hilft.


1
Keine der Antworten hat funktioniert, diese hat mir das Leben gerettet! Vielen Dank!
michaeltintiuc

Der Reset - Hard hat nach dem Klonen für mich funktioniert! Vielen Dank.
Nick-ACNB

3
-1: "destruktive" Befehle, wie sie git reset --hardin verallgemeinerten Lösungen verwendet werden, können Menschen in Fallen führen, in denen sie Daten verlieren (oder in diesem Fall in einem Zustand, in dem das Zurückholen ihrer Daten nicht trivial ist).
yaauie

54

Sie können einfach ein einzelnes Commit eines Remote-Repos mit abrufen

git fetch <repo> <commit>

wo,

  • <repo>kann ein Remote-Repo-Name (z. B. origin) oder sogar eine Remote-Repo-URL (z. B. https://git.foo.com/myrepo.git) sein
  • <commit> kann das SHA1-Commit sein

beispielsweise

git fetch https://git.foo.com/myrepo.git 0a071603d87e0b89738599c160583a19a6d95545

Nachdem Sie das Commit (und die fehlenden Vorfahren) abgerufen haben, können Sie es einfach mit auschecken

git checkout FETCH_HEAD

Beachten Sie, dass Sie dadurch in den Zustand "Abgelöster Kopf" versetzt werden.


10
Wenn ich fetcheine bestimmte Umdrehung versuche, wie Sie es dort tun, schlägt git mit Fehlercode 1 und ohne Ausgabe fehl. War dies etwas, das in früheren Versionen funktioniert hat? (Ich bin v2.0.2.)
Jack O'Connor

2
Bearbeiten: Es funktioniert, wenn ich das Commit bereits lokal habe, wie wenn ich bereits ein vollständiges Commit durchgeführt habe fetch, obwohl ich in diesem Fall nicht sicher bin, was die Verwendung ist.
Jack O'Connor

2
In der Tat scheint dies auch mit Git 2.0.2 für mich nicht mehr zu funktionieren. :(
Flow

2
git checkout FETCH_HEADhilft.
lzl124631x

1
Diese Methode funktioniert nicht mit flachem Abruf (zB --depth=1)!
Kingmakerking

16

Sie können das Remote-Repo einfach abrufen mit:

git fetch <repo>

wo,

  • <repo>kann ein Remote-Repo-Name (z. B. origin) oder sogar eine Remote-Repo-URL (z. B. https://git.foo.com/myrepo.git) sein

beispielsweise:

git fetch https://git.foo.com/myrepo.git 

Nachdem Sie die Repos abgerufen haben, können Sie die gewünschten Commits zusammenführen (da es um das Abrufen eines Commits geht, können Sie stattdessen Cherry-Pick verwenden, um nur ein Commit auszuwählen):

git merge <commit>
  • <commit> kann das SHA1-Commit sein

beispielsweise:

git cherry-pick 0a071603d87e0b89738599c160583a19a6d95545

oder

git merge 0a071603d87e0b89738599c160583a19a6d95545

Wenn es sich um das letzte Commit handelt, das Sie zusammenführen möchten, können Sie auch die Variable FETCH_HEAD verwenden:

git cherry-pick (or merge) FETCH_HEAD

Dies erfordert die Einrichtung eines Git-Kontos auf einem Computer. Es funktioniert nicht unter einem Testkonto. Haben Sie etwas, das unter einem Testkonto funktioniert?
jww

Was meinst du ? Sie können nicht Git holen.
Sérgio

Ummm also wäre der Befehl git config set uploadpack.allowReachableSHA1InWant ?
Alexander Mills

2

Das funktioniert am besten:

git fetch origin specific_commit
git checkout -b temp FETCH_HEAD

Nennen Sie "temp", was auch immer Sie wollen ... dieser Zweig könnte jedoch verwaist sein


Offensichtlich NICHT mit älteren Git-Versionen wie 1.8.x
Sorin

1

Schließlich habe ich einen Weg gefunden, ein bestimmtes Commit mit zu klonen Git Cherry-Pick . Angenommen, Sie haben kein lokales Repository und ziehen ein bestimmtes Commit von der Remote-Adresse.

1) Erstellen Sie ein leeres Repository in lokalen und git init

2) git remote add origin " URL des Repositorys "

3) Git holen Ursprung [Dadurch werden Ihre Dateien nur dann in Ihren lokalen Arbeitsbereich verschoben, wenn Sie sie zusammenführen.]

4) git cherry-pick " Geben Sie den Long-Commit-Hash ein, den Sie brauchen "

Fertig. Auf diese Weise haben Sie nur die Dateien von diesem bestimmten Commit in Ihrem lokalen.

Enter-Long-Commit-Hash:

Sie können dies mit -> git log --pretty = oneline erhalten



0

Wenn sich das angeforderte Commit in den Pull-Anforderungen des Remote-Repos befindet, können Sie es anhand seiner ID abrufen:

# Add the remote repo path, let's call it 'upstream':
git remote add upstream https://github.com/repo/project.git

# checkout the pull ID, for example ID '60':
git fetch upstream pull/60/head && git checkout FETCH_HEAD
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.