Làm cách nào để sao chép thư mục con chỉ của kho Git?


1410

Tôi có kho Git của tôi, ở thư mục gốc, có hai thư mục con:

/finisht
/static

Khi điều này ở SVN , /finishtđã được kiểm tra ở một nơi, trong khi /staticđược kiểm tra ở nơi khác, như vậy:

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

Có cách nào để làm điều này với Git?



1
Đối với người dùng năm 2014, git clonelệnh đơn giản nhất là gì ?? Tôi đã sử dụng câu trả lời đơn giản này . Nếu có một cái gì đó đơn giản hơn, xin vui lòng bình luận
Peter Krauss

Đối với những người cố gắng sao chép nội dung của kho lưu trữ (không tạo thư mục gốc), đây là một giải pháp rất dễ dàng: stackoverflow.com/questions/6224626/ Lỗi
Marc

@JoachimBreitner: Câu hỏi đó là về việc kiểm tra các thư mục con trong Git (rất dễ), trong khi câu hỏi này là về nhân bản các thư mục con trong Git (không thể).
Jörg W Găngag

@NickSergeant: Kể từ Git 2.19, được phát hành 3 tuần trước, điều này cuối cùng cũng có thể, như có thể thấy trong câu trả lời này: stackoverflow.com/a/52269934/2988 Hãy xem xét chấp nhận điều đó ngay bây giờ. Lưu ý: trong Git 2.19, chỉ hỗ trợ phía máy khách được triển khai, hỗ trợ phía máy chủ vẫn bị thiếu, do đó, nó chỉ hoạt động khi nhân bản kho lưu trữ cục bộ. Cũng lưu ý rằng các máy chủ lưu trữ Git lớn, ví dụ GitHub không thực sự sử dụng máy chủ Git, họ sử dụng triển khai của riêng họ, vì vậy ngay cả khi hỗ trợ xuất hiện trong máy chủ Git, điều đó không tự động có nghĩa là nó hoạt động trên máy chủ Git. (OTOH, họ có thể thực hiện nó nhanh hơn.)
Jörg W Mittag

Câu trả lời:


612

EDIT : Kể từ Git 2.19, điều này cuối cùng có thể, như có thể thấy trong câu trả lời này .

Hãy xem xét nâng cao câu trả lời đó.

Lưu ý: trong Git 2.19, chỉ hỗ trợ phía máy khách được triển khai, hỗ trợ phía máy chủ vẫn bị thiếu, do đó, nó chỉ hoạt động khi nhân bản kho lưu trữ cục bộ. Cũng lưu ý rằng các máy chủ lưu trữ Git lớn, ví dụ GitHub, không thực sự sử dụng máy chủ Git, họ sử dụng triển khai của riêng họ, vì vậy ngay cả khi hỗ trợ xuất hiện trong máy chủ Git, điều đó không tự động có nghĩa là nó hoạt động trên máy chủ Git. (OTOH, vì họ không sử dụng máy chủ Git, họ có thể triển khai nó nhanh hơn trong các triển khai của riêng họ trước khi nó xuất hiện trong máy chủ Git.)


Không, điều đó là không thể trong Git.

Việc thực hiện một cái gì đó như thế này trong Git sẽ là một nỗ lực đáng kể và điều đó có nghĩa là tính toàn vẹn của kho khách hàng không còn có thể được đảm bảo. Nếu bạn quan tâm, hãy tìm kiếm các cuộc thảo luận về "bản sao thưa thớt" và "tìm nạp thưa thớt" trong danh sách gửi thư git.

Nói chung, sự đồng thuận trong cộng đồng Git là nếu bạn có một số thư mục luôn được kiểm tra độc lập, thì đây thực sự là hai dự án khác nhau và nên sống trong hai kho lưu trữ khác nhau. Bạn có thể dán chúng lại với nhau bằng Git Submodules .


6
Tùy thuộc vào kịch bản, bạn có thể muốn sử dụng git subree thay vì git subodule. Xem alumnit.ca/~apenwarr/log/?m=200904#30
C Pirate

9
@StijndeWitt: Thanh toán thưa thớt xảy ra trong thời gian git-read-treedài get-fetch. Câu hỏi không phải là về việc kiểm tra chỉ một thư mục con, mà là về việc nhân bản chỉ một thư mục con. Tôi không thấy cách kiểm tra thưa thớt có thể làm điều đó, vì git-read-treechạy sau khi bản sao đã hoàn thành.
Jörg W Mittag

9
Thay vì "sơ khai" này, bạn có muốn tôi xóa câu trả lời này để Chronial có thể nổi lên hàng đầu không? Bạn không thể tự xóa nó, bởi vì nó được chấp nhận, nhưng người điều hành thì có thể. Bạn sẽ giữ được danh tiếng mà bạn kiếm được từ nó, vì nó quá cũ. (Tôi đã gặp phải điều này vì ai đó đã gắn cờ nó là "chỉ liên kết". :-)
Cody Grey

1
@CodyGray: Câu trả lời theo thời gian vẫn nhân bản toàn bộ kho lưu trữ và không chỉ là thư mục con. (Đoạn cuối thậm chí còn nói rõ ràng như vậy.) Chỉ nhân bản một thư mục con là không thể trong Git. Giao thức mạng không hỗ trợ nó, định dạng lưu trữ không hỗ trợ nó. Mỗi câu trả lời cho câu hỏi này luôn luôn nhân bản toàn bộ kho lưu trữ. Câu hỏi là một câu hỏi Có / Không đơn giản và câu trả lời là hai ký tự: Không. Nếu có, câu trả lời của tôi dài không cần thiết , không ngắn.
Jörg W Mittag

1
@ JörgWMittag: Câu trả lời của Ciro Santili dường như mâu thuẫn với bạn.
Dan Dascalescu

1525

Những gì bạn đang cố gắng thực hiện được gọi là thanh toán thưa thớt và tính năng đó đã được thêm vào git 1.7.0 (tháng 2 năm 2012). Các bước để thực hiện một bản sao thưa thớt như sau:

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

Điều này tạo ra một kho lưu trữ trống với điều khiển từ xa của bạn và tìm nạp tất cả các đối tượng nhưng không kiểm tra chúng. Sau đó làm:

git config core.sparseCheckout true

Bây giờ bạn cần xác định tập tin / thư mục nào bạn muốn thực sự kiểm tra. Điều này được thực hiện bằng cách liệt kê chúng trong .git/info/sparse-checkout, ví dụ:

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

Cuối cùng nhưng không kém phần quan trọng, hãy cập nhật repo trống của bạn với trạng thái từ xa:

git pull origin master

Bây giờ bạn sẽ có các tập tin "kiểm tra" cho some/diranother/sub/tree trên hệ thống tệp của bạn (vẫn còn các đường dẫn đó) và không có đường dẫn nào khác xuất hiện.

Bạn có thể muốn xem hướng dẫn mở rộng và có lẽ bạn nên đọc tài liệu chính thức để kiểm tra thưa thớt .

Là một chức năng:

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
)

Sử dụng:

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

Lưu ý rằng điều này vẫn sẽ tải xuống toàn bộ kho lưu trữ từ máy chủ - chỉ có phần thanh toán bị giảm kích thước. Hiện tại không thể chỉ sao chép một thư mục duy nhất. Nhưng nếu bạn không cần lịch sử của kho lưu trữ, ít nhất bạn có thể tiết kiệm băng thông bằng cách tạo một bản sao nông. Xem câu trả lời của udondan dưới đây để biết thông tin về cách kết hợp bản sao nông và kiểm tra thưa thớt.


Kể từ git 2.25.0 (tháng 1 năm 2020), một lệnh kiểm tra thưa thớt thử nghiệm được thêm vào trong 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
trên Apple, chu vi '-f' không hoạt động. chỉ cần git từ xa thêm nguồn gốc <url> mà không -f
Anno2001

135
Đây là một cải tiến nhưng vẫn cần tải xuống và lưu trữ một bản sao đầy đủ của kho lưu trữ từ xa, mà người ta có thể muốn tránh nếu anh ta chỉ quan tâm đến các phần của cơ sở mã (hoặc nếu có thư mục con tài liệu như trong trường hợp của tôi )
a1an

56
Có cách nào để sao chép nội dung thư mục mong muốn (không phải chính thư mục) vào kho lưu trữ của tôi không? Ví dụ: tôi muốn sao chép nội dung của https://github.com/Umkus/nginx-boilerplate/tree/master/srcquyền vào/etc/nginx
mac

25
@Chronial, @ErikE: bạn đều đúng / sai: P git remote addLệnh không ngụ ý tìm nạp, nhưng git remote add -f, như được sử dụng ở đây, không! Đó là những gì -fcó nghĩa.
ntc2

21
Sử dụng cái này và --depth=1tôi đã nhân bản Chromium Devtools trong 338 MB thay vì 4,9 GB nguồn Blink đầy đủ + lịch sử. Thông minh.
Rudie

444

git clone --filter từ Git 2.19

Tùy chọn này thực sự sẽ bỏ qua việc tìm nạp các đối tượng không cần thiết từ máy chủ. Ngoài ra, bao gồm --filter=tree:0từ Git 2.20--filter=combinebộ lọc tổng hợp được thêm vào trong Git 2.24, chúng tôi kết thúc với:

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/

Máy chủ nên được cấu hình với:

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

Một phần mở rộng đã được tạo cho giao thức từ xa Git để hỗ trợ tính năng này trong v2.19.0 và thực sự bỏ qua việc tìm nạp các đối tượng không cần thiết, nhưng không có hỗ trợ máy chủ tại thời điểm đó. Nhưng nó đã có thể được thử nghiệm tại địa phương.

Sự cố lệnh:

Các định dạng của --filtertài liệu trên man git-rev-list.

Tài liệu trên cây Git:

Kiểm tra nó ra

#!/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 ngược dòng .

Đầu ra trong 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

Kết luận: tất cả các đốm màu từ bên ngoài d1/bị thiếu. Ví dụ 0975df9b39e23c15f63db194df7f45c76528bccb, d2/bkhông có ở đó sau khi kiểm tra d1/a.

Lưu ý rằng root/rootmybranch/mybranchcũng bị thiếu, nhưng --depth 1ẩn nó khỏi danh sách các tệp bị thiếu. Nếu bạn loại bỏ --depth 1, sau đó họ hiển thị trên danh sách các tập tin bị thiếu.

Tôi có một giấc mơ

Tính năng này có thể cách mạng hóa Git.

Hãy tưởng tượng có tất cả các cơ sở mã của doanh nghiệp của bạn trong một repo duy nhất mà không có các công cụ của bên thứ ba xấu xí như thế nàorepo .

Hãy tưởng tượng lưu trữ các đốm màu lớn trực tiếp trong repo mà không có bất kỳ tiện ích mở rộng bên thứ ba xấu xí nào .

Hãy tưởng tượng nếu GitHub sẽ cho phép mỗi siêu dữ liệu tệp / thư mục như sao và quyền, vì vậy bạn có thể lưu trữ tất cả nội dung cá nhân của mình trong một repo duy nhất.

Hãy tưởng tượng nếu các mô hình con được xử lý chính xác như các thư mục thông thường : chỉ cần yêu cầu SHA cây và cơ chế giống như DNS giải quyết yêu cầu của bạn , trước tiên hãy tìm kiếm cục bộ~/.git của bạn , sau đó trước tiên đến các máy chủ gần hơn (nhân bản / bộ đệm của doanh nghiệp của bạn) và kết thúc trên GitHub.


Điều kỳ lạ là trên macOS với phiên bản git 2.20.1 (Apple Git-117), nó phàn nàn rằng "nhiều thông số kỹ thuật không thể kết hợp"
muru

1
Đáng buồn thay, không có may mắn với phiên bản macOS git. fatal: invalid filter-spec 'combine:blob:none+tree:0'Dù sao cũng cảm ơn bạn! Có lẽ nó sẽ hoạt động với các phiên bản mới hơn.
muru

1
Điều này không thành công khi thử nó trên Windows 10 bằng GIT 2.24.1 (ném hàng tấn "không thể đọc tệp sha1 của .." + "Hủy liên kết tệp xxx không thành công."). Làm việc như một cơ duyên với cùng một phiên bản trên Linux.
Oyvind

1
@Ciro Santilli Điều này vẫn thất bại với "không thể đọc tệp sha1 của ..." trong phiên bản git 2.26.1.windows.1. Tôi đã mở một báo cáo lỗi: github.com/git-for-windows/git/issues/2590
nharrer

1
@nharrer cảm ơn vì thông tin!
Ciro Santilli 冠状 病毒 审查 事件

405

Bạn có thể kết hợp kiểm tra thưa thớt và các tính năng nhân bản nông . Bản sao nông cắt bỏ lịch sử và thanh toán thưa thớt chỉ kéo các tệp phù hợp với mẫu của bạn.

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

Bạn sẽ cần git 1.9 tối thiểu để làm việc này. Bản thân nó chỉ thử nghiệm với 2.2.0 và 2.2.2.

Bằng cách này, bạn sẽ vẫn có thể đẩy , điều này là không thể git archive.


21
Điều này hữu ích và có thể là câu trả lời tốt nhất hiện có, nhưng nó vẫn sao chép nội dung mà bạn không quan tâm (nếu nó nằm trên nhánh mà bạn kéo), mặc dù nó không hiển thị trong thanh toán.
tộc

1
Phiên bản git của bạn là gì? Theo git giúp là tùy chọn độ sâu có sẵn?
udondan

2
không làm việc cho tôi khi lệnh cuối cùng không git pull --depth=1 origin masternhưng git pull --depth=1 origin <any-other-branch>. Điều này thật kỳ lạ, hãy xem câu hỏi của tôi ở đây, stack stackoverflow.com/questions353863030 / Lời
Shuman

5
Trên Windows, dòng thứ hai đến cuối cùng cần bỏ qua dấu ngoặc kép hoặc kéo không thành công.
nateirvin

4
Điều này vẫn tải tất cả dữ liệu! Tìm thấy giải pháp này, sử dụng svn: stackoverflow.com/a/18324458/2302437
electronix384128

157

Đối với những người dùng khác chỉ muốn tải xuống tệp / thư mục từ github, chỉ cần sử dụng:

svn export <repo>/trunk/<folder>

ví dụ

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

(vâng, đó là svn ở đây. Rõ ràng trong năm 2016 bạn vẫn cần svn để tải xuống một số tệp github)

Lịch sự: Tải xuống một thư mục hoặc thư mục từ repo GitHub

Quan trọng - Đảm bảo bạn cập nhật URL github và thay thế /tree/master/bằng '/ trunk /'.

Như bash script:

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

Lưu ý Phương pháp này tải xuống một thư mục, không sao chép / kiểm tra nó. Bạn không thể đẩy các thay đổi trở lại kho lưu trữ. Mặt khác - điều này dẫn đến tải xuống nhỏ hơn so với thanh toán thưa thớt hoặc thanh toán nông.


9
phiên bản duy nhất làm việc cho tôi với github. Các lệnh git đã kiểm tra các tệp> 10k, svn chỉ xuất 700 tôi muốn. Cảm ơn!
Christopher Lörken

4
Đã thử làm điều này với https://github.com/tensorflow/tensorflow/tree/master/tensorflow/examples/trunk/udacitynhưng có svn: E170000: URL 'https://github.com/tensorflow/tensorflow/tree/master/tensorflow/examples/trunk/udacity' doesn't existlỗi :(
zthomas.nc

9
@ zthomas.nc Bạn cần xóa udacity trước 'thân cây' và thay thế / cây / chủ / bằng / thân / thay vào đó.
Tốc độ

2
Lệnh này là một trong những làm việc cho tôi! Tôi chỉ muốn lấy một bản sao của một tập tin từ một repo để tôi có thể sửa đổi nó cục bộ. Chúc SVN già đến cứu!
Michael J

3
Nó hoạt động, nhưng có vẻ chậm. mất một chút để bắt đầu và sau đó các tệp cuộn tương đối chậm
Aryeh Beitz

73

Nếu bạn không bao giờ có kế hoạch tương tác với kho lưu trữ mà bạn đã nhân bản, bạn có thể thực hiện một bản sao git đầy đủ và viết lại kho lưu trữ của bạn bằng cách sử dụng bộ lọc git - nhánh -subdirectory-filter . Bằng cách này, ít nhất là lịch sử sẽ được bảo tồn.


11
Đối với những người không biết lệnh, đó làgit filter-branch --subdirectory-filter <subdirectory>
Jaime Hablutzel

9
Phương pháp này có lợi thế là thư mục con bạn chọn trở thành thư mục gốc của kho lưu trữ mới, chính xác là điều tôi muốn.
Andrew Schulman

Đó chắc chắn là cách tiếp cận tốt nhất và dễ sử dụng nhất. Đây là lệnh một bước sử dụng bộ lọc thư mục congit clone https://github.com/your/repo_xx.git && cd repo_xx && git filter-branch --subdirectory-filter repo_xx_subdir
Alex

66

Điều này có vẻ đơn giản hơn nhiều:

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

17
Khi tôi làm điều này trên github, tôi sẽ bị chết: Hoạt động không được hỗ trợ bởi giao thức. Kết thúc luồng lệnh bất ngờ
Michael Fox

1
Lỗi giao thức có thể là do HTTPS hoặc: trong url repo. Nó cũng có thể là do thiếu khóa ssh.
Umair A.

2
Nếu bạn đang sử dụng github, bạn có thể sử dụng svn exportthay thế
Milo Wielondek

2
Không hoạt động khi Github -> Lệnh không hợp lệ: 'git-upload-archive' xxx / yyy.git '' Bạn dường như đang sử dụng ssh để sao chép git: // URL. Đảm bảo tùy chọn cấu hình core.gitProxy của bạn và biến môi trường GIT_PROXY_COMMAND KHÔNG được đặt. gây tử vong: Kết thúc từ xa treo lên bất ngờ
Nianliang

3
Lý do tại sao điều này không hoạt động với GitHub: "Chúng tôi không hỗ trợ sử dụng git-archive để lấy một kho lưu trữ trực tiếp từ GitHub. Bạn có thể sao chép repo cục bộ và chạy git-archive hoặc nhấp vào nút Tải xuống ZIP trên trang repo. " github.com/xuwupeng2000/capistrano-scm-gitcopy/issues/16
Donn Lee

63

Git 1.7.0 có tính năng kiểm tra thưa thớt trên mạng. Xem phần lõi của Core.spzzyCheckout, trong trang web cấu hình git , trang kiểm tra thưa thớt, trong trang quản trị cây đọc git và bit Skip-worktree bit trong trang web chỉ mục cập nhật git .

Giao diện không thuận tiện như SVN (ví dụ: không có cách nào để thực hiện kiểm tra thưa thớt tại thời điểm sao chép ban đầu), nhưng chức năng cơ bản dựa trên đó có thể xây dựng giao diện đơn giản hơn.


37

Không thể sao chép thư mục con chỉ với Git, nhưng dưới đây là một số cách giải quyết.

Nhánh lọc

Bạn có thể muốn viết lại kho lưu trữ để trông như thể trunk/public_html/là gốc dự án của nó và loại bỏ tất cả lịch sử khác (sử dụng filter-branch), hãy thử trên nhánh đã kiểm tra:

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

Lưu ý: Việc --tách các tùy chọn nhánh lọc khỏi các tùy chọn sửa đổi và --allđể viết lại tất cả các nhánh và thẻ. Tất cả thông tin bao gồm thời gian cam kết ban đầu hoặc thông tin hợp nhất sẽ được lưu giữ . Lệnh này tôn vinh .git/info/graftstập tin và refs trong refs/replace/không gian tên, vì vậy nếu bạn có bất kỳ mảnh ghép hoặc thay thế nào refsđược xác định, chạy lệnh này sẽ làm cho chúng vĩnh viễn.

Cảnh báo! Lịch sử viết lại sẽ có các tên đối tượng khác nhau cho tất cả các đối tượng và sẽ không hội tụ với nhánh ban đầu. Bạn sẽ không thể dễ dàng đẩy và phân phối nhánh viết lại trên đầu của nhánh ban đầu. Vui lòng không sử dụng lệnh này nếu bạn không biết đầy đủ ý nghĩa và tránh sử dụng nó, nếu một cam kết đơn giản sẽ đủ để khắc phục vấn đề của bạn.


Thanh toán thưa thớt

Dưới đây là các bước đơn giản với cách tiếp cận kiểm tra thưa thớt sẽ cư trú thư mục làm việc thưa thớt, vì vậy bạn có thể cho Git biết (các) thư mục hoặc tệp nào trong thư mục làm việc đáng để kiểm tra.

  1. Kho lưu trữ bản sao như bình thường ( --no-checkoutlà tùy chọn):

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

    Bạn có thể bỏ qua bước này, nếu kho lưu trữ của bạn đã được sao chép.

    Gợi ý: Đối với các repos lớn, hãy xem xét nông clone ( --depth 1) để kiểm tra chỉ sửa đổi mới nhất hoặc / và --single-branchchỉ.

  2. Cho phép sparseCheckouttùy chọn:

    git config core.sparseCheckout true
    
  3. Chỉ định (các) thư mục để kiểm tra thưa thớt ( không có khoảng trống ở cuối):

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

    hoặc chỉnh sửa .git/info/sparse-checkout.

  4. Kiểm tra chi nhánh (ví dụ master):

    git checkout master
    

Bây giờ bạn nên có các thư mục được chọn trong thư mục hiện tại của bạn.

Bạn có thể xem xét các liên kết tượng trưng nếu bạn có quá nhiều cấp độ thư mục hoặc bộ lọc thay thế.



Would Lọc chi nhánh vẫn cho phép bạn pull?
sam

2
@sam: không. filter-branchsẽ viết lại các xác nhận gốc để chúng có các ID SHA1 khác nhau và do đó cây được lọc của bạn sẽ không có các cam kết chung với cây từ xa. git pullsẽ không biết phải cố gắng hợp nhất từ ​​đâu.
Peter Cordes

Cách tiếp cận này chủ yếu là thỏa mãn câu trả lời cho trường hợp của tôi.
Abbas

10

Tôi vừa viết một kịch bản cho GitHub .

Sử dụng:

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

11
FYI, chỉ dành cho GitHub .
Sz.

9
Và rõ ràng đây là để tải xuống một thư mục, không phải nhân bản một mẩu repo với tất cả siêu dữ liệu của nó ... phải không?
LarsH

5
Bạn nên bao gồm bạn mã ở đây và không phải nơi nào khác.
jww

urllib2.HTTPError: Lỗi HTTP 403: vượt quá giới hạn tốc độ
tự làm

9

Điều này sẽ sao chép một thư mục cụ thể và xóa tất cả lịch sử không liên quan đến nó.

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

Đây là những con rồng. Bạn được chào đón bởi CẢNH BÁO: git-filter-branch có một thị trường bất gotchas tạo viết lại lịch sử đọc sai .. . Sau đó, các tài liệu git-filter-Branch có một danh sách cảnh báo khá dài.
Oyvind

6

Đây là một kịch bản shell tôi đã viết cho trường hợp sử dụng của một kiểm tra thưa thớt thư mục con

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
Kịch bản hay, chỉ có thứ cần được sửa là liên kết tượng trưng, ​​nên ln -s ./.$localRepo/$subDir $localRepothay vìln -s ./.$localRepo$subDir $localRepo
valentin_nasta

2

Tôi đã viết một .gitconfig [alias]để thực hiện một "kiểm tra thưa thớt". Kiểm tra xem (không có ý định chơi chữ):

Trên Windows chạy trong 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"

Nếu không thì:

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'

Cách sử dụng :

# 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

Các git configlệnh được 'rút gọn' để thuận tiện và lưu trữ, nhưng đây là bí danh được mở rộng:

# 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

Tại sao điều này hoạt động : L=${1##*/} L=${L%.git}? Là không gian một nhà điều hành?
Gulzt

2

Sử dụng Linux? Và chỉ muốn dễ dàng truy cập và làm sạch cây làm việc? mà không làm phiền phần còn lại của mã trên máy của bạn. hãy thử liên kết tượng trưng !

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

Kiểm tra

cd ~/Desktop/my-subfolder
git status

1

Chỉ cần làm rõ một số câu trả lời tuyệt vời ở đây, các bước được nêu trong nhiều câu trả lời cho rằng bạn đã có một kho lưu trữ từ xa ở đâu đó.

Đã cho: một kho git hiện có, ví dụ git@github.com:some-user/full-repo.git, với một hoặc nhiều thư mục mà bạn muốn kéo độc lập với phần còn lại của repo, ví dụ: các thư mục có tên app1app2

Giả sử bạn có một kho lưu trữ git như trên ...

Sau đó: bạn có thể chạy các bước như sau để chỉ kéo các thư mục cụ thể từ repo lớn hơn đó:

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

Tôi đã lầm tưởng rằng các tùy chọn thanh toán thưa thớt phải được đặt trên kho lưu trữ ban đầu: đây không phải là trường hợp. Bạn xác định thư mục nào bạn muốn cục bộ, trước khi lấy từ xa. Hy vọng sự làm rõ này sẽ giúp người khác.


0

Trong khi tôi ghét thực sự phải sử dụng svn khi giao dịch với git repos: / Tôi sử dụng điều này mọi lúc;

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

Điều này cho phép bạn sao chép từ url github mà không cần sửa đổi. Sử dụng;

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

Nếu bạn thực sự quan tâm đến các tệp sửa đổi mới nhất của một thư mục, Github cho phép bạn tải xuống một kho lưu trữ dưới dạng tệp Zip, không chứa lịch sử. Vì vậy, tải xuống nhanh hơn rất nhiều.


0

Vì vậy, tôi đã thử mọi thứ trong guồng quay này và không có gì hiệu quả với tôi ... Hóa ra là trên phiên bản 2.24 của Git (phiên bản đi kèm với cpanel tại thời điểm trả lời này), bạn không cần phải làm điều này

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

tất cả những gì bạn cần là tên thư mục

wpm/*

Vì vậy, trong ngắn hạn, bạn làm điều này

git config core.sparsecheckout true

sau đó bạn chỉnh sửa .git / thông tin / kiểm tra thưa thớt và thêm tên thư mục (một trên mỗi dòng) với / * ở cuối để lấy các thư mục con và tệp

wpm/*

Lưu và chạy lệnh thanh toán

git checkout master

Kết quả là thư mục dự kiến ​​từ repo của tôi và không có gì khác Upvote nếu điều này làm việc cho bạn

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.