为什么git pull --rebase导致强制更新?

时间:2018-03-08 03:30:00

标签: git

我将某些内容推送到master分支,然后运行git pull --rebase,我得到了强制更新,然后我发现我的上一次提交丢失了,这是我的命令行病史:

➜  ljmall git:(master) git commmit -m "refactor: enable self checkout on every environments"
[master 694c4c0f9] refactor: enable self checkout on every environments
 3 files changed, 2 insertions(+), 17 deletions(-)

➜  ljmall git:(master) gp ----> (git push)
Counting objects: 9, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (9/9), done.
Writing objects: 100% (9/9), 1.36 KiB | 1.36 MiB/s, done.
Total 9 (delta 8), reused 0 (delta 0)
To git.dmright.com:/opt/git/ljmall.git
   fd72e86d7..694c4c0f9  master -> master

➜  ljmall git:(master) gst ----> (git status)
On branch master
Your branch is up to date with 'origin/master'.

nothing to commit, working tree clean


➜  ljmall git:(master) veil pull ----> (git pull --rebase)
From git.dmright.com:/opt/git/ljmall
 + 694c4c0f9...fd72e86d7 master     -> origin/master  (forced update)
First, rewinding head to replay your work on top of it...

我不知道为什么git服务器接受了我的提交,但在git pull --rebase之后,它就丢失了。

我不确定我是否可以重现这个问题,因为这是我第一次,在此之前我已经做了100次以上没有任何问题。

我的Git版本是2.16.2,Git服务器版本是2.14.2,我构建了git服务器:git clone --mirror git@github.com:/xxx/xxx.git

我也使用PyCharm IDE,我不知道它可能与此问题有关。

获取网址与推送网址相同。

我尝试通过PyCharm功能恢复我丢失的文件修改,所以我提交并再次推送,没有任何问题,这是我的命令行历史记录:

➜  ljmall git:(master) ✗ git add .
➜  ljmall git:(master) ✗ git commit -nm "refactor: enable self checkout on every environments"
[master bc0dbb78e] refactor: enable self checkout on every environments
 3 files changed, 2 insertions(+), 17 deletions(-)
➜  ljmall git:(master) gp
Counting objects: 9, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (9/9), done.
Writing objects: 100% (9/9), 1.36 KiB | 1.36 MiB/s, done.
Total 9 (delta 8), reused 0 (delta 0)
To git.dmright.com:/opt/git/ljmall.git
   fd72e86d7..bc0dbb78e  master -> master
➜  ljmall git:(master) git pull --rebase
Already up to date.
Current branch master is up to date.

2 个答案:

答案 0 :(得分:1)

只有当其他人被强制推送(git push --force)到git.dmright.com:/opt/git/ljmall.git之间时才会发生这种情况:

  • 你的第一次推动
  • 你的第一次拉--rebase

您可以在" git pull --rebase lost commits after coworker's git push --force"

中了解该方案

答案 1 :(得分:1)

TL; DR

正如VonC建议的那样,可能是其他人(例如,同事)滥用git push --force的情况。这与git pull--fork-point代码交互(严重)的方式相结合,试图从上游倒带或历史重写中恢复。使用Git的reflogs,即使没有PyCharm IDE功能的帮助,你也可以恢复丢失的提交,但是如果你避免使用git pull,你可以避免必须这样做(如果你特别是老鹰眼睛和/或小心,至少)。

  

我不知道为什么git服务器接受了我的提交,但在git pull --rebase之后,它就丢失了。

这很奇怪。我会在您的粘贴输出中注意以下内容:

➜  ljmall git:(master) gp ----> (git push)
[snip]
To git.dmright.com:/opt/git/ljmall.git
   fd72e86d7..694c4c0f9  master -> master

这告诉我们您的Git已调出git.dmright.com并让该服务器在/opt/git/ljmall.git中查看和工作。请注意,此名称.git 结尾。最后一行告诉我们,他们的Git(git.dmright.com上的那个 - 最终同意了你的Git要求将master设置为694c4c0f9;它早于fd72e86d7,从fd72e86d7转移到694c4c0f9是一个快速的操作。

然而不久之后:

➜  ljmall git:(master) veil pull ----> (git pull --rebase)
[snip]
From git.dmright.com:/opt/git/ljmall
 + 694c4c0f9...fd72e86d7 master     -> origin/master  (forced update)

你的Git再一次用任何机器回答互联网电话号码git.dmright.com。那台机器正在寻找/opt/git/ljmall请注意,此名称不会以.git结尾。这可能完全正常且无害,但可能不是。我们马上回过头来看看。

同时,最后一行 - :

  

+ 694c4c0f9...fd72e86d7 master -> origin/master (forced update)

部分 - 告诉我们你的Git认为他们的master,你的Git记得origin/master 指向694c4c0f9。这是有道理的,因为当他们告诉你他们将master设置为694c4c0f9时,系统会相信他们的系统,这是git push的最后一步。但他们告诉你:不,我的master指向fd72e86d7换句话说,他们的主人似乎扔掉了你发送的提交。

这也是“强制更新”消息的内容。移动您自己的origin/master - 您对master的记忆 - 从694c4c0f9fd72e86d7要求您也丢弃提交(来自origin/master < em> only - 你把它保存在你自己的master中! - 你自己的分支是安全的,至少在git fetch级别。执行此操作“从origin/master丢弃”需要使用强制选项;但更新远程跟踪名称时隐含强制选项,因为你的Git打算记住他们的Git有什么,即使这需要丢弃提交。

但是,后续问题立即存在,因为git pull --rebase在启用了fork-point代码的情况下运行git rebase。这可能会产生副作用,将您自己的提交从您自己的分支中删除! (请参阅我对VonC's answer链接的StackOverflow问题的回答。)如果避免 git pull,您可能已经注意到此强制更新。然后你可以小心立即运行git rebase:你可以环顾四周看看发生了什么,以及你是否应该采取额外的步骤(例如还没有使用git rebase恢复。

这是一件小事,但git pull往往充满了这些小锐边。今天比Git 1.5和1.6要好得多,但我仍然建议避免使用git pull,至少在你对Git非常熟悉之前。

.git后缀

的奇怪之处

Git服务器在被要求查找(例如)/opt/git/ljmall时,将首先检查是否存在。如果没有,他们会继续自己添加.git后缀,寻找/opt/git/ljmall.git。如果存在第二条路径,即使您告诉他们使用不带.git后缀的名称,他们也会使用该路径。

但是:如果 /opt/git/ljmall /opt/git/ljmall.git存在,会发生什么?如果您有时告诉他们:使用.git一个,有时会告诉他们:使用未填充的,您将最终使用两个独立的存储库不幸的是 - 相似的名字。这将导致混乱。确保服务器不具备这两者是明智的,但是作为服务器的客户端,它也是明智的,以避免使用后缀和非后缀名称。确保您的抓取和推送网址匹配 - 或者如果它们的目的不同,请确保它们与仅仅.git后缀的差别更大。