git clone --filter
von git 2.19 funktioniert jetzt auf GitHub (getestet 2021-01-14, git 2.30.0)
Diese Option wurde zusammen mit einer Aktualisierung des Remote-Protokolls hinzugefügt und verhindert tatsächlich, dass Objekte vom Server heruntergeladen werden.
Zum Beispiel, um nur Objekte zu klonen, die für d1
dieses minimalen Test-Repositorys: https://github.com/cirosantilli/test-git-partial-clone Ich kann das:
git clone \
--depth 1 \
--filter=blob:none \
--sparse \
https://github.com/cirosantilli/test-git-partial-clone \
;
cd test-git-partial-clone
git sparse-checkout set d1
Hier ist eine weniger minimalistische und realistischere Version unter https://github.com/cirosantilli/test-git-partial-clone-big-small
git clone \
--depth 1 \
--filter=blob:none \
--sparse \
https://github.com/cirosantilli/test-git-partial-clone-big-small \
;
cd test-git-partial-clone-big-small
git sparse-checkout set small
Dieses Repository enthält:
- ein großes Verzeichnis mit 10 10MB-Dateien
- ein kleines Verzeichnis mit 1000 Dateien von einem Byte Größe
Alle Inhalte sind pseudo-zufällig und daher nicht komprimierbar.
Klonzeiten auf meinem 36,4 Mbps Internet:
- voll: 24s
- teilweise: "sofort"
El sparse-checkout
Teil wird leider auch benötigt. Sie können auch nur bestimmte Dateien mit dem viel verständlicher herunterladen:
git clone \
--depth 1 \
--filter=blob:none \
--no-checkout \
https://github.com/cirosantilli/test-git-partial-clone \
;
cd test-git-partial-clone
git checkout master -- d1
aber diese Methode ist aus irgendeinem Grund lädt Dateien sehr langsam nacheinander herunter Dadurch wird es unbrauchbar, es sei denn, Sie haben nur sehr wenige Dateien in diesem Verzeichnis.
Analyse der Objekte im minimalen Repository
Der Befehl clone erhält nur:
- eine einzige Objekt übergeben mit der Spitze des
master
Zweigstelle
- alle 4 Baumobjekte des Repositorys:
- Toplevel-Verzeichnis von commit
- die drei Verzeichnisse
d1
, d2
, master
Dann wird die git sparse-checkout set
holt nur die fehlenden Blobs (Dateien) vom Server ab:
Noch besser: Später wird GitHub wahrscheinlich damit beginnen, diese zu unterstützen:
--filter=blob:none \
--filter=tree:0 \
wobei --filter=tree:0
ab Git 2.20 wird die unnötige clone
Holen aller Baumobjekte und Aufschieben des Holens auf checkout
. Aber auf meinem Test 2020-09-18 schlägt das mit fehl:
fatal: invalid filter-spec 'combine:blob:none+tree:0'
Vermutlich weil die --filter=combine:
zusammengesetzter Filter (hinzugefügt in Git 2.24, impliziert durch mehrere --filter
) ist noch nicht implementiert.
Ich habe beobachtet, mit welchen Gegenständen geholt wurde:
git verify-pack -v .git/objects/pack/*.pack
wie erwähnt bei: Wie kann man ALLE Git-Objekte in der Datenbank auflisten? Es gibt mir keinen super klaren Hinweis darauf, was jedes Objekt genau ist, aber es gibt den Typ jedes Objekts an ( commit
, tree
, blob
), und da es so wenige Objekte in diesem minimalen Repo gibt, kann ich eindeutig ableiten, was jedes Objekt ist.
git rev-list --objects --all
hat eine klarere Ausgabe mit Pfaden für Baum/Blobs erzeugt, aber leider holt es einige Objekte, wenn ich es ausführe, was es schwer macht, festzustellen, was wann geholt wurde. Lassen Sie mich wissen, wenn jemand einen besseren Befehl hat.
TODO finden GitHub Ankündigung, die sagt, wann sie begonnen haben, es zu unterstützen. https://github.blog/2020-01-17-bring-your-monorepo-down-to-size-with-sparse-checkout/ vom 2020-01-17 bereits erwähnt --filter blob:none
.
git sparse-checkout
Ich denke, dass dieser Befehl dazu gedacht ist, eine Einstellungsdatei zu verwalten, die besagt, dass "ich mich nur um diese Teilbäume kümmere", so dass zukünftige Befehle nur diese Teilbäume betreffen werden. Aber es ist ein bisschen schwer, sicher zu sein, weil die aktuelle Dokumentation ein bisschen... spärlich ist ;-)
Sie verhindert nicht von sich aus das Abrufen von Blobs.
Wenn dieses Verständnis richtig ist, dann wäre dies eine gute Ergänzung zu git clone --filter
wie oben beschrieben, da es das unbeabsichtigte Holen weiterer Objekte verhindern würde, wenn Sie beabsichtigen, Git-Operationen in dem teilweise geklonten Projektarchiv durchzuführen.
Als ich es mit Git 2.25.1:
git clone \
--depth 1 \
--filter=blob:none \
--no-checkout \
https://github.com/cirosantilli/test-git-partial-clone \
;
cd test-git-partial-clone
git sparse-checkout init
Es hat nicht funktioniert, weil die init
tatsächlich alle Objekte abgerufen hat.
In Git 2.28 wurden die Objekte jedoch nicht wie gewünscht geholt. Aber dann, wenn ich tun:
git sparse-checkout set d1
d1
nicht abgerufen und ausgecheckt wird, obwohl dies ausdrücklich vorgesehen ist: https://github.blog/2020-01-17-bring-your-monorepo-down-to-size-with-sparse-checkout/#sparse-checkout-and-partial-clones Mit Haftungsausschluss:
Achten Sie darauf, dass die Funktion des teilweisen Klonens allgemein verfügbar wird[1].
[1]: GitHub evaluiert diese Funktion noch intern, während sie in einigen wenigen Repositories aktiviert ist (einschließlich des in diesem Beitrag verwendeten Beispiels). Wenn sich die Funktion stabilisiert und ausgereift ist, werden wir Sie über die Fortschritte auf dem Laufenden halten.
Also ja, es ist einfach zu schwer, im Moment sicher zu sein, auch dank der Freuden, dass GitHub ein geschlossener Quellcode ist. Aber wir sollten es im Auge behalten.
Aufschlüsselung der Befehle
Der Server sollte mit konfiguriert werden:
git config --local uploadpack.allowfilter 1
git config --local uploadpack.allowanysha1inwant 1
Aufschlüsselung der Befehle:
-
--filter=blob:none
überspringt alle Blobs, holt aber trotzdem alle Baumobjekte
-
--filter=tree:0
überspringt die nicht benötigten Bäume: https://www.spinics.net/lists/git/msg342006.html
-
--depth 1
impliziert bereits --single-branch
, siehe auch: Wie klone ich einen einzelnen Zweig in Git?
-
file://$(path)
ist erforderlich zur Überwindung git clone
Protokollaffären: Wie kann man ein lokales Git-Repository mit einem relativen Pfad klonen?
-
--filter=combine:FILTER1+FILTER2
ist die Syntax zur gleichzeitigen Verwendung mehrerer Filter, die versuchen, die --filter
schlägt aus irgendeinem Grund fehl mit: "Mehrere Filter-Spezifikationen können nicht kombiniert werden". Dies wurde in Git 2.24 unter e987df5fe62b8b29be4cdcdeb3704681ada2b29e "list-objects-filter: implementiere zusammengesetzte Filter" hinzugefügt.
Bearbeiten: auf Git 2.28, sehe ich experimentell, dass --filter=FILTER1 --filter FILTER2
hat ebenfalls den gleichen Effekt, da GitHub keine combine:
noch ab 2020-09-18 und beschwert sich fatal: invalid filter-spec 'combine:blob:none+tree:0'
. TODO in welcher Version eingeführt?
Das Format der --filter
ist dokumentiert auf man git-rev-list
.
Docs auf Git-Baum:
Testen Sie es vor Ort
Das folgende Skript erzeugt reproduzierbar die https://github.com/cirosantilli/test-git-partial-clone Repository lokal, führt einen lokalen Klon durch und beobachtet, was geklont wurde:
#!/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 vorgelagert .
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 von d1/
fehlen. z.B. 0975df9b39e23c15f63db194df7f45c76528bccb
que es d2/b
nach dem Auschecken nicht vorhanden ist d1/a
.
Beachten Sie, dass root/root
y mybranch/mybranch
fehlen ebenfalls, aber --depth 1
blendet diese aus der Liste der fehlenden Dateien aus. Wenn Sie entfernen --depth 1
dann werden sie in der Liste der fehlenden Dateien angezeigt.
Ich habe einen Traum
Diese Funktion könnte Git revolutionieren.
Stellen Sie sich vor, Sie hätten die gesamte Codebasis Ihres Unternehmens in einem einzigen Repo ohne hässliche Tools von Drittanbietern wie repo
.
Stellen Sie sich vor: Speicherung großer Blobs direkt im Repo ohne hässliche Erweiterungen von Drittanbietern .
Stellen Sie sich vor, GitHub würde erlauben Metadaten pro Datei/Verzeichnis wie z.B. Sterne und Berechtigungen, so dass Sie alle Ihre persönlichen Daten in einem einzigen Repository speichern können.
Stellen Sie sich vor, wenn Untermodule wurden genau wie normale Verzeichnisse behandelt : fordern Sie einfach einen Baum SHA an, und einen DNS-ähnlicher Mechanismus löst Ihre Anfrage auf , zuerst auf Ihr . ~/.git
, dann zunächst zu näheren Servern (dem Mirror/Cache Ihres Unternehmens) und schließlich auf GitHub.
18 Stimmen
Mögliche Duplikate von Unterverzeichnisse in Git auschecken?
2 Stimmen
Für einen Nutzer des Jahres 2014, was die
git clone
einfachsten Befehl? Ich habe este einfache Antwort . Wenn es etwas mehr einfach, bitte kommentieren1 Stimmen
Für diejenigen, die versuchen, den Inhalt des Repositorys zu klonen (und nicht den Root-Ordner zu erstellen), ist dies eine sehr einfache Lösung: stackoverflow.com/questions/6224626/
1 Stimmen
@JoachimBreitner: Diese Frage bezieht sich auf ausprobierend Unterverzeichnisse in Git (was einfach ist), während es bei dieser Frage um Klonen Unterverzeichnisse in Git (was unmöglich ist).
2 Stimmen
@NickSergeant: Seit Git 2.19, das vor 3 Wochen veröffentlicht wurde, ist dies endlich möglich, wie in dieser Antwort zu sehen ist: stackoverflow.com/a/52269934/2988 Überlegen Sie, ob Sie das jetzt akzeptieren. Hinweis: In Git 2.19 ist nur clientseitige Unterstützung implementiert, serverseitige Unterstützung fehlt noch, daher funktioniert es nur beim Klonen von lokalen Repositories. Beachten Sie auch, dass große Git-Hoster, wie z.B. GitHub, nicht den Git-Server verwenden, sondern ihre eigene Implementierung, so dass selbst wenn die Unterstützung im Git-Server auftaucht, dies nicht automatisch bedeutet, dass sie auf Git-Hostern funktioniert. (Außerdem könnten sie es schneller implementieren.)
1 Stimmen
Siehe auch: stackoverflow.com/questions/466303/
1 Stimmen
Ich habe eine
bash
Funktion, die das Herunterladen der Historie vermeidet, die einen einzelnen Zweig abruft und die eine Liste von Dateien oder Verzeichnissen abruft, die Sie benötigen. Sehen Sie es hier: stackoverflow.com/questions/60190759/5 Stimmen
Wenn Sie einen Ordner aus einem GitHub Repo herunterladen möchten, download-directory.github.io könnte genau das Richtige sein
1 Stimmen
@jemand771 Das war ein ausgezeichneter Kommentar. Genau das, was ich brauchte. Danke!
0 Stimmen
Svn rockt. Ich verwende diese Funktion für untergeordnete und verschachtelte Repos. git kann das nicht.