为啥 Git 说我的主分支“已经是最新的”,即使它不是?

Posted

技术标签:

【中文标题】为啥 Git 说我的主分支“已经是最新的”,即使它不是?【英文标题】:Why does Git say my master branch is "already up to date" even though it is not?为什么 Git 说我的主分支“已经是最新的”,即使它不是? 【发布时间】:2013-02-28 20:27:17 【问题描述】:

基本问题

我刚刚从我的项目中的一个文件中删除了所有代码,并将更改提交到我的本地 git(故意)。我做了

git pull upstream master

从上游获取和合并(理论上删除的代码应该返回)。

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

一切都绝对不是最新的——所有被删除的代码仍然被删除。

其他相关信息

我只有一个名为“master”的分支。

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

分支 master 设置为从上游跟踪远程分支 master。

git branch -vv 命令产生:

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

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

更新

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

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

请原谅我的愤怒,但是这么简单的任务为什么要这么难呢?

【问题讨论】:

很明显,如果你删除你的源代码,然后尝试用一个简单的“pull”拉取,git 不会覆盖你的本地更改(在这种情况下是你的删除),而不确保你真的想要覆盖你的本地变化。第一个答案似乎准确地解释了你可以如何去做。 【参考方案1】:

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

你的分支是最新的'origin/master'。 没有什么可提交的,工作树干净

如果文件位于.gitignore

,就会发生这种情况

尝试运行

cat .gitignore 

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

【讨论】:

【参考方案2】:

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

git fetch origin

这对我有用。

【讨论】:

一样!经过2小时的搜索,这是什么原因??? git fetch --all 和 Eclipse 中的刷新为我完成了这项工作!【参考方案3】:

我和你有同样的问题。

我做了git statusgit fetchgit pull,但我的分支仍然落后于原点。我将文件夹和文件推送到远程,我在网络上看到了这些文件,但在我的本地它们丢失了。

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

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

或者如果你想要一个分支

git checkout your_branch_name_here
git reset --hard origin/your_branch_name_here

【讨论】:

谢谢!这确实有效。请记住,分支名称区分大小写! 哇,它对我有用。 成功了:D 谢谢【参考方案4】:

就所提供信息的广度和深度而言,最佳答案要好得多,但似乎如果您希望几乎立即解决您的问题,并且不介意践踏版本控制的一些基本原则,您可以...

    切换到主人

    $ git checkout upstream master
    

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

    $ git branch -d <branch_name>
    

    新建一个分支

    $ git checkout -b <new_branch_name>
    

【讨论】:

【参考方案5】:

您提交的任何更改(例如删除所有项目文件)在拉取后仍然存在。拉取所做的只是将其他地方的最新更改合并到您自己的分支中,如果您的分支删除了所有内容,那么当上游更改影响您已删除的文件时,您最多会遇到合并冲突。所以,简而言之,是的,一切都是最新的。

如果您描述您希望得到的结果而不是“删除所有文件”,也许有人可以建议适当的行动方案。

更新:

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

您似乎不明白的是,您已经拥有最新的代码,这是您的。如果您真正想要的是查看 其他人在 master 分支上的最新工作,只需执行以下操作:

git fetch upstream
git checkout upstream/master

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

【讨论】:

事实上,我确实想要在我的系统上使用最新版本的其他人的代码。但是,这两个命令并没有这样做。我得到的只是“已经在分支主机上”。我文件中的代码不反映其他人的代码。 对不起,应该是upstream/master。更新了我的答案。【参考方案6】:

我认为你的基本问题是你误解和/或误解了 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 的新本地分支,用于“跟踪”(我不太喜欢这个术语,因为我认为它会使人感到困惑,但这是 git 术语 :-))起源(或上游)master:

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/ 开头的命令。将“yours”与“theirs”匹配是常规的(所以如果他们有remotes/origin/mauve,你也可以将你的命名为mauve),但你可以在想要命名/查看提交时输入“theirs”“从他们”。 (请记住,“一次提交”是一整棵源代码树。您可以从一次提交中挑选出一个特定文件,例如,如果需要,可以使用 git show。)

【讨论】:

我从您的出色回答中学到了很多。但是我仍然对为什么我得到 git 状态消息感到困惑:“当上游仓库在我当前的仓库之前提交了几个提交时,你的分支是最新的‘origin/master’”。我可以使用 git pull 来获取最新信息,但是如果消息说我是最新的,我怎么知道我需要拉取呢? @torek 除了git status 之外,还有什么命令可以用来查看上游仓库是否在我当前的仓库之前?我从git status 收​​到的消息说“您的分支与 'origin/master' 是最新的”,这让我感到困惑,以为我有最新的更改,而我没有。有时,我确实收到一条消息,上面写着“origin/master is 5 commits ahead of your branch”(释义)。但这并不一致。 这仍然不能真正回答为什么git status 说“你的分支是最新的”,而直接的git fetch 然后拉下一百多个对象并解决了近一百个增量,提到了几个新分支和几个新标签并更改主要(远程跟踪)分支头提交 - 然后另一个 git status 愉快地,不诚实地,仍然说“你的分支是最新的”。很明显,很多东西都是从原产地下来的,但分支在之前和之后都是“与原产地同步的”? 谢谢@torek,我在这里找到了一些清晰的东西:***.com/questions/37694515/… 要实现的关键点是“远程跟踪分支”实际上是本地,并且自动保持最新。因此,在fetch 之前,git status 只是与仍然较旧的 local(远程)跟踪分支进行比较。 status 不与 actual 远程分支进行比较。 fetch 将远程的更改带到本地(远程)跟踪分支,然后status 才有意义。 git pull 首先运行git fetch,然后运行git merge(或您选择的其他第二个命令)。 git fetch 步骤通过调用 他们的 Git 并从他们那里获取任何新信息来更新 您的 Git 对 他们的 Git 状态的记忆。您的 git status 仅检查您的 Git 对其 Git 的记忆。【参考方案7】:

正如其他发帖人所说,将上游的更改合并到您的存储库中。如果您想用上游的内容替换存储库中的内容,您有多种选择。袖手旁观,我会去的

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

【讨论】:

以上是关于为啥 Git 说我的主分支“已经是最新的”,即使它不是?的主要内容,如果未能解决你的问题,请参考以下文章

Git,合并已经是最新的但有差异?

为啥我的 git bash 总是从 master 分支开始?

重新提交在 git 中恢复的提交

git:为啥我不能在壁球合并后删除我的分支?

为啥当我执行 git subtree push 时它说我拥有的文件不存在?

git merge master branch来发布分支问题