我遇到了git的问题。
我做了什么
昨晚深夜,我提交并推送了几个文件。然而它是为时已晚,我没有注意到我没有git添加一个小文件。所以今天早上在办公室,当我注意到它时,我决定重做工作(因为文件很小)。之后我添加了更多东西,这次添加并成功将其推送到远程。
我想要什么
现在我在家里,有一个未跟踪的文件和远程存储库中的许多好的更改。我想覆盖我昨晚用当前的变化所做的事情,但是git只是不接受。
我尝试了什么
git pull origin branch_name
git reset --hard origin/branch_name
我可能只是去手动更新文件,添加它并重新提交但我觉得很愚蠢。它接缝我不是像我们想的那样使用git。
任何帮助?
答案 0 :(得分:3)
你的问题有些根本奇怪,我会稍微谈谈。但是,您不应该期望 Git对未跟踪的文件执行任何操作。
首先,我们应该定义:在Git中,未跟踪文件是一个不在索引中的文件。
好吧,好的,但现在我们必须定义Git的索引是什么。索引至少有点神秘,因为看它没有简单的方法;但是在Git中,你总是有三个副本,每个文件 Git知道并关心。最后一个用粗体显示的短语是使用未跟踪文件进行操作的关键。但是,重要的是要意识到虽然Git总是有一个索引,但索引中的是暂时的和可变的。 (这与提交不同!)
Git知道的每个文件的一个副本是当前提交中的副本。此文件的副本无法更改,因为它存储在提交中,并且任何提交的任何部分都无法更改。
此同一文件的第二个副本现在是Git的索引。这个额外的副本存储在Git用于所有文件的相同压缩格式中。通常,它与当前提交中的完全相同。存储在Git 中的重复文件,使用Git自己的内部压缩格式,基本上没有任何磁盘空间。因此,第二个副本没有额外的磁盘空间,但第二个副本存在的事实 Git知道该文件的方式。
该文件的第三个也是最后一个副本位于您的工作树中。第三个副本在Git的特殊内部Gitty表单中不。它需要真实的空间 - 尽可能多的空间;它根本没有被压缩。但这也意味着您计算机上的所有其他程序(包括编辑器和编译器等)都可以处理该文件。 (特殊的Git形式只对Git本身有用。)
git commit
生成索引的快照这可以让我们回到未经跟踪的文件:您的工作树中的任何文件目前 >。此外,它让我们回到了索引的一个关键目的,即: 索引包含将在下次提交时生成的文件。
这就是您必须始终git add
个文件的原因:git add somefile
将somefile
的内容复制到索引中存储的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
索引现在中的内容是四个文件的集合README
,afile
,bfile
和nfile
。但对于之前的提交,这并非如此。我们来看看:
$ 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
(这个存储库真的不是很有趣,因为它只有这两个提交)。如果我们再次查看master
,nfile
会重新显示:
$ 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 fetch
。 git 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 merge
和git 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_name
,git 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更改它,您将丢失文件并且您无权访问它,因为它是未跟踪的文件。