Bagaimana cara mengkloning subdirektori hanya dari repositori Git?


1410

Saya memiliki repositori Git saya yang, pada dasarnya, memiliki dua sub direktori:

/finisht
/static

Ketika ini di SVN , /finishtdiperiksa di satu tempat, sementara /staticdiperiksa di tempat lain, seperti:

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

Apakah ada cara untuk melakukan ini dengan Git?



1
Untuk pengguna tahun 2014, git cloneperintah apa yang paling sederhana ?? Saya menggunakan jawaban sederhana ini . Jika ada sesuatu yang lebih sederhana, silakan komentar
Peter Krauss

Bagi mereka yang mencoba mengkloning isi repositori (tidak membuat folder root), ini adalah solusi yang sangat mudah: stackoverflow.com/questions/6224626/…
Marc

@ JoachimBreitner: Pertanyaan itu adalah tentang memeriksa subdirektori di Git (yang mudah), sedangkan pertanyaan ini tentang kloning subdirektori di Git (yang tidak mungkin).
Jörg W Mittag

@NickSergeant: Pada Git 2.19, dirilis 3 minggu yang lalu, ini akhirnya mungkin, seperti yang dapat dilihat dalam jawaban ini: stackoverflow.com/a/52269934/2988 Pertimbangkan untuk menerimanya sekarang. Catatan: di Git 2.19, hanya dukungan sisi-klien yang diimplementasikan, dukungan sisi-server masih hilang, sehingga hanya berfungsi saat kloning repositori lokal. Perhatikan juga bahwa host Git besar, misalnya GitHub tidak benar-benar menggunakan server Git, mereka menggunakan implementasinya sendiri, jadi walaupun dukungan muncul di server Git, itu tidak secara otomatis berarti bahwa ia bekerja pada host Git. (OTOH, mereka bisa menerapkannya lebih cepat.)
Jörg W Mittag

Jawaban:


612

EDIT : Pada Git 2.19, ini akhirnya mungkin, seperti yang dapat dilihat dalam jawaban ini .

Pertimbangkan untuk membatalkan jawaban itu.

Catatan: di Git 2.19, hanya dukungan sisi-klien yang diimplementasikan, dukungan sisi-server masih hilang, sehingga hanya berfungsi saat kloning repositori lokal. Perhatikan juga bahwa host Git yang besar, misalnya GitHub, tidak benar-benar menggunakan server Git, mereka menggunakan implementasinya sendiri, jadi walaupun dukungan muncul di server Git, itu tidak secara otomatis berarti bahwa ia bekerja pada host Git. (OTOH, karena mereka tidak menggunakan server Git, mereka dapat mengimplementasikannya lebih cepat dalam implementasi mereka sendiri sebelum muncul di server Git.)


Tidak, itu tidak mungkin di Git.

Menerapkan sesuatu seperti ini di Git akan menjadi upaya yang substansial dan itu berarti bahwa integritas repositori klien tidak dapat lagi dijamin. Jika Anda tertarik, cari diskusi tentang "sparse clone" dan "sparse fetch" di milis git.

Secara umum, konsensus dalam komunitas Git adalah bahwa jika Anda memiliki beberapa direktori yang selalu diperiksa secara independen, maka ini benar-benar dua proyek yang berbeda dan harus hidup dalam dua repositori yang berbeda. Anda dapat merekatkannya kembali menggunakan Git Submodules .


6
Bergantung pada skenario, Anda mungkin ingin menggunakan subtree git alih-alih submitule git. Lihat alumnit.ca/~apenwarr/log/?m=200904#30
C Pirate

9
@StijndeWitt: Checkout jarang terjadi selama git-read-tree, yang lama setelah itu get-fetch. Pertanyaannya bukan tentang memeriksa hanya sebuah subdirektori, tetapi tentang mengkloning hanya subdirektori. Saya tidak melihat bagaimana jarangnya checkout bisa melakukan itu, karena git-read-treeberjalan setelah klon telah selesai.
Jörg W Mittag

9
Daripada "rintisan" ini, apakah Anda ingin saya menghapus jawaban ini sehingga Chronial's dapat mengapung ke atas? Anda tidak dapat menghapusnya sendiri, karena diterima, tetapi seorang moderator bisa. Anda akan menjaga reputasi yang Anda peroleh darinya, karena sudah sangat tua. (Saya datang di ini karena seseorang ditandai sebagai "link-satunya" :-).
Cody Gray

1
@CodyGray: Jawaban kronial masih mengkloning seluruh repositori, dan bukan hanya subdirektori. (Paragraf terakhir bahkan secara eksplisit mengatakannya.) Mengkloning hanya subdirektori tidak dimungkinkan di Git. Protokol jaringan tidak mendukungnya, format penyimpanan tidak mendukungnya. Setiap jawaban tunggal untuk pertanyaan ini selalu mengkloning seluruh repositori. Pertanyaannya adalah pertanyaan Ya / Tidak yang sederhana, dan jawabannya adalah dua karakter: Tidak. Jika sama sekali, jawaban saya tidak terlalu panjang , tidak pendek.
Jörg W Mittag

1
@ JörgWMittag: Jawaban Ciro Santili sepertinya bertentangan dengan Anda.
Dan Dascalescu

1525

Apa yang Anda coba lakukan disebut sparse checkout , dan fitur itu ditambahkan di git 1.7.0 (Feb. 2012). Langkah-langkah untuk melakukan klon jarang adalah sebagai berikut:

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

Ini membuat repositori kosong dengan remote Anda, dan mengambil semua objek tetapi tidak memeriksanya. Lalu lakukan:

git config core.sparseCheckout true

Sekarang Anda perlu menentukan file / folder mana yang ingin Anda periksa. Ini dilakukan dengan mendaftarkan mereka .git/info/sparse-checkout, misalnya:

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

Last but not least, perbarui repo kosong Anda dengan status dari jarak jauh:

git pull origin master

Anda sekarang akan memiliki file "check out" untuk some/dirdan another/sub/treepada sistem file Anda (dengan jalur tersebut masih), dan tidak ada jalur lain yang ada.

Anda mungkin ingin melihat tutorial yang diperluas dan Anda mungkin harus membaca dokumentasi resmi untuk checkout jarang .

Sebagai fungsi:

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
)

Pemakaian:

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

Perhatikan bahwa ini masih akan mengunduh seluruh repositori dari server - hanya ukuran checkout yang dikurangi. Saat ini tidak mungkin untuk mengkloning hanya satu direktori. Tetapi jika Anda tidak memerlukan riwayat repositori, Anda setidaknya dapat menghemat bandwidth dengan membuat klon yang dangkal. Lihat jawaban udondan di bawah ini untuk informasi tentang cara menggabungkan clone dangkal dan checkout jarang.


Pada git 2.25.0 (Jan 2020) perintah sparse-checkout eksperimental ditambahkan di git:

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
di Apple perimeter '-f' tidak berfungsi. lakukan saja git remote add origin <url> tanpa -f
Anno2001

135
Ini merupakan peningkatan tetapi masih perlu mengunduh dan menyimpan salinan lengkap dari repositori jarak jauh asalnya, yang mungkin ingin dihindari sama sekali jika ia hanya tertarik pada bagian basis kode (atau jika ada subfolder dokumentasi seperti dalam kasus saya) )
a1an

56
Apakah ada cara untuk mengkloning isi direktori yang diinginkan (bukan direktori itu sendiri) langsung ke repositori saya? Misalnya saya ingin mengkloning konten https://github.com/Umkus/nginx-boilerplate/tree/master/srclangsung ke/etc/nginx
mac

25
@Chronial, @ErikE: Anda berdua benar / salah: P git remote addPerintah ini tidak menyiratkan pengambilan, tetapi git remote add -f, seperti yang digunakan di sini, tidak! Itulah -fartinya.
ntc2

21
Dengan menggunakan ini dan --depth=1saya mengkloning Chromium Devtools dalam 338 MB, bukannya 4,9 GB riwayat + sumber Blink penuh. Luar biasa.
Rudie

444

git clone --filter dari Git 2.19

Pilihan ini sebenarnya akan melewatkan mengambil objek yang tidak dibutuhkan dari server. Juga termasuk --filter=tree:0dari Git 2.20 dan --filter=combinefilter komposit yang ditambahkan di Git 2.24, kita berakhir dengan:

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/

Server harus dikonfigurasi dengan:

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

Ekstensi dibuat untuk protokol jarak jauh Git untuk mendukung fitur ini v2.19.0dan benar-benar melewatkan mengambil objek yang tidak dibutuhkan, tetapi tidak ada dukungan server pada saat itu. Tetapi sudah bisa diuji secara lokal.

Perintah rusak:

Format --filterdidokumentasikan pada man git-rev-list.

Documents on Git tree:

Uji itu

#!/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 hulu .

Output dalam 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

Kesimpulan: semua gumpalan dari luar d1/hilang. Misalnya 0975df9b39e23c15f63db194df7f45c76528bccb, yang d2/btidak ada di sana setelah check out d1/a.

Perhatikan itu root/rootdan mybranch/mybranchjuga hilang, tetapi --depth 1menyembunyikannya dari daftar file yang hilang. Jika Anda menghapus --depth 1, maka mereka muncul di daftar file yang hilang.

Aku mempunyai impian

Fitur ini dapat merevolusi Git.

Bayangkan memiliki semua basis kode perusahaan Anda dalam satu repo tanpa alat pihak ketiga yang jelekrepo .

Bayangkan menyimpan gumpalan besar langsung di repo tanpa ekstensi pihak ketiga yang jelek .

Bayangkan jika GitHub akan mengizinkan metadata file / direktori seperti bintang dan izin, sehingga Anda dapat menyimpan semua barang pribadi Anda dalam satu repo.

Bayangkan jika submodula diperlakukan persis seperti direktori biasa : cukup minta SHA pohon, dan mekanisme mirip DNS menyelesaikan permintaan Anda , pertama cari di lokal~/.git Anda , lalu pertama-tama ke server yang lebih dekat (mirror / cache perusahaan Anda) dan berakhir di GitHub.


Anehnya, pada macOS dengan git versi 2.20.1 (Apple Git-117), ia mengeluh bahwa "beberapa filter-spesifikasi tidak dapat digabungkan"
muru

1
Sayangnya, tidak beruntung dengan versi macOS git. fatal: invalid filter-spec 'combine:blob:none+tree:0'Bagaimanapun, terima kasih! Mungkin ini akan bekerja dengan versi yang lebih baru.
muru

1
Ini gagal ketika mencobanya di Windows 10 menggunakan GIT 2.24.1 (melempar ton "tidak dapat membaca file sha1 .." + "Membatalkan tautan file xxx gagal."). Bekerja sebagai pesona dengan versi yang sama di Linux.
Oyvind

1
@Ciro Santilli Ini masih gagal dengan "tidak dapat membaca file sha1 ..." di git versi 2.26.1.windows.1. Saya membuka laporan bug: github.com/git-for-windows/git/issues/2590
nharrer

1
@nharrer terima kasih atas informasinya!
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

405

Anda dapat menggabungkan checkout jarang dan fitur klon dangkal . The dangkal clone pemotongan off sejarah dan checkout jarang hanya menarik file yang cocok pola Anda.

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

Anda membutuhkan minimum git 1.9 agar ini berfungsi. Mengujinya sendiri hanya dengan 2.2.0 dan 2.2.2.

Dengan cara ini Anda masih bisa mendorong , yang tidak mungkin dilakukan dengan git archive.


21
Ini berguna, dan mungkin jawaban terbaik yang tersedia, tetapi masih mengkloning konten yang tidak Anda pedulikan (jika ada di cabang yang Anda tarik), meskipun itu tidak muncul di checkout.
nobar

1
Apa versi git Anda? Menurut git bantuan, apakah opsi kedalaman tersedia?
udondan

2
tidak bekerja untuk saya ketika perintah terakhir tidak git pull --depth=1 origin mastertetapi git pull --depth=1 origin <any-other-branch>. ini sangat aneh, lihat pertanyaan saya di sini :stackoverflow.com/questions/35820630/…
Shuman

5
Pada Windows, baris kedua hingga terakhir perlu menghilangkan tanda kutip, atau tarikan gagal.
nateirvin

4
Ini masih mengunduh semua data! Menemukan solusi ini, menggunakan svn: stackoverflow.com/a/18324458/2302437
electronix384128

157

Untuk pengguna lain yang hanya ingin mengunduh file / folder dari github, cukup gunakan:

svn export <repo>/trunk/<folder>

misalnya

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

(ya, itu svn di sini. rupanya pada tahun 2016 Anda masih perlu svn untuk cukup mengunduh beberapa file github)

Courtesy: Unduh satu folder atau direktori dari repo GitHub

Penting - Pastikan Anda memperbarui URL github dan ganti /tree/master/dengan '/ trunk /'.

Sebagai skrip bash:

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

Catatan Metode ini mengunduh folder, tidak mengkloning / checkout. Anda tidak dapat mendorong perubahan kembali ke repositori. Di sisi lain - ini menghasilkan unduhan lebih kecil dibandingkan dengan checkout jarang atau checkout dangkal.


9
hanya versi yang bekerja untuk saya dengan github. Perintah git memeriksa> 10rb file, svn hanya mengekspor 700 yang saya inginkan. Terima kasih!
Christopher Lörken

4
Mencoba melakukan ini dengan https://github.com/tensorflow/tensorflow/tree/master/tensorflow/examples/trunk/udacitytetapi mendapat svn: E170000: URL 'https://github.com/tensorflow/tensorflow/tree/master/tensorflow/examples/trunk/udacity' doesn't existkesalahan :(
zthomas.nc

9
@ zthomas.nc Anda harus menghapus 'trunk' sebelumnya, dan ganti / tree / master / dengan / trunk / sebagai gantinya.
Speedy

2
Perintah ini adalah yang bekerja untuk saya! Saya hanya ingin mendapatkan salinan file dari repo sehingga saya bisa memodifikasinya secara lokal. SVN tua yang baik untuk menyelamatkan!
Michael J

3
itu bekerja, tetapi tampaknya lambat. Dibutuhkan sedikit untuk memulai dan kemudian file bergulir dengan relatif lambat
Aryeh Beitz

73

Jika Anda tidak pernah berencana untuk berinteraksi dengan repositori tempat Anda melakukan kloning, Anda dapat melakukan klon git penuh dan menulis ulang repositori Anda menggunakan git-cabang -subdirectory-filter . Dengan cara ini, setidaknya sejarah akan dilestarikan.


11
Bagi orang yang tidak tahu perintahnya, itu adalahgit filter-branch --subdirectory-filter <subdirectory>
Jaime Hablutzel

9
Metode ini memiliki keuntungan bahwa subdirektori yang Anda pilih menjadi root dari repositori baru, yang kebetulan persis seperti yang saya inginkan.
Andrew Schulman

Itu adalah pendekatan terbaik dan termudah untuk digunakan. Berikut adalah perintah satu langkah menggunakan subdirektori-filtergit clone https://github.com/your/repo_xx.git && cd repo_xx && git filter-branch --subdirectory-filter repo_xx_subdir
Alex

66

Ini terlihat jauh lebih sederhana:

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

17
Ketika saya melakukan ini pada github, saya mendapatkan fatal: Operasi tidak didukung oleh protokol. Akhir aliran perintah yang tidak terduga
Michael Fox

1
Kesalahan protokol bisa karena HTTPS atau: di url repo. Bisa juga karena kunci ssh hilang.
Umair A.

2
Jika Anda menggunakan github Anda dapat menggunakan svn exportbukannya
Milo Wielondek

2
Tidak akan berfungsi dengan Github -> Perintah tidak valid: 'git-upload-archive' xxx / yyy.git '' Anda tampaknya menggunakan ssh untuk mengkloning git: // URL. Pastikan opsi konfigurasi core.gitProxy Anda dan variabel lingkungan GIT_PROXY_COMMAND TIDAK diatur. fatal: Ujung yang jauh menutup secara tak terduga
Nianliang

3
Alasan mengapa ini tidak bekerja dengan GitHub: "Kami tidak mendukung menggunakan git-arsip untuk menarik arsip langsung dari GitHub. Anda dapat mengkloning repo secara lokal dan menjalankan git-arsip, atau klik tombol Unduh ZIP pada halaman repo. " github.com/xuwupeng2000/capistrano-scm-gitcopy/issues/16
Donn Lee


37

Tidak mungkin untuk mengkloning subdirektori hanya dengan Git, tetapi di bawah ini ada beberapa solusi.

Saring cabang

Anda mungkin ingin menulis ulang repositori agar seolah-olah trunk/public_html/telah menjadi root proyeknya, dan membuang semua riwayat lainnya (menggunakan filter-branch), coba pada cabang checkout yang sudah ada:

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

Catatan: Opsi --yang memisahkan opsi cabang-filter dari opsi revisi, dan --alluntuk menulis ulang semua cabang dan tag. Semua informasi termasuk waktu komit asli atau menggabungkan informasi akan dipertahankan . Perintah ini menghargai .git/info/graftsfile dan referensi di refs/replace/namespace, jadi jika Anda memiliki graf atau penggantian yang refsditentukan, menjalankan perintah ini akan membuatnya permanen.

Peringatan! Sejarah yang ditulis ulang akan memiliki nama objek yang berbeda untuk semua objek dan tidak akan bertemu dengan cabang asli. Anda tidak akan dapat dengan mudah mendorong dan mendistribusikan cabang yang ditulis ulang di atas cabang asli. Tolong jangan gunakan perintah ini jika Anda tidak tahu implikasi penuh, dan hindari menggunakannya, jika komit tunggal sederhana sudah cukup untuk memperbaiki masalah Anda.


Checkout jarang

Berikut adalah langkah-langkah sederhana dengan pendekatan checkout jarang yang akan mengisi direktori kerja secara jarang, sehingga Anda dapat memberi tahu Git folder atau file mana di direktori kerja yang layak untuk dicoba.

  1. Repositori klon seperti biasa ( --no-checkoutopsional):

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

    Anda dapat melewati langkah ini, jika repositori Anda sudah dikloning.

    Petunjuk: Untuk repo besar, pertimbangkan clone dangkal ( --depth 1) untuk checkout hanya revisi terbaru atau / dan --single-branchhanya.

  2. Aktifkan sparseCheckoutopsi:

    git config core.sparseCheckout true
    
  3. Tentukan folder untuk checkout jarang ( tanpa ruang di bagian akhir):

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

    atau edit .git/info/sparse-checkout.

  4. Periksa cabang (mis. master):

    git checkout master
    

Sekarang Anda harus memiliki folder yang dipilih di direktori Anda saat ini.

Anda dapat mempertimbangkan tautan simbolis jika Anda memiliki terlalu banyak direktori atau cabang penyaringan sebagai gantinya.



Apakah cabang Filter masih mengizinkan Anda pull?
sam

2
@sam: tidak. filter-branchakan menulis ulang komit induk sehingga mereka memiliki ID SHA1 yang berbeda, dan dengan demikian pohon yang Anda filterkan tidak memiliki komit yang sama dengan pohon jarak jauh. git pulltidak akan tahu dari mana harus mencoba untuk bergabung.
Peter Cordes

Pendekatan ini sebagian besar merupakan jawaban yang memuaskan untuk kasus saya.
Abbas

10

Saya baru saja menulis naskah untuk GitHub .

Pemakaian:

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

11
FYI, itu hanya untuk GitHub .
Sz.

9
Dan ternyata ini untuk mengunduh direktori, bukan mengkloning sepotong repo dengan semua metadata-nya ... kan?
LarsH

5
Anda harus memasukkan kode Anda di sini dan bukan di tempat lain.
jww

urllib2.HTTPError: Kesalahan HTTP 403: batas tingkat terlampaui
diyisme

9

Ini akan mengkloning folder tertentu dan menghapus semua riwayat yang tidak terkait dengannya.

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

Di sini ada naga. Anda mendapatkan disambut oleh PERINGATAN: git-filter-cabang memiliki kekenyangan gotchas menghasilkan penulisan ulang sejarah hancur .. . Kemudian dokumen git-filter-branch memiliki daftar peringatan yang agak panjang.
Oyvind

6

Berikut ini adalah skrip shell yang saya tulis untuk kasus penggunaan checkout subdirektori tunggal

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
Skrip yang bagus, hanya sesuatu yang harus diperbaiki adalah symlink, yang seharusnya ln -s ./.$localRepo/$subDir $localRepobukanln -s ./.$localRepo$subDir $localRepo
valentin_nasta

2

Saya menulis .gitconfig [alias]untuk melakukan "checkout jarang". Lihatlah (tidak ada permainan kata-kata yang dimaksudkan):

Pada Windows dijalankan 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"

Jika tidak:

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'

Penggunaan :

# 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

The git configperintah adalah 'minified' untuk kenyamanan dan penyimpanan, tapi di sini adalah alias diperluas:

# 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

Mengapa ini bekerja L=${1##*/} L=${L%.git}:? Apakah ruang operator?
Gulzt

2

Menggunakan Linux? Dan hanya ingin akses mudah dan membersihkan pohon yang bekerja? tanpa mengganggu sisa kode di mesin Anda. coba symlink !

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

Uji

cd ~/Desktop/my-subfolder
git status

1

Hanya untuk memperjelas beberapa jawaban hebat di sini, langkah-langkah yang dijabarkan dalam banyak jawaban mengasumsikan bahwa Anda sudah memiliki repositori jarak jauh di suatu tempat.

Diberikan: repositori git yang ada, misalnya git@github.com:some-user/full-repo.git, dengan satu atau lebih direktori yang ingin Anda tarik secara independen dari sisa repo, misalnya direktori yang dinamai app1danapp2

Dengan asumsi Anda memiliki repositori git seperti di atas ...

Kemudian: Anda dapat menjalankan langkah-langkah seperti berikut ini untuk menarik hanya direktori tertentu dari repo yang lebih besar:

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

Saya keliru berpikir bahwa opsi checkout jarang harus ditetapkan pada repositori asli: ini tidak terjadi. Anda menentukan direktori mana yang Anda inginkan secara lokal, sebelum menarik dari remote. Semoga klarifikasi ini membantu orang lain.


0

Walaupun saya benci sebenarnya harus menggunakan svn ketika berhadapan dengan git repos: / Saya menggunakan ini sepanjang waktu;

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

Ini memungkinkan Anda menyalin dari url github tanpa modifikasi. Pemakaian;

--- /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

Jika Anda benar-benar tertarik pada file revisi terbaru dari sebuah direktori, Github memungkinkan Anda mengunduh repositori sebagai file Zip, yang tidak mengandung histori. Jadi mengunduh sangat cepat.


0

Jadi saya mencoba semuanya dalam tapak ini dan tidak ada yang berhasil untuk saya ... Ternyata pada versi 2.24 dari Git (yang ada pada cpanel pada saat jawaban ini), Anda tidak perlu melakukan ini

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

yang Anda butuhkan hanyalah nama folder

wpm/*

Jadi singkatnya Anda melakukan ini

git config core.sparsecheckout true

Anda kemudian mengedit .git / info / sparse-checkout dan menambahkan nama folder (satu per baris) dengan / * di akhir untuk mendapatkan subfolder dan file

wpm/*

Simpan dan jalankan perintah checkout

git checkout master

Hasilnya adalah folder yang diharapkan dari repo saya dan tidak ada yang lain Upvote jika ini berhasil untuk Anda

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.