当我将提交推送到远程仓库时,为什么Git会显示我的本地“从远程拉”?

时间:2013-10-25 18:37:06

标签: git

所以我在理解Git时遇到了一些麻烦。我在Windows上使用它,带有远程(GitLab安装)repo。我有一个主分支的本地副本,我非常努力地经常使用git pull来保持我的本地副本是最新的。

所以这是发布时间(当然......当发生这种情况时不是吗?)并且我想检查我已经改变的ONE文件。我键入git pull但收到错误:

error: Your local changes to the following files would be overwritten by merge:
        <path>/filename.py
Please, commit your changes or stash them before you can merge.
Aborting

我使用git diff,当然,另一位开发人员在我试图提交的同一地点修正了一个拼写错误。快速git status显示:

Your branch is behind 'origin/master' by 4 commits, and can be fast-forwarded

所以,不知所措,我将更改提交到我的本地仓库。

git add <filename>
git commit -m "reworking to ignore logs"

现在,我可以git pull成功。

git pull origin master 
...
Merge made by the 'recursive' strategy
file1
file2...
....
<filename>
5 files changed, 1 insertion, 63 deletions...

现在,我可以将我的更改推送到远程仓库

git push

但是:这是我的问题。在远程服务器上,它显示了我的提交以及我提交后由本地pull引起的文件更改。也就是说,它基本上表明远程文件已更改,但实际上已更改为远程存储库中的 ALREADY

我的老板惊慌失措地问我为什么要更改所有这些(其他四个)文件,我无法回答。我们最终检查了两个提交(当前和我之前的更改)并对它们进行区分,以证明只有我的一个文件的更改才有所不同,然后我们才松一口气。

所以我的问题是:我错过了什么?为什么Git认为我想看到我更改了文件以匹配遥控器中的远程HEAD?我见过this question about git squashing,并意识到有一个git rebase也可以帮助我。有人可以帮我理解为什么Git会这样做吗?我觉得好像我并没有完全接受“分布式”范式的转变。

2 个答案:

答案 0 :(得分:1)

显然,你你的老板都错过了同样的事情,你的老板也会感到恐慌。 : - )

这是你所做的,以图形形式绘制为提交。最初你在你的回购中有这个:

... - F - G    <-- HEAD=master, origin/master

其中G是当时最新版本。但是在一个文件中存在拼写错误,因此您在工作树中编辑了该文件,从而解决了问题。 (我将在下面方便地命名文件typo。)

$ vim typo
...

你还没有提交,但你确实改变了它。然后你做了:

$ git pull

给你的错误信息。

现在,在幕后,git pull只是git fetch后跟git merge。那么让我们来看看git fetch做了些什么。似乎其他开发者做了四次提交;让我们将它们绘制到commit-tree的图形表示中:

              H - I - J - K      <-- origin/master
            /
... - F - G                      <-- HEAD=master

git merge失败,因为其他人也修改了文件typo

所以,现在你做了:

$ git add typo
$ git commit -m "reworking to ignore logs"

这会在您当前的分支上添加一个新的提交(无论HEAD指向哪个),这显然是master。这给出了一个如下所示的提交树:

              H - I - J - K      <-- origin/master
            /
... - F - G ------------- L      <-- HEAD=master

现在您再次运行git pull,这只是fetch,然后是merge。此次提取无法获取(提交HK,标签origin/master已全部处理完毕)。合并然后将提交Korigin/master)合并到当前分支master,创建新的合并提交M

              H - I - J - K      <-- origin/master
            /               \
... - F - G ------------- L - M  <-- HEAD=master

如果您现在git push结果,则提交M,将您的更改L合并为合并的第一个父级,并将其提交K合并为第二个父母。

这是生成M(正如评论中提到的hobbs)所发生的事情的实际历史,并且完全正常。但是,你(和你的恐慌老板)可能更愿意构建一个不同的历史记录,假装你在之后注意到typo 中的问题,你选择了提交H到{{1 }}。要做到这一点,您需要“修改”您的提交(K,以上),使其位于L之上。

您可以使用origin/master执行此操作(与我在键入此长文件时出现的hobbs' answer一样),或者在执行git pull --rebase后使用普通的git rebase执行此操作。在这种情况下,您要做的是对提交git fetch中的更改进行复制(人们通常拼写为“commit L”):

L'

此时,您不再需要提交 H - I - J - K - L' / ... - F - G ------------- L - 因为git的“reflogs”,它会在回购中停留90天左右,但它会从正常{{1}消失例如,输出 - 所以你只需要稍微重新绘制一下这个图形,将该行留给L,然后像这样贴上标签:

git log

这正是命令序列中的L

              H - I - J - K      <-- origin/master
            /               \
... - F - G                   L' <-- HEAD=master

会做的。 (或者,再次,您可以提交,然后使用git rebase,这只会让git使用$ git add typo $ git commit -m "reworking to ignore logs" $ git rebase - 然后 - git pull --rebase序列,而不是fetch - 然后 - {{ 1}}。如果没有东西可以获取,就像在这种情况下那样,就像运行rebase一样。)

答案 1 :(得分:0)

当您git pull在具有本地更改的分支上,并且还有上游更改时,pull会将上游更改合并到您的本地更改中,从而创建合并提交。当您推送时,此合并提交将被发送到服务器并成为您看到的历史记录的一部分。

可能有所帮助的两件事:

  1. 教你的老板正确阅读历史,而不是对实际不存在的变化感到不满。
  2. 在功能分支上使用git pull --rebase来提取上游更改并在其上重新定位您未经删除的本地工作。这导致了更清晰的历史,除了反历史重写纯粹主义者之外,通常被认为是一种改进。