停止git从静默地破坏ignorefiles(git中的bug?)?

sab*_*ton 8 git

我找到了一种方法,git不会要求你藏匿,而是默默地删除你认为在.gitignore中安全的文件.即使您在初始提交后拥有相同的忽略文件,也是如此.

当您在提交中删除了所述文件但在.gitignore中列出然后您签出另一个存在的提交时,会发生此问题:

git init
mkdir ignored/
echo stuff > ignored/file
echo otherstuff > otherfile
git add -A
# Opps added my ignored folders files
# Forgeting to rm --cache
echo ignored/ > .gitignore ; git add .gitignore
git commit -m 'accidentally add ignored/file'
git status
touch dummyfile; git add dummyfile
# Remembered to rm --cache
git rm --cache -rf ignored/file #This file is now vulnerable to clobber
git commit -m 'add stuff'
echo somechange >> ignored/file

## Wait for it..
git checkout HEAD~
## somechange has been silently clobbered!!

# Please paste first paragraph, observe and then past the second.
# Note both commits have the correct ignore file and are not immune!
Run Code Online (Sandbox Code Playgroud)

(在将上面的代码粘贴到终端之前,cd到一个空文件夹)

反正有没有阻止这个无声的咒语?

tor*_*rek 6

这不是一个错误(或者至少,git开发人员不认为它是一个).

的内容.gitignore不是 "文件应该被忽略"或"不应该触及路径名称"; 相反,它们是"不会自动添加的路径,并且被禁止显示为未跟踪"(这使得.gitignore名称不佳).

一旦您提交了文件,或者甚至将其添加到索引中,它就不再被忽略,无论它是否列在.gitignore.

对于某些文件,您可以使用git update-index --assume-unchanged或(更好)git update-index --skip-worktree,但一般情况下,如果您不小心提交了一个您不应该拥有的文件,并且您希望它被忽略,则必须"重写历史记录"以将其完全从存储库中删除得到好的行为.如果你没有推送任何内容并且几乎没有包含不需要的文件的提交,那就不是太难了,但是如果你已经推送或者有很多这样的提交会更难.

另请参阅Git - "假设未更改"和"跳过工作树"之间的差异.

[2016年12月添加的文字]

技术细节

对于Git,跟踪文件有一个简短而简洁的定义:当且仅当索引中有条目时才跟踪文件.

"假设未更改"和"跳过工作树"事物是您可以在索引中手动设置或清除的标志.它们是单独的标志,可以单独设置,但不清楚设置它们意味着什么."假设未改变" 的意图仅仅是让Git更快,允许它假设文件没有改变,因此不需要更新git add,而"skip worktree"标志的意图是告诉Git"放手":不要只是假设它没有变化,尽量保持不变.这比看起来第一次脸红更难; 有关此内容的更多信息,请参阅上面的链接帖子.

为了设置这些标志,文件必须具有索引条目,因此必须对其进行跟踪.

如果跟踪文件,则可能也可能不会忽略该文件.这些有很多来源:不仅仅是顶级.gitignore,它包含Git的pathspec变体的列表(每行一个),仅限于全局匹配和否定,还.gitignore包含存储库中每个子目录中的文件,文件$GIT_DIR/info/exclude是否存在,以及core.excludesFile如果该配置条目存在而命名的文件.要查找是否以及为何忽略文件,请使用git check-ignore自Git 1.8.2版本开始提供的文件.该-v选项告诉您哪个控制文件将文件标记为忽略.

不幸的是,正如在这个答案的问题中,"被忽略"有两个含义.匹配一个忽略路径使Git对未被跟踪的文件保持安静,这使得Git可以随意破坏该文件.