Git clean排除嵌套的子目录

时间:2014-01-09 16:40:08

标签: git

我在使用git clean时遇到了问题,并排除了嵌套目录的选项。

我想从repo中清除所有未提交的文件,不包括vendor/bundle目录。 我的测试报告喜欢:

debugg-dir/
  .git/
  file.txt
  not-commited-file
  not-commited-folder
      another-not-commited-file
  vendor/
    bundle/
      another-not-commited-file

重现测试回购:

git init debugg-dir && cd debugg-dir
touch file.txt && g a . && git ci -m "Commit" 
mkdir -p not-commited-folder && touch not-commited-folder/another-not-commited-file
mkdir -p vendor/bundle && touch vendor/bundle/another-not-commited-file && touch not-commited-file

Git clean命令:

git clean -d -x -n -e vendor/bundle

清洁后预计有:

debugg-dir/
  .git/
  file.txt
  vendor/
    bundle/
      another-not-commited-file

有没有正确的方法从git clean命令中排除嵌套的dir?

#编辑:

解释

这种情况没有“干净”的解决方案。 Git clean用git clean -d -x -n -e dir_name排除dirs,但这不适用于嵌套目录。 这是git中的错误还是有一些很好的理由?更多信息为什么这不起作用你可以找到in source。长话短说,排除模式仅适用于字符串,直到模式中的第一个'/'。

我的解决方案:

cd vendor && git clean -dxf -e bundle && cd ..
git clean -dxf -e vendor

有了这个我设法只保留嵌套的目录和它的内容。

4 个答案:

答案 0 :(得分:1)

这是因为vendor是一个未跟踪的目录,您使用的是- d选项。

正如the manual所说:

  

-d

     
    

除了未跟踪的文件外,还删除未跟踪的目录。如果未跟踪的目录由不同的git存储库管理,则默认情况下不会删除它。如果你真的想删除这样的目录,请使用-f选项两次。

  

我可以使用此命令获得所需的输出:

git clean -x -n

这在真实场景中有效吗?如果没有,您可能希望在vendor/bundle中提交其他文件,然后查看。

答案 1 :(得分:1)

根据git clean --help

  

git-clean - 从工作树中删除未跟踪的文件

如果您添加Floyd Pink关于-d的解释(很快,该选项也允许删除未跟踪的目录而不仅仅是文件),那么这也是您删除vendor的原因。<登记/> 现在,据说你只想删除not-commited-file(所以,没有任何未跟踪的目录也没有another-not-commited-file我认为你应该git clean交互模式,所以

git clean -i

会询问您如何为每个未跟踪的文件做些什么(只有文件,如果您也想要提供目录,请添加-d。)
<登记/> OP编辑问题后编辑:您也想删除目录,因此请运行

git clean -i -d

编辑2 :由于-e的含义在手册中并不清楚,我用Google搜索并找到了this。我建议阅读对话,因为它解释了-e的真正含义,而不是OP的意图(或者可以从手册中理解)

编辑3 ,更多关于-e切换。根据我在编辑2 中找到的链接,我决定尝试一下。结果,我希望这将有助于您理解-e 内容.gitignore,所以我不提交临时文件:

*.tmp

我发出了命令:

echo "Temporary file" > sample.tmp
git st //which of course shows *nothing to commit, working directory clean*
git clean -fX -e \!sample.tmp

结果是删除了具有tmp扩展名的所有文件(由于-X)但是sample.tmp。所以,总而言之,-e真正做了什么,在我的理解中,如果我错了,请纠正我,不要排除清洁过程中的模式,但

  

从清除规则中排除模式(在我的情况下,规则是删除所有.tmp文件,我从中手动排除了sample.tmp)。

答案 2 :(得分:1)

这是我用来清理git repos的代码,同时排除了venv/目录和子目录:

git clean -nXd -e \!venv -e \!venv/**

对于您来说,第一个排除就足够了:

git clean -nXd -e \!vendor

第二个排除项\!venv/**适用于.gitignore中的其他规则,这些规则可能适用于供应商内部的文件或文件夹。例如:

.gitignore    
*.log

vendor/
  bundle/
    another-not-commited-file.log

答案 3 :(得分:0)

Git 2.24(2019年第四季度)使git clean在嵌套Git 存储库(不仅是文件夹)方面更加强大

请参见commit 69f272b(2019年10月1日)以及commit 902b90ccommit ca8b539commit 09487f2commit e86bbcfcommit 3aca580,{{3} },commit 29b577bcommit 89a1f4acommit a3d89d8commit 404ebcecommit a5e916ccommit bbbb6b0(由commit 7541cc5)(2019年9月17日)。< br /> (由Elijah Newren (newren)Junio C Hamano -- gitster --中合并,2019年10月11日)

  

clean:避免在嵌套的Git存储库中删除未跟踪的文件

     

用户希望嵌套git存储库中的文件可以单独放置,除非有足够的强制(带有两个-f)。

     

不幸的是,在某些情况下,git会删除嵌套存储库中的跟踪文件(可能是脏文件)和未跟踪文件。

     

为解释这种情况是如何发生的,我们来比较一下两种情况。

     

首先,采用以下示例设置(假​​设我们已经在git repo中):

git init nested
cd nested
>tracked
git add tracked
git commit -m init
>untracked
cd ..
  

在此设置中,一切正常。运行“ git clean -fd”将导致fill_directory()返回以下路径:

nested/
nested/tracked
nested/untracked
  

然后correct_untracked_entries()会注意到可以将其压缩为:

nested/
  

然后由于“ nested/”是目录,因此我们将调用remove_dirs("nested/", ...),它将检查is_nonbare_repository_dir()然后决定跳过它。

     

但是,如果有人还创建了一个忽略的文件:

>nested/ignored
  

然后运行“ git clean -fd”将导致fill_directory()返回   相同的路径:

nested/
nested/tracked
nested/untracked
  

但是correct_untracked_entries()会注意到我们已经忽略了条目   在nested /下,因此可以简化此列表为

nested/tracked
nested/untracked
  

由于这些不是目录,因此我们没有call remove_dirs(),这是唯一经过is_nonbare_repository_dir()安全检查的地方,这导致我们同时删除了未跟踪的文件和被跟踪的文件(并且可能很脏)文件。

     

此问题的一种可能的解决方法是遍历每个路径的父目录,并检查它们是否代表非裸存储库,但这很浪费。
  即使我们添加了某种形式的缓存,也仍然很浪费,因为我们甚至应该首先进入“ nested /”就可以代表一个非裸存储库。
  在DIR_SKIP_NESTED_GIT上添加dir_struct.flags标志,并使用它来防止fill_directory()和朋友进入嵌套的git repos。

     

通过此更改,我们还修改了commit aafb754中添加的两个回归测试(“ t7300:添加测试以记录干净和嵌套git的行为”,2015-06-15,Git v2.6.0 -rc0)。
  那个提交,它的系列,或者邮件列表上该系列的前六个迭代都讨论了为什么这些测试编码了他们的期望。
  实际上,看来他们的目的只是为了测试现有行为,以确保性能变化不会改变行为。
  但是,这两个测试直接与联机帮助页上的说法相矛盾,该手册页声称需要两个-f来删除嵌套git存储库下的文件/目录。
  尽管有人可能会说用户给出了一条与嵌套存储库中的文件/目录相匹配的显式路径,但是一旦您沿着这条路线走,用户就会很难理解它的滑坡(例如,如果他们指定了“ {{ 1}}“?)
  也很难解释确切的行为是什么。通过使其变得非常简单来避免此类问题。

     

最后,仍然存在一些错误,其中git clean -f -d '*.c'清理不充分(例如,缺少嵌套的-ffd),而.git可能清理了错误的文件(注意外部-ffdX而非内部)。
  此修补程序根本无法解决这些情况(并且不会更改相对于这些标志的行为),仅在给定单个.gitignore时修复了处理。
  有关-f错误的更多讨论,请参见commit 91479b9