特定のフォルダー内のすべてのgitリポジトリを見つける方法(高速)


9

素朴なアプローチはですがfind dir1 dir2 dir3 -type d -name .git | xargs -I {} dirname {} 、gitリポジトリ内に多くの深いフォルダ構造があるため、私には遅すぎます(少なくともこれが理由だと思います)。prune何かが見つかると、findがディレクトリに再帰するのを防ぐために使用できることを読みましたが、2つあります。私は確かにどのようにこの作品(私は何を理解していないわけではないよprune、それが妨げられるので、私はmanページを読んだもののん)と第二は、それは私の場合は動作しないでしょうfindに再帰する.gitフォルダすべてではないに他のフォルダ。

だから私が実際に必要なのは:

すべてのサブディレクトリについて、それらに.gitフォルダが含まれているかどうかを確認し、フォルダがこのファイルシステムブランチでの検索を停止して結果を報告します。これにより、非表示のディレクトリも検索から除外されれば完璧です。


1
getpof .git私が使用するものです。github.com/thrig/scripts/blob/master/filesys/getpof.c
2016

回答:


8

わかりました。これがどのように機能するかはまだ完全にはわかりませんが、テストしてみました。

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

6 directories, 0 files

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

同じことをもっと速くすることを楽しみにしています。


2
この-pruneように:ツリーのルートから開始してツリーを下に移動し、特定の条件が適用されると、サブツリー全体(実際の「プルーニング」など)をカットするため、このサブツリー内のノードはこれ以上確認しません。 。
phk

@phkああ、ありがとう。今は把握しているようです。-type d条件test -e ...がtrue であるディレクトリを検索し、trueの場合は、-print -pruneそれを印刷してサブツリーを切り取るというアクションを実行します。
user1685095 16

はい、それがルートであるサブツリーをカットします。
phk 2016

クイック1は、「更新」に、すべてのgitリポジトリをあなたのソリューションを使用する:find . -type d -exec test -e '{}/.git' \; -print -prune | parallel cd "{}" \&\& git pull --rebaseGNUはparallelのための非常に便利な代替品ですxargs
マルチェロ・マーニ

git reposでもあるサブモジュールは取得できません。このコマンドでroot-reposリストが返されたら、サブモジュールを再帰的にフェッチしてフェッチすることをお勧めします。
hoijui

2

可能な解決策

GNU findおよびその他をサポートする実装の場合-execdir

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

(コメントを参照)

以前に議論されたもの

以下の剪定.gitで十分な場合の解決策

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

場合は-printf '%h'(GNUのの場合のようにサポートされていますfind)私たちは必要ありませんdirname

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

.git現在のパスにあるフォルダーに出くわすと、それが出力され、サブツリーを見下ろすのをやめます。

a .gitが見つかったらフォルダーツリー全体を剪定する必要がある場合の解決策

-quitあなたfindがそれをサポートしている場合の使用:

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

StéphaneChazelasによるこの詳細な投稿に よると-quit、GNUとFreeBSD find、およびNetBSDではとしてサポートされてい-exitます。)

再び-printf '%h'サポートされている場合:

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

.gitフォルダーがある場所と同じレベルで剪定するためのソリューション

この特定の問題の現在の解決については、「考えられる解決策」の部分を参照してください。

(ああ、そして明らかに使用xargsするソリューションは、パスに改行がないと仮定します。そうでなければ、ヌルバイトの魔法が必要になります。)


もしdir1二つのディレクトリが含まれていますdirxし、diryそれぞれ含まれている.gitディレクトリを、このレポートのみ dirx/.git
iruvar

@iruvarああ、その場合は誤解しました。解決策を再試行します。
phk '30 / 12/16

新しいソリューションの問題は、これがdir1/.git存在する場合、それでも下降しdir1/dirxます。OPの要件の読み取りに基づいて、これは望ましくありません
iruvar

@iruvar OK、それも追加しました。OPが何を意味する可能性があるかについて、他に何か考えはありますか?;-)
phk '30 / 12/16

@iruvar正確
user1685095 2016

2

理想的には、.gitエントリを含むディレクトリのディレクトリツリーをクロールし、それらをさらに検索するのをやめることをお勧めします(git repos内にgit reposがない場合)。

問題は、標準findのでこの種のチェック(ディレクトリに.gitエントリが含まれていること)を行うとtest-exec述語を使用してユーティリティを実行するプロセスが生成されることです。

例外はfindboshシェルの組み込み(@schilyによって開発されたBourneシェルのPOSIX化されたフォーク)を使用する場合です。これには-call、新しいshインタープリターを生成せずにシェル内のコードを評価する述語があります。

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

または使用perlさん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' .

長いが、より速いzshさんprintf '%s\n' **/.git(:h)(全ての非隠しディレクトリに下降する)、またはGNU findfind . -name '.?*' -prune -o -type d -exec test -e '{}/.git' \; -prune -print1つの実行しtest、各非隠されたディレクトリのための新しいプロセスでコマンドを。


1
.git経由で-だけでなく、ファイルにすることができますgit worktree
スティーヴン・ペニー

1
@StevenPennyに感謝します。私はそれを知りませんでした。をに変更し-dました-e
ステファンChazelas

1

Locateを使用すると、次のディレクトリが見つかります。

locate .git | grep "/.git$"

結果リストは高速で、その後の処理も簡単です。


2
locate '*/.git'十分なはずです。
ステファンChazelas

0

使用する

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

timeこれで、の有無による違いを確認でき-pruneます。

これは、のソリューションに基づいていますman find。必要に応じて、CVSを編集できますsvn。マニュアルページの内容が続きます

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

次のプロジェクトのディレクトリとそれに関連するSCM管理ディレクトリを指定して、プロジェクトのルートを効率的に検索します。

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

この例では、-prune既に検出されているディレクトリへの不要な下降を防止します(たとえば、project3/src既に検出しているため、検索しませんproject3/.svn)。ただし、兄弟ディレクトリ(project2およびproject3)は確実に検出されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.