停止git从默默地clobbering ignorefiles(bug在git?)? [英] Stop git from silently clobbering ignorefiles (bug in git?)?

查看:104
本文介绍了停止git从默默地clobbering ignorefiles(bug在git?)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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

  git init 
mkdir忽略/
回声的东西>忽略/文件
echo otherstuff> otherfile
git add -A
#Opps添加了我忽略的文件夹文件
#Forgeting to rm --cache
echo ignored /> .gitignore; git add .gitignore
git commit -m'意外添加忽略/文件'
git status
touch dummyfile; git add dummyfile
#记住rm --cache
git rm --cache -rf忽略/ file#这个文件现在容易受到clobber
的影响git commit -m'add stuff'
回声改变>>忽略/文件

##等待它..
git checkout HEAD〜
##某些变化已被无声地玷污!

#请粘贴第一段,观察,然后过第二段。
#注意这两个提交都有正确的忽略文件,并且不能免除!

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

有没有办法阻止这种沉默的clobber?

解决方案

这不是一个bug(或者至少, git开发人员并不认为它是一个)。

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



一旦你提交了一个文件,甚至将其添加到索引中,它就不会被忽略,不管它是否列在 .gitignore



对于某些文件,您可以使用 git update-index --assume-unchanged 或者(更好) git update-index --skip-worktree ,但是一般来说,如果你意外提交了一个你不应该拥有的文件,并且你希望忽略它,你必须重写历史记录,将其完全从存储库中取出来以获得良好的行为。如果你没有推送任何东西并且提交包含不需要的文件的提交,那么这并不难,但是如果你推送或者提交了很多这样的提交,就会更加困难。

另请参阅 Git - '假定 - 不变'和'skip-worktree'之间的区别



[文字如下2016年12月添加]



技术细节



是一个被跟踪文件的短,简单和甜美的定义:当且仅当在索引中有一个条目时才跟踪文件



假设不变和跳过工作树是您可以在索引中手动设置或清除的标志。它们是单独的标志,可以单独设置,但不清楚它们的设置意味着什么。 假定不变的 intent 仅仅是为了让Git更快,通过允许它假设文件没有改变,因此不需要被 git add ,而skip worktree标志的 intent 则是告诉Git手动关闭:不只是假设它没有改变,尽量保持不变。这比看起来乍一看更难;有关详情,请参阅上述链接的帖子



为了设置这些标志,文件必须有一个索引条目,所以它必须被跟踪。



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



不幸的是,这是一个答案,忽略有两个的含义。虽然匹配一个忽略路径让Git保持对未被跟踪的文件的安静,但它也使得Git可以随意 clobber 文件。


I have found a way that git will not ask you to stash but instead silently delete your files that you believed to be safe in .gitignore. This is true even if you had the same ignore file since your initial commit.

The problem occurs when you are in a commit that has a said file removed but listed in .gitignore and then you checkout another commit where it existed:

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!

(cd to an empty folder before pasting above code into terminal)

Is there anyway to prevent this silent clobber?

解决方案

It's not a bug (or at least, the git developers don't consider it to be one).

The contents of .gitignore are not "files that should be ignored" or "path names that should not be touched"; instead, they're "paths that don't get automatically added, and are suppressed from being shown as untracked" (which makes .gitignore a poor name).

Once you've committed a file, or even added it to the index, it's no longer ignored, regardless of whether it is listed in a .gitignore.

For some files, you can use git update-index --assume-unchanged or (better) git update-index --skip-worktree, but in general, if you've accidentally committed a file you should not have, and you want it ignored, you must "rewrite history" to take it entirely out of the repository to get good behavior. That's not too difficult if you haven't pushed anything and have few commits that contain the unwanted file, but much harder if you have pushed, or have many such commits.

See also Git - Difference Between 'assume-unchanged' and 'skip-worktree'.

[Text below added December 2016]

Technical details

For Git, there is a short, simple, and sweet definition of a tracked file: A file is tracked if and only if there is an entry for it in the index.

The "assume unchanged" and "skip worktree" things are flags you can manually set or clear in the index. They are separate flags and can be set individually, although it's not clear what it means to set both. The intent of "assume unchanged" is merely to make Git faster, by allowing it to assume that the file is not changed and hence does not need to be updated by git add, while the intent of the "skip worktree" flag is to tell Git "hands off": don't just assume it's unchanged, try hard to keep it unchanged. That's harder than it may look at first blush; for more about this, see the above linked post.

In order to set these flags, the file must have an index entry, so it must be tracked.

If a file is not tracked, it may or may not also be ignored. There are numerous sources for these: not just the top-level .gitignore, which contains a list (one per line) of a variant of Git's pathspec that is limited to glob matching and negation, but also .gitignore files within each sub-directory within a repository, the file $GIT_DIR/info/exclude if it exists, and the file named by core.excludesFile if that configuration entry exists. To find whether and why a file is ignored, use git check-ignore, available since Git version 1.8.2. The -v option tells you which control file marked the file as ignored.

Unfortunately, as in the question to which this is an answer, "ignored" has two meanings. While matching an ignore path keeps Git quiet about the file being untracked, it also makes Git feel free to clobber the file.

这篇关于停止git从默默地clobbering ignorefiles(bug在git?)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆