Git不会重写未跟踪的文件

时间:2017-11-23 19:12:50

标签: git

我遇到了git的问题。

我做了什么

昨晚深夜,我提交并推送了几个文件。然而它是为时已晚,我没有注意到我没有git添加一个小文件。

所以今天早上在办公室,当我注意到它时,我决定重做工作(因为文件很小)。之后我添加了更多东西,这次添加并成功将其推送到远程。

我想要什么

现在我在家里,有一个未跟踪的文件和远程存储库中的许多好的更改。我想覆盖我昨晚用当前的变化所做的事情,但是git只是不接受。

我尝试了什么

git pull origin branch_name
git reset --hard origin/branch_name

我可能只是去手动更新文件,添加它并重新提交但我觉得很愚蠢。它接缝我不是像我们想的那样使用git。

任何帮助?

2 个答案:

答案 0 :(得分:3)

你的问题有些根本奇怪,我会稍微谈谈。但是,您不应该期望 Git对未跟踪的文件执行任何操作。

未经跟踪的文件和Git的索引

首先,我们应该定义:在Git中,未跟踪文件是一个不在索引中的文件。

好吧,好的,但现在我们必须定义Git的索引是什么。索引至少有点神秘,因为它没有简单的方法;但是在Git中,你总是有三个副本,每个文件 Git知道并关心。最后一个用粗体显示的短语是使用未跟踪文件进行操作的关键。但是,重要的是要意识到虽然Git总是有一个索引,但索引中的是暂时的和可变的。 (这与提交不同!)

Git知道的每个文件的一个副本是当前提交中的副本。此文件的副本无法更改,因为它存储在提交中,并且任何提交的任何部分都无法更改。

此同一文件的第二个副本现在是Git的索引。这个额外的副本存储在Git用于所有文件的相同压缩格式中。通常,它与当前提交中的完全相同。存储在Git 中的重复文件,使用Git自己的内部压缩格式,基本上没有任何磁盘空间。因此,第二个副本没有额外的磁盘空间,但第二个副本存在的事实 Git知道该文件的方式。

该文件的第三个也是最后一个副本位于您的工作树中。第三个副本在Git的特殊内部Gitty表单中。它需要真实的空间 - 尽可能多的空间;它根本没有被压缩。但这也意味着您计算机上的所有其他程序(包括编辑器和编译器等)都可以处理该文件。 (特殊的Git形式只对Git本身有用。)

git commit生成索引的快照

这可以让我们回到未经跟踪的文件:您的工作树中的任何文件目前 >。此外,它让我们回到了索引的一个关键目的,即: 索引包含将在下次提交时生成的文件。

这就是您必须始终git add个文件的原因:git add somefilesomefile的内容复制到索引中存储的somefile版本中。该文件现在是在索引中,如果它之前没有,并且匹配工作树版本,如果它之前没有。而且,现在下一个git commit将存储该文件的版本。

通过运行git commit,您可以进行新的提交。新提交中的内容是此时索引中的内容。新提交成为当前提交;索引保持原样;现在,索引中的每个文件都与当前提交中的文件副本完全匹配,因为这些文件是索引中的副本。但这仅提交跟踪的文件 - 仅提供Git知道的文件

由于未跟踪文件根据定义不在索引中,因此Git不了解它。它不会进入您将进行的下一次提交。 现在不在索引中,因此不会在任何新提交中。

将其添加到索引后,使其与索引中的所有其他文件一起加入, 就在那里,现在已被跟踪。运行git commit将使其永久存储,作为新提交的一部分存储;新提交成为当前提交,文件继续在索引中,因此继续被跟踪。

跟踪哪些文件? (再次)

显然,如果你创建了一个 new 文件,然后git add创建了索引和git commit,那么提交的文件集就是改变。旧提交, 之前的提交,可能只有几个文件:

$ ls
README  afile   bfile
$ git status
On branch master
nothing to commit, working tree clean
$ echo new file > nfile
$ git add nfile
$ git commit -m 'add new file'
[master 72536ab] add new file
 1 file changed, 1 insertion(+)
 create mode 100644 nfile

索引现在中的内容是四个文件的集合READMEafilebfilenfile 。但对于之前的提交,这并非如此。我们来看看:

$ git checkout HEAD^
Note: checking out 'HEAD^'.
[snip]
HEAD is now at 311a932... initial
$ ls
README  afile   bfile

nfile发生了什么事?它已经消失了!嗯,事实上, 已经从工作树和索引中消失了。但它作为快照安全地存储在提交72536ab...中,这是分支master上的最后一次提交,并且是名称master指向的提交:< / p>

$ git log --all --decorate --oneline --graph
* 72536ab (master) add new file
* 311a932 (HEAD) initial

(这个存储库真的不是很有趣,因为它只有这两个提交)。如果我们再次查看masternfile 会重新显示:

$ git checkout master
Previous HEAD position was 311a932... initial
Switched to branch 'master'
$ ls
README  afile   bfile   nfile

文件nfile现在是索引中的,因此会被跟踪。

当我们从切换 具有nfile的提交时, 不提交 t 中有nfile,Git知道从索引和工作树中删除文件。

此时文件根本不存在。没有&#34;未跟踪&#34; -ness为它,它只是没有

当我们从拥有它的311a932...之类的提交切换到 之类的72536ab...之类的提交时,Git知道创建文件,在索引和工作树中。现在该文件存在且 被跟踪。

然后,未跟踪的文件是确实存在的文件,但Git 不知道,因为索引中缺少该文件。< / p>

相同的文件可能在当前(HEAD)提交中不是,但它可能是。例如,我们现在可以从索引中删除afile,而不从工作树中删除它:

$ git rm --cached afile
rm 'afile'
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        deleted:    afile

Untracked files:
  (use "git add <file>..." to include in what will be committed)

        afile

请注意,该文件现在已同时删除未跟踪。这是因为git status实际上运行了两个比较。第一个将HEAD(当前提交)与索引进行比较。当前提交中有一个文件afile,但索引中没有,因此删除了afile。第二个将索引与工作树进行比较。工作树中的文件afile不在索引中,因此afile未跟踪。

您问题中最奇怪的部分

你说:

  

现在我在家里,有一个未跟踪的文件和远程存储库中的许多好的更改。我想用当前的变化覆盖我昨晚所做的事情,但是git似乎并不在意。 ...

git pull origin branch_name

git pull命令做了两件事,我总是鼓励Git的初学者单独做,因为第一个是非常安全的,第二个是......好吧,我们会看到。< / p>

git pull的第一部分是运行git fetchgit fetch命令有你的Git,它正在管理你的存储库,调用另一个Git。其他Git有一个不同的存储库,但您的存储库和它们的存储库通常共享很多提交。

你的Git问他们:你有什么提交?他们将返回一个分支名称列表并提交哈希ID。您可以通过运行以下方式直接查看此列表:

$ git ls-remote origin

让你的Git调用他们的Git并获取列表,然后打印它。但是,当您运行git fetch origin时,您的Git会继续向他们询问他们没有提交的任何提交,然后更新您自己的远程跟踪名称,例如origin/branch_name,要记住哪些提交符合 分支名称,例如branch_name

在这种情况下,由于您已向origin上传了一些新提交,因此可能他们在其分支名称branch_name下有新的提交。您的Git现在将在您的存储库中提交这些提交,存储在您的远程跟踪名称origin/branch_name下。这些你的分支中的任何一个都没有(但是),但是通过这个远程跟踪名称会记住它们。

此时,您通常 - 但并非总是如此 - 希望将您在本地完成的任何工作组合起来进行他们不会做的新提交,任何工作都可以通过git fetch从他们那里接过来。您可以结合几个命令之一来完成此操作。最常见的两个是git mergegit rebase

git pull为您运行git fetch,然后立即,而不给您任何考虑事项或改变主意的机会,运行其中一个两个命令。这里的想法是,这对你来说比给你机会先查看,决定运行哪个命令,然后运行命令更方便。有时这真的是真的!但有时它不是。

现在,如果您的工作树中有未跟踪的文件,那么根据Git的定义,该文件不是“安全的”#34; 。它甚至不在你的索引中,所以Git不能假设它在任何提交中都安全地保存了下来。 (如果 在索引中,Git将有一种简单的方法来测试它是否安全地保存在当前提交中。)如果此时运行git merge,并且传入提交你想与合并有文件,git merge命令将失败,告诉你它会覆盖未跟踪的文件。

因此,大概git pull命令失败了。你没有表现出失败,但可能确实失败了 - 但如果确实失败了,那么可能是命令的git merge部分失败了。

然后你说你跑了:

git reset --hard origin/branch_name

现在,只要你的Git至少是1.8.4版本,这个应该完成你想要的。 git fetch步骤已更新origin/branch_namegit reset --hard告诉Git 扔掉当前工作树中的任何内容,将其替换为您可以通过将当前分支更改为指向其哈希存储在origin/branch_name下的提交。 --hard暗示--mixed,它告诉Git也会丢弃当前索引,将其替换为从所选提交中提取的内容。

如果您的家庭Git早于1.8.4,那么这一切都有意义。 git pull与较旧的Gits 中的git fetch进行互动的方式会抑制 origin/branch_name的更新。

如果是这种情况,您只需运行git fetch而不是git pull。虽然这些旧版本的Git在今天非常罕见,但这是我鼓励那些刚接触Git的人首先使用git fetch的另一个原因,并且只有在它完成后才使用第二个Git命令 - 这可能不是{{1 }}或git merge,而是git rebase就像这一个特殊的情况 - 之后检查git reset --hard获取的内容。

答案 1 :(得分:0)

因为您有一个文件的2个版本。其中一个文件位于您的git提交中,另一个文件是您未跟踪的文件。我建议您先从系统中删除未跟踪的文件。 你可以使用这样的git命令:

git clean -fx

有关如何删除未跟踪文件的详细信息,您可以看到this webpage

如果您在未跟踪的文件中有一些有用的信息并且git更改它,您将丢失文件并且您无权访问它,因为它是未跟踪的文件