首页 > 解决方案 > 如何在此递归查找和替换中引用当前路径?

问题描述

免责声明:(离题警告)这不是关于输出在 repo 中实际检测到的被忽略文件的列表。这是关于被忽略的路径,即使实际上没有文件与这些路径之一匹配。


上下文:我正在尝试编写一个 git 别名以递归地“展平”所有 .gitignore 模式并输出从顶层看到的路径列表。

我的意思是举个例子:

├─ .git
├─ .gitignore
└─ dir1
    ├─ .gitignore
    ├─ file1.txt
    └─ file2.txt

.gitignore文件中包含这些内容:

# (currently pointing at top-level directory)
$ cat .gitignore
some_path

$ cat dir1/.gitignore
yet_another_path
*.txt

我尝试有一个别名来输出一些类似的东西

$ git flattened-ignore-list
some_path
dir1/yet_another_path
dir1/*.txt

到目前为止我有什么?

我知道我可以在 repo 中搜索所有 .gitignore 文件

find . -name ".gitignore"

在这种情况下会输出

.gitignore
dir1/.gitignore

所以我试图将其与cat获取它们的内容(这些工作中的任何一个)结合起来

find . -name ".gitignore" | xargs cat
# or
cat $(find . -name ".gitignore")

结果:

some_path
yet_another_path
*.txt

这在技术上是预期的,但不幸的是对我想要实现的目标没有帮助。所以(终于!)到达我的实际问题:

对于 的每个结果,我如何find参考当前路径?(为了最终将其添加到行中)


怀疑 XY 问题的人的注意事项可能是这种情况,我的方法在这里可能只是幼稚,但也许不是,我不确定。例如,我没有考虑嵌套 .gitignore 文件可以引用上层文件或带有 .gitignore 的特殊语法的复杂情况**。我现在坚持非常简单的结构,所以如果你发现一个缺陷和/或可以提出完全不同的方法来实现相同的目标,我当然也会很高兴听到它。

标签: bashgitgitignore

解决方案


我尝试有一个别名来输出一些类似的东西

$ git flattened-ignore-list
some_path
dir1/yet_another_path
dir1/*.txt

不幸的是,这种方法是幼稚的(也许注定要失败,但也许不是),因为.gitignore文件中的条目有点复杂。

您提出的简单问题的简单答案是使用相对于顶级目录名称的前缀。由于find从不输出不必要的复杂名称,您可以通过直接字符串处理来做到这一点:

.gitignore
dir1/.gitignore

dir1告诉您,在读取第一个文件时,不要添加任何内容,而在读取第二个文件时,请添加到每个条目的前面。在 shell 中执行此操作有点棘手,但 bash 有所需的工具:您只需将行减去/.gitignore末尾的行,使用正则表达式替换或仅从任何有斜杠的内容中删除 11 个字符(如果我数正确的话)或者不是文字 10-character string .gitignore。将目录从/.gitignore名称之前的部分中取出并使用sedawk插入它,并在非注释条目前面加上斜线(并记住处理!条目略有不同)。

你可能最好单独处理顶层.gitignore——你可以直接复制它,必要时添加一个最后的换行符——然后.gitignore在不同的代码路径中处理子目录。

请注意,子目录.gitignore 不能引用它上面的东西:无论是否被忽略,dir1/.gitignore都无法改变。所以那部分不是问题。./foodir2/foo

有问题的部分,在dir1,条目:

*.txt

意味着顶层不仅应该忽略未跟踪的dir1/*.txt文件,还应该忽略dir1/sub/*.txt文件,dir1/sub/sub2/*.txt等等。然而,一个dir1条目阅读:

sub/*.txt

意味着顶层应该只忽略未跟踪的dir1/sub/*.txt文件,而不忽略任何dir1/sub/sub2/*.txt文件!

您也许可以使用更多代码来挽救这一点:在读取子目录.gitignore时,检查任何给定行中是否有嵌入的斜杠。嵌入的斜线不是最终的斜线,因为最终的斜线被删除以用于这种特殊的区分。

  • 如果条目包含嵌入的斜杠,则它仅适用于完整路径相对于子目录。因此,您可以dir1/在前面添加并完成,例如:

    dir1/foo/*.txt
    
  • 如果条目不包含嵌入的斜杠,则它适用于子目录及其所有嵌套的子子目录。您将需要允许任意数量的子目录。这可能是正确的,但它未经测试:

    dir1/*.txt
    dir1/**/*.txt
    

    (理论上也应该**/匹配子目录的空列表,因此只需要第二行,但实际上我发现在某些情况下不会发生这种情况。我不记得这是在其他路径规范、文件还是两者中。 ).gitignore

通常,大多数.gitignore条目似乎不包含嵌入的斜杠,因此与输入长度相比,您编写的任何成功的脚本都可能会产生一个几乎双倍长度的“扁平”忽略文件。


推荐阅读