GIT: Thanh toán vào một thư mục cụ thể


128

Tôi muốn sử dụng một cái gì đó tương tự như:

git checkout -- <path>/<file>

nhưng tôi muốn kiểm tra tập tin vào một số thư mục tôi chọn, thay vì ghi đè lên cục bộ <path>/<file>.

Bất kỳ ý tưởng?


Câu trả lời:


57

Theo "xuất git" (như "xuất svn")?

Bạn có thể sử dụng git checkout-indexcho điều đó, đây là một lệnh cấp thấp, nếu bạn muốn xuất mọi thứ, bạn có thể sử dụng -a,

git checkout-index -a -f --prefix=/destination/path/

Để trích dẫn các trang người đàn ông:

Cuối cùng "/" [trên tiền tố] là quan trọng. Tên được xuất theo nghĩa đen chỉ là tiền tố với chuỗi được chỉ định.

Nếu bạn muốn xuất một thư mục nhất định, có một số thủ thuật liên quan. Lệnh chỉ lấy các tập tin, không phải thư mục. Để áp dụng nó cho các thư mục, sử dụng lệnh 'find' và dẫn đầu ra cho git.

find dirname -print0 | git checkout-index --prefix=/path-to/dest/ -f -z --stdin

Cũng từ các trang người đàn ông:

Trực giác không phải là mục tiêu ở đây. Lặp lại là.


Đáng buồn là điều này sẽ không hoạt động từ kho lưu trữ git trần, ngay cả với tập --prefix :-( (được thử nghiệm với git 1.9.1)
apeiros

1
nếu bạn muốn kiểm tra một nhánh / cam kết của một kho lưu trữ git trần, hãy sử dụngGIT_WORK_TREE=../path/to/place git checkout
allicoder

4
git worktree(xem bên dưới) imho là câu trả lời kinh điển ngày hôm nay và có thể được thêm vào đây.
geek-merlin

213

Một giải pháp khác sạch hơn một chút - chỉ cần xác định một cây công việc khác.

Để kiểm tra mọi thứ từ ĐẦU của bạn (không phải chỉ mục) đến một thư mục cụ thể:

git --work-tree=/path/to/outputdir checkout HEAD -- .

Để kiểm tra thư mục con hoặc tệp từ CHÍNH của bạn đến một thư mục cụ thể:

git --work-tree=/path/to/outputdir checkout HEAD -- subdirname

4
Lưu ý nhỏ - bạn không cần một đường dẫn tuyệt đối vì việc mở rộng vỏ tilde không xảy ra, tức là --work-tree=/home/thomasg/okcopythay vì --work-tree=~/okcopy(có thể sử dụng một đường dẫn tương đối trong khi ngồi trong cùng một cây git cũng hoạt động, nhưng cách đó nằm ở sự điên rồ và git statusđầu ra trong R'lyehian)
Tom Goodfellow

10
Nó cũng hoạt động như mong đợi với các xác nhận cũ (ví dụ: đặt SHA thay cho HEAD), tuy nhiên git statussau đó hiển thị rất nhiều mod (có lẽ vì chỉ mục hiện khớp với thư mục khác và không phải là cây công việc bình thường chưa được xử lý). git resetđã đưa nó trở lại trạng thái tốt.
Tom Goodfellow

2
Tương tự ở đây git statuscho thấy rất nhiều mod, và git resetkhông giúp được gì. Tôi đã phải git checkout -f HEADkhôi phục lại trạng thái của repo của tôi.
DUzun

11
FYI: bạn cần tự tạo thư mục, nếu không bạn sẽ gặp lỗi này:fatal: This operation must be run in a work tree
timaschew 2/2/2016

13
Điều này làm thay đổi thảm hại chỉ số của cây làm việc chính, thường là xấu. Như @Tomoodfellow gợi ý, git resetđủ để khôi phục cây làm việc chính trở nên tỉnh táo. Để xuất một cách an toàn các thư mục con của kho lưu trữ tại bất kỳ SHA1, chi nhánh hoặc thẻ nào mà không sửa đổi cây làm việc chính, hãy xem giải pháp khét tiếng của Charles Bailey . Tương tự, để kiểm tra an toàn nhiều chi nhánh cùng một lúc, tiểu ban mới là bạn của bạn. git archivegit worktree add
Cecil Curry

25

Đối với một tệp duy nhất:

git show HEAD:abspath/to/file > file.copy

2
+1 và để làm rõ về "một số cam kết trước đó" (thay vì CHÍNH): Nó đề cập đến những SHA1 IDgì có thể dễ dàng tìm thấy thông qua gitk. Nếu tôi chỉ cần "kiểm tra" tệp đó đến một vị trí tạm thời (nghĩa là không hoàn nguyên), thì tôi sẽ sử dụng showtiểu ban:git show 82e54378856215ef96c5db1ff1160a741b5dcd70:MyProj/proguard/mapping.txt > myproj_mapping.txt
ef2011

19

Các giải pháp trên không hiệu quả với tôi vì tôi cần kiểm tra một phiên bản được gắn thẻ cụ thể của cây. Nhân tiện, đó là cách cvs exportsử dụng. git checkout-indexkhông lấy đối số thẻ, vì nó kiểm tra các tệp từ chỉ mục. git checkout <tag>sẽ thay đổi chỉ mục bất kể cây công việc, vì vậy tôi sẽ cần thiết lập lại cây ban đầu. Giải pháp hiệu quả với tôi là sao chép kho lưu trữ. Bản sao được chia sẻ khá nhanh và không tốn nhiều dung lượng. Thư mục .gitcó thể được gỡ bỏ nếu muốn.

git clone --shared --no-checkout <repository> <destination>
cd <destination>
git checkout <tag>
rm -rf .git

Các phiên bản mới hơn của git sẽ hỗ trợ git clone --branch <tag>để tự động kiểm tra thẻ được chỉ định:

git clone --shared --branch <tag> <repository> <destination>
rm -rf <destination>/.git

3
git --work-tree=/path/to/outputdir checkout <tag> -- .không làm việc cho bạn?
warvariuc

1
Không, nó không. Tệp thực tế trong thư mục công việc gốc không thay đổi, nhưng phiên bản theo giai đoạn bị mất và được thay thế bằng phiên bản từ thẻ. Điều này đặc biệt tệ nếu phiên bản dàn dựng có một bộ các thay đổi được chọn cẩn thận sẽ được cam kết. Tôi không muốn lệnh xuất chạm vào chỉ mục, giai đoạn của tôi.
proski

19

Nếu bạn đang làm việc theo tính năng của mình và không muốn kiểm tra lại thành chủ, bạn có thể chạy:

cd ./myrepo

git worktree add ../myrepo_master master

git worktree remove ../myrepo_master

Nó sẽ tạo ../myrepo_masterthư mục với các mastercam kết chi nhánh, nơi bạn có thể tiếp tục làm việc


1
Câu trả lời hay nhất - đơn giản và không giống như git --work-tree=/path/to/outputdir checkout HEAD -- .nó không làm gì với chỉ mục, chỉ cần sao chép nhánh được chọn vào vị trí đã chỉ định (có thêm tệp .git).
Roger Dueck

Và làm thế nào tôi hoàn tác thay đổi này?
Scott P.

@ ScottP.just xóa myrepo_masterthư mục
itnikolay

1
hoàn tác đây là một tiểu ban từ worktree:git worktree remove ../myrepo_master
Martijn

8

Câu trả lời của Adrian đã ném "gây tử vong: Hoạt động này phải được chạy trong một cây làm việc." Sau đây là những gì làm việc cho chúng tôi.

git worktree add <new-dir> --no-checkout --detach
cd <new-dir>
git checkout <some-ref> -- <existing-dir>

Ghi chú:

  • --no-checkout Không kiểm tra bất cứ điều gì vào worktree mới.
  • --detach Không tạo một nhánh mới cho bàn làm việc mới.
  • <some-ref>làm việc với bất kỳ ref, ví dụ, nó hoạt động với HEAD~1.
  • Dọn dẹp với git worktree prune.

+1 để nhận xét về cách dọn dẹp - mọi người khác rất vui khi tạo ra một mớ hỗn độn của repo hiện tại. chỉ có điều này không có tác dụng phụ.
Andrew Hill

1

Ngoài câu trả lời của @ hasen . Để liệt kê các tệp cần thanh toán , bạn có thể muốn sử dụng git ls-filesthay vì findthích:

git ls-files -z *.txt | git checkout-index --prefix=/path-to/dest/ -f -z --stdin

Cảm ơn bạn đã sử dụng đúng cách -z! Rất vui khi bạn cung cấp tập lệnh không dễ bị tấn công nhất định.
ErikE

0

Tôi đã xác định một bí danh git để đạt được điều này (trước khi tôi tìm thấy câu hỏi này).

Đây là một hàm bash ngắn giúp lưu đường dẫn hiện tại, chuyển sang repo git, thực hiện kiểm tra và trả về nơi nó bắt đầu.

kiểm tra git để phát triển ~ / my_project_git

Ví dụ này sẽ kiểm tra nhánh phát triển vào thư mục "~ / my_project_git".

Đây là mã bí danh bên trong ~/.gitconfig:

[alias]
    checkTo = "!f(){ [ -z \"$1\" ] && echo \"Need to specify branch.\" && \
               exit 1; [ -z \"$2\" ] && echo \"Need to specify target\
               dir\" && exit 2; cDir=\"$(pwd)\"; cd \"$2\"; \
               git checkout \"$1\"; cd \"$cDir\"; };f"

0

Tôi đang sử dụng bí danh này để kiểm tra một nhánh trong một thư mục tạm thời:

[alias]
    cot = "!TEMP=$(mktemp -d); f() { git worktree prune && git worktree add $TEMP $1 && zsh -c \"cd $TEMP; zsh\";}; f" # checkout branch in temporary directory

Sử dụng:

git cot mybranch

Sau đó, bạn được thả vào một shell mới trong thư mục tạm thời nơi bạn có thể làm việc trên nhánh. Bạn thậm chí có thể sử dụng các lệnh git trong thư mục này.

Khi bạn hoàn tất, xóa thư mục và chạy:

git worktree prune

Điều này cũng được thực hiện tự động trong bí danh, trước khi thêm một worktree mới.


0

Sử dụng git archive branch-index | tar -x -C your-folder-on-PCđể sao chép một nhánh vào thư mục khác. Tôi nghĩ, sau đó bạn có thể sao chép bất kỳ tập tin nào bạn cầ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.