为什么Git会说我的主分支“已经更新”了,尽管还没有?


118

基本问题

我只是从项目中的文件中删除了所有代码,然后将更改提交到了本地git(故意)。我做了

git pull upstream master

从上游获取并合并(因此从理论上讲应该删除已删除的代码)。

Git告诉我一切都是最新的。

一切绝对不是最新的-所有删除的代码仍将被删除。

其他相关信息

我只有一个分支称为“主”。

我最近设置了“主人”来跟踪上游,如下所示:

设置分支主机,以从上游跟踪远程分支主机。

该命令git branch -vv产生:

* master 7cfcb29 [upstream/master: ahead 9] deletion test

为什么为什么会这样呢?我即将通过电子邮件将我对代码所做的任何更改发送给我的项目经理。

更新资料

我以为这很明显,但是无论如何,这是我的目标:

获取我系统上的最新代码。

请原谅我的愤怒,但是为什么这么简单的任务必须如此艰巨?


1
显然,如果您删除源,然后尝试使用简单的“拉”进行拉动,则git将不会覆盖您的本地更改(在这种情况下为您的删除),而不会确保您真的要覆盖本地更改。第一个答案似乎确切地解释了您如何去做。
CashCow

Answers:


208

我认为您的基本问题是您误解和/或误解了git的作用以及为什么这样做。

当您克隆其他存储库时,git会复制“那里”的任何内容。它也需要“自己的”分支的标签,比如master,使该标签在其“全名”的副本,的git树(正常)remotes/origin/master(但在你的情况下,remotes/upstream/master)。大多数时候,您也可以省略remotes/零件,因此您可以将原始副本称为upstream/master

如果您现在对某些文件进行一些更改并将其提交,那么您将是仅有的那些更改。同时,其他人可能会使用原始存储库(从中创建克隆)来创建其他克隆并更改这些克隆。当然,他们是唯一具有更改的人。最终,某人可能会有更改,他们会将更改发送回原始所有者(通过“推送”或补丁或其他方式)。

git pull命令主要是的缩写,git fetch后跟git merge。这很重要,因为这意味着您需要了解这两个操作的实际作用。

git fetch命令说,可以返回到您从其克隆的任何位置(或以其他方式设置为从其获取的位置)并找到“其他人添加或更改或删除的新内容”。这些更改将被复制并应用于您之前从中获得的内容的副本。他们不是用于您自己的作品,仅适用于您的作品。

git merge命令更加复杂,您将在哪里出错。简单地说,它所做的是将“您在副本中所做的更改”与“从其他人那里获取的更改,并因此添加到您的其他人的副本中”进行比较。如果您的更改及其更改似乎没有冲突,那么该merge操作会将它们混合在一起,并为您提供一个“合并提交”,将您的开发及其开发联系在一起(尽管在非常简单的情况下,您没有变化,您将获得“快速前进”)。

您现在所遇到的情况是您进行了更改并做出了更改(实际上是九次,因此是“提前9”),并且他们没有做出任何更改更改。因此,fetch尽职尽责不获取任何东西,然后merge接受他们的零钱,也什么也不做。

您想要的是查看代码,甚至“重置”其“代码”版本。

如果您只想看一下,可以简单查看该版本:

git checkout upstream/master

这告诉git您想将当前目录移动到其全名实际上是的分支remotes/upstream/master。您将在上次运行时看到他们的代码git fetch并获得他们的最新代码。

如果您要放弃所有自己的更改,则需要做的就是更改git的标签master(应该命名)的想法。当前,它命名您的最新提交。如果回到该分支:

git checkout master

那么该git reset命令将允许您像以前一样“移动标签”。剩下的唯一问题(假设您已经准备好放弃自己所做的一切)是找到标签应该指向的位置。

git log可以让您找到数字名称(例如类似的数字)7cfcb29,它们是永久性的(永不更改)名称,并且还有很多其他方式来命名它们,但是在这种情况下,您只想要名称upstream/master

要移动标签,消灭自己的更改(任何你犯是相当长的,而实际上可恢复的,但它在这之后要困难得多,所以要非常肯定):

git reset --hard upstream/master

--hard告诉的Git消灭你一直在做什么,将当前分支标签,然后检查了指定的提交。

真正想要git reset --hard并消灭大量工作并不罕见。一种更安全的方法(如果您认为其中的某些事情值得,那么使恢复工作容易得多)是重命名现有分支:

git branch -m master bunchofhacks

然后创建一个新的本地分支,命名为master“ tracks”(我不太喜欢这个术语,因为我认为它会使人们感到困惑,但这是git术语:-))。

git branch -t master upstream/master

然后,您可以使用以下方法:

git checkout master

最后三个命令的作用(有一些快捷方式使它仅是两个命令)是更改粘贴在现有标签上的名称,然后创建一个新标签,然后切换到它:

在做任何事情之前:

C0 -    "remotes/upstream/master"
    \
     \- C1 --- C2 --- C3 --- C4 --- C5 --- C6 --- C7 --- C8 --- C9    "master"

之后git branch -m

C0 -    "remotes/upstream/master"
    \
     \- C1 --- C2 --- C3 --- C4 --- C5 --- C6 --- C7 --- C8 --- C9    "bunchofhacks"

之后git branch -t master upstream/master

C0 -    "remotes/upstream/master", "master"
    \
     \- C1 --- C2 --- C3 --- C4 --- C5 --- C6 --- C7 --- C8 --- C9    "bunchofhacks"

C0是您第一次执行时获得的最新提交(完整的源代码树)git clone。C1到C9是您的提交。

请注意,如果您之前选择git checkout bunchofhacks,然后git reset --hard HEAD^^将更改为:

C0 -    "remotes/upstream/master", "master"
    \
     \- C1 --- C2 --- C3 --- C4 --- C5 --- C6 --- C7 -    "bunchofhacks"
                                                      \
                                                       \- C8 --- C9

原因是HEAD^^将修订版本从当前分支的开头(重置之前为bunchofhacks)的名称命名为两个,reset --hard然后移动标签。提交C8和C9现在几乎是不可见的(您可以使用reflog之类的东西git fsck来查找它们,但不再琐碎了)。您可以随意移动标签。该fetch命令负责以开头的命令remotes/。通常将“您的”与“他们的”匹配(因此,如果他们也有一个remotes/origin/mauve您自己的名字mauve),但是只要您要命名/查看您从“他们”那里得到的提交,就可以键入“他们”。(请记住,“一次提交”是整个源代码树。您可以从一次提交中选择一个特定的文件,git show例如,


12
我从您的出色回答中学到了很多东西。但是对于为什么收到git status消息,我仍然感到困惑:当上游回购协议比我当前回购协议多提交时,“您的分支使用'origin / master'是最新的”。我可以使用git pull来获取最新信息,但是如果消息显示我是最新的信息,我怎么知道需要拉出信息呢?
Christopher Werby

@ChristopherWerby:听起来您正在git merge作为命令行命令运行(这是我自己做的,这是一种合理的方法)。不过请注意,git pull首先要先运行git fetch然后再运行git merge(或者git rebase如果您告诉它这样做)。这是获取步骤,实际上带来了要合并的新提交(或仅基于重新生成的)。
torek

@torek除了git status,还有其他命令可以用来查看上游存储库是否在当前存储库之前吗?我收到的消息是git status“您的分支是'origin / master'的最新信息”,这使我误以为我拥有最新的更改,而我没有。有时,我确实收到一条消息,上面写着“起源/母版是您的分支之前5次提交”(措辞)。但这并不一致。
Christopher Werby 2015年

1
这实际上仍然无法回答为什么git status当立即git fetch实例然后拉下100个对象并解析将近100个增量,提及几个新分支和几个新标签并更改主对象(远程)时说“您的分支是最新的”的原因跟踪)分支头的提交-然后又高兴又不知不觉地出现另一个git状态,仍然说“您的分支是最新的”。显然有很多是从起源降下来的,但是分支之前和之后都是“最新的起源”?
NeilG

1
git pullgit fetch先运行,然后运行git merge(或您选择的其他第二个命令)。该git fetch步骤通过调用他们的 Git并从他们那里获取任何新信息来更新您的 Git 对其状态的记忆。您只检查Git对Git的记忆。git status
torek

18

我和你有同样的问题。

我做了git status git fetch git pull,但是我的分支仍然落后。我将文件夹和文件推送到远程,但我在网上看到了文件,但是在本地,它们却丢失了。

最后,这些命令更新了本地的所有文件和文件夹:

git fetch --all
git reset --hard origin/master 

或者如果你想要一个分支

git checkout your_branch_name_here
git reset --hard origin/your_branch_name_here

1
谢谢!这确实有效。请记住,分支名称区分大小写!
安德烈·拉蒙

4

您提交的任何更改(例如删除所有项目文件)在拉动后仍将保留。拉动所要做的就是将最新更改从其他位置合并到自己的分支中,如果分支已删除所有内容,那么当上游更改影响已删除的文件时,充其量您会遇到合并冲突。简而言之,是的,一切都是最新的。

如果您描述的是您希望获得的结果,而不是“删除所有文件”,那么也许有人可以建议采取适当的措施。

更新:

在我的系统上获取最新的代码

您似乎不了解的是,您已经拥有了最新的代码。如果您真正想要的是查看master分支上其他人的最新作品,请执行以下操作:

git fetch upstream
git checkout upstream/master

请注意,这不会让您立即(重新)开始自己的工作。如果您需要知道如何撤消已完成的操作或以其他方式还原您或其他人所做的更改,请提供详细信息。另外,考虑阅读版本控制的用途,因为您似乎误解了版本控制的基本目的。


实际上,我确实需要系统上其他人代码的最新版本。但是,这两个命令没有这样做。我得到的只是“已经在分支机构主管上了”。我文件中的代码不反映其他人的代码。
user1971506 2013年

抱歉,应该已经upstream/master。更新了我的答案。
瑞安·斯图尔特

3

正如其他发布者所说,pull将更改从上游合并到您的存储库中。如果要将存储库中的内容替换为上游中的内容,则有几种选择。袖口,我会去

git checkout HEAD^1  # Get off your repo's master.. doesn't matter where you go, so just go back one commit
git branch -d master  # Delete your repo's master branch
git checkout -t upstream/master  # Check out upstream's master into a local tracking branch of the same name

1

在给出的信息的广度和深度方面,最佳答案要好得多,但似乎如果您希望几乎立即解决问题,并且不介意在版本控制的某些基本原理上涉猎,则可以...

  1. 切换至主人

    $ git checkout upstream master
    
  2. 删除不需要的分支。(注意:它必须具有-D,而不是普通的-d标志,因为您的分支在master之前有很多提交。)

    $ git branch -d <branch_name>
    
  3. 创建一个新分支

    $ git checkout -b <new_branch_name>
    

1

尽管这些答案都不适合我,但我可以使用以下命令解决此问题。

git fetch origin

这对我来说是个窍门。


0

如果您有本地不在github中的文件,但您git status却说了几句,只是一个友好的提醒

您的分支机构的最新信息是“来源/主”。没什么可做的,正在工作的树干净

如果文件位于 .gitignore

尝试跑步

cat .gitignore 

并查看这些文件是否显示在此处。那可以解释为什么git不想将它们移动到远程。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.