rsync loại trừ theo .gitignore & .hgignore & svn: bỏ qua như --filter =: C


113

Rsync bao gồm một tùy chọn tiện lợi --cvs-excludeđể "bỏ qua các tệp theo cách giống như CVS", nhưng CVS đã lỗi thời trong nhiều năm. Có cách nào để làm cho nó cũng loại trừ các tệp sẽ bị bỏ qua bởi các hệ thống kiểm soát phiên bản hiện đại (Git, Mercurial, Subversion) không?

Ví dụ: tôi có rất nhiều dự án Maven được kiểm tra từ GitHub. Thông thường, chúng bao gồm .gitignoreít nhất một danh sách target, thư mục xây dựng Maven mặc định (có thể có ở cấp cao nhất hoặc trong các mô-đun con). Vì nội dung của các thư mục này hoàn toàn dùng một lần và chúng có thể lớn hơn nhiều so với mã nguồn, tôi muốn loại trừ chúng khi sử dụng rsync để sao lưu.

Tất nhiên tôi có thể rõ ràng --exclude=target/nhưng điều đó sẽ vô tình ngăn chặn các thư mục không liên quan chỉ tình cờ được đặt tên targetvà không được phép bỏ qua.

Và tôi có thể cung cấp một danh sách đầy đủ các đường dẫn tuyệt đối cho tất cả các tên tập tin và các mẫu nêu tại bất kỳ .gitignore, .hgignorehoặc svn:ignoretài sản trên đĩa của tôi, nhưng đây sẽ là một danh sách rất lớn mà có thể có được sản xuất bởi một số loại kịch bản.

Vì rsync không có hỗ trợ tích hợp cho các kiểm tra VCS ngoài CVS, có mẹo hay nào để cung cấp cho nó các mẫu bỏ qua của họ không? Hoặc một số loại hệ thống gọi lại, theo đó một kịch bản người dùng có thể được hỏi liệu một tệp / thư mục nhất định có nên được đưa vào hay không?

Cập nhật : --filter=':- .gitignore'theo đề xuất của LordJavac dường như hoạt động tốt cho Git cũng như --filter=:Ccho CVS, ít nhất là trên các ví dụ tôi đã tìm thấy, mặc dù không rõ liệu cú pháp có khớp chính xác hay không. --filter=':- .hgignore'không hoạt động rất tốt cho Mercurial; ví dụ: một .hgignorechứa một dòng như ^target$(tương đương Mercurial của Git /target/) không được rsync nhận dạng là một biểu thức chính quy. Và dường như không có gì hoạt động đối với Subversion, mà bạn sẽ phải phân tích cú pháp .svn/dir-prop-basecho một bản sao làm việc 1.6 hoặc cũ hơn, và thất vọng đối với bản sao làm việc 1.7 hoặc mới hơn.


11
Âm thanh một chút như nó sẽ là một ý tưởng tốt để nộp một bản vá cho rsync bổ sung hỗ trợ cho .gitignore, .hgignore vv
ThiefMaster

3
@ThiefMaster: Tôi đã nộp bugzilla.samba.org/show_bug.cgi?id=9744 làm điểm khởi đầu.
Jesse Glick

2
chỉ là một lưu ý cho người khác, nhu cầu .gitignore được trong hệ thống phân cấp thư mục được rysnc'd, không phải trong thư mục lệnh đang được thực hiện
myol

Không gì :-có nghĩa là chính xác? Dấu hai chấm có nghĩa là gì? Dấu gạch ngang là gì?
David

Git hiện có một check-ignorelệnh con có thể giải quyết công việc khó phân tích cú pháp các tệp "bỏ qua" khác nhau, nếu bạn muốn đi với tùy chọn "tạo danh sách tất cả các tệp không bị bỏ qua". Câu trả lời của tôi ở đây cung cấp chi tiết về cách làm điều đó.
cjs

Câu trả lời:


120

Như đã đề cập bởi luksan, bạn có thể làm điều này với --filternút chuyển sang rsync. Tôi đã đạt được điều này với --filter=':- .gitignore'(có một khoảng trắng trước ".gitignore") cho biết rsyncthực hiện hợp nhất thư mục với .gitignorecác tệp và yêu cầu chúng loại trừ theo quy tắc của git. Bạn cũng có thể muốn thêm tệp bỏ qua chung của mình, nếu bạn có. Để dễ sử dụng hơn, tôi đã tạo một bí danh rsyncbao gồm bộ lọc.


Một khởi đầu tốt, mặc dù tôi ngần ngại "chấp nhận" câu trả lời này vì nó chỉ bao gồm Git.
Jesse Glick vào

23
Một phiên bản nhiều tiết mà cũng không bao gồm .git file:--exclude='/.git' --filter="dir-merge,- .gitignore"
VasiliNovikov

2
Tôi có một cái gì đó như thế này bây giờ: rsync -rvv --exclude='.git*' --exclude='/rsync-to-dev.sh' --filter='dir-merge,-n /.gitignore' $DIR/ development.foobar.com:~/test/.. nhưng mặc dù nó nói [sender] hiding file .gitignore because of pattern .git*, tập tin vẫn được gửi đến desintation
rolandow

2
Nếu bạn cũng muốn sử dụng --deletetùy chọn, đây là dòng lệnh làm việc: rsync --delete-after --filter=":e- .gitignore" --filter "- .git/" -v -a .... Điều này khiến tôi mất một lúc ... etrong bộ lọc và --delete-aftercả hai đều quan trọng. Tôi khuyên bạn nên đọc chương "QUY TẮC VÀ XÓA MỖI HƯỚNG DẪN" của rsynctrang nam.
dbolotin

1
Để đồng bộ hóa việc xóa cũng như thêm & cập nhật, bạn chỉ cần thêm --delete-aftervào phiên bản lệnh của @ VasiliNovikov. (Điều này có vẻ tương đương với phiên bản lệnh của @ dboliton, ngoại trừ @db sử dụng: e mà tôi nghĩ loại trừ các tệp .gitignore khỏi bị sao chép, đó không phải là những gì tôi muốn.)
Bampfer

10

Bạn có thể sử dụng git ls-filesđể xây dựng danh sách các tệp bị loại trừ bởi các .gitignoretệp của kho lưu trữ . https://git-scm.com/docs/git-ls-files

Các tùy chọn:

  • --exclude-standardXem xét tất cả .gitignorecác tệp.
  • -o Đừng bỏ qua những thay đổi không theo giai đoạn.
  • -i Chỉ xuất các tệp bị bỏ qua.
  • --directory Chỉ xuất đường dẫn thư mục nếu toàn bộ thư mục bị bỏ qua.

Điều duy nhất tôi bỏ qua là .git.

rsync -azP --exclude=.git --exclude=`git -C <SRC> ls-files --exclude-standard -oi --directory` <SRC> <DEST>

4
điều này không hoạt động. nó loại trừ tệp đầu tiên khỏi lệnh con git và sau đó coi phần còn lại như một phần của danh sách SRC. cái này hoạt động: rsync -azP --exclude-from="$(git -C SRC ls-files --exclude-standard -oi --directory > /tmp/excludes; echo /tmp/excludes)" SRC DEST
marathon

2
Đây là phương pháp duy nhất hoạt động nếu bạn có cả loại trừ và bao gồm các dòng trong của bạn .gitignore(tức là các dòng bắt đầu bằng !). Nó cũng rsyncs các tệp mà bạn --forceđã thêm vào kho lưu trữ của mình, đây thường là một điều tốt.
ostrokach

1
Quả thực câu trả lời này KHÔNG HOẠT ĐỘNG, vì vậy tôi đã viết một câu trả lời có hiệu quả: stackoverflow.com/a/50059607/99834
sorin

6

làm thế nào về rsync --exclude-from='path/.gitignore' --exclude-from='path/myignore.txt' source destination?
Nó đã làm việc cho tôi.
Tôi tin rằng bạn cũng có thể có nhiều --exclude-fromthông số hơn .


3
Điều này sẽ hoạt động trong chừng mực khi các .gitignoretệp của bạn sử dụng cú pháp tương thích với rsync.
Jesse Glick vào

@JesseGlick nói đúng, rsync không thể phân tích cú pháp các tệp .gitignore, hãy xem cách giải quyết stackoverflow.com/a/50059607/99834 .
sorin

6

Giải pháp năm 2018 được xác nhận

rsync -ah --delete 
    --include .git --exclude-from="$(git -C SRC ls-files \
        --exclude-standard -oi --directory >.git/ignores.tmp && \
        echo .git/ignores.tmp')" \
    SRC DST 

Chi tiết: --exclude-fromlà bắt buộc thay vì --exclude vì có khả năng trường hợp loại trừ danh sách sẽ không được phân tích cú pháp như một đối số. Loại trừ khỏi yêu cầu tệp và không thể hoạt động với đường ống.

Giải pháp hiện tại lưu tệp loại trừ bên trong thư mục .git để đảm bảo tệp sẽ không ảnh hưởng git statustrong khi vẫn giữ kín. Nếu bạn muốn, bạn có thể sử dụng / tmp.


3
Điều này có vẻ như nó sẽ hoạt động nếu bạn có một kho lưu trữ Git cụ thể mà bạn muốn đồng bộ hóa — SRCở đây — nhưng không phải cho vấn đề ban đầu mà tôi đã nêu, đó là một thư mục rộng lớn với hàng nghìn kho lưu trữ Git dưới dạng thư mục con ở nhiều độ sâu khác nhau, nhiều trong số đó có idiosyncratic .gitignores.
Jesse Glick vào

1
Nếu bạn đang sử dụng shell có hỗ trợ thay thế quy trình (bash, zsh, v.v.), bạn có thể sử dụng--exclude-from=<(git -C SRC ls-files --exclude-standard -oi --directory)
Roland W

3

Đối với sự lanh lợi, bạn có thể sử dụng

hg status -i | sed 's/^I //' > /tmp/tmpfile.txt

để thu thập danh sách các tệp KHÔNG bị kiểm soát trọng thương vì các hạn chế .hgignore và sau đó chạy

rsync -avm --exclude-from=/tmp/tmpfile.txt --delete source_dir/ target_dir/

để rsync tất cả các tệp ngoại trừ những tệp bị bỏ qua. Thông báo -m gắn cờ trong rsync sẽ loại trừ các thư mục trống khỏi đồng bộ hóa vì trạng thái hg -i sẽ chỉ liệt kê các tệp bị loại trừ, không phải dirs


2

Thử cái này:

rsync -azP --delete --filter=":- .gitignore" <SRC> <DEST>

Nó có thể sao chép tất cả các tệp vào thư mục từ xa, ngoại trừ các tệp trong '.gitignore' và xóa các tệp không có trong thư mục hiện tại của bạn.


1

Trên rsynctrang người đàn ông, ngoài danh sách tiêu chuẩn của các mẫu tệp:

các tệp được liệt kê trong $ HOME / .cvsignore được thêm vào danh sách và bất kỳ tệp nào được liệt kê trong biến môi trường CVSIGNORE

Vì vậy, tệp $ HOME / .cvsignore của tôi trông giống như sau:

.git/
.sass-cache/

để loại trừ .git và các tệp do Sass tạo ra .


2
Ngược lại, tôi chắc chắn muốn bao gồm các .git/thư mục, có lẽ thậm chí còn mạnh hơn bản sao đang làm việc. Những gì tôi muốn loại trừ là các sản phẩm xây dựng.
Jesse Glick vào

Ngoài ra, cài đặt này không di động. Đó là cho mỗi người dùng, không phải cho mỗi dự án.
VasiliNovikov

@JesseGlick Tôi thứ hai cho bạn về việc bao gồm .git / dirs. Git là một SCM phân tán, điều quan trọng là phải sao lưu toàn bộ kho lưu trữ cục bộ.
Johan Boulé

1 / Câu từ rsynctrang người đàn ông được trích dẫn trong câu trả lời này mô tả --cvs-excludetùy chọn, vì vậy bạn phải sử dụng nó một cách rõ ràng. 2 / Bạn có thể tạo .cvsignorecác tệp trong bất kỳ thư mục nào để có các tệp bỏ qua dành riêng cho từng dự án, chúng cũng được đọc. 3 / .gitđã bị bỏ qua khi bạn sử dụng --cvs-exclude, theo hướng dẫn sử dụng, vì vậy việc có nó $HOME/.cvsignorecó vẻ thừa.
Niavlys

1

Tôi có một số .gitignoretệp rất lớn và không có giải pháp "thuần rsync" nào phù hợp với tôi. Tôi đã viết tập lệnh trình bao bọc rsync này , nó hoàn toàn tôn trọng .gitignorecác quy tắc (bao gồm các !ngoại lệ kiểu và .gitignoretệp trong thư mục con) và đã hoạt động như một sự quyến rũ đối với tôi.


Đang thử điều này thông qua locate -0e .gitignore | (while read -d '' x; do process_git_ignore "$x"; done), nhưng có rất nhiều vấn đề. Các tệp trong cùng một thư mục .gitignorekhông được phân tách chính xác khỏi tên thư mục với /. Dòng trống và nhận xét bị hiểu sai. Ngắt .gitignorecác tệp trong đường dẫn có khoảng trắng (đừng bận tâm đến điều quái đản /opt/vagrant/embedded/gems/gems/rb-fsevent-0.9.4/spec/fixtures/custom 'path/.gitignoretừ vagrantgói dành cho Ubuntu). Có lẽ tốt hơn nên thực hiện như một tập lệnh Perl.
Jesse Glick vào

@JesseGlick Tôi không chắc tại sao bạn lại gọi hàm trong tập lệnh. nó dự định được sử dụng như một phần thay thế cho rsync, vì lý do cụ thể là việc xử lý trích dẫn / khoảng trắng là một vấn đề khó khăn. Nếu bạn có một ví dụ về một gsyncdòng lệnh bị lỗi và các .gitignoretệp được liên kết với nó, tôi rất vui được xem xét kỹ hơn.
cobbzilla

Tôi cần rsynctoàn bộ hệ thống tệp, với nhiều kho lưu trữ Git khác nhau nằm rải rác xung quanh nó. Có lẽ kịch bản của bạn hoạt động tốt đối với trường hợp đồng bộ hóa một đơn kho.
Jesse Glick

1
Vâng chắc chắn. xin lỗi tôi đã không nói rõ điều đó. Với tập lệnh này, bạn sẽ phải gọi nó một lần cho mỗi git repo, từ trong thư mục repo.
cobbzilla

0

Kiểm tra phần QUY TẮC BỘ LỌC MERGE-FILES trong rsync (1).

Có vẻ như có thể tạo quy tắc rsync --filter sẽ bao gồm các tệp .gitignore khi duyệt qua cấu trúc thư mục.


0

Thay vì tạo bộ lọc loại trừ, bạn có thể sử dụng git ls-filesđể chọn từng tệp để rsync:

#!/usr/bin/env bash

if [[ ! $# -eq 2 ]] ; then
    echo "Usage: $(basename $0) <local source> <rsync destination>"
    exit 1
fi

cd $1
versioned=$(git ls-files --exclude-standard)
rsync --verbose --links --times --relative --protect-args ${versioned} $2

Điều này hoạt động ngay cả khi git ls-filestrả về các đường dẫn phân cách dòng mới. Có thể sẽ không hoạt động nếu bạn có các tệp được tạo phiên bản có khoảng trắng trong tên tệp.


0

Các lựa chọn thay thế:

git ls-files -zi --exclude-standard |rsync -0 --exclude-from=- ...

git ls-files -zi --exclude-per-directory=".gitignore" |...

(rsync chỉ hiểu một phần .gitignore)


0

Câu trả lời ngắn

rsync -r --info=progress2 --filter=':- .gitignore' SOURCE DEST/

Ý nghĩa thông số:

-r: đệ quy

--info=...: hiển thị tiến trình

--filter=...: loại trừ theo các quy tắc được liệt kê trên tệp .gitignore

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.