将git的.gitignore规则应用于现有存储库

50

我开始在Xcode项目中使用Git,并最近发现可以使用.gitignore和.gitattributes文件来忽略编译器和系统产生的无用信息。既然我已经放置了.gitignore和.gitattributes文件,那么我该如何“应用”新的忽略规则并从版本控制中摆脱冗余内容?

我的 .gitignore 文件:

# xcode noise
*.modelv3
*.pbxuser
*.perspective
*.perspectivev3
*.pyc
*~.nib/
build/*

# Textmate - if you build your xcode projects with it
*.tm_build_errors

# old skool
.svn

# osx noise
.DS_Store
profile

我的.gitattributes文件内容如下:

*.pbxproj -crlf -diff -merge

谢谢!


2
+1 Chris在这里的评论中的链接对我来说比本页面上的任何内容都更好。 - Jorin
不不不,这才是正确的方法。大多数建议的答案都会重新提交所有文件。 - fregante
6个回答

64

以下是一种“取消追踪”任何文件的方法,这些文件在当前排除模式下本应被忽略:

(GIT_INDEX_FILE=some-non-existent-file \
 git ls-files --exclude-standard --others --directory --ignored -z) |
xargs -0 git rm --cached -r --ignore-unmatch --

这将使文件保留在你的工作目录中,但从索引中删除。

这里使用的技巧是向git ls-files提供一个不存在的索引文件,以便它认为没有被跟踪的文件。上面的Shell代码询问如果索引为空,则会忽略所有文件,并使用git rm从实际索引中删除它们。

在文件被“取消跟踪”之后,使用git status来验证是否删除了任何重要内容(如果是,请调整你的排除模式并使用git reset -- path恢复已删除的索引条目)。然后创建一个新的提交,省略掉“crud”。

“crud”仍将存在于旧提交中。如果你确实需要一个干净的历史记录,你可以使用git filter-branch来生成旧提交的干净版本(注意,使用git filter-branch将“重写历史记录”,因此如果有任何合作者在“crud”首次引入后拉取了你的历史提交,则不应轻易地进行操作)。


1
这个解决方案对我来说更有意义:https://dev59.com/L3M_5IYBdhLWcg3w-4nw - wfbarksdale
这个命令该如何执行?将其粘贴到终端中会出现错误“-bash: git: command not found”,但是我可以在该目录下执行git命令。 - memmons
@Answerbot:type git 会输出什么?听起来像是一个别名(或者 shell 函数?)。由于 git 对你来说不仅仅是一个普通的外部命令,所以当与临时环境变量赋值结合使用时(例如 FOO=bar git … 不会扩展你的 git 别名,并且你的 PATH 中也没有 git),导致 shell 失败。使用 xargs 也会失败,因为 xargs 是自己执行命令,而不是使用 shell 执行。你需要将你的 git 使用扩展到匹配你的别名/函数,或者使用一个包含相同效果的外部包装脚本。 - Chris Johnsen
感谢@ChrisJohnsen的详细回答。type git返回git is hashed (/usr/local/bin/git)。有没有关于扩展git以匹配或使用外部包装器的好参考资料? - memmons
@Answerbot:既然你的 git 确实不是外部命令,那么我的猜测就是错误的;扩展或包装不适用于你的 git,因为它不是别名或 shell 函数。我编写了一个命令,可以粘贴到(Bourne 兼容的)shell 中,并且在 kshbashzsh 中都可以正常工作。目前,我没有其他猜测,也不知道为什么你的 shell 会出现这些症状。 - Chris Johnsen

41

对于文件使用git rm --cached,对于build/目录使用git rm -r --cached


25
尽管那是准确的,但我从Google搜索中得到的答案并不有帮助,因为它只能逐个文件地处理。像Chris Johnsen所提供的答案一样,一次性解决所有应忽略的文件会更有帮助和高效。 - Brighid McDonnell
4
这是一个更好的答案:https://dev59.com/L3M_5IYBdhLWcg3w-4nw#1139797。 - James Billingham
这不必一次一个文件地进行。运行 git rm -r --cached * 来清除所有内容。 - cbartondock
甚至更好的答案,它正确地重新应用了gitignore。 - fregante

12

如果你已经在跟踪要忽略的文件,你需要使用以下命令将它们删除:

git rm --cached <file>

Git不会忽略已经被跟踪的文件(即使用git add添加过的文件)。


这个命令总是将文件标记为已删除... - Mladen Danic
@MladenDanic 没关系,git 表示它将文件视为已删除。由于 '--cached' 运算符的存在,文件实际上不会被删除,但是 git 现在有效地将其视为已删除。 - Chris Foster
但如果我没记错的话,它会从远程仓库中删除它,对吗? - Mladen Danic
是的,如果之后你推送的话。但我认为如果你这样做,那正是你想要的。 - Sven Koschnicke

2

mv the_file_i_want_to_ignore the_file_i_want_to_ignore.back

git rm the_file_i_want_to_ignore

mv the_file_i_want_to_ignore.back the_file_i_want_to_ignore

git status

git commit -m '忽略一些之前应该忽略的东西'

这是一个有点手动的工作流程,但这是我过去做这个的方式。


6
你真的想要使用 git rm --cached - Josh Lee

2
如果您想完全删除文件,那么这里有一份来自Github的方便参考(链接)
请注意:
1. 这将重写您的历史记录,因此最好在发布存储库之前执行此操作。 2. 请记住,旧的shas仍将存在于对象数据库中,但我链接的指南也会向您展示如何处理这些shas。

-1

您不应该"应用"更改。只需将.gitignore文件放在您的主目录中(如果要使其全局),或者放在项目根目录中(如果要使其仅对该项目独有)。

编辑:我意识到您可能因为已经添加了不想跟踪的文件而遇到了这个问题。下面是gitignore手册对此的说明:

请注意,所有gitignore文件实际上只关注尚未被git跟踪的文件;为了忽略已跟踪文件中未提交的更改,请参阅git update-index --assume-unchanged文档。


那些不喜欢这个答案的人,请提供反馈,说明你为什么不喜欢它。没有理由就进行负评是没有帮助的。 - Nick Res

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