有没有一种方法可以在git checkout中使用通配符?

87
我想要做的是检出单个文件或一组具有相同名称部分的文件,如下所示:
git checkout myBranch */myFile.md 和
git checkout myBranch -- */*Test* (不确定“--”部分)
而不是:
git checkout myBranch src/main/java/a/deep/package/structure/myFile.md 和
git checkout myBranch src/test/java/a/deep/package/structure/TestOne.java git checkout myBranch src/test/java/a/deep/package/structure/TestTwo.java git checkout myBranch src/test/java/a/deep/package/structure/resources/TestData.sql
我知道某些 git 命令(如 diff 和 add)具有一些有限的通配符功能,但在 checkout 中找不到任何东西。有办法吗?
编辑:我在 Linux 上使用 git 1.7.9.5。也可以接受 git 和 shell 命令的工作组合。

奇怪,git diff 对通配符好像不支持,但 git addcommit 支持。 - TankorSmash
9个回答

96
Git可以使用fnmatch(3)处理通配符。请参阅Git词汇表中的pathspec条目。但是,为确保git可以看到通配符,必须对其进行转义,否则您的shell将首先扩展它们。通常,我在单引号之间使用通配符。
git checkout myBranch -- '*/myFile.md'

通配符应用于整个名称,包括目录。
如您在文档中所见,pathspec 还允许使用魔术签名来更改 pathspec 的解释方式。例如,您可以使用 icase(可以键入“:(icase)*readme*”以查找所有自己的 readme)来获得不区分大小写的路径。
我在此引用 @bambams 的评论,以防 Windows 出现问题:

This is not working for me in Windows with 2.8.1.windows.1 and I'm utilizing Git from the cmd.exe shell so no globbing built in. There is however a solution if you're in such a sorry state. Combine git diff --name-only and xargs to achieve your goal:

git diff --name-only <COMMIT> -- <GLOB>... | xargs git checkout <COMMIT> 

2
有点晚了,但无疑是正确的。谢谢 @coredump,是时候移动绿色勾号了 :) - kostja
@kostja 是的,肯定晚了一点 ;-) 谢谢 - coredump
4
不能使用通配符匹配分支名称,例如git checkout my* - dumbledad
6
在Windows操作系统的2.8.1.windows.1版本中,我无法使用该方法,并且我是在cmd.exe shell中使用Git,因此没有内置的globbing功能。不过,如果你也处于类似状况中,仍然有解决方法。可以结合使用git diff --name-only和xargs来实现你的目标:git diff --name-only <COMMIT> -- <GLOB>... | xargs git checkout <COMMIT> -- - bambams
1
Git v2.13.2.windows.1 不需要转义单引号,git checkout */myFile.md 可以正常工作并浏览子文件夹。 - CAD bloke
在Windows上,@bambams有一个很好的解决方法,但是我的路径上没有xargs。最近的Git版本在\<path to Git>\usr\bin中包含了许多其他Linux工具,因此我将其添加到我的路径中,一切都准备就绪了。 - Myk Willis

24
Git 不处理通配符,但是您的 shell 可以。
尝试这样做:
git checkout myBranch **/myFile.md

并且

git checkout myBranch  **/*Test*

使用**,你的shell将会在当前工作目录下的所有子目录中查找文件。

按照广告所述正常工作。谢谢Intrepidd。 - kostja
12
请注意,这仅考虑外壳程序看到的文件,例如已检出的文件。它不会检出尚未存在的文件。 - vonbrand
1
@vonbrand:有没有办法处理那些在提交中但当前不在文件系统中的文件? - Gauthier
3
哪个shell?我正在使用Cygwin的bash,但这对我不起作用。 - bacar
愚蠢的问题 - 如何包含所有*Test*的情况,即使文件在根目录中? ** / * Test *不包括根目录中的文件(我相信)。 - Marcus Leon
1
@MarcusLeon 可能取决于shell,但我尝试过zsh并且它可以工作。 - Intrepidd

2

使用Windows git bash和xargs

git difftool myBranch --name-only *.java | xargs git checkout myBranch

2

Powershell

@(gci -Recurse *test* | Resolve-Path -Relative) | %{git checkout mybranch -- $_)

gci 生成一个符合条件(*test*)的所有文件列表,然后将其传输到 Resolve-Path 以获取相对路径。最后,文件名的扁平化 (@) 列表被传输到 git 调用中(每找到一个文件执行一次)。


0
如果您需要获取提交的文件,无论它们是否在提交中被更改,可以使用以下命令:
git ls-tree --name-only -r myBranch | grep myFilePattern | xargs git checkout myBranch

0

我的任务是检查几个按照一定模式命名的文件:

  • ./a/b/c/FirstTest.java
  • .d/e/f/SecondTest.java
  • ./g/h/i/ThirdTest.java

我使用了以下 Bash 命令:

# 1. Find files named after "*Test.java" pattern.
# 2. Execute checkout command on every found file.

find . -name "*Test.java" -exec git checkout master {} \;

首先,您可以使用简单的echo测试find命令,它只会打印给定的文本(在我们的情况下是{},它将被shell替换为当前找到的文件名):

find . -name "*Test.java" -exec echo {} \;

0

知道 git 返回从第三个字符开始的分支列表名称,可以通过[mask]定义所需的分支来切换:

BRANCH_NAME=$(git branch --list | grep [mask] | cut -c3-)
git checkout ${BRANCH_NAME}

0

其他答案都没有用,但是bambams的评论起作用了。我将其制作成一个bash函数,接受两个参数。

用法:

gitcheckout myBranch '*file*'

gitcheckout()
{
    GIT_DIR=$(git rev-parse --git-dir 2>/dev/null); 
    pushd .;
    cd $GIT_DIR/../;
    git diff --name-only $1 -- $2 | xargs git checkout $1 --;
    popd;
}

0
如果您有一个.gitignore文件或未跟踪的文件,并且想要在git checkout中使用通配符,那么可能会遇到问题,解决方法如下:
git ls-files '*/myFile.md' | tr '\n' '\0' | xargs -0 -L1 -I '$' git checkout -- '$'

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接