【问题标题】:Why git pull --rebase results a forced update?为什么 git pull --rebase 会导致强制更新?
【发布时间】:2018-03-08 03:29:59
【问题描述】:

我将一些东西推送到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,不知道会不会和这个问题有关。

获取 URL 与推送 URL 相同。

我已经尝试通过 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.

【问题讨论】:

    标签: git


    【解决方案1】:

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

    • 您的第一次推送
    • 你的第一个 pull --rebase

    您可以在“git pull --rebase lost commits after coworker's git push --force”中了解该场景

    【讨论】:

    • 我希望有人跑git push --force,如果是这样,告诉他/她你不应该这样做。只有我从昨天下午开始提交到 git 服务器,几乎只有我最近 24 小时的提交,而我丢失的提交和之前的提交之间的时间间隔非常短暂,我无法想象有人可以这样做: 1. 偷了我的 SSH私人或修改服务器身份验证日志,2.拉我的提交。 3. 强制推送到服务器。
    • @dawncold 你的远程服务器上是否有两个 repo(一个在 .git 中,一个没有 .git),正如 torek 所建议的那样?
    • git 服务器上只有一个 repo,但我发现有些奇怪:我们有一个 github repo 并通过以下方式创建另一个 git 服务器:git clone --mirror GITHUB_REPO_URL,所以我们推送到我们的 git 服务器并有一个定期作业(每 5 分钟)运行 git push --mirror 到 github。我发现执行了一个 cron 作业(之前或同时)我将丢失的提交推送到 git 服务器。它可能导致回滚?所以我拉了一个回滚的回购然后强制更新?我认为这有点合理。
    • @dawncold 只要推送 --mirror (git-scm.com/docs/git-push#git-push---mirror) 是从远程到 GitHub 完成的,这无关紧要:不会推送任何“回滚”。是否还有一个可以拉的 cron?
    • 我启用了一个只有exec git update-server-info 的更新后挂钩,在 git 服务器上没有另一个 git pull cron 作业。我之前收集了一些 git push --mirror 输出,有一些错误,例如:[remote denied] env-ljmall-public--4 -> env-ljmall-public--4 (cannot lock ref 'refs/heads/ env-ljmall-public--4': 在 c8160801358f1d9019d5f5bf1c737228fba86c43 但预期为 1f00bef7a80c3bf939f06d1b602a57ccc8d58d6d) 我认为这与这个问题有关。
    【解决方案2】:

    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 再次与任何一台回答 Internet-phone-number git.dmright.com 的机器对话。那台机器正在寻找/opt/git/ljmall请注意,此名称不以.git 结尾。这可能是完全正常且无害的,但也可能不是。我们稍后再讨论这个问题。

    与此同时,最后一行——the:

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

    part — 告诉我们您的 Git 相信他们的 master,您的 Git 将其记住为 origin/master 此时指向 694c4c0f9。这是有道理的,因为当他们告诉您他们将master 设置为694c4c0f9 时,您的系统相信他们的系统,这是您git push 的最后一步。但他们告诉你:不,我的 master 指向 fd72e86d7 换句话说,他们的主人似乎已经丢弃了你发送给他们的提交。

    这也是“强制更新”消息的含义。将您自己的 origin/master(您对他们的 master 的记忆)从 694c4c0f9 移动到 fd72e86d7 也需要您丢弃提交(来自您的 origin/master )-您保留它在你自己的master!——你自己的分支是安全的,至少在git fetch级别)。执行此“从origin/master 丢弃”需要使用强制选项;但是在更新远程跟踪名称时会隐含 force 选项,因为您的 Git 打算记住他们的 Git 拥有的内容,即使这需要丢弃提交。

    但是,随后会立即出现问题,因为git pull --rebase 运行git rebase 时启用了fork-point 代码。这可能会产生将您自己的提交从您自己的分支中抛出的副作用! (请参阅我对 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 后缀的名称。

    但是:如果 both /opt/git/ljmall /opt/git/ljmall.git 存在会发生什么?如果您有时告诉他们:使用.git 一个,有时告诉他们:使用不带后缀的一个,那么不幸的是,您最终会使用两个独立的存储库-相似的名字。这只会导致混乱。明智的做法是确保服务器没有两者兼有,但作为服务器的客户端,避免同时使用带后缀和不带后缀的名称也是明智之举。确保您的 fetch 和 push URL 匹配——或者如果它们故意不同,请确保它们比仅仅 .git 后缀有更大的不同。

    【讨论】:

    • 它有问题,但我没有足够的信息来解释为什么会这样。有人运行git push --force 可能是一个原因,如果有同事这样做,我很高兴听到。只有少数人可以推送到 git 服务器,他们都通过 SSH 和 RSA 推送提交,所以我可以检查我的服务器身份验证日志,但是日志文件中只有我的 SSH 密钥,实际上从昨天下午开始就没有人提交了.
    猜你喜欢
    • 1970-01-01
    • 2016-10-27
    • 2016-11-18
    • 2015-04-14
    • 2020-06-08
    • 2015-03-21
    • 1970-01-01
    • 2017-06-30
    • 2011-09-11
    相关资源
    最近更新 更多