不删除跟踪的 Git 忽略文件

17

我对基本的git概念感到有些困惑 :/

在我的git托管网站进行一些操作之前,我正在本地Windows机上进行测试。

我已经有了:

gittesting/repo1:
    file.txt
    ignoreme:
        ignore.txt

而且

gittesting/repo2
    file.txt
    ignoreme:
        ignore.txt

Repo2是repo1的一个副本,ignoreme已经被追踪。ignore.txt在repo2中发生了变化,但我想停止追踪它,让git完全忽略它。问题是如果我创建一个.gitignore文件并添加ignoreme,那就太晚了,因为它已经被追踪了,所以我必须用git rm --cached ignore来取消追踪,但这样会标记为已删除,如果我将提交拉到repo1中,该目录将被删除而不是保留。

总结一下:

  1. ignore.txt在两个仓库中具有不同的内容。
  2. 我希望ignore.txt的内容保持原样,并且被git完全忽略。

我在网上搜索过,向IRC提问过,也看过相关的问题,但找不到解决方法。我知道这个示例看起来很琐碎,但这正是我在网站上需要做的事情,其中目录是Forum/cache。


编辑:

这有点像hack,我更喜欢更好的答案,但我最终做了以下操作:

cd repo2
echo "ignoreme" > .gitignore
echo "ignoreme/*" > .gitignore
git rm --cache -r ignoreme
git commit -m "Should ignore now"
cd ../repo1
mv ignoreme ignoreme2
git pull ../repo2
mv ignoreme2 ignoreme
5个回答

20

试试这个

git update-index --assume-unchanged ignoreme/ignore.txt

如果不更改存储库,Git 将忽略此文件的任何未来更改。要重新开始跟踪更改,请使用

git update-index --no-assume-unchanged ignoreme/ignore.txt

请注意,这只对当前工作副本生效,因此每次克隆存储库时都需要执行此操作。


1
这不会阻止文件被更改。它只会停止git显示文件已更改。如果您想完全防止对文件的更改,可以将其设置为只读。 - Michael Mior
3
如果你确实没有更改文件,使用--assume-unchanged是合法的。但如果你更改了它,你就是在欺骗 Git,这种行为往往不会有好结果。 - Seth Robertson
谢谢,正是我所需要的。 - prdatur
2
如果您实际上不更改文件,则无需使用“--assume-unchanged”。例如,您可能需要暂时修改不应提交到存储库的配置设置。我同意这也很危险,因为很容易忘记发生了什么,并避免提交重要更改。 - Michael Mior
我猜这个问题是一个“择优困境”问题...记得重新开始跟踪文件或者记得删除密码。两者都可能是灾难性的。 - gabeio
显示剩余2条评论

7
如果我理解您的问题正确,您希望repo2知道ignoreme/目录的存在,但您不希望Git关注该目录的任何修改。使用git rm --cached命令无法解决问题,因为这会告诉Git从现在开始停止跟踪此内容。

Git用子模块来解决此类问题。以下是Git Book的摘录(已加粗显示):

虽然rack是工作目录中的子目录,但Git将其视为子模块,当您不在该目录中时,不会跟踪其内容。相反,Git会记录它作为来自该存储库的特定提交。

您可以尝试以下操作:

  1. Copy the ignoreme/ directory to a new location, and make it a git repository

  2. Add it back as a submodule in repo2:

    git submodule add file:///path/to/ignoreme ignoreme
    git commit -m"Add ignoreme/ as a submodule"
    

ignoreme子模块现在已经固定到一个特定的提交版本。 repo2仍然跟踪子模块中的任何内容,但是除非您在子模块中提交更改,否则不会在repo2中跟踪ignoreme/中文件的更改。假设ignoreme/ignore.txt被某种方式修改:

$ git status
# On branch master
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#   (commit or discard the untracked or modified content in submodules)
#
#       modified:   ignoreme (modified content)
#
no changes added to commit (use "git add" and/or "git commit -a")

即使你运行了git add .,除非将ignoreme/ignore.txt提交到子模块中,否则更改不会被添加到索引中。
$ cd ignoreme
$ git commit -am"Time to change ignore.txt"
$ cd ..
$ git add .
$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:   ignoreme
#

然而,如果你想忘记子模块中的本地修改:
$ cd ignoreme
$ git reset --hard
$ cd ..

1

Git不存储目录。如果您想在Git中保留一个空目录,惯例是在其中放置一个名为.keepme的空文件,并将其提交。

至于这个问题,据我所知,您将无法从克隆中隐藏上游分支中的文件。这不是Git设计的功能。考虑其他选项,例如拆分为两个存储库(可能使用子树或子模块)。或者在上游保留一个单独的分支以供下游跟踪,并通过后接收钩子从该分支过滤ignore.txt

告诉我们更多为什么要这样做,也许有更好的方法。

无论如何,我希望您不要因为“安全”原因而尝试隐藏此文件-否则事情会变得更加复杂(例如,您必须从整个历史记录中清除它等)。


2
我总是更喜欢将.gitignore放在“空”目录的内部。 - user229044
定制化的方法是提交一个空的.gitkeep文件。原因是简洁明了的前缀:.* # 忽略点文件 !.git* # 但不包括那些配置存储库的文件,例如.gitignore、.gitkeep - Filip Dupanović
“.keepme”是一个广泛使用的习语。像往常一样,你可以违反惯例,按照自己的方式去做,但要自担风险。 - Alexander Gladysh
@AlexanderGladysh FWIW,我从未见过.keepme,但我见过.gitkeep和空的.gitignore - Michael Mior

0

检出包含该文件的提交将替换它,从具有该文件的提交过渡到没有该文件的提交将删除它。Git 无法做其他事情。 .gitignore 不会覆盖存储库,它是一种方便的方法,可以使您的状态报告保持简洁。

您可以将该文件制作为指向 git 领域之外某个地方的符号链接,这样可以轻松恢复由于检出错误历史而造成的损坏。如果这不是一个选项,则可以使用 filter-branch。


0

Git 只对未跟踪的文件应用忽略模式。您不能使用忽略模式来忽略已由 Git 跟踪的文件的更改。不过,可以参考 https://gist.github.com/1423106 了解人们解决该问题的方法。

请注意,如果您担心 .gitignore 文件本身,可以尝试使用 .git/info/excludes 来创建一个仅限于本地仓库的 .gitignore 文件。请注意,这将不会解决更改已跟踪文件的问题,只会为您提供补充的 .gitignores,这些文件将不会被跟踪。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接