Wie klone ich nur ein Unterverzeichnis eines Git-Repositorys?


1410

Ich habe mein Git-Repository, das im Stammverzeichnis zwei Unterverzeichnisse hat:

/finisht
/static

Wenn dies in SVN war , /finishtwurde es an einem Ort ausgecheckt , während /statices an anderer Stelle ausgecheckt wurde, wie folgt:

svn co svn+ssh://admin@domain.com/home/admin/repos/finisht/static static

Gibt es eine Möglichkeit, dies mit Git zu tun?



1
Was ist für einen Benutzer von 2014 der git cloneeinfachste Befehl? Ich habe diese einfache Antwort verwendet . Wenn es etwas Einfacheres gibt, kommentieren Sie bitte
Peter Krauss

Für diejenigen, die versuchen, den Inhalt des Repositorys zu klonen (ohne den Stammordner zu erstellen), ist dies eine sehr einfache Lösung: stackoverflow.com/questions/6224626/…
Marc

@JoachimBreitner: Bei dieser Frage geht es um das Auschecken von Unterverzeichnissen in Git (was einfach ist), während es bei dieser Frage um das Klonen von Unterverzeichnissen in Git geht (was unmöglich ist).
Jörg W Mittag

@NickSergeant: Ab Git 2.19, das vor 3 Wochen veröffentlicht wurde, ist dies endlich möglich, wie aus dieser Antwort hervorgeht: stackoverflow.com/a/52269934/2988 Erwägen Sie, diese jetzt zu akzeptieren. Hinweis: In Git 2.19 ist nur die clientseitige Unterstützung implementiert. Die serverseitige Unterstützung fehlt noch, sodass sie nur beim Klonen lokaler Repositorys funktioniert. Beachten Sie auch, dass große Git-Hoster, z. B. GitHub, den Git-Server nicht verwenden, sondern ihre eigene Implementierung. Selbst wenn die Unterstützung auf dem Git-Server angezeigt wird, bedeutet dies nicht automatisch, dass sie auf Git-Hostern funktioniert. (OTOH, sie könnten es schneller implementieren.)
Jörg W Mittag

Antworten:


612

EDIT : Ab Git 2.19 ist dies endlich möglich, wie aus dieser Antwort hervorgeht .

Erwägen Sie, diese Antwort zu verbessern.

Hinweis: In Git 2.19 ist nur die clientseitige Unterstützung implementiert. Die serverseitige Unterstützung fehlt noch, sodass sie nur beim Klonen lokaler Repositorys funktioniert. Beachten Sie auch, dass große Git-Hoster, z. B. GitHub, den Git-Server nicht verwenden, sondern ihre eigene Implementierung. Selbst wenn die Unterstützung auf dem Git-Server angezeigt wird, bedeutet dies nicht automatisch, dass sie auf Git-Hostern funktioniert. (OTOH, da sie den Git-Server nicht verwenden, können sie ihn in ihren eigenen Implementierungen schneller implementieren, bevor er auf dem Git-Server angezeigt wird.)


Nein, das ist in Git nicht möglich.

Die Implementierung von so etwas in Git wäre ein erheblicher Aufwand und würde bedeuten, dass die Integrität des clientseitigen Repositorys nicht mehr garantiert werden kann. Wenn Sie interessiert sind, suchen Sie auf der Git-Mailingliste nach Diskussionen zu "Sparse Clone" und "Sparse Fetch".

Im Allgemeinen besteht in der Git-Community der Konsens, dass wenn Sie mehrere Verzeichnisse haben, die immer unabhängig ausgecheckt werden, dies wirklich zwei verschiedene Projekte sind und in zwei verschiedenen Repositorys leben sollten. Sie können sie mit Git-Submodulen wieder zusammenkleben .


6
Je nach Szenario möchten Sie möglicherweise den Git-Teilbaum anstelle des Git-Submoduls verwenden. Siehe alumnit.ca/~apenwarr/log/?m=200904#30
C Pirate

9
@StijndeWitt: Sparsame Kassen finden während git-read-tree, was lange danach ist get-fetch. Bei der Frage ging es nicht darum, nur ein Unterverzeichnis auszuchecken, sondern nur ein Unterverzeichnis zu klonen . Ich sehe nicht ein, wie spärliche Kassen dies möglicherweise tun könnten, da git-read-treeder Klon bereits abgeschlossen ist.
Jörg W Mittag

9
Möchten Sie, dass ich anstelle dieses "Stubs" diese Antwort lösche, damit Chronial's nach oben schweben kann? Sie können es nicht selbst löschen, da es akzeptiert wird, ein Moderator jedoch. Sie würden den Ruf behalten, den Sie sich damit verdient haben, da es so alt ist. (Ich bin darauf
Cody Gray

1
@CodyGray: Die chronische Antwort klont immer noch das gesamte Repository und nicht nur ein Unterverzeichnis. (Der letzte Absatz sagt dies sogar ausdrücklich.) Das Klonen nur eines Unterverzeichnisses ist in Git nicht möglich . Das Netzwerkprotokoll unterstützt es nicht, das Speicherformat unterstützt es nicht. Jede einzelne Antwort auf diese Frage klont immer das gesamte Repository. Die Frage ist eine einfache Ja / Nein-Frage, und die Antwort besteht aus zwei Zeichen: Nein. Wenn überhaupt, ist meine Antwort unnötig lang und nicht kurz.
Jörg W Mittag

1
@ JörgWMittag: Die Antwort von Ciro Santili scheint dir zu widersprechen.
Dan Dascalescu

1525

Was Sie versuchen, wird als spärliches Auschecken bezeichnet , und diese Funktion wurde in Git 1.7.0 (Februar 2012) hinzugefügt. Die Schritte zum Erstellen eines Sparse- Klons lauten wie folgt:

mkdir <repo>
cd <repo>
git init
git remote add -f origin <url>

Dadurch wird mit Ihrer Fernbedienung ein leeres Repository erstellt und alle Objekte abgerufen, aber nicht ausgecheckt. Dann mach:

git config core.sparseCheckout true

Jetzt müssen Sie definieren, welche Dateien / Ordner Sie tatsächlich auschecken möchten. Dies geschieht durch Auflisten in .git/info/sparse-checkoutz.

echo "some/dir/" >> .git/info/sparse-checkout
echo "another/sub/tree" >> .git/info/sparse-checkout

Zu guter Letzt aktualisieren Sie Ihr leeres Repo mit dem Status von der Fernbedienung:

git pull origin master

Sie haben jetzt Dateien für some/dirund "ausgecheckt"another/sub/tree auf Ihrem Dateisystem (mit diesen Pfaden noch) und keine anderen Pfade vorhanden.

Vielleicht möchten Sie sich das erweiterte Tutorial ansehen und sollten wahrscheinlich die offizielle Dokumentation für spärliches Auschecken lesen .

Als eine Funktion:

function git_sparse_clone() (
  rurl="$1" localdir="$2" && shift 2

  mkdir -p "$localdir"
  cd "$localdir"

  git init
  git remote add -f origin "$rurl"

  git config core.sparseCheckout true

  # Loops over remaining args
  for i; do
    echo "$i" >> .git/info/sparse-checkout
  done

  git pull origin master
)

Verwendungszweck:

git_sparse_clone "http://github.com/tj/n" "./local/location" "/bin"

Beachten Sie, dass dadurch weiterhin das gesamte Repository vom Server heruntergeladen wird - nur der Checkout wird verkleinert. Derzeit ist es nicht möglich, nur ein einziges Verzeichnis zu klonen. Wenn Sie jedoch den Verlauf des Repositorys nicht benötigen, können Sie zumindest Bandbreite sparen, indem Sie einen flachen Klon erstellen. Siehe udondan Antwort unten für Informationen darüber , wie seicht zu kombinieren Klon und spärliche Kasse.


Ab Git 2.25.0 (Januar 2020) wird in Git ein experimenteller Sparse-Checkout- Befehl hinzugefügt:

git sparse-checkout init
# same as: 
git config core.sparseCheckout true

git sparse-checkout set "A/B"
# same as:
echo "A/B" >> .git/info/sparse-checkout

git sparse-checkout list
# same as:
cat .git/info/sparse-checkout

14
Bei Apple funktioniert der Perimeter "-f" nicht. einfach git remote add origin <url> ohne -f
Anno2001

135
Es ist eine Verbesserung, muss aber noch eine vollständige Kopie des Remote-Repositorys im Ursprung herunterladen und speichern, die man möglicherweise vermeiden möchte, wenn er nur an Teilen der Codebasis interessiert ist (oder wenn es Dokumentationsunterordner wie in meinem Fall gibt )
a1an

56
Gibt es eine Möglichkeit, den gewünschten Verzeichnisinhalt (nicht das Verzeichnis selbst) direkt in mein Repository zu klonen? Zum Beispiel möchte ich den Inhalt von https://github.com/Umkus/nginx-boilerplate/tree/master/srcRight in/etc/nginx
Mac

25
@Chronial, @ErikE: Sie sind beide richtig / falsch: P Der git remote addBefehl ist nicht implizieren eine holen, aber git remote add -f, wie hier verwendet, tut! Das ist was das -fbedeutet.
Ntc2

21
Damit habe --depth=1ich Chromium Devtools in 338 MB anstelle von 4,9 GB vollständigem Blink-Quell- + Verlauf geklont. Ausgezeichnet.
Rudie

444

git clone --filter ab Git 2.19

Diese Option überspringt das Abrufen nicht benötigter Objekte vom Server. Auch --filter=tree:0ab Git 2.20 und dem --filter=combinein Git 2.24 hinzugefügten Composite-Filter erhalten wir:

git clone \
  --depth 1 \
  --filter=combine:blob:none+tree:0 \
  --no-checkout \
  "file://$(pwd)/server_repo" \
  local_repo \
;
cd local_repo
git checkout master -- mydir/

Der Server sollte konfiguriert sein mit:

git config --local uploadpack.allowfilter 1
git config --local uploadpack.allowanysha1inwant 1

Das Git-Remote-Protokoll wurde erweitert, um diese Funktion in zu unterstützen v2.19.0 und das Abrufen nicht benötigter Objekte zu überspringen. Derzeit wird jedoch kein Server unterstützt. Es kann aber schon lokal getestet werden.

Befehlsaufschlüsselung:

Das Format von --filterist am dokumentiert man git-rev-list.

Dokumente auf Git-Baum:

Probieren Sie es aus

#!/usr/bin/env bash
set -eu

list-objects() (
  git rev-list --all --objects
  echo "master commit SHA: $(git log -1 --format="%H")"
  echo "mybranch commit SHA: $(git log -1 --format="%H")"
  git ls-tree master
  git ls-tree mybranch | grep mybranch
  git ls-tree master~ | grep root
)

# Reproducibility.
export GIT_COMMITTER_NAME='a'
export GIT_COMMITTER_EMAIL='a'
export GIT_AUTHOR_NAME='a'
export GIT_AUTHOR_EMAIL='a'
export GIT_COMMITTER_DATE='2000-01-01T00:00:00+0000'
export GIT_AUTHOR_DATE='2000-01-01T00:00:00+0000'

rm -rf server_repo local_repo
mkdir server_repo
cd server_repo

# Create repo.
git init --quiet
git config --local uploadpack.allowfilter 1
git config --local uploadpack.allowanysha1inwant 1

# First commit.
# Directories present in all branches.
mkdir d1 d2
printf 'd1/a' > ./d1/a
printf 'd1/b' > ./d1/b
printf 'd2/a' > ./d2/a
printf 'd2/b' > ./d2/b
# Present only in root.
mkdir 'root'
printf 'root' > ./root/root
git add .
git commit -m 'root' --quiet

# Second commit only on master.
git rm --quiet -r ./root
mkdir 'master'
printf 'master' > ./master/master
git add .
git commit -m 'master commit' --quiet

# Second commit only on mybranch.
git checkout -b mybranch --quiet master~
git rm --quiet -r ./root
mkdir 'mybranch'
printf 'mybranch' > ./mybranch/mybranch
git add .
git commit -m 'mybranch commit' --quiet

echo "# List and identify all objects"
list-objects
echo

# Restore master.
git checkout --quiet master
cd ..

# Clone. Don't checkout for now, only .git/ dir.
git clone --depth 1 --quiet --no-checkout --filter=blob:none "file://$(pwd)/server_repo" local_repo
cd local_repo

# List missing objects from master.
echo "# Missing objects after --no-checkout"
git rev-list --all --quiet --objects --missing=print
echo

echo "# Git checkout fails without internet"
mv ../server_repo ../server_repo.off
! git checkout master
echo

echo "# Git checkout fetches the missing directory from internet"
mv ../server_repo.off ../server_repo
git checkout master -- d1/
echo

echo "# Missing objects after checking out d1"
git rev-list --all --quiet --objects --missing=print

GitHub stromaufwärts .

Ausgabe in Git v2.19.0:

# List and identify all objects
c6fcdfaf2b1462f809aecdad83a186eeec00f9c1
fc5e97944480982cfc180a6d6634699921ee63ec
7251a83be9a03161acde7b71a8fda9be19f47128
62d67bce3c672fe2b9065f372726a11e57bade7e
b64bf435a3e54c5208a1b70b7bcb0fc627463a75 d1
308150e8fddde043f3dbbb8573abb6af1df96e63 d1/a
f70a17f51b7b30fec48a32e4f19ac15e261fd1a4 d1/b
84de03c312dc741d0f2a66df7b2f168d823e122a d2
0975df9b39e23c15f63db194df7f45c76528bccb d2/a
41484c13520fcbb6e7243a26fdb1fc9405c08520 d2/b
7d5230379e4652f1b1da7ed1e78e0b8253e03ba3 master
8b25206ff90e9432f6f1a8600f87a7bd695a24af master/master
ef29f15c9a7c5417944cc09711b6a9ee51b01d89
19f7a4ca4a038aff89d803f017f76d2b66063043 mybranch
1b671b190e293aa091239b8b5e8c149411d00523 mybranch/mybranch
c3760bb1a0ece87cdbaf9a563c77a45e30a4e30e
a0234da53ec608b54813b4271fbf00ba5318b99f root
93ca1422a8da0a9effc465eccbcb17e23015542d root/root
master commit SHA: fc5e97944480982cfc180a6d6634699921ee63ec
mybranch commit SHA: fc5e97944480982cfc180a6d6634699921ee63ec
040000 tree b64bf435a3e54c5208a1b70b7bcb0fc627463a75    d1
040000 tree 84de03c312dc741d0f2a66df7b2f168d823e122a    d2
040000 tree 7d5230379e4652f1b1da7ed1e78e0b8253e03ba3    master
040000 tree 19f7a4ca4a038aff89d803f017f76d2b66063043    mybranch
040000 tree a0234da53ec608b54813b4271fbf00ba5318b99f    root

# Missing objects after --no-checkout
?f70a17f51b7b30fec48a32e4f19ac15e261fd1a4
?8b25206ff90e9432f6f1a8600f87a7bd695a24af
?41484c13520fcbb6e7243a26fdb1fc9405c08520
?0975df9b39e23c15f63db194df7f45c76528bccb
?308150e8fddde043f3dbbb8573abb6af1df96e63

# Git checkout fails without internet
fatal: '/home/ciro/bak/git/test-git-web-interface/other-test-repos/partial-clone.tmp/server_repo' does not appear to be a git repository
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

# Git checkout fetches the missing directory from internet
remote: Enumerating objects: 1, done.
remote: Counting objects: 100% (1/1), done.
remote: Total 1 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (1/1), 45 bytes | 45.00 KiB/s, done.
remote: Enumerating objects: 1, done.
remote: Counting objects: 100% (1/1), done.
remote: Total 1 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (1/1), 45 bytes | 45.00 KiB/s, done.

# Missing objects after checking out d1
?8b25206ff90e9432f6f1a8600f87a7bd695a24af
?41484c13520fcbb6e7243a26fdb1fc9405c08520
?0975df9b39e23c15f63db194df7f45c76528bccb

Schlussfolgerungen: Alle Blobs von außerhalb d1/fehlen. ZB 0975df9b39e23c15f63db194df7f45c76528bccb, was d2/bnach dem Auschecken nicht da ist d1/a.

Beachten Sie, dass root/rootund mybranch/mybranchauch fehlen, aber --depth 1das aus der Liste der fehlenden Dateien verbirgt. Wenn Sie entfernen --depth 1, werden sie in der Liste der fehlenden Dateien angezeigt.

Ich habe einen Traum

Diese Funktion könnte Git revolutionieren.

Stellen Sie sich vor, Sie haben die gesamte Codebasis Ihres Unternehmens in einem einzigen Repo ohne hässliche Tools von Drittanbieternrepo .

Stellen Sie sich vor, Sie speichern riesige Blobs direkt im Repo ohne hässliche Erweiterungen von Drittanbietern .

Stellen Sie sich vor, GitHub würde Metadaten wie Sterne und Berechtigungen pro Datei / Verzeichnis zulassen , sodass Sie alle Ihre persönlichen Daten unter einem einzigen Repo speichern können.

Stellen Sie sich vor, Submodule würden genau wie reguläre Verzeichnisse behandelt : Fordern Sie einfach eine Baum-SHA an, und ein DNS-ähnlicher Mechanismus löst Ihre Anfrage auf . Schauen Sie zuerst auf Ihren lokalen~/.git Server, dann auf nähere Server (den Spiegel / Cache Ihres Unternehmens) und landen Sie auf GitHub.


Seltsamerweise wird unter MacOS mit Git-Version 2.20.1 (Apple Git-117) beanstandet, dass "mehrere Filterspezifikationen nicht kombiniert werden können"
3.

1
Leider kein Glück mit der macOS git Version. fatal: invalid filter-spec 'combine:blob:none+tree:0'Danke trotzdem! Vielleicht funktioniert es mit neueren Versionen.
Muru

1
Dies schlägt fehl, wenn Sie es unter Windows 10 mit GIT 2.24.1 versuchen (es werden Tonnen von "sha1-Datei von .. kann nicht gelesen werden" + "Unlink der Datei xxx fehlgeschlagen" ausgelöst). Arbeitete als Zauber mit der gleichen Version unter Linux.
Oyvind

1
@Ciro Santilli Dies schlägt immer noch fehl, wenn die sha1-Datei von ... in der Git-Version 2.26.1.windows.1 nicht gelesen werden kann. Ich habe einen Fehlerbericht geöffnet: github.com/git-for-windows/git/issues/2590
nharrer


405

Sie können die Funktionen für spärliches Auschecken und flache Klone kombinieren . Der flache Klon schneidet den Verlauf ab und die spärliche Kasse zieht nur die Dateien, die Ihren Mustern entsprechen.

git init <repo>
cd <repo>
git remote add origin <url>
git config core.sparsecheckout true
echo "finisht/*" >> .git/info/sparse-checkout
git pull --depth=1 origin master

Sie benötigen mindestens Git 1.9, damit dies funktioniert. Habe es selbst nur mit 2.2.0 und 2.2.2 getestet.

Auf diese Weise können Sie immer noch pushen , was mit nicht möglich ist git archive.


21
Dies ist nützlich, und kann die beste verfügbare Lösung sein, aber es immer noch klont den Inhalt , dass Sie kümmern sich um nicht (wenn es auf dem Zweig ist , dass Sie ziehen), auch wenn sie nicht in der Kasse nicht angezeigt.
Nobar

1
Was ist deine Git-Version? Laut Git-Hilfe ist die Tiefenoption verfügbar?
Udondan

2
nicht für mich arbeiten , wenn der letzte Befehl nicht git pull --depth=1 origin masteraber git pull --depth=1 origin <any-other-branch>. Das ist so seltsam, siehe meine Frage hier: stackoverflow.com/questions/35820630/…
Shuman

5
Unter Windows muss in der vorletzten Zeile die Anführungszeichen weggelassen werden, sonst schlägt das Ziehen fehl.
Nateirvin

4
Dies lädt immer noch alle Daten herunter! Fand diese Lösung mit svn: stackoverflow.com/a/18324458/2302437
elektronix384128

157

Für andere Benutzer, die nur eine Datei / einen Ordner von github herunterladen möchten, verwenden Sie einfach:

svn export <repo>/trunk/<folder>

z.B

svn export https://github.com/lodash/lodash.com/trunk/docs

(Ja, das ist SVN hier. Anscheinend benötigen Sie 2016 noch SVN, um einfach einige Github-Dateien herunterzuladen.)

Mit freundlicher Genehmigung: Laden Sie einen einzelnen Ordner oder ein einzelnes Verzeichnis von einem GitHub-Repo herunter

Wichtig - Stellen Sie sicher, dass Sie die Github-URL aktualisieren und ersetzen/tree/master/ '/ trunk /' .

Als Bash-Skript:

git-download(){
    folder=${@/tree\/master/trunk}
    folder=${folder/blob\/master/trunk}
    svn export $folder
}

Hinweis Diese Methode lädt einen Ordner herunter und klont / checkt ihn nicht aus. Sie können Änderungen nicht in das Repository zurückschieben. Auf der anderen Seite führt dies zu einem geringeren Download im Vergleich zu einem spärlichen oder flachen Checkout.


9
einzige Version, die bei mir mit Github funktioniert hat. Die Git-Befehle checkten> 10k Dateien aus, der SVN exportierte nur die 700, die ich wollte. Vielen Dank!
Christopher Lörken

4
Versuchte dies mit https://github.com/tensorflow/tensorflow/tree/master/tensorflow/examples/trunk/udacityaber bekam svn: E170000: URL 'https://github.com/tensorflow/tensorflow/tree/master/tensorflow/examples/trunk/udacity' doesn't existFehler :(
zthomas.nc

9
@ zthomas.nc Sie müssen den 'Stamm' vor udacity entfernen und stattdessen / tree / master / durch / trunk / ersetzen.
Schneller

2
Dieser Befehl hat bei mir funktioniert! Ich wollte nur eine Kopie einer Datei aus einem Repo erhalten, damit ich sie lokal ändern kann. Guter alter SVN zur Rettung!
Michael J

3
es funktioniert, scheint aber langsam. Der Start dauert etwas und dann rollen die Dateien relativ langsam vorbei
Aryeh Beitz

73

Wenn Sie nie vorhaben, mit dem Repository zu interagieren, aus dem Sie geklont haben, können Sie einen vollständigen Git-Klon erstellen und Ihr Repository mithilfe des Git-Filter-Zweigs - Unterverzeichnis-Filter neu schreiben . Auf diese Weise bleibt zumindest die Geschichte erhalten.


11
Für Leute, die den Befehl nicht kennen, ist esgit filter-branch --subdirectory-filter <subdirectory>
Jaime Hablutzel

9
Diese Methode hat den Vorteil, dass das von Ihnen ausgewählte Unterverzeichnis zum Stammverzeichnis des neuen Repositorys wird, das genau das ist, was ich möchte.
Andrew Schulman

Das ist definitiv der beste und einfachste Ansatz. Hier ist ein einstufiger Befehl mit Unterverzeichnisfiltergit clone https://github.com/your/repo_xx.git && cd repo_xx && git filter-branch --subdirectory-filter repo_xx_subdir
Alex

66

Das sieht viel einfacher aus:

git archive --remote=<repo_url> <branch> <path> | tar xvf -

17
Wenn ich dies auf Github mache, werde ich fatal: Operation wird vom Protokoll nicht unterstützt. Unerwartetes Ende des Befehlsstroms
Michael Fox

1
Der Protokollfehler kann auf HTTPS oder: in der Repo-URL zurückzuführen sein. Es könnte auch an einem fehlenden SSH-Schlüssel liegen.
Umair A.

2
Wenn Sie Github verwenden, können Sie svn exportstattdessen verwenden
Milo Wielondek

2
Funktioniert nicht mit Github -> Ungültiger Befehl: 'git-upload-archive' xxx / yyy.git '' Sie scheinen ssh zu verwenden, um eine git: // URL zu klonen. Stellen Sie sicher, dass Ihre Konfigurationsoption core.gitProxy und die Umgebungsvariable GIT_PROXY_COMMAND NICHT festgelegt sind. tödlich: Das entfernte Ende legte unerwartet auf
Nianliang

3
Der Grund, warum dies mit GitHub nicht funktioniert: "Wir unterstützen die Verwendung von git-archive nicht, um ein Archiv direkt aus GitHub abzurufen. Sie können das Repo entweder lokal klonen und git-archive ausführen oder auf die Schaltfläche ZIP herunterladen klicken die Repo-Seite. " github.com/xuwupeng2000/capistrano-scm-gitcopy/issues/16
Donn Lee

63

Git 1.7.0 hat "spärliche Kassen". Siehe „core.sparseCheckout“ in der git config - Man - Page „Sparse Kasse“ in der git las Baum manpage und „Überspringen-worktree Bit“ im git update-Index manpage .

Die Schnittstelle ist nicht so praktisch wie die von SVNs (z. B. gibt es zum Zeitpunkt eines ersten Klons keine Möglichkeit, eine spärliche Prüfung durchzuführen), aber die Basisfunktionalität, auf der einfachere Schnittstellen aufgebaut werden könnten, ist jetzt verfügbar.


37

Es ist nicht möglich, ein Unterverzeichnis nur mit Git zu klonen, aber im Folgenden finden Sie einige Problemumgehungen.

Zweig filtern

Möglicherweise möchten Sie das Repository so umschreiben, dass es so aussieht, als wäre trunk/public_html/es das Projektstammverzeichnis, und den gesamten anderen Verlauf verwerfen (mithilfe von filter-branch). Versuchen Sie es mit dem bereits ausgecheckten Zweig:

git filter-branch --subdirectory-filter trunk/public_html -- --all

Hinweise: --Diese Option trennt Filterzweigoptionen von Revisionsoptionen und --allschreibt alle Zweige und Tags neu. Alle Informationen, einschließlich der ursprünglichen Festschreibungszeiten oder Zusammenführungsinformationen, bleiben erhalten . Dieser Befehl berücksichtigt .git/info/graftsDateien und Verweise im refs/replace/Namespace. Wenn Sie also Transplantate oder Ersetzungen refsdefiniert haben, werden diese durch Ausführen dieses Befehls dauerhaft.

Warnung! Der neu geschriebene Verlauf hat für alle Objekte unterschiedliche Objektnamen und konvergiert nicht mit dem ursprünglichen Zweig. Sie können den umgeschriebenen Zweig nicht einfach über den ursprünglichen Zweig schieben und verteilen. Verwenden Sie diesen Befehl nicht, wenn Sie die vollständigen Auswirkungen nicht kennen, und vermeiden Sie es trotzdem, ihn zu verwenden, wenn ein einfaches Commit ausreichen würde, um Ihr Problem zu beheben.


Sparsame Kasse

Hier sind einfache Schritte mit spärlichem Checkout- Ansatz, bei denen das Arbeitsverzeichnis nur spärlich gefüllt wird, sodass Sie Git mitteilen können, welche Ordner oder Dateien im Arbeitsverzeichnis einen Check-out wert sind.

  1. Klonen Sie das Repository wie gewohnt ( --no-checkoutoptional):

    git clone --no-checkout git@foo/bar.git
    cd bar
    

    Sie können diesen Schritt überspringen, wenn Sie Ihr Repository bereits geklont haben.

    Hinweis: Bei großen Repos sollten Sie den flachen Klon ( --depth 1) in Betracht ziehen, um nur die neueste Version oder / und --single-branchnur auszuchecken .

  2. sparseCheckoutOption aktivieren :

    git config core.sparseCheckout true
    
  3. Geben Sie Ordner für das Auschecken mit geringer Dichte an ( ohne Leerzeichen am Ende):

    echo "trunk/public_html/*"> .git/info/sparse-checkout
    

    oder bearbeiten .git/info/sparse-checkout.

  4. Kasse der Filiale (zB master):

    git checkout master
    

Jetzt sollten Sie Ordner in Ihrem aktuellen Verzeichnis ausgewählt haben.

Sie können symbolische Links in Betracht ziehen, wenn Sie stattdessen zu viele Ebenen von Verzeichnissen oder Filterzweigen haben.



Würde Ihnen der Filterzweig noch erlauben pull?
Sam

2
@sam: nein. filter-branchwürde die übergeordneten Commits neu schreiben, damit sie unterschiedliche SHA1-IDs haben, und somit würde Ihr gefilterter Baum keine Commits mit dem Remote-Baum gemeinsam haben. git pullIch würde nicht wissen, wo ich versuchen soll, mich zusammenzuschließen.
Peter Cordes

Dieser Ansatz ist meistens eine zufriedenstellende Antwort auf meinen Fall.
Abbas

10

Ich habe gerade ein Skript für GitHub geschrieben .

Verwendungszweck:

python get_git_sub_dir.py path/to/sub/dir <RECURSIVE>

11
Zu Ihrer Information, das ist nur für GitHub .
Gr.

9
Und anscheinend dient dies zum Herunterladen eines Verzeichnisses und nicht zum Klonen eines Repo-Teils mit all seinen Metadaten ... richtig?
LarsH

5
Sie sollten Ihren Code hier und nicht woanders einfügen.
Jww

urllib2.HTTPError: HTTP-Fehler 403:
Ratenlimit

9

Dadurch wird ein bestimmter Ordner geklont und der gesamte Verlauf entfernt, der nicht damit zusammenhängt.

git clone --single-branch -b {branch} git@github.com:{user}/{repo}.git
git filter-branch --subdirectory-filter {path/to/folder} HEAD
git remote remove origin
git remote add origin git@github.com:{user}/{new-repo}.git
git push -u origin master

Hier sind Drachen. Sie werden von WARNUNG begrüßt : Git-Filter-Branch hat eine Flut von Fallstricken, die verstümmelte Verlaufsumschreibungen erzeugen . Dann hat das Git-Filter-Branch-Dokument eine ziemlich lange Warnliste.
Oyvind

6

Hier ist ein Shell-Skript, das ich für den Anwendungsfall einer einzelnen Unterverzeichnis-Sparse-Prüfung geschrieben habe

coSubDir.sh

localRepo=$1
remoteRepo=$2
subDir=$3


# Create local repository for subdirectory checkout, make it hidden to avoid having to drill down to the subfolder
mkdir ./.$localRepo
cd ./.$localRepo
git init
git remote add -f origin $remoteRepo
git config core.sparseCheckout true

# Add the subdirectory of interest to the sparse checkout.
echo $subDir >> .git/info/sparse-checkout

git pull origin master

# Create convenience symlink to the subdirectory of interest
cd ..
ln -s ./.$localRepo/$subDir $localRepo

2
Nettes Skript, nur etwas, das behoben werden sollte, ist der Symlink, sollte ln -s ./.$localRepo/$subDir $localRepoanstelle vonln -s ./.$localRepo$subDir $localRepo
valentin_nasta

2

Ich habe eine .gitconfig [alias]für die Durchführung einer "spärlichen Kasse" geschrieben. Probieren Sie es aus (kein Wortspiel beabsichtigt):

Unter Windows laufen in cmd.exe

git config --global alias.sparse-checkout "!f(){ [ $# -eq 2 ] && L=${1##*/} L=${L%.git} || L=$2; mkdir -p \"$L/.git/info\" && cd \"$L\" && git init --template= && git remote add origin \"$1\" && git config core.sparseCheckout 1; [ $# -eq 2 ] && echo \"$2\" >> .git/info/sparse-checkout || { shift 2; for i; do echo $i >> .git/info/sparse-checkout; done }; git pull --depth 1 origin master;};f"

Andernfalls:

git config --global alias.sparse-checkout '!f(){ [ $# -eq 2 ] && L=${1##*/} L=${L%.git} || L=$2; mkdir -p "$L/.git/info" && cd "$L" && git init --template= && git remote add origin "$1" && git config core.sparseCheckout 1; [ $# -eq 2 ] && echo "$2" >> .git/info/sparse-checkout || { shift 2; for i; do echo $i >> .git/info/sparse-checkout; done }; git pull --depth 1 origin master;};f'

Verwendung :

# Makes a directory ForStackExchange with Plug checked out
git sparse-checkout https://github.com/YenForYang/ForStackExchange Plug

# To do more than 1 directory, you have to specify the local directory:
git sparse-checkout https://github.com/YenForYang/ForStackExchange ForStackExchange Plug Folder

Die git configBefehle werden aus Bequemlichkeits- und Speichergründen "minimiert", aber hier ist der erweiterte Alias:

# Note the --template= is for disabling templates.
# Feel free to remove it if you don't have issues with them (like I did)
# `mkdir` makes the .git/info directory ahead of time, as I've found it missing sometimes for some reason
f(){
    [ "$#" -eq 2 ] && L="${1##*/}" L=${L%.git} || L=$2;
    mkdir -p "$L/.git/info"
        && cd "$L"
        && git init --template=
        && git remote add origin "$1"
        && git config core.sparseCheckout 1;
    [ "$#" -eq 2 ]
        && echo "$2" >> .git/info/sparse-checkout
        || {
            shift 2;
            for i; do
                echo $i >> .git/info/sparse-checkout;
            done
        };
    git pull --depth 1 origin master;
};
f

Warum funktioniert das : L=${1##*/} L=${L%.git}? Ist der Weltraum ein Operator?
Gulzt

2

Verwenden Sie Linux? Und wollen nur leicht zugänglichen und sauberen Arbeitsbaum? ohne den Rest des Codes auf Ihrem Computer zu stören. versuche symlinks !

git clone https://github.com:{user}/{repo}.git ~/my-project
ln -s ~/my-project/my-subfolder ~/Desktop/my-subfolder

Prüfung

cd ~/Desktop/my-subfolder
git status

1

Um einige der großartigen Antworten hier zu verdeutlichen, setzen die in vielen Antworten beschriebenen Schritte voraus, dass Sie bereits irgendwo über ein Remote-Repository verfügen.

Gegeben: ein vorhandenes Git-Repository, z. B. git@github.com:some-user/full-repo.gitmit einem oder mehreren Verzeichnissen, die Sie unabhängig vom Rest des Repos abrufen möchten , z. B. Verzeichnisse mit den Namen app1undapp2

Angenommen, Sie haben ein Git-Repository wie oben beschrieben ...

Dann: Sie können Schritte wie die folgenden ausführen, um nur bestimmte Verzeichnisse aus diesem größeren Repo abzurufen:

mkdir app1
cd app1
git init
git remote add origin git@github.com:some-user/full-repo.git
git config core.sparsecheckout true
echo "app1/" >> .git/info/sparse-checkout
git pull origin master

Ich habe fälschlicherweise gedacht, dass die Sparse-Checkout-Optionen im ursprünglichen Repository festgelegt werden müssen: Dies ist nicht der Fall. Sie definieren, welche Verzeichnisse Sie lokal möchten, bevor Sie von der Fernbedienung abrufen. Hoffe, diese Klarstellung hilft jemand anderem.


0

Während ich es hasse, svn tatsächlich verwenden zu müssen, wenn ich mit Git-Repos zu tun habe: / Ich benutze dies die ganze Zeit;

function git-scp() (
  URL="$1" && shift 1
  svn export ${URL/blob\/master/trunk}
)

Auf diese Weise können Sie ohne Änderungen aus der Github-URL kopieren. Verwendungszweck;

--- /tmp » git-scp https://github.com/dgraph-io/dgraph/blob/master/contrib/config/kubernetes/helm                                                                                                                  1 ↵
A    helm
A    helm/Chart.yaml
A    helm/README.md
A    helm/values.yaml
Exported revision 6367.

--- /tmp » ls | grep helm
Permissions Size User    Date Modified    Name
drwxr-xr-x     - anthony 2020-01-07 15:53 helm/

0

Wenn Sie nur an den neuesten Revisionsdateien eines Verzeichnisses interessiert sind, können Sie mit Github ein Repository als Zip-Datei herunterladen, die keinen Verlauf enthält. Das Herunterladen ist also sehr viel schneller.


0

Also habe ich alles in diesem Profil ausprobiert und nichts hat bei mir funktioniert ... Es stellt sich heraus, dass Sie dies in Version 2.24 von Git (der Version, die zum Zeitpunkt dieser Antwort mit cpanel geliefert wurde) nicht tun müssen

echo "wpm/*" >> .git/info/sparse-checkout

Sie benötigen lediglich den Ordnernamen

wpm/*

Kurz gesagt, du machst das

git config core.sparsecheckout true

Anschließend bearbeiten Sie die Datei .git / info / sparse-checkout und fügen die Ordnernamen (einen pro Zeile) mit / * am Ende hinzu, um Unterordner und Dateien abzurufen

wpm/*

Speichern Sie den Befehl checkout und führen Sie ihn aus

git checkout master

Das Ergebnis war der erwartete Ordner aus meinem Repo und nichts anderes Upvote, wenn dies für Sie funktioniert hat

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.