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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15376241/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 15:44:07  来源:igfitidea点击:

Why does Git say my master branch is "already up to date" even though it is not?

gitgithubmerge

提问by user1971506

Basic Problem

基本问题

I just deleted ALL the code from a file in my project and committed the change to my local git (on purpose). I did

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

git pull upstream master

to fetch and merge from upstream (so in theory that deleted code should be back).

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

Git tells me everything is up to date.

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

Everything is definitely NOT up to date -- all that deleted code is still deleted.

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

Other Relevant Info

其他相关信息

I only have one branch called "master".

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

I recently set up "master" to track upstream like so:

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

Branch master set up to track remote branch master from upstream.

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

The command git branch -vvyields:

该命令git branch -vv产生:

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

Why why why is this happening? I'm on the verge of just e-mailing my project manager any changes I make to our code.

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

Update

更新

I thought it was obvious, but anyways this is my goal:

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

Get the most recent of the code on my system.

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

Excuse my anger here, but why does such a simple task as that have to be so hard?

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

回答by torek

I think your basic issue here is that you're misinterpreting and/or misunderstanding what git does and why it does it.

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

When you clone some other repository, git makes a copy of whatever is "over there". It also takes "their" branch labels, such as master, and makes a copy of that label whose "full name" in yourgit tree is (normally) remotes/origin/master(but in your case, remotes/upstream/master). Most of the time you get to omit the remotes/part too, so you can refer to that original copy as upstream/master.

当您克隆某个其他存储库时,git 会复制“那边”的任何内容。它还需要“他们的”分支标签,例如master,并制作该标签的副本,该标签在您的git 树中的“全名”是(通常)remotes/origin/master(但在您的情况下是remotes/upstream/master)。大多数情况下,您也可以省略该remotes/部分,因此您可以将该原始副本称为upstream/master.

If you now make and commit some change(s) to some file(s), you're the only one with those changes. Meanwhile other people may use the original repository (from which you made your clone) to make other clones and change those clones. They are the only ones with their changes, of course. Eventually though, someone may have changes they send back to the original owner (via "push" or patches or whatever).

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

The git pullcommand is mostly just shorthand for git fetchfollowed by git merge. This is important because it means you need to understand what those two operations actually do.

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

The git fetchcommand says to go back to wherever you cloned from (or have otherwise set up as a place to fetch from) and find "new stuff someone else added or changed or removed". Those changes are copied over and applied to your copy of what you got from them earlier. They are notapplied to your own work, only to theirs.

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

The git mergecommand is more complicated and is where you are going awry. What it does, oversimplified a bit, is compare "what you changed in your copy" to "changes you fetched from someone-else and thus got added to your-copy-of-the-someone-else's-work". If your changes and their changes don't seem to conflict, the mergeoperation mushes them together and gives you a "merge commit" that ties your development and their development together (though there is a very common "easy" case in which you have no changes and you get a "fast forward").

git merge命令更复杂,并且是您出错的地方。它所做的稍微简单化了一点,就是将“您在副本中更改的内容”与“您从其他人那里获取的更改内容添加到您的其他人的工作副本中”进行比较。如果您的更改和它们的更改似乎没有冲突,则merge操作会将它们融合在一起并为您提供“合并提交”,将您的开发和它们的开发联系在一起(尽管有一种非常常见的“简单”情况,您没有变化,你会得到一个“快进”)。

The situation you're encountering now is one in which you have made changes and committed them—nine times, in fact, hence the "ahead 9"—and they have made nochanges. So, fetchdutifully fetches nothing, and then mergetakes their lack-of-changes and also does nothing.

您现在遇到的情况是您进行了更改并进行了更改——实际上是 9 次,因此是“前进 9”——而他们没有进行任何更改。所以,fetch尽职尽责地什么都不取,然后merge把他们的缺乏变化也没有做。

What you want is to look at, or maybe even "reset" to, "their" version of the code.

您想要的是查看或什至“重置”到“他们的”代码版本。

If you merely want to look at it, you can simply check out that version:

如果你只是想看看它,你可以简单地查看那个版本:

git checkout upstream/master

That tells git that you want to move the current directory to the branch whose full name is actually remotes/upstream/master. You'll see their code as of the last time you ran git fetchand got their latest code.

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

If you want to abandonall your own changes, what you need to do is change git's idea of which revision your label, master, should name. Currently it names your most recent commit. If you get back onto that branch:

如果您想放弃自己的所有更改,您需要做的是更改 git 的想法,即您的标签master应该命名为哪个版本。目前它命名你最近的提交。如果你回到那个分支:

git checkout master

then the git resetcommand will allow you to "move the label", as it were. The only remaining problem (assuming you're really ready to abandon everything you've don) is finding where the label should point.

那么该git reset命令将允许您“移动标签”,就像它一样。唯一剩下的问题(假设你真的准备放弃你所做的一切)是找到标签应该指向的地方。

git logwill let you find the numeric names—those things like 7cfcb29—which are permanent (never changing) names, and there are a ridiculous number of other ways to name them, but in this case you just want the name upstream/master.

git log将让您找到数字名称 - 诸如7cfcb29- 永久(永不更改)的名称,并且有许多其他方法可以命名它们,但在这种情况下,您只需要 name upstream/master

To move the label, wiping out your own changes (any that you have committed are actually recoverable for quite a while but it's a lot harder after this so be verysure):

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

git reset --hard upstream/master

The --hardtells git to wipe out what you have been doing, move the current branch label, and then check out the given commit.

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

It's not super-common to reallywant to git reset --hardand wipe out a bunch of work. A safer method (making it a lot easier to recover that work if you decide some of it was worthwhile after all) is to rename your existing branch:

真正想要git reset --hard并抹去一堆工作并不是常见。一种更安全的方法(如果您认为其中的一些工作是值得的,那么恢复工作会更容易)是重命名现有分支:

git branch -m master bunchofhacks

and then make a new local branch named masterthat "tracks" (I don't really like this term as I think it confuses people but that's the git term :-) ) the origin (or upstream) master:

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

git branch -t master upstream/master

which you can then get yourself on with:

然后你可以开始:

git checkout master

What the last three commands do (there's shortcuts to make it just two commands) is to change the name pasted on the existing label, then make a new label, then switch to it:

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

before doing anything:

在做任何事情之前:

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

after git branch -m:

之后git branch -m

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

after git branch -t master upstream/master:

之后git branch -t master upstream/master

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

Here C0is the latest commit (a complete source tree) that you got when you first did your git clone. C1 through C9 are your commits.

C0是您第一次执行git clone. C1 到 C9 是你的提交。

Note that if you were to git checkout bunchofhacksand then git reset --hard HEAD^^, this would change the last picture to:

请注意,如果您要git checkout bunchofhacks然后git reset --hard HEAD^^,这会将最后一张图片更改为:

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

The reason is that HEAD^^names the revision two up from the head of the current branch (which just before the reset would be bunchofhacks), and reset --hardthen moves the label. Commits C8 and C9 are now mostly invisible (you can use things like the reflog and git fsckto find them but it's no longer trivial). Your labels are yours to move however you like. The fetchcommand takes care of the ones that start with remotes/. It's conventional to match "yours" with "theirs" (so if they have a remotes/origin/mauveyou'd name yours mauvetoo), but you can type in "theirs" whenever you want to name/see commits you got "from them". (Remember that "one commit" is an entire source tree. You can pick out one specific file from one commit, with git showfor instance, if and when you want that.)

原因是HEAD^^将修订从当前分支的头部命名为 2(就在重置之前bunchofhacks),reset --hard然后移动标签。提交 C8 和 C9 现在大部分是不可见的(您可以使用诸如 reflog 之类的东西并git fsck找到它们,但这不再是微不足道的了)。您的标签可以随心所欲地移动。该fetch命令处理以remotes/. 通常将“你的”与“他们的”匹配(所以如果他们有一个remotes/origin/mauvemauve也可以命名你的),但是你可以在你想命名/查看你从“他们”那里得到的提交时输入“他们的”。(请记住,“一次提交”是一棵完整的源代码树。您可以从一次提交中挑选出一个特定的文件,git show例如,

回答by jturi

I had the same problem as you.

我和你有同样的问题。

I did git statusgit fetchgit pull, but my branch was still behind to origin. I had folders and files pushed to remote and I saw the files on the web, but on my local they were missing.

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

Finally, these commands updated all the files and folders on my local:

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

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

or if you want a branch

或者如果你想要一个分支

git checkout your_branch_name_here
git reset --hard origin/your_branch_name_here

回答by Ryan Stewart

Any changes you commit, like deleting all your project files, will still be in place after a pull. All a pull does is merge the latest changes from somewhere else into your own branch, and if your branch has deleted everything, then at best you'll get merge conflicts when upstream changes affect files you've deleted. So, in short, yes everything is up to date.

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

If you describe what outcome you'd like to have instead of "all files deleted", maybe someone can suggest an appropriate course of action.

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

Update:

更新:

GET THE MOST RECENT OF THE CODE ON MY SYSTEM

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

What you don't seem to understand is that you already have the most recent code, which is yours. If what you really want is to see the most recent of someone else'swork that's on the master branch, just do:

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

git fetch upstream
git checkout upstream/master

Note that this won't leave you in a position to immediately (re)start your own work. If you need to know how to undo something you've done or otherwise revert changes you or someone else have made, then please provide details. Also, consider reading up on what version control is for, since you seem to misunderstand its basic purpose.

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

回答by Paul

As the other posters say, pull merges changes from upstream into your repository. If you want to replace what is in your repository with what is in upstream, you have several options. Off the cuff, I'd go with

正如其他海报所说,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

回答by Kenny

While none of these answers worked for me, I was able to fix the issue using the following command.

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

git fetch origin

git fetch origin

This did a trick for me.

这对我有用。

回答by Jorge Israel Pe?a

Someone please correct me if I'm wrong, but I believe this is because your branch is ahead of the upstream master branch by 9 commits. When you do a pull from the remote, you already have those changes, it's just that you're ahead of them by 9 commits. It wouldn't make sense for those old changes, which you already have in your history and are ahead of by 9 commits, to replace your new changes.

如果我错了,请有人纠正我,但我相信这是因为您的分支领先于上游主分支 9 次提交。当您从远程拉取时,您已经有了这些更改,只是您比它们领先 9 次提交。对于那些您已经在历史记录中并且领先 9 次提交的旧更改来替换您的新更改是没有意义的。

I believe if the commits in the remote were newer thenthey would be merged in (by default; unless you specify --rebase) to your current branch.

我相信如果远程提交较新,那么它们将被合并(默认情况下;除非您指定--rebase)到您的当前分支。

Like Ryan said, I suggest you specify exactly what your goal is so that someone may help you more directly.

正如瑞安所说,我建议你明确说明你的目标是什么,这样有人可以更直接地帮助你。

回答by BrotherDonkey

The top answer is much better in terms of breadth and depth of information given, but it seems like if you wanted your problem fixed almost immediately, and don't mind trodding on some of the basic principles of version control, you could ...

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

  1. Switch to master

    $ git checkout upstream master
    
  2. Delete your unwanted branch. (Note: it must be have the -D, instead of the normal -d flag because your branch is many commits ahead of the master.)

    $ git branch -d <branch_name>
    
  3. Create a new branch

    $ git checkout -b <new_branch_name>
    
  1. 切换到主

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

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

    $ git checkout -b <new_branch_name>