Jak sklonować podkatalog tylko repozytorium Git?

1409

Mam moje repozytorium Git, które w katalogu głównym ma dwa podkatalogi:

/finisht
/static

Gdy było to w SVN , /finishtzostało wyewidencjonowane w jednym miejscu, podczas gdy /staticzostało wyewidencjonowane w innym miejscu, tak:

svn co svn+ssh://[email protected]/home/admin/repos/finisht/static static

Czy jest na to sposób w Git?

Nick Sierżant
źródło
14
możliwy duplikat podkatalogów Checkout w Git?
Joachim Breitner
1
Dla użytkownika 2014, jakie git clonenajprostsze polecenie? Użyłem tej prostej odpowiedzi . Jeśli jest coś prostszego, prosimy o komentarz
Peter Krauss
Dla tych, którzy próbują sklonować zawartość repozytorium (nie tworząc folderu głównego), jest to bardzo łatwe rozwiązanie: stackoverflow.com/questions/6224626/...
Marc
@JachachBreitner: To pytanie dotyczy sprawdzania podkatalogów w Git (co jest łatwe), podczas gdy to pytanie dotyczy klonowania podkatalogów w Git (co jest niemożliwe).
Jörg W Mittag
@NickSergeant: Począwszy od Gita 2.19, wydanego 3 tygodnie temu, jest to w końcu możliwe, jak widać w tej odpowiedzi: stackoverflow.com/a/52269934/2988 Rozważ zaakceptowanie tego teraz. Uwaga: w Git 2.19 implementowana jest tylko obsługa po stronie klienta, nadal brakuje obsługi po stronie serwera, więc działa tylko podczas klonowania lokalnych repozytoriów. Zauważ również, że duże hosty Git, np. GitHub, tak naprawdę nie używają serwera Git, używają własnej implementacji, więc nawet jeśli wsparcie pojawia się na serwerze Git, nie oznacza to automatycznie, że działa na hostach Git. (OTOH, mogliby to szybciej wdrożyć.)
Jörg W Mittag

Odpowiedzi:

612

EDYCJA : Począwszy od Gita 2.19, jest to w końcu możliwe, jak widać w tej odpowiedzi .

Zastanów się nad poprawieniem tej odpowiedzi.

Uwaga: w Git 2.19 implementowana jest tylko obsługa po stronie klienta, nadal brakuje obsługi po stronie serwera, więc działa tylko podczas klonowania lokalnych repozytoriów. Zauważ również, że duże hosty Git, np. GitHub, tak naprawdę nie używają serwera Git, używają własnej implementacji, więc nawet jeśli wsparcie pojawia się na serwerze Git, nie oznacza to automatycznie, że działa na hostach Git. (OTOH, ponieważ nie używają serwera Git, mogą go zaimplementować szybciej we własnych implementacjach, zanim pojawi się na serwerze Git).


Nie, to nie jest możliwe w Git.

Wdrożenie czegoś takiego w Git byłoby dużym wysiłkiem i oznaczałoby, że nie można już zagwarantować integralności repozytorium po stronie klienta. Jeśli jesteś zainteresowany, poszukaj dyskusji na temat „sparse clone” i „sparse fetch” na liście mailowej git.

Ogólnie rzecz biorąc, konsensus w społeczności Git jest taki, że jeśli masz kilka katalogów, które są zawsze sprawdzane niezależnie, to tak naprawdę są to dwa różne projekty i powinny żyć w dwóch różnych repozytoriach. Możesz skleić je z powrotem za pomocą Git Submodules .

Jörg W Mittag
źródło
6
W zależności od scenariusza możesz użyć poddrzewa git zamiast submodułu git. Zobacz alumnit.ca/~apenwarr/log/?m=200904#30
C Pirate
9
@StijndeWitt: Rzadkie kasy zdarzają się w trakcie git-read-tree, który jest długo po get-fetch. Pytanie nie dotyczyło wyewidencjonowania tylko podkatalogu, ale dotyczyło klonowania tylko podkatalogu. Nie widzę, jak mogłyby to zrobić rzadkie kasy, ponieważ git-read-treedziała po zakończeniu klonowania.
Jörg W Mittag
9
Czy zamiast tego „odcinka” chciałbym, żebym usunął tę odpowiedź, aby Chronial mógł przejść na samą górę? Nie możesz go usunąć sam, ponieważ jest akceptowany, ale moderator może. Zachowałbyś reputację, którą sobie zasłużyłeś, ponieważ jest tak stary. (Natknąłem się na to, ponieważ ktoś oznaczył to jako „tylko link”. :-)
Cody Gray
1
@CodyGray: Chroniczna odpowiedź nadal klonuje całe repozytorium, a nie tylko podkatalog. (Ostatni akapit nawet wyraźnie tak mówi.) Klonowanie tylko podkatalogu nie jest możliwe w Git. Protokół sieciowy go nie obsługuje, format pamięci go nie obsługuje. Każda odpowiedź na to pytanie zawsze klonuje całe repozytorium. Pytanie jest proste pytanie Tak / Nie, a odpowiedź składa się z dwóch znaków: Nie. Jeśli w ogóle moja odpowiedź jest niepotrzebnie długa , nie krótka.
Jörg W Mittag
1
@ JörgWMittag: Odpowiedź Ciro Santili wydaje się zaprzeczać.
Dan Dascalescu,
1524

To, co próbujesz zrobić, nazywa się rzadką realizacją transakcji , a ta funkcja została dodana w git 1.7.0 (luty 2012 r.). Kroki, aby wykonać rzadki klon są następujące:

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

Tworzy to puste repozytorium za pomocą pilota i pobiera wszystkie obiekty, ale ich nie sprawdza. Następnie wykonaj:

git config core.sparseCheckout true

Teraz musisz określić, które pliki / foldery chcesz faktycznie sprawdzić. Odbywa się to poprzez umieszczenie ich na liście .git/info/sparse-checkout, np .:

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

Na koniec zaktualizuj swoje puste repozytorium o stan ze zdalnego:

git pull origin master

Będziesz teraz mieć pliki „wyrejestrowany” do some/diri another/sub/treeod systemu plików (z tych ścieżek wciąż), a nie inne ścieżki teraźniejszości.

Możesz zajrzeć do rozszerzonego samouczka i prawdopodobnie powinieneś przeczytać oficjalną dokumentację dotyczącą rzadkich transakcji .

Jako funkcja:

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
)

Stosowanie:

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

Zauważ, że nadal pobierze to całe repozytorium z serwera - tylko rozmiar kasy zostanie zmniejszony. W tej chwili nie można klonować tylko jednego katalogu. Ale jeśli nie potrzebujesz historii repozytorium, możesz przynajmniej zaoszczędzić na przepustowości, tworząc płytki klon. Zobacz odpowiedź udondan poniżej, aby dowiedzieć się, jak połączyć płytki klon i rzadkie kasy.


Od wersji git 2.25.0 (styczeń 2020) w git dodano eksperymentalną komendę rzadkiego sprawdzania :

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
Chronial
źródło
14
w Apple obwód „-f” nie działa. po prostu zrób zdalnie dodaj pochodzenie <url> bez -f
Anno2001
135
Jest to ulepszenie, ale nadal wymaga pobrania i przechowywania pełnej kopii zdalnego repozytorium w miejscu pochodzenia, którego można by w ogóle uniknąć, jeśli jest zainteresowany tylko częściami bazy kodu (lub jeśli istnieją podfoldery dokumentacji, jak w moim przypadku )
a1an
56
Czy istnieje sposób na sklonowanie pożądanej zawartości katalogu (nie samego katalogu) bezpośrednio w moim repozytorium? Na przykład chcę sklonować zawartość https://github.com/Umkus/nginx-boilerplate/tree/master/srcbezpośrednio do/etc/nginx
Mac
25
@Chronial, @ErikE: oboje macie rację / zło: P git remote addPolecenie to nie oznacza pobrania, ale git remote add -fużyte tutaj! To właśnie -foznacza.
ntc2
21
Korzystając z tego --depth=1, sklonowałem Chromium Devtools w 338 MB zamiast 4,9 GB pełnego źródła Blink + historii. Świetny.
Rudie
442

git clone --filter z Git 2.19

Ta opcja faktycznie pomija pobieranie niepotrzebnych obiektów z serwera. Również --filter=tree:0z Git 2.20 i --filter=combinefiltra kompozytowego dodanego w Git 2.24, otrzymujemy:

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/

Serwer powinien być skonfigurowany z:

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

Rozszerzono zdalny protokół Git, aby obsługiwać tę funkcję v2.19.0i faktycznie pomijać pobieranie niepotrzebnych obiektów, ale w tym czasie nie ma obsługi serwera. Ale można go już przetestować lokalnie.

Podział poleceń:

Format --filterjest udokumentowany na man git-rev-list.

Dokumenty na drzewie Git:

Przetestuj to

#!/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 w górę .

Dane wyjściowe w 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

Wnioski: d1/brakuje wszystkich obiektów blob spoza . Np. 0975df9b39e23c15f63db194df7f45c76528bccb, Którego d2/bnie ma po sprawdzeniu d1/a.

Zauważ, że root/rooti mybranch/mybranchrównież ich brakuje, ale --depth 1ukrywa to na liście brakujących plików. Jeśli usuniesz --depth 1, zostaną one wyświetlone na liście brakujących plików.

Mam Marzenie

Ta funkcja może zrewolucjonizować Git.

Wyobraź sobie, że cała baza kodu Twojego przedsiębiorstwa znajduje się w jednym repozytorium bez brzydkich narzędzi innych firm, takich jakrepo .

Wyobraź sobie, że przechowujesz ogromne obiekty BLOB bezpośrednio w repozytorium bez żadnych brzydkich rozszerzeń stron trzecich .

Wyobraź sobie, że GitHub zezwala na metadane dla plików / katalogów, takie jak gwiazdki i uprawnienia, abyś mógł przechowywać wszystkie swoje rzeczy osobiste w jednym repozytorium.

Wyobraź sobie, że podmoduły były traktowane dokładnie tak, jak zwykłe katalogi : po prostu poproś o SHA drzewa, a mechanizm podobny do DNS rozwiąże twoje żądanie , najpierw patrząc na lokalne~/.git , a następnie bliżej serwerów (dublowanie / pamięć podręczna przedsiębiorstwa) i kończąc na GitHub.

Ciro Santilli
źródło
Co dziwne, na macOS z gitem w wersji 2.20.1 (Apple Git-117) narzeka, że ​​„nie można łączyć wielu specyfikacji filtrów”
muru
1
Niestety, nie ma szczęścia z wersją git macOS. fatal: invalid filter-spec 'combine:blob:none+tree:0'W każdym razie dzięki! Może będzie działać z nowszymi wersjami.
muru
1
Nie udaje się to podczas wypróbowania go w systemie Windows 10 przy użyciu GIT 2.24.1 (wyrzuca mnóstwo „niemożności odczytania pliku sha1 z…” + „Nie można odłączyć pliku xxx”. Działa jako urok w tej samej wersji w systemie Linux.
Oyvind
1
@Ciro Santilli W dalszym ciągu kończy się to niepowodzeniem z powodu „niemożności odczytu pliku SHA1 z ...” w wersji git 2.26.1.windows.1. Otworzyłem raport o błędzie: github.com/git-for-windows/git/issues/2590
nharrer
1
@nharrer dzięki za informacje!
Ciro Santilli 18 病毒 审查 六四 事件 法轮功
405

Możesz połączyć rzadką kasę i płytkie funkcje klonowania . Te płytkie klonów odcina historii i rozrzedzony kasie ciągnie tylko pliki dopasowania wzorców.

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

Aby to zadziałało, potrzebujesz minimum git 1.9. Testowałem to sam tylko w wersji 2.2.0 i 2.2.2.

W ten sposób będziesz w stanie naciskać , co nie jest możliwe git archive.

udondan
źródło
21
Jest to przydatne i może być najlepszą dostępną odpowiedzią, ale nadal klonuje treść, na której ci nie zależy (jeśli znajduje się w wyciągniętej gałęzi), nawet jeśli nie pojawia się w kasie.
nobar
1
Jaka jest twoja wersja git? Czy według pomocy git dostępna jest opcja głębokości?
udondan
2
nie działa dla mnie, gdy ostatnim poleceniem jest nie, git pull --depth=1 origin masterale git pull --depth=1 origin <any-other-branch>. to takie dziwne, patrz moje pytanie tutaj :stackoverflow.com/questions/35820630/...
Shuman
5
W systemie Windows wiersz od ostatniego do ostatniego musi pomijać cudzysłowy, w przeciwnym razie pobieranie nie powiedzie się.
nateirvin
4
To nadal pobiera wszystkie dane! Znaleziono to rozwiązanie, używając svn: stackoverflow.com/a/18324458/2302437
electronix384128
157

W przypadku innych użytkowników, którzy chcą tylko pobrać plik / folder z github, po prostu użyj:

svn export <repo>/trunk/<folder>

na przykład

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

(tak, to jest svn tutaj. najwyraźniej w 2016 roku nadal potrzebujesz svn, aby po prostu pobrać niektóre pliki github)

Dzięki uprzejmości: Pobierz pojedynczy folder lub katalog z repozytorium GitHub

Ważne - upewnij się, że zaktualizowałeś adres URL github i zastąpiłeś /tree/master/go „/ trunk /”.

Jako skrypt bash:

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

Uwaga Ta metoda pobiera folder, nie klonuje go / nie pobiera. Nie możesz wypchnąć zmian z powrotem do repozytorium. Z drugiej strony - powoduje to mniejsze pobieranie w porównaniu do rzadkiego pobierania lub płytkiego pobierania.

Anona112
źródło
9
jedyna wersja, która działała dla mnie z github. Polecenia git pobrały pliki> 10k, svn wyeksportował tylko 700, które chciałem. Dzięki!
Christopher Lörken
4
Próbowałem to zrobić, https://github.com/tensorflow/tensorflow/tree/master/tensorflow/examples/trunk/udacityale dostałem svn: E170000: URL 'https://github.com/tensorflow/tensorflow/tree/master/tensorflow/examples/trunk/udacity' doesn't existbłąd :(
zthomas.nc
9
@ zthomas.nc Musisz usunąć „trunk” poprzedzający udacity i zastąpić / tree / master / na / trunk /.
Speedy
2
To polecenie działało dla mnie! Chciałem tylko pobrać kopię pliku z repozytorium, aby móc go zmodyfikować lokalnie. Dobry stary SVN na ratunek!
Michael J
3
to działa, ale wydaje się powolne. zaczyna się trochę, a potem pliki przesuwają się stosunkowo wolno
Aryeh Beitz
73

Jeśli nigdy nie planujesz wchodzić w interakcje z repozytorium, z którego sklonowałeś, możesz wykonać pełny klon git i przepisać swoje repozytorium za pomocą git filter-branch --subdirectory-filter . W ten sposób przynajmniej historia zostanie zachowana.

Hillu
źródło
11
Dla ludzi, którzy nie znają polecenia, jest togit filter-branch --subdirectory-filter <subdirectory>
Jaime Hablutzel
9
Zaletą tej metody jest to, że wybrany przez ciebie podkatalog staje się katalogiem głównym nowego repozytorium, co jest dokładnie tym, czego chcę.
Andrew Schulman,
To zdecydowanie najlepsze i najprostsze podejście do użycia. Oto jednoetapowe polecenie z użyciem filtru podkatalogówgit clone https://github.com/your/repo_xx.git && cd repo_xx && git filter-branch --subdirectory-filter repo_xx_subdir
Alex
66

To wygląda na znacznie prostsze:

git archive --remote=<repo_url> <branch> <path> | tar xvf -
ErichBSchulz
źródło
17
Gdy robię to na githubie, mam fatalne skutki: Operacja nie jest obsługiwana przez protokół. Nieoczekiwany koniec strumienia poleceń
Michael Fox,
1
Błąd protokołu może wynikać z HTTPS lub: w adresie URL repo. Może to być również spowodowane brakującym kluczem ssh.
Umair A.
2
Jeśli używasz github, możesz użyć svn exportzamiast tego
Milo Wielondek,
2
Nie będzie działać z Github -> Niepoprawne polecenie: 'git-upload-archive' xxx / yyy.git '' Wygląda na to, że używasz ssh do sklonowania adresu URL git: //. Upewnij się, że opcja konfiguracji core.gitProxy i zmienna środowiskowa GIT_PROXY_COMMAND NIE są ustawione. fatal:
Odległy
3
Powód, dla którego nie działa z GitHub: „Nie obsługujemy używania git-archive do pobierania archiwum bezpośrednio z GitHub. Możesz sklonować repo lokalnie i uruchomić git-archive, lub kliknąć przycisk Pobierz ZIP na strona repo. ” github.com/xuwupeng2000/capistrano-scm-gitcopy/issues/16
Donn Lee
63

Git 1.7.0 ma „rzadkie kasy”. Patrz „core.sparseCheckout” w git config podręcznika systemowego „Sparse kasie” w git odczytu drzewo manpage i „bit Skip-worktree” w git update-index podręcznika .

Interfejs nie jest tak wygodny jak SVN (np. Nie ma sposobu na rzadkie pobranie w momencie początkowego klonowania), ale dostępna jest teraz podstawowa funkcjonalność, na której można zbudować prostsze interfejsy.

Chris Johnsen
źródło
37

Nie można klonować podkatalogu tylko za pomocą Git, ale poniżej jest kilka obejść.

Filtruj gałąź

Możesz przepisać repozytorium, aby wyglądało, jakby trunk/public_html/było jego katalogiem głównym projektu, i odrzucić całą pozostałą historię (używając filter-branch), spróbuj na gałęzi już kasy:

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

Uwagi: To, --które oddziela opcje gałęzi filtru od opcji rewizji oraz --allprzepisuje wszystkie gałęzie i znaczniki. Wszystkie informacje, w tym oryginalne czasy zatwierdzenia lub informacje o scaleniu, zostaną zachowane . To polecenie honoruje .git/info/graftsplik i odwołuje się do refs/replace/przestrzeni nazw, więc jeśli masz refszdefiniowane przeszczepy lub zamienniki , uruchomienie tego polecenia spowoduje, że będą trwałe.

Ostrzeżenie! Przepisana historia będzie mieć różne nazwy obiektów dla wszystkich obiektów i nie będzie zbieżna z oryginalną gałęzią. Nie będzie można łatwo przesuwać i rozpowszechniać przepisanej gałęzi nad oryginalną gałęzią. Nie używaj tego polecenia, jeśli nie znasz pełnych implikacji, i unikaj go mimo to, jeśli wystarczy jedno zatwierdzenie, aby rozwiązać problem.


Rzadka kasa

Oto proste kroki z rzadkim podejściem do pobierania, które rzadko wypełnia katalog roboczy, dzięki czemu możesz powiedzieć Gitowi, które foldery lub pliki w katalogu roboczym warto sprawdzić.

  1. Klonuj repozytorium jak zwykle ( --no-checkoutjest opcjonalne):

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

    Możesz pominąć ten krok, jeśli repozytorium zostało już sklonowane.

    Wskazówka: w przypadku dużych repozytoriów rozważ płytkie klonowanie ( --depth 1), aby pobrać tylko najnowszą wersję i / lub --single-branchtylko.

  2. Włącz sparseCheckoutopcję:

    git config core.sparseCheckout true
    
  3. Określ foldery dla rzadkich transakcji ( bez spacji na końcu):

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

    lub edytuj .git/info/sparse-checkout.

  4. Kasa oddziału (np. master):

    git checkout master
    

Teraz powinieneś wybrać foldery w bieżącym katalogu.

Możesz rozważyć użycie dowiązań symbolicznych, jeśli masz zbyt wiele poziomów katalogów lub gałęzi filtrujących.


kenorb
źródło
Czy gałąź filtrów nadal na to pozwala pull?
sam
2
@sam: no. filter-branchprzepisałby zatwierdzenia nadrzędne, aby miały różne identyfikatory SHA1, a zatem twoje filtrowane drzewo nie miałoby żadnych wspólnych zatwierdzeń z drzewem zdalnym. git pullnie wiedziałbym, skąd próbować się połączyć.
Peter Cordes,
Takie podejście jest w większości satysfakcjonujące w mojej sprawie.
Abbas
10

Właśnie napisałem skrypt dla GitHub .

Stosowanie:

python get_git_sub_dir.py path/to/sub/dir <RECURSIVE>
david_adler
źródło
11
Do Twojej wiadomości, to tylko dla GitHub .
Sz.
9
I najwyraźniej służy to pobraniu katalogu, a nie klonowaniu fragmentu repozytorium ze wszystkimi jego metadanymi ... prawda?
LarsH
5
Powinieneś dołączyć swój kod tutaj, a nie gdzie indziej.
jww
urllib2.HTTPError: Błąd HTTP 403: przekroczony limit prędkości
majizm
9

Spowoduje to sklonowanie określonego folderu i usunięcie całej niezwiązanej z nim historii.

git clone --single-branch -b {branch} [email protected]:{user}/{repo}.git
git filter-branch --subdirectory-filter {path/to/folder} HEAD
git remote remove origin
git remote add origin [email protected]:{user}/{new-repo}.git
git push -u origin master
BARJ
źródło
Oto smoki. Zostajesz przywitany przez OSTRZEŻENIE: git-filter-branch ma nadmiar gotchas generujących zniekształcone zapisy historii . Następnie dokumentacja git-filter-branch ma dość długą listę ostrzeżeń.
Oyvind,
6

Oto skrypt powłoki, który napisałem dla przypadku użycia pojedynczego rzadkiego pobrania z podkatalogu

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
jxramos
źródło
2
Fajny skrypt, tylko coś, co powinno zostać naprawione, to dowiązanie symboliczne, powinno być ln -s ./.$localRepo/$subDir $localRepozamiastln -s ./.$localRepo$subDir $localRepo
valentin_nasta
2

Napisałem a .gitconfig [alias]za wykonanie „rzadkiej kasy”. Sprawdź to (bez zamierzonej gry słów):

W systemie Windows uruchom 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"

Inaczej:

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'

Zastosowanie :

# 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

Te git configpolecenia są „minified” dla wygody i przechowywania, ale tutaj jest alias rozszerzony:

# 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
YenForYang
źródło
Dlaczego to działa L=${1##*/} L=${L%.git}:? Czy kosmos jest operatorem?
Gulzt,
2

Używasz Linuksa? I chcesz tylko mieć łatwy dostęp i czyste drzewo robocze? bez kłopotania się resztą kodu na twoim komputerze. spróbuj dowiązań symbolicznych !

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

Test

cd ~/Desktop/my-subfolder
git status
Nasir Iqbal
źródło
1

Aby wyjaśnić niektóre świetne odpowiedzi tutaj, kroki przedstawione w wielu odpowiedziach zakładają, że masz już gdzieś zdalne repozytorium.

Biorąc pod uwagę: istniejące repozytorium git, np. [email protected]:some-user/full-repo.gitZ jednym lub większą liczbą katalogów, które chcesz pobrać niezależnie od reszty repozytorium, np. Katalogi o nazwach app1iapp2

Zakładając, że masz repozytorium git jak wyżej ...

Następnie: możesz uruchomić następujące kroki, aby pobrać tylko określone katalogi z tego większego repozytorium:

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

Myślałem błędnie, że opcje rzadkich transakcji musiały być ustawione w oryginalnym repozytorium: tak nie jest. Definiujesz katalogi, które chcesz lokalnie, przed pobraniem ze zdalnego. Mam nadzieję, że to wyjaśnienie pomoże komuś innemu.

Everett
źródło
0

Chociaż nienawidzę faktycznego korzystania z svn podczas obsługi repozytoriów git: / Używam tego cały czas;

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

Umożliwia to skopiowanie z adresu github bez modyfikacji. Stosowanie;

--- /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/
wydalony
źródło
0

Jeśli jesteś naprawdę zainteresowany najnowszymi plikami wersji katalogu, Github umożliwia pobranie repozytorium jako pliku Zip, który nie zawiera historii. Pobieranie jest więc znacznie szybsze.

weberjn
źródło
0

Więc próbowałem wszystkiego w tym bieżniku i nic nie działało dla mnie ... Okazuje się, że w wersji 2.24 Git (tej, która jest dostarczana z panelem w momencie tej odpowiedzi), nie musisz tego robić

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

wszystko czego potrzebujesz to nazwa folderu

wpm/*

Krótko mówiąc, robicie to

git config core.sparsecheckout true

następnie edytujesz .git / info / sparse-checkout i dodajesz nazwy folderów (jeden w linii) za pomocą / * na końcu, aby uzyskać podfoldery i pliki

wpm/*

Zapisz i uruchom polecenie kasy

git checkout master

Rezultatem był oczekiwany folder z mojego repozytorium i nic więcej Upvote, jeśli to zadziałało dla Ciebie

Patrick Simard
źródło