【问题标题】:Recursively add files by pattern按模式递归添加文件
【发布时间】:2011-02-20 18:13:42
【问题描述】:

如何通过位于不同目录中的模式(或 glob)递归地添加文件?

例如,我想用一个命令添加A/B/C/foo.javaD/E/F/bar.java(以及其他几个java 文件):

git add '*.java'

很遗憾,这并没有按预期工作。

【问题讨论】:

标签: git glob filepattern


【解决方案1】:
我在GNUmakefile 中使用的一个变体

.PHONY: docs
docs:
    @echo docs
    bash -c "if pgrep MacDown; then pkill MacDown; fi"
    bash -c 'cat $(PWD)/HEADER.md                >  $(PWD)/README.md'
    bash -c 'cat $(PWD)/COMMANDS.md              >> $(PWD)/README.md'
    bash -c 'cat $(PWD)/FOOTER.md                >> $(PWD)/README.md'
    bash -c 'pandoc -s README.md -o index.html'
    bash -c "if hash open 2>/dev/null; then open README.md; fi || echo failed to open README.md"
    #git add --ignore-errors *.md
    git ls-files -co --exclude-standard | grep '\.md/$\' | xargs git 



【讨论】:

    【解决方案2】:

    由于这里没有提到,还可以考虑使用“magic signature:/ 在项目根目录下递归添加任何匹配的内容:

    git add :/*.{java,pom}
    

    发送至:https://stackoverflow.com/a/64210713/2586761

    【讨论】:

    • 您介意解释一下您的路径规范以及它的目的吗?我猜你的意思是添加所有带有.java.pom 扩展名的文件,从项目根目录开始,即使有人可能在其他地方调用git add。此外,在花括号上提供一些解释/文档也很棒。我自己无法让它工作
    • 嗨@CervEd - 是的 - 你已经确定了路径规范的用例和解释。我不确定卷曲 - 它可能是一个 bashism(我刚刚再次测试它,它在 bash 上对我有用),但我没有找到任何特定于 git pathspec 的参考,抱歉?‍♂️ 我建议搜索 bash 通配符和扩展 ?
    • 感谢您的信息。它在 CMD 中没有按预期工作,这就是为什么我猜这是在成为 git 的路径规范之前由 shell 扩展的原因。
    【解决方案3】:

    Sergio Acosta's answer 可能是您最好的选择,如果某些要添加的文件可能尚未被跟踪。如果您想将自己限制在 git 已经知道的文件中,您可以将 git-ls-files 与过滤器结合使用:

    git ls-files [path] | grep '\.java$' | xargs git add
    

    Git 本身并没有提供任何花哨的机制来执行此操作,因为它基本上是一个 shell 问题:如何获取文件列表以作为给定命令的参数提供。

    【讨论】:

    • 谢谢!我稍微改进了你的命令,现在它正在做我正在寻找的事情:git ls-files -co --exclude-standard | grep '\.java$' | xargs git add
    • 这样的 xargs 对我不起作用,因为文件名中有空格......你觉得这个版本怎么样? git ls 文件。 | grep -ie '\.bat$' |同时读取 x;做 git add "$x";完成
    【解决方案4】:

    添加尚未提及的 Windows 命令行解决方案:

    for /f "delims=" %G in ('dir /b/s *.java') do @git add %G
    

    【讨论】:

      【解决方案5】:

      在 ~/.gitconfig 中加入一行

      [alias] addt = !sh -c 'git ls-files | grep \"\\.$1*\" | xargs git add' -

      如果你想添加所有修改过的java文件可以这样做: git addt java

      同样,如果你想添加所有修改过的python文件可以这样做: git addt py

      【讨论】:

        【解决方案6】:

        您可以使用git add [path]/\*.java从子目录添加java文件,
        例如git add ./\*.java 当前目录。

        来自git add documentation

        Documentation 目录及其子目录下的所有*.txt 文件中添加内容:

        $ git add Documentation/\*.txt
        

        请注意,星号* 在本例中是从shell 中引用的;这让命令包含来自Documentation/ 目录的子目录的文件。

        【讨论】:

        • @MichelKrämer 可能不是,但现在是。
        • 这是最好的解决方案,也适用于 windows。
        • "星号 * 是从 shell 中引用的"。我想你的意思是“逃脱”。在任何情况下,反斜杠都会阻止 shell 扩展它。
        • @gwideman 我认为你是对的,但不是我。引用自文档git-scm.com/docs/git-add#_examples
        【解决方案7】:

        只需使用git add *\*.java。这将在根目录和所有子目录中添加所有 .java 文件。

        【讨论】:

        • 很好的答案。我做了 git add */pom.xml 添加所有文件名 pom.xml.
        【解决方案8】:

        我只想添加基于git status 具有特定字符串的文件:

        git status | grep string | xargs git add

        然后能够git commit -m 'commit msg提交所有更改的文件,文件标题中带有“字符串”

        【讨论】:

          【解决方案9】:

          如“git: How do I recursively add all files in a directory subtree that match a glob pattern?”中所述,如果您正确地转义或引用您的路径规范通配符(如'*.java'),那么是的,git add '*.java'

          Git 2.13(2017 年第二季度)改进了交互式添加:

          参见Jeff King (peff)commit 7288e12(2017 年 3 月 14 日)。
          (由 Junio C Hamano -- gitster -- 合并于 commit 153e0d7,2017 年 3 月 17 日)

          add --interactive:不要使用 ls-files 扩展路径规范

          当我们想要获取修改文件的列表时,我们首先使用“ls-files”扩展任何用户提供的路径规范,然后将生成的路径列表作为参数提供给“diff-index”和“diff-files” "。
          如果您的路径规范扩展到大量路径,您可能会遇到以下两个问题之一:

          1. 操作系统可能会抱怨参数的大小 列表,并拒绝运行。例如:

            $ (ulimit -s 128 && git add -p drivers)
            Can't exec "git": Argument list too long at .../git-add--interactive line 177.
            Died at .../git-add--interactive line 177.
            

          这是在 linux.git 存储库中,“驱动程序”目录中有大约 20K 文件(在这种情况下,它们都没有被修改)。 “ulimit -s”技巧对于在 Linux 上显示问题是必要的,即使对于如此庞大的路径集也是如此。
          其他操作系统的限制要小得多(例如,在 OS X 上看到的实际案例只有 5K 文件)。

          1. 即使它确实有效,它也确实很慢。路径规范 代码没有针对大量路径进行优化。这里是 没有 ulimit 的情况相同:

            $ time git add -p drivers
              No changes.
            
            real  0m16.559s
            user    0m53.140s
            sys 0m0.220s
            

          我们可以通过完全跳过“ls-files”来改进这一点,只需将原始路径规范提供给 diff 命令。

          从历史上看,“diff-index”支持的 pathspec 语言较弱,但现在已不再如此。

          【讨论】:

            【解决方案10】:

            使用zsh,您可以运行:

            git add "**/*.java"
            

            您的所有*.java 文件都将被递归添加。

            【讨论】:

            • 谢谢你,但我在 Windows 上使用 msysgit,它只有一个 bash。
            • 好吧,我看到有一个用于 windows 的 zsh shell...你会帮自己一个忙,用它代替 bash,恕我直言。
            • zsh的windows移植是基于非常老的版本,一直崩溃(比如我输入ls)。
            • 哇,完美。我不知道这个功能!
            • 这与zsh无关。我认为这个答案错过了您想要将通配符完整的路径传递给 git 并让 git 处理它的观点。因此,您希望防止您使用的任何 shell 扩展通配符。为此,您需要以适合您正在使用的外壳的方式引用它。有关详细信息,请参阅其他答案。
            【解决方案11】:

            如果您已经在跟踪您的文件并对其进行了更改,现在您想根据模式有选择地添加它们,您可以使用--modified 标志

            git ls-files --modified | grep '<pattern>' | xargs git add
            

            例如,如果你只想在这次提交中添加 CSS 更改,你可以这样做

            git ls-files --modified | grep '\.css$' | xargs git add
            

            更多标志请见man git-ls-files

            【讨论】:

              【解决方案12】:

              Sergey's answer(不要相信我)正在工作:

              You can use git add [path]/\*.java
              

              使用最近的 git:

              $git version
              git version 1.7.3.4
              

              测试文件:

              $find -name .git -prune -o -type f -print | sort
              ./dirA/dirA-1/dirA-1-1/file1.txt
              ./dirA/dirA-1/dirA-1-2/file2.html
              ./dirA/dirA-1/dirA-1-2/file3.txt
              ./dirA/dirA-1/file4.txt
              ./dirB/dirB-1/dirB-1-1/file5.html
              ./dirB/dirB-1/dirB-1-1/file6.txt
              ./file7.txt
              

              Git 状态:

              $git status -s
              ?? dirA/
              ?? dirB/
              ?? file7.txt
              

              添加 *.txt:

              $git add \*.txt
              

              更新状态:

              $git status -s
              A  dirA/dirA-1/dirA-1-1/file1.txt
              A  dirA/dirA-1/dirA-1-2/file3.txt
              A  dirA/dirA-1/file4.txt
              A  dirB/dirB-1/dirB-1-1/file6.txt
              A  file7.txt
              ?? dirA/dirA-1/dirA-1-2/file2.html
              ?? dirB/dirB-1/dirB-1-1/file5.html
              

              【讨论】:

                【解决方案13】:

                有点离题(与 git 无关),但如果您使用的是 linux/unix,解决方法可能是:

                find . -name '*.java' | xargs git add
                

                如果您希望路径带有空格:

                find . -name '*.java' -print0 | xargs -0 git add
                

                但我知道你问的不是这个。

                【讨论】:

                • 这种方法的小问题——如果你“找到”一个与你的 .gitignore 匹配的文件,那么 git 会抱怨你试图添加一个你告诉它忽略的文件。
                • @yoyo - 我刚刚在最后添加了 -f ,并且解决了这个问题
                • @Maslow,它将强制添加文件,即使它应该被忽略(基于 .gitignore)。我希望得到投诉而不是添加文件(这是默认行为。)
                • 这比让 git 执行通配符扩展有什么好处?
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2014-05-09
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多