当公共存储库时,应该包含什么.gitignore文件? [英] What should contain .gitignore file when is a public repository?
问题描述
我一直在学习有关.gitignore文件的所有内容,但有一个问题我想解决。.gitignore应包含您要忽略的所有文件。因此,您应该忽略由操作系统、您正在使用的IDE生成的文件...我的问题出现在存储库在Github上时,人们可以克隆它并推送更改。这些人可以使用其他操作系统,也可以使用其他IDE。因此,gitignore应该忽略由这些其他操作系统和IDE生成的文件。
你应该怎么做?是否必须在gitignore中写入所有操作系统生成的和所有IDE生成的文件?
推荐答案
我想马上强调两个背景要点:
如果您拥有存储库,您设置规则。你为迁就他人所做的任何事情都是出于普遍的友好。
动词忽略是...往好了说,这很棘手。我稍后会描述我的意思。重要的是,在
.gitignore
中列出文件并不会完全忽略,除非您对"忽略"一词有一个奇怪的个人定义。
也就是说,友好的方法是让存储库只忽略项目将生成的文件。然后,让个人忽略文件忽略系统将生成的文件。
让我们使用一个具体的例子。假设您有一个使用Python的项目,其中运行python foo.py
会创建foo.pyc
、foo.pyo
和/或__pycache__/*
文件,这些文件都不应该提交。因此,您应该从:
*.pyc
*.pyo
__pycache__/
在您的.gitignore
中,因为使用您的项目的任何人--您、您的同事或其他任何人--最终都会得到这些特定于特定Python版本的Python"目标代码"文件,因此不应包括在内。
但假设您个人正在使用MacOS及其Finder。Finder程序创建名为.DS_Store
的文件。因此,您很可能会添加以下内容:
.DS_Store
到您的.gitignore
。这不是错误的,但它对任何使用Windows的人都没有任何好处。Windows人员需要忽略哪些文件?我不确定,我不用Windows。但是,Linux人员可能会忽略vim
编辑器创建的.*.swp
文件。
如果您将.DS_Store
放在您自己的$HOME/.gitignore
中,而Linux人员将.*.swp
放在他们的$HOME/.gitignore
中,那么所有人都会对您的项目有一个愉快的体验。此外,他们的项目没有列出.DS_Store
,因为他们是从Linux开始的,所以您会有一个愉快的体验。
这就是大意:您的项目(存储库).gitignore
应该列出在使用您的项目时将在工作树中找到的文件的名称或命名模式,但这不应该提交给项目。换句话说,它不是特定于操作系统的,而是特定于项目的。其他文件名模式-特定于操作系统、特定于编辑器、特定于IDE等等-可以包含在其他忽略文件中,因此不需要在项目的.gitignore
文件中列出。将它们列出在项目文件中不一定会伤害,但如果每个人员对事情都很明智,也没有什么帮助。
不是实际答案一部分的次要背景(您可以在此处停止阅读!)
人们对Git的.gitignore
文件感到困惑。(我做了,从StackOverflow上的数百个问题来看,几乎每个人都做了。)我认为很大一部分原因是误解了Git的存储模式。
关于Git的第一件事--可能是最重要的一件事--是Git不是关于文件的,也不是关于分支的。Git实际上是关于提交的。Git存储库的核心部分由两个数据库组成。大型数据库保存提交和支持提交所需的其他内部Git对象。
git clone
复制的是Git提交和其他Git对象的这个大型数据库。还有第二个更小的名称数据库:分支机构名称、标记名等。此数据库对其他Git可见,因此可以由git clone
复制,但通常不只是复制。相反,git clone
读取较小数据库并修改它,完全丢弃一些名称并更改其他名称。因此,当您使用git clone
时,您会得到一个大型数据库的副本(所有提交)和一个修改后的小型数据库副本。(我们不会太仔细地查看此处较小的文件,因为它不会影响.gitignore
个文件。)
提交本身都具有唯一的散列ID。这些是又大又丑的字母和数字字符串,例如b994622632154fc3b17fb40a38819ad954a5fb88
。Git存储库可以快速判断它是否具有与其他Git存储库相同的提交:发送Git的Git只列出散列ID。接收Git只检查:我是否具有该散列ID的提交?如果有,则接收Git已该提交。它不需要再次获得它。如果不是,则接收Git需要获得该提交。
这意味着您的第一个git clone
可能很慢:您可能需要获取许多MB的对象。然而,在此之后,更新克隆只是获得它们仍然需要的的任何新提交的问题。你的Git调用他们的Git,他们列出一些散列ID,你的Git知道要得到什么,他们的Git知道你拥有什么。或者,如果您有新的承诺要提供给他们,您的Git会调用他们的Git,向他们提供一些散列ID,他们可以说我已经有那个或我没有那个,给我!
但是,如果提交中的文件是冻结的、仅Git格式的,而您的计算机上的其他程序无法使用,那么您将如何实际使用这些文件?答案是:您不会。也就是说,您不会使用这些文件。Git要做的是提取这些文件到某个地方。该"某处"是您的工作树或工作树。
这里值得一提的是,尽管我们不会更深入,但每次提交不仅存储冻结的快照,还存储一些额外的元数据。这主要是您在git log
输出中看到的内容:例如,谁提交了、何时提交以及为什么提交。为什么部分取决于提交的人:这是日志消息。一条好的日志消息非常有价值。Git可以告诉您发生了什么:Git会将前一个或父提交的快照与当前或子提交的快照进行比较,对于每个不同的文件,Git将向您显示将父副本更改为子副本的方法。但Git无法告诉您为什么添加或删除了某一行。只有这样做的人才能说出为什么他们这样做。
这意味着您看到和使用的文件根本不在Git中
如果您运行过:
git clone https://github.com/git/git
并有一份Git副本,您可以查看Git的源代码:有Makefile
、README.md
等等。但这些都是你电脑上的普通文件。它们不是提交中的文件。它们是Git通过从快照中提取提交的文件而创建的副本。这些副本位于您的工作树或工作树中。您可以使用文件查看器查看它们,在编辑器中打开它们,等等。但它们不在Git中。它们在您的工作树中,您可以随心所欲地使用它们。
Git将在您要求的任何时间将任何给定的提交提取到您的工作树中:
git checkout v2.21.0
例如,将使用标记v2.21.0
来查找特定的提交散列ID(确切地说,8104ec994ea3849a968b4667d072fedd1e688642
)并将该提交提取到您的工作树。(如果您的Git是2.23或更高版本,您可以使用git switch
而不是git checkout
:它们在这里做的事情完全相同。)此提取过程包括从您的工作树中删除您的文件,并根据您要切换到的提交创建新的文件。但所有这些文件都是您的文件,而不是Git的。
幸运的是,git checkout
/git switch
具有一些安全检查功能,可避免在您未保存所做的某些更改时删除文件。您可以将其关闭(例如,git checkout --force
)或故意使用其他破坏性命令(git reset --hard
)来擦除未保存的工作。在所有情况下,您基本上只是告诉Git擦除您对文件所做的内容,并从Git的文件中取回一些其他版本,例如保存在其他提交中的版本。
Git的索引或临时区域
如果Git只使用两个东西--它的提交,其中一个是当前提交,以及您的工作树--那么git commit
本身就很简单了。不幸的是,Git隐藏了第三个位置来保存每个文件。当您选择某个提交(通过git checkout
或git switch
)作为当前提交时,Git不会将提交快照提取到您的工作树中。相反,它首先将提交快照提取到Git的索引中。
索引很复杂,有多种用途,但它的主要用途实际上很容易描述,而且您应该记住从这里开始:索引是您计划建立的下一个提交的地方。这就是它之所以被命名为临时区域的原因。索引保存每个文件的副本1,最初取自提交。你的工作树上也有一份副本。因此有三个活动副本:
- 您可以使用
git show HEAD:README.md
看到的那个被冻结在提交中。 - 您可以用
git show :README.md
看到的是在Git的索引中。它是冻结的格式,但与提交中的格式不同,它是可替换的。(这些文件有一半在Git中:准备提交,但尚未实际提交。) - 您实际可以使用的--在一个普通文件中--就是普通的
README.md
。这是您的,而且根本不在Git中。
当您运行git commit
时,Git收集适当的元数据,冻结其索引中的所有文件然后,并使用这些文件作为新提交的新快照。
:README.md
与HEAD:README.md
匹配,则这两个文件是重复的,因此新的提交只是重用该文件。如果不是,可能它与其他提交和重复数据删除匹配,或者可能是全新的,并且实际上是真实存储的。无论如何,一旦你提交了它,它现在就冻结了,而且真的,完全在Git中。但是,如果您更改了工作树副本README.md
,您可能希望Git冻结更新后的README.md
。这就是git add
的用武之地。
<2-46]>命令告诉Git:使索引副本与我的工作树副本匹配。即,Git将从您的工作树复制(并压缩为冻结格式)更新的README.md
文件,并将副本放入:README.md
的索引中。因此,这就是为什么经常要求您git add
文件的原因:每次您更改您的副本时,如果您希望Git更改其建议的下一次提交副本,则必须再次git add
。
当您稍后运行git commit
时,Git将获取所有索引文件并将它们冻结为新的提交。因为索引副本都是冻结的格式,所以此过程可以而且通常确实会非常快。
1从技术上讲,索引包含的不是数据的实际副本,而是文件名、模式和Blob散列ID。除非您使用git ls-files --stage
或git update-index
直接开始挖掘索引,否则您无法真正区分它们。因此,可以将索引视为拥有文件的完整副本:Git很好地隐藏了BLOB对象技巧,因此您不需要关心。
这是.gitignore
的用武之地
Git从其索引而不是从您的工作树进行新的提交。您的工作树是您的,可以随心所欲地处理。当您告诉Git覆盖它时,您只需要稍微小心一点,因为您的工作树中的文件都不是在Git中(它们至多是旁边的或在Git的旁边)。但这也意味着您可以在工作树中创建您永远不希望Git存储到其任何提交中的文件。由于这些文件不在提交中,并且git clone
只复制提交,因此这些文件不会出现在任何克隆中。
对于*.pyc
、*.o
fromcc
或c++
这样的编译器输出文件,或者从Java编译器输出的文件或其他文件,这是一件好事:您通常不希望这些文件出现在任何克隆中。
但如果这些文件只是在您的工作树中闲置,则可能会出现两个问题:
git status
会不会向您唠叨。- 如果您使用集中
git add everything
操作,git add
将将这些文件复制到Git的索引中作为新文件,现在,如果您git commit
,它们将被提交。
.gitignore
中列出文件名是防止这两种情况发生的一种方法。但这里有一个诀窍:如果文件已在Git的索引中,则将其列在.gitignore
中没有任何效果。
Git索引中的文件称为跟踪。跟踪的文件当前位于Git的索引中。未跟踪的文件位于您的工作树中,但当前不在Git的索引中。
请记住,您现在可以使用git add
将全新的(To Git)文件放入Git的索引中。您还可以使用git rm
将文件从Git的索引中完全删除。因此,索引的内容并不是固定的。Agit checkout
填充索引,然后,您可以-也将-修改它:您将替换要在下一次提交中更新的任何文件。
当您运行git status
时,status
命令进行两个单独的比较。首先,它告诉您其他有用的东西,但我们将跳过这一点,转到两个比较:
两个比较中的第一个将当前提交或
HEAD
与索引中的内容进行比较。对于每个完全匹配的文件,git status
不会显示任何内容。如果有一些文件与不匹配,或者是新的或丢失的,则git status
表示为提交而暂存的更改并列出这些文件的名称。第二个比较将索引与您的工作树进行比较。对于每个完全匹配的文件,
/li>git status
不会显示任何内容。如果有些文件与不匹配或丢失,git status
将显示更改未暂存并列出这些文件的名称。
这里的一个特例是未跟踪的文件:对于每个未跟踪的文件,git status
列出文件的名称,2称这些未跟踪的文件。但如果您在.gitignore
中列出这些名称,git status
将关闭。
请注意,跟踪的文件没有发生任何特殊情况。这些已经在Git的索引中了。它们包含在第一次比较中,Git会将索引副本与工作树副本进行比较,而不管文件是否列在.gitignore
中。
因此,从这个意义上讲,这些.gitignore
条目并不意味着忽略该文件。它们的意思是当文件未被跟踪时闭嘴。跟踪后,它们不起作用。
同时,git add
有.
和*
(以及其他),用于对多个或所有文件执行集体添加操作。如果所有文件都包含未跟踪的文件,这些操作将非常不方便。因此,在.gitignore
中列出文件名或模式会抑制整体添加操作。它甚至抑制了刻意的git add
:
$ touch foo.pyo
$ git add foo.pyo
The following paths are ignored by one of your .gitignore files:
foo.pyo
Use -f if you really want to add them.
所以.gitignore
应该被称为.git-do-not-complain-about-these-untracked-files-and-do-not-automatically-add-them-when-using-en-masse-add-operations-or-even-explicit-requests
,或者类似的名称。但谁愿意输入这样的名字呢?所以.gitignore
就是这样。
2从技术上讲,每次需要git status -uall
或git status -u
时都会得到这个。否则,它有时会将物理存储在单个文件夹中的一堆文件组合在一起,并且只会不厌其烦地提到文件夹名称。
这篇关于当公共存储库时,应该包含什么.gitignore文件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!