2008-11-10 67 views
51

只是說我有一個文件:「HelloWorld.pm」在多個子目錄一個Git倉庫內。我可以使用Git在存儲庫中搜索匹配的文件名嗎?

我想發出一個命令來查找所有的文件匹配「HelloWorld.pm」的完整路徑:

例如:

/path/to/repository/HelloWorld.pm 
/path/to/repository/but/much/deeper/down/HelloWorld.pm 
/path/to/repository/please/dont/make/me/search/through/the/lot/HelloWorld.pm 

如何使用Git的有效找到所有匹配給定文件名的完整路徑?

我知道我可以在Linux/Unix find命令這樣做,但我希望能避免掃描尋找文件名的情況下,所有子目錄。

回答

19

嘗試:

git ls-tree -r HEAD | grep HelloWorld.pm 
+1

或Windows:`git的LS-樹-r HEAD | findstr HelloWorld.pm` – 2014-08-13 10:10:06

79

git ls-files會給你在庫中的所有文件的列表。您可以傳入一個模式來獲取匹配該模式的文件。

git ls-files '*/HelloWorld.pm' 

如果你想通過自己的內容,找到一組文件和grep的,你可以做到這一點與git grep

git grep some-string -- '*/HelloWorld.pm' 
+0

ls文件也可以採用一種模式。 – 2011-04-15 20:20:26

+0

@jleedev啊,對。更新了我的答案,以簡化它並修復`git grep`中的模式問題。 – 2011-04-15 20:25:42

+0

(煩人,它被稱爲[pathspec](http://www.kernel.org/pub/software/scm/git/docs/gitglossary.html#def_pathspec)在gitglossary(7),但該術語並不一致地使用) – 2011-04-15 20:34:05

38

嗯,原來的問題是關於資源庫。一個存儲庫包含多個提交(至少在一般情況下),但只有通過一次提交才能搜索到的答案。

因爲我無法找到一個答案,真正搜索整個提交歷史我寫了一個快速蠻力腳本的git-發現按名稱需要(幾乎)所有提交考慮。

#! /bin/sh 
tmpdir=$(mktemp -td git-find.XXXX) 
trap "rm -r $tmpdir" EXIT INT TERM 

allrevs=$(git rev-list --all) 
# well, nearly all revs, we could still check the log if we have 
# dangling commits and we could include the index to be perfect... 

for rev in $allrevs 
do 
    git ls-tree --full-tree -r $rev >$tmpdir/$rev 
done 

cd $tmpdir 
grep $1 * 

也許有一種更優雅的方式。

請注意參數傳遞到grep的瑣碎的方式,所以它會匹配文件名的部分。如果不需要,則錨定您的搜索表達式和/或添加合適的grep選項。

對於深層次的歷史記錄,輸出可能太吵,我想過一個腳本,它將 修訂列表轉換成一個範圍,就像git rev-list可以做的事情相反。但到目前爲止,這仍然是一個想法。

3

[這是一個有點評論濫用,我承認,但我還不能發表評論,我想我會提高@烏韋 - geuder的答案。]

#!/bin/bash 
# 
# 

# I'm using a fixed string here, not a regular expression, but you can easily 
# use a regular expression by altering the call to grep below. 
name="$1" 

# Verify usage. 
if [[ -z "$name" ]] 
then 
    echo "Usage: $(basename "$0") <file name>" 1>&2 
    exit 100 
fi 

# Search all revisions; get unique results. 
while IFS= read rev 
do 
    # Find $name in $rev's tree and only use its path. 
    grep -F -- "$name" \ 
     <(git ls-tree --full-tree -r "$rev" | awk '{ print $4 }') 
done < \ 
    <(git rev-list --all) \ 
    | sort -u 

再次+1 @烏韋 - geuder爲了一個很好的答案。

如果你有興趣在BASH本身:

除非你在一個(使用一個這樣的數組時,如:for item in "${array[@]}")保證字拆分的for循環,我強烈建議使用while IFS= read var ; do ... ; done < <(command)時你遍歷命令輸出被換行分隔(或read -d''當輸出由空字符串$'\0'分隔)。雖然git rev-list --all是保證使用40字節十六進制字符串(無空格),我從來不喜歡冒險。我現在可以輕鬆地將命令從git rev-list --all更改爲任何生成行的命令

我還推薦使用內置的BASH機制來注入輸入和過濾器輸出而不是臨時文件。

7
git ls-files | grep -i HelloWorld.pm 

grep的-i使grep的不區分大小寫。

0

Uwe Geuder(@ uwe-geuder)的腳本很棒,但實際上並不需要將每個ls-tree輸出轉儲到它自己的目錄中,而不需要過濾。

更快速,使用更少的存儲:運行在輸出上的grep,然後儲存,如本gist

相關問題