Cách tìm tất cả các kho git trong các thư mục đã cho (nhanh)


9

Cách tiếp cận ngây thơ là vậy find dir1 dir2 dir3 -type d -name .git | xargs -I {} dirname {} , nhưng nó quá chậm đối với tôi, vì tôi có rất nhiều cấu trúc thư mục sâu bên trong kho git (ít nhất tôi nghĩ rằng đây là lý do). Tôi đã đọc về điều mà tôi có thể sử dụng pruneđể ngăn chặn tìm lại trong thư mục một khi nó tìm thấy thứ gì đó, nhưng có hai điều. Tôi không chắc nó hoạt động như thế nào (ý tôi là tôi không hiểu prunemặc dù tôi đã đọc trang man) và lần thứ hai nó sẽ không hoạt động trong trường hợp của tôi, bởi vì nó sẽ ngăn không findcho vào lại .gitthư mục nhưng không vào tất cả các thư mục khác.

Vì vậy, những gì tôi thực sự cần là:

đối với tất cả các thư mục con kiểm tra xem chúng có chứa một .gitthư mục hay không và nếu nó dừng tìm kiếm trong nhánh hệ thống tập tin này và báo cáo kết quả. Sẽ là hoàn hảo nếu điều này cũng sẽ loại trừ bất kỳ thư mục ẩn khỏi tìm kiếm.


1
getpof .gitlà những gì tôi sử dụng. github.com/thrig/scripts/blob/master/filesys/getpof.c
thrig

Câu trả lời:


8

Được rồi, tôi vẫn không hoàn toàn chắc chắn cách thức hoạt động của nó, nhưng tôi đã thử nó và nó hoạt động.

.
├── a
│   ├── .git
│   └── a
│       └── .git
└── b
    └── .git

6 directories, 0 files

% find . -type d -exec test -e '{}/.git' ';' -print -prune
./a
./b

Tôi đang mong muốn làm cho cùng một nhanh hơn.


2
Cách -prunenày: Bạn bắt đầu từ gốc của cây bạn di chuyển xuống và khi một điều kiện nhất định áp dụng, bạn cắt toàn bộ cây con (như "cắt tỉa" thực sự), vì vậy bạn sẽ không nhìn vào bất kỳ nút nào nữa trong cây con này .
phk

@phk ơi, cảm ơn. Tôi dường như nắm bắt nó bây giờ. Chúng tôi tìm kiếm các thư -type dmục cho điều kiện nào test -e ...là đúng và nếu đúng thì chúng tôi thực hiện các hành động -print -prunecó nghĩa là in nó và cắt cây con, phải không?
dùng1685095

Vâng, chúng tôi cắt các cây con mà nó là gốc.
phk

Nhanh chóng sử dụng giải pháp của bạn để "cập nhật" tất cả các repos git: find . -type d -exec test -e '{}/.git' \; -print -prune | parallel cd "{}" \&\& git pull --rebaseGNU parallellà một sự thay thế rất tiện dụng choxargs
Marcello Romani

bạn sẽ không nhận được các mô-đun phụ, cũng là các repos git. Bạn có thể muốn tìm nạp chúng bằng cách tìm nạp đệ quy các mô đun con, một khi bạn có danh sách repos gốc được trả về bởi lệnh này.
hoijui

2

Giải pháp có thể

Đối với GNU findvà các triển khai khác hỗ trợ -execdir:

find dir1 dir2 dir3 -type d -execdir test -d '.git' \; -print -prune

(xem các bình luận)

Công cụ thảo luận trước đây

Giải pháp nếu cắt tỉa dưới đây .gitlà đủ

find dir1 dir2 dir3 -type d -path '*/.git' -print -prune | xargs -I {} dirname {}

Nếu -printf '%h'được hỗ trợ (như trong trường hợp của GNU find), chúng tôi không cần dirname:

find dir1 dir2 dir3 -type d -path '*/.git' -printf '%h\n' -prune

Một khi nó đi qua một thư mục .gittrong đường dẫn hiện tại, nó sẽ xuất nó và sau đó dừng nhìn xuống phía dưới cây con.

Giải pháp nếu toàn bộ cây thư mục nên được cắt tỉa một khi .gittìm thấy

Sử dụng -quitnếu bạn findhỗ trợ nó:

for d in dir1 dir2 dir3; do
  find "$d" -type d -name .git -print -quit
done | xargs -I {} dirname {}

(Theo bài viết chi tiết này của Stéphane Chazelas -quit được hỗ trợ trong GNU và FreeBSD findvà trong NetBSD như -exit.)

Một lần nữa với -printf '%h'nếu được hỗ trợ:

for d in dir1 dir2 dir3; do
  find "$d" -type d -name .git -printf '%h\n' -quit
done

Giải pháp cho việc cắt tỉa ở cùng cấp độ với vị trí của .gitthư mục

Xem phần "Giải pháp có thể" để biết giải pháp hiện tại cho vấn đề cụ thể này.

(Ồ và rõ ràng là các giải pháp sử dụng xargsgiả định không có dòng mới nào trong các đường dẫn, nếu không bạn sẽ cần phép thuật byte rỗng.)


nếu dir1chứa hai thư mục dirxdirymỗi thư mục chứa một .gitthư mục, thì điều này chỉ báo cáo dirx/.git
iruvar

@iruvar Ah OK, tôi đã hiểu lầm bạn trong trường hợp đó, tôi sẽ cố gắng làm lại giải pháp sau đó.
phk

vấn đề với giải pháp mới của bạn là điều này nếu dir1/.gittồn tại, nó vẫn giảm dir1/dirx, điều này, dựa trên việc tôi đọc yêu cầu của OP, là không mong muốn
iruvar

@iruvar OK, thêm vào đó là tốt. Bất kỳ ý tưởng khác về những gì OP có thể có nghĩa là gì? ;-)
phk

@iruvar chính xác
user1685095

2

Lý tưởng nhất là bạn muốn thu thập dữ liệu cây thư mục cho các thư mục chứa .gitmục nhập và ngừng tìm kiếm thêm những mục đó (giả sử bạn không có thêm git repos bên trong git repos).

Vấn đề là với tiêu chuẩn find, thực hiện loại kiểm tra này (rằng một thư mục chứa .gitmục nhập) liên quan đến việc sinh ra một quy trình thực thi một testtiện ích bằng cách sử dụng -execvị ngữ, sẽ kém hiệu quả hơn so với việc liệt kê nội dung của một vài thư mục.

Một ngoại lệ sẽ là nếu bạn sử dụng phần finddựng sẵn của boshshell (một ngã ba POSIXified của shell Bourne được phát triển bởi @schily ) có một -callvị từ để đánh giá mã trong shell mà không phải sinh ra trình thông dịch sh mới:

#! /path/to/bosh
find . -name '.?*' -prune -o \
  -type d -call '[ -e "$1/.git" ]' {} \; -prune -print

Hoặc sử dụng perl's File::Find:

perl -MFile::Find -le '
  sub wanted {
    if (/^\../) {$File::Find::prune = 1; return}
    if (-d && -e "$_/.git") {
       print $File::Find::name; $File::Find::prune = 1
    }
  }; find \&wanted, @ARGV' .

Lâu hơn, nhưng nhanh hơn so với zsh's printf '%s\n' **/.git(:h)(mà rơi vào tất cả các thư mục không ẩn), hoặc GNU find' s find . -name '.?*' -prune -o -type d -exec test -e '{}/.git' \; -prune -printmà chạy một testlệnh trong một quá trình mới cho mỗi thư mục không ẩn.


1
Lưu ý rằng đó .gitcũng có thể là một tệp - thông quagit worktree
Steven Penny

1
Cảm ơn @StevenPenny, tôi đã không biết điều đó. Bây giờ tôi đã thay đổi -ds thành -e.
Stéphane Chazelas

1

Nếu bạn sử dụng định vị, bạn có thể tìm thấy các thư mục với:

locate .git | grep "/.git$"

Danh sách kết quả là nhanh chóng và tiếp tục xử lý là dễ dàng, quá.


2
locate '*/.git'nên là đủ.
Stéphane Chazelas

0

Sử dụng

find ~/GIT-REPOSITORIES \( -exec test -d '{}'/.git \; \) -print -prune

timeĐiều này, để thấy sự khác biệt có và không có -prune.

Điều này dựa trên một giải pháp trong man find. Bạn có thể chỉnh sửa CVSsvnnếu không cần thiết. nội dung trang người đàn ông sau

find repo/ \( -exec test -d '{}'/.svn \; -or \
       -exec test -d {}/.git \; -or -exec test -d {}/CVS \; \) \
       -print -prune

Đưa ra thư mục sau của các dự án và các thư mục quản trị SCM được liên kết của chúng, thực hiện tìm kiếm hiệu quả cho các gốc của dự án:

repo/project1/CVS
repo/gnu/project2/.svn
repo/gnu/project3/.svn
repo/gnu/project3/src/.svn
repo/project4/.git

Trong ví dụ này, -prunengăn chặn việc hạ xuống không cần thiết vào các thư mục đã được phát hiện (ví dụ: chúng tôi không tìm kiếm project3/src, vì chúng tôi đã tìm thấy project3/.svn), nhưng đảm bảo các thư mục anh chị em ( project2project3) được tìm thấy.

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.