tjw*_*992 1 git gitignore git-pull
我遇到过这样的情况:一些之前签入 Git 的文件现在需要被忽略。为了忽略它们,我将文件添加到“.gitignore”并执行了以下操作:
git rm -r --cached .
git add --all
git commit -m "Removed files from git tracking that should be ignored"
git push
Run Code Online (Sandbox Code Playgroud)
现在我遇到一种情况,我需要将这些“.gitignore”更改拉到另一台服务器,但是当我执行此操作时,git pull刚刚添加到“.gitignore”的文件不会被忽略,而是会被完全删除!
我认为发生的事情是在拉取过程中它使用本地“.gitignore”文件,该文件不会忽略这些文件......并且它检测到这些文件不再在 git 中,因此它只是删除它们。如果我手动添加回文件并执行另一个 git pull 然后它开始正常工作(现在正确的“.gitignore”文件位于服务器上。)
有没有办法告诉git pull使用来自远程服务器的“.gitignore”文件而不是本地文件,这样这些文件就可以被正确忽略并且不会在 git pull 上被删除?
列出文件.gitignore并不意味着忽略该文件,也不意味着不删除该文件,或者任何您希望它表示的含义。你在这里所做的任何事情都不会改变这一点。我们将在这个答案接近尾声时回到这里.gitignore,但让我们首先看看你所处的可怕的、糟糕的、不好的情况,你实际上无法解决这个问题。你必须以某种方式绕过它。
事实是,一些现有提交具有这些文件,而其他一些现有提交\xe2\x80\x94那些在这些文件存在之前发生的提交,以及您从 Git 索引\xe2\x80\x94 中取出文件后所做的提交没有这些文件。没有什么可以改变这些事实。
\n要理解为什么会出现这种情况,我们需要注意的是 Git 与文件无关。Git 是关于提交的。提交确实会存储文件,但这是一揽子交易:全部或全部。你有一个提交,并且你有它的所有文件。或者,您没有提交,也没有其文件(因此您将使用该git fetch提交将其添加到您的集合中,然后您就拥有了它及其所有文件)。
此外,提交内的文件采用无用的格式(我们将在下一节中讨论这一点)。它们经过压缩和重复数据删除,因为大多数提交大多具有与其他提交中相同的文件。因此,Git 不会将它们存储为文件,而是存储为内部对象,从而自动删除它们的重复项。
\n这些对象都已编号,Git 称之为哈希 ID。特别是提交总是会获得一个唯一的编号。(文件可能是其他提交文件的重复项,可能具有非唯一的编号,这就是对它们进行重复删除的原因。)该编号实际上是内部对象内容的加密哈希。这限制了 Git:甚至 Git 也无法更改提交。
\n如果你取出一个提交,进行一些更改,然后放回不同的东西,它就会不同,因此会得到一个新的不同的哈希 ID。现有对象保留在 Git 存储库中,并位于其现有 ID 下。新的和改进的(我们希望)对象现在已添加到存储库中,并在其新 ID 下。任何使用旧ID 的人都会获得旧对象。任何使用新ID 的人都会获得新对象。这部分确实非常简单。
\n现在,提交中的数据不仅仅是每个文件的快照。是的,它就在那里,但是还有一些元数据,或者有关提交本身的信息。例如,这包括提交人的姓名和电子邮件地址。它还包括一个时间戳\xe2\x80\x94,这有助于确保每个提交都是完全唯一的,因此,如果两个不同的人做出相同的提交,但由于某种原因,两者都声称是同一个人,他们仍然会获得不同的提交,除非他们同时进行(在这种情况下,他们真的是两个不同的人吗?Git 说不)。
\n因此,每次提交中都有所有这些元数据:作者、提交者、一些时间戳、日志消息等。但在这些元数据中,Git 添加了自己的信息。Git 在每次提交时都会存储一组早期提交的哈希 ID。大多数提交只存储一个哈希 ID,Git 将其称为父提交。
\n这些父提交哈希 ID 形成向后查找链中的提交。我们从右侧最近(最后)的提交开始。我们不会写出其真实的哈希 ID,而是直接调用此提交H(对于Hash):
<-H\nRun Code Online (Sandbox Code Playgroud)\nCommitH中包含快照\xe2\x80\x94files\xe2\x80\x94 和元数据,并且在该元数据中,commitH存储早期提交的哈希 ID。让我们假设它的哈希 ID 是G,并将其绘制出来:
<-G <-H\nRun Code Online (Sandbox Code Playgroud)\n当然,提交G指向更早的提交,它不断指向向后:
... <-F <-G <-H\nRun Code Online (Sandbox Code Playgroud)\n因为每个提交都向后指向其父级,所以如果 Git 能够找到链中的最后一个提交,Git 就可以并且将会找到整个提交链。这就是分支名称的用武之地:Git\xe2\x80\x94 中的每个名称、分支名称、标记名称、远程跟踪名称等\xe2\x80\x94 都存储一个哈希 ID。对于分支名称,该哈希 ID 是其链中最后一次提交的 ID 。即使链中还有稍后的提交,这也是如此,这通常发生在开发新东西但尚未将其放在主分支上时:
\n...--G--H <-- main\n \\\n I--J <-- feature\nRun Code Online (Sandbox Code Playgroud)\n在这里,feature分支比分支多了两次提交main。提交J指向I、指向H、指向G,依此类推。所以提交H和更早的提交都在两个分支上。提交I并目前J仅启用,但如果我们愿意,我们可以“向前feature滑动名称”:main
...--G--H--I--J <-- main, feature\nRun Code Online (Sandbox Code Playgroud)\n现在所有提交都在两个分支上。
\n分支名称会四处移动,并且根据定义,每个名称都会挑选出要被视为“在该分支上”的最后一次提交。提交本身决定了这些分支上较早的内容。所以重要的是提交:名称只是让我们找到特定的。并且,请记住,所有提交都将永远冻结。任何现有提交的任何部分都不能更改。
\n正如我们上面提到的,提交内的文件采用的格式只有 Git 可以使用它们。即使如此,Git 也只能读取它们。我们需要其他程序能够读取和写入我们的文件。解决方案很简单\xe2\x80\x94,并且与其他版本控制系统使用的相同:Git在某个时刻将文件从提交中复制出来。这些副本一旦脱离版本控制系统,现在就可以使用了。事实上,它们只是普通的文件:计算机上的任何东西都可以使用它们。Git 不再对它们有任何控制权。
\n让 Git 从某些提交中复制文件的正常日常方法是使用git checkout. 例如,如果我们有:
...--G--H <-- main\n \\\n I--J <-- feature\nRun Code Online (Sandbox Code Playgroud)\n当我们运行时git checkout main,Git会将所有已提交的文件复制出commit H。main这也有选择名称作为我们当前分支的副作用。由于名称main指向 commit H,这意味着这H是我们当前的提交。我们可以通过将特殊名称附加HEAD到名称来绘制它main:
...--G--H <-- main (HEAD)\n \\\n I--J <-- feature\nRun Code Online (Sandbox Code Playgroud)\n请注意,我们现在每个文件都有两个副本:其中有提交的副本H,我们无法触及它,并且在 Git 称为我们的工作树或工作树的地方有一个普通形式的日常文件。
在其他版本控制系统中,文件的这两个副本是您能找到的唯一副本。1 如果您想知道发生了什么,您可以将某个文件的工作树版本与活动的提交版本进行比较:不同之处就是我们所做的更改。但无论出于什么原因 \xe2\x80\x94 无论您是否认为这是一个好主意2 \xe2\x80\x94Git 将每个文件的第三个副本3存储在 Git 称为的索引或暂存区域中,或者\xe2\x80\x94这些天很少\xe2\x80\x94缓存。
\n每个文件的第三个副本位于只读提交副本和工作树副本之间。与提交的副本不同,它可以被覆盖。它已被预压缩和预重复数据删除,以便准备好进入下一次提交。事实上,这可能是考虑 Git 索引/暂存区域的最佳一般方式:它保存您建议的下一次提交。4
\n所以,当你进行git checkout一些提交时,比如 commit H,Git:
HEAD到分支名称,假设您使用分支名称main来选择提交。(如果没有,您将进入“分离 HEAD”模式,我们在此不讨论该模式。)如果您现在对文件的工作树副本进行更改,通常还必须运行git add:这告诉 Git使索引副本与工作树副本匹配。对于就地更新的文件,这会用新索引副本覆盖旧索引副本。对于您删除的文件,这将删除索引副本。对于新文件,这会在 Git 的索引中创建一个新文件。
无论哪种方式,添加文件都会暂存更改,因为任何时候运行,Git 都会根据当时索引中的任何内容git commit创建新快照。如果您没有更改索引,新快照将与当前快照完全匹配。在这种情况下,Git 通常要求您使用该标志:新提交实际上并不是空的,它只是在快照方面与旧提交相匹配(因此 Git 想知道:为什么要麻烦?并让您使用该标志)。--allow-empty
无论您是否对工作树进行任何更改和/或运行以更新工作树中的git addGit 索引,当前提交都保持不变。一旦你进行了新的提交,Git:
我们最终得到,例如:
\n K <-- main (HEAD)\n /\n...--G--H\n \\\n I--J <-- feature\nRun Code Online (Sandbox Code Playgroud)\n现在有一个main不在 上的提交feature。
1非当前提交中的其他只读副本也可以找到,就像它们在 Git 中一样,但它们不像当前提交那样处于活动状态。
\n2其他系统没有索引,证明没有索引也可以工作。
\n3这个“副本”是预先去重复的,所以大多数时候,它几乎不占用空间。因此,称其为副本有点误导。然而,与向用户展示的许多其他 Git 部分不同,这个“副本”会自动删除重复的事实实际上是隐藏得很好的。您可以将其视为每个文件的第三个副本,并且一切正常。好吧,在您开始摆弄像git ls-files --stage和git update-index: 这样的内部命令之前,您需要了解git hash-object.
4冲突合并期间索引会扩展,这意味着此描述不完整,但至少没有错误。:-) 索引还有一个让 Git 运行得更快的作用,这就是它有旧名缓存的原因。如今,您通常会在选项标志中看到这个名称,例如git rm --cached.
假设在提交H和提交之间I我们删除了一个文件。进一步说,我们把它放在一个新的分支 X 上:
git checkout main\ngit checkout -b X\ngit rm somefile\ngit commit -m 'remove a file'\nRun Code Online (Sandbox Code Playgroud)\n提交H 有一个名为 的文件somefile,而提交I 缺少一个名为 的文件somefile。
到时候我们的git checkout main文件somefile已经回来了。Git 将其从提交复制H到 Git 的索引和我们的工作树,现在我们有了该文件。
当我们git checkout X返回提交时I,文件somefile必须消失。Git 将其从 Git 的索引和我们的工作树中删除。
此属性由两次提交中的文件集确定。 我想说完全是这样,但如果你尝试一下,你会发现 Git删除文件somefile是有条件的:
git checkout main # file somefile comes back\ngit rm --cached somefile # take somefile out of Git's index\nRun Code Online (Sandbox Code Playgroud)\n因为我们在这里使用git rm --cached,Git 会somefile从其索引中删除,但不会触及我们的工作树副本。如果我们现在运行:
git checkout X\nRun Code Online (Sandbox Code Playgroud)\nI\xe2\x80\x94 请记住,按分支名称选择的Xcommit缺少文件\ somefilexe2\x80\x94Git不会somefile从我们的工作树中删除。原因是此后git rm --cached,文件somefile未被跟踪。
在 Git 中,未跟踪的文件只是当前位于工作树中但不在 Git 索引中的文件。 就是这样\xe2\x80\x94,这就是整个定义\xe2\x80\x94,但它会产生很多后果,包括在新提交中不包含未跟踪的文件,以及我们刚刚看到的git commit缺乏删除的情况。
因为您的工作树是 您的,所以您可以随时在其中创建和销毁文件。
\n因为Git的索引是Git的,所以Git可以把文件放在那里\xe2\x80\x94但是我们知道它什么时候会做哪件事:
\n当您git add创建文件时,Git 会根据该文件在工作树中的外观添加或删除该文件。
当您git checkout提交时,Git 根据这些文件是否在其他提交中向索引添加或删除文件。
当您运行时git rm --cached,Git 会按照指示从 Git 索引中删除文件。
这里没有涉及的其他情况包括如何git merge操作 Git 的索引、如何git reset工作git restore等等。
因此,在某种程度上,您可以控制哪些文件位于 Git 的索引\xe2\x80\x94 中,但它们往往会镜像提交。
\nGit 对于索引和工作树是否包含在存储库中有点矛盾。具体来说,git init --bare创建一个没有工作树的存储库,但这样的存储库仍然有一个索引。(可能不应该,但确实如此。)git worktree add从 Git 2.5 开始,还有一个命令,它将一对 \xe2\x80\x94a 工作树和一个索引 \xe2\x80\x94 添加到存储库。因此,任何给定的存储库中都可以有多个索引和工作树集。
不过,很明显,这git clone 不会复制任何现有存储库的索引和工作树(无论该存储库中存在多少)。因此索引或所有索引和工作树对于每个克隆都是私有的。您无法直接控制任何其他存储库的索引和工作树:您必须将其留给可能在另一台计算机上操作 Git 的人(假设另一个克隆位于另一台计算机上)。
.gitignore该.gitignore文件命名错误。更好的名字是.git-do-not-complain-about-these-files-if-they-are-untracked-and-if-they-are-untracked-and-I-use-an-en-masse-add-command-do-not-add-them-to-the-index-either.
当我们运行时git status,Git会抱怨未跟踪的文件。它变得非常发牢骚!这非常烦人,因为工作树是一个普通目录,并且我们使用的软件类型,我们运行的程序会在工作树中创建大量构建工件。这留下了大量未跟踪的文件。命令git status变得嘈杂,我们的生产力直线下降。
为了让git status____闭嘴,我们可以在文件中列出这些预期的构建产品.gitignore。 这对于这些文件现在是否在索引中没有影响。 但如果它们不在索引\xe2\x80\x94中,如果它们现在未被跟踪\xe2\x80\x94,那么就git status 不会抱怨它们。
当然,如果不抱怨,如果也“工作正常”,不添加它们git status,那就太好了。这就是在 中列出文件的第二个主要效果:如果文件尚未被跟踪\xe2\x80\x94 如果它现在不在索引中\xe2\x80\x94 并且我们运行,我们希望 Git 不添加它。git add ..gitignoregit add .
如果文件已在索引中(已跟踪),则将其列出对和.gitignore没有影响:将检查文件的状态,然后将添加文件。5 因此对于已经跟踪的文件没有帮助。这就是文件名不正确的原因。但更正确的名称将无法使用,事实就是如此。git statusgit addgit add .gitignore.gitignore
列出文件.gitignore还有一个副作用:它授予 Git破坏该文件的权限。这主要涉及在文件未被跟踪和忽略时检查包含该文件的旧提交。结帐继续进行,现在您已经跟踪了文件,而未跟踪的文件的数据实际上已被销毁。所以真正的全名可能是.git-about-some-files-that-may-be-untracked-and-what-to-do-if-they-are:do-not-complain-and-do-not-auto-add-but-do-feel-free-to-destroy-these-files,或者什么的。(但许多 Microsoft 系统不允许使用冒号字符。)
5有一些索引标志\xe2\x80\x94是索引\xe2\x80\x94的缓存git status方面的一部分,人们可以滥用这些标志来防止查看和git add添加。这些是假设未更改和跳过工作树标志。它们不是为此目的而设计的,因此出现了上面的滥用概念,并且它们无助于解决这个问题的答案,但它们值得一提。
您有多种选择。最彻底、但最容易执行、或许也是最容易做到的方法是:创建一个全新的 Git 存储库。请小心,切勿添加这些文件,以免它们被跟踪,从而永远不会成为问题。将所有系统移至新的 Git 存储库,放弃(并最终销毁)旧的 Git 存储库。
\n或者,您可以进行最小更新:进行新的提交,与旧的提交相比,删除文件。然后,仔细检查每个部署并手动更新这些系统,小心地保留文件,同时使它们不被跟踪。您可以使用该git rm --cached技巧,或者在结账期间将文件保存在工作树之外,或者您喜欢的任何其他方式。这些方法中的任何一种都有效。然后要非常小心,不要返回会使这些文件被跟踪的有毒提交。
在这两个选项之间,您可以使用历史重写工具(filter-branch、filter-repo、The BFG,无论您喜欢什么)来获取现有的提交,并将它们转换为新的和改进的提交,其中这些文件从未已承诺。这很像第一个和/或第三个选项:您仍然必须仔细地进行每个部署并更新它,因为重写的存储库实际上是一个新的存储库。它的缺点是,如果历史记录同步,拥有旧(重写前)存储库的人很容易意外地重新引入错误的提交。(它们是否确实取决于前几次提交中的内容和/或您如何重写历史记录。)
\n如果您完全控制该软件,最好的选择通常是:
\nconfig.defaults。config.site。config.site它不会出现在任何过去、现在或未来的提交中。 请务必将其列出.gitignore,以免意外添加和提交。config.site文件。你无法改变过去,但也没有必要这样做。
\n| 归档时间: |
|
| 查看次数: |
749 次 |
| 最近记录: |