天道酬勤,学无止境

git push --force,幕后(git push --force, behind the scenes)

问题

当你用 --force git push 时到底发生了什么?

我已经在网上搜索了大约一个小时,我能找到的最相关的答案是:

Same as [git push], but force the push even if it results in a non-fast-forward merge. Do not use the --force flag unless you’re absolutely sure you know what you’re doing.

- 来自 https://www.atlassian.com/git/tutorial/remote-repositories#!push

我想我很清楚这一点,但对我来说这就像说git push --force会强制推送。 尽管我进行了搜索,但我找不到任何真正具体的内容来概述强制推动所涉及的过程。

假设,我有一个名为 git@heroku.com:my-app.git 的主存储库设置,以及在 Heroku 上设置的用于暂存的该存储库的镜像,名为 git@heroku.com:my-app-staging.git。

我创建了一个名为“new_changes”的本地分支,完成了工作,并从该分支推送到暂存。

我不喜欢结果,所以我放弃了这个项目,建立了一个名为“more_new_changes”的新分支,做了一些工作,在本地进行了测试,与 master 合并,并尝试推送到 staging,只是为了确保 staging 已启动-迄今为止。

我的推动告诉我...

Pushing to git@heroku.com:my-app-staging.git
Fetching repository, done.
To git@heroku.com:my-app-staging.git
 ! [rejected]        master -> master (non-fast-forward)
error: failed to push some refs to 'git@heroku.com:my-app-staging.git'
To prevent you from losing history, non-fast-forward updates were rejected
Merge the remote changes (e.g. 'git pull') before pushing again.  See the
'Note about fast-forwards' section of 'git push --help' for details.

我不想将暂存代码合并到我的本地主分支中 - 事实上,我希望暂存代码消失。 (显然,分支将用哈希命名,但为了争论)我想如果我的分期看起来像

push079 -> push080 -> new_changes(HEAD)

我的本地人看起来像

push079 -> push080 -> more_new_changes(HEAD)

我决定使用 --force 推送到暂存,然后结果将是一个看起来像的暂存分支

push079 -> push080 -> more_new_changes(HEAD)

或者它看起来更像

push079 -> push080 -> new_changes
\
> more_new_changes(HEAD)

但如果我错了,它只是将两者挤压在一起,我最终会得到类似的东西

push079 -> push080 -> new_changes -> more_new_changes(HEAD)

然后我失去了拥有一个镜像反映我的生产仓库的临时仓库的连续性。

那么,当您使用 --force 推送时,幕后实际发生了什么?

回答1

这非常简单:Git 客户端发送一条消息,相当于“使引用指向此提交”。 服务器和客户端交换信息,直到服务器具有所需的提交及其历史记录。 然后服务器更新 ref,即将 SHA1 写入文本文件。

在您的情况下,服务器拒绝强制推送,因为它不想丢失任何历史记录。

回答2

git push --force的结果实际上是:

push079->push080->more_new_changes(HEAD)
             \
              ->new_changes (reflog only or git fsck)

一个提交将替换另一个:在推送新提交之前,您不需要删除之前的提交。

这个答案说明了 git fsck 如何让您取回您将用git push --force替换的历史记录。

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 变基后无法推送到分支(can't push to branch after rebase)
    问题 我们使用 git 并有一个 master 分支和 developer 分支。 我需要添加一个新功能,然后将提交重新设置为 master,然后将 master 推送到 CI 服务器。 问题是,如果我在 rebase 期间遇到冲突,我无法在 rebase 完成后推送到我的远程开发人员分支(在 Github 上),直到我拉我的远程分支。 这会导致重复提交。 当没有冲突时,按预期工作。 问题:在变基和解决冲突后,如何在不创建重复提交的情况下同步我的本地和远程开发人员分支 设置: // master branch is the main branch git checkout master git checkout -b myNewFeature // I will work on this at work and at home git push origin myNewFeature // work work work on myNewFeature // master branch has been updated and will conflict with myNewFeature git pull --rebase origin master // we have conflicts // solve conflict git rebase --continue /
  • Updates were rejected because the tip of your current branch is behind
    最近本地一个flutter项目因为当时使用可视化创建的时候出了一些问题,但是起初没有注意,后来因为需要新增一个语音插件,需要修改原生android MainActivity.java,才发现这个目录根本不存在,于是重新创建一个项目将原来那个项目文件拷入,等修改好后再使用git 连接原来那个项目的github仓库进行代码推送,发现老是提示如下错误 $ git push -u origin master To https://github.com/dengxiaoning/flutter-trip.git ! [rejected] master -> master (non-fast-forward) error: failed to push some refs to 'https://github.com/dengxiaoning/flutter-trip.git' hint: Updates were rejected because the tip of your current branch is behind hint: its remote counterpart. Integrate the remote changes (e.g. hint: 'git pull ...') before pushing again. hint: See the 'Note about
  • 无法推送到GitHub-一直说需要合并
    我是GitHub的新手。 今天,当我尝试将代码推送到GitHub时遇到了一个问题。 Pushing to git@github.com:519ebayproject/519ebayproject.git To git@github.com:519ebayproject/519ebayproject.git ! [rejected] master -> master (non-fast-forward) error: failed to push some refs to 'git@github.com:519ebayproject/519ebayproject.git' hint: Updates were rejected because the tip of your current branch is behind hint: its remote counterpart. Merge the remote changes (e.g. 'git pull') hint: before pushing again. hint: See the 'Note about fast-forwards' in 'git push --help' for details. 我尚未在存储库中推送任何内容,那么为什么需要提取内容? #1楼 您在推送之前是否已更新代码? 推送任何内容之前
  • ! [拒绝]管理员->管理员(先获取)(! [rejected] master -> master (fetch first))
    问题 有没有很好的方法来解释如何在Git中解析“ ! [rejected] master -> master (fetch first)' ? 当我使用此命令$ git push origin master它显示一条错误消息。 ! [rejected] master -> master (fetch first) error: failed to push some refs to 'git@github.com:zapnaa/abcappp.git' 回答1 答案就在那里,git告诉您先获取。 可能其他人已经推动精通,而您的承诺却落伍了。 因此,您必须获取,合并变更集,然后才能再次推送。 如果不这样做(或者更糟的是,如果使用--force选项来强制它),则可能会弄乱提交历史记录。 编辑:关于最后一点,我会做更多详细的介绍,因为这里的一个人刚刚给出了使用--force选项的非常不好的建议。 因为git是DVCS,所以理想情况下,许多其他开发人员正在使用相同的存储库(或其中的一个分支)来与您进行同一个项目。 如果用更改集强行覆盖,则存储库将与其他人的存储库不匹配,因为“您重写了历史记录”。 您将使其他人不满意,并且存储库将遭受损失。 可能世界上的小猫也会哭。 TL; DR 如果要解决,请先获取(然后合并)。 如果要破解,请使用--force选项。 不过,您要求的是前者。 始终选择1)
  • Git Force推送语法,“-f”和“ + branch”(Git Force push syntax, “-f” versus “+branch”)
    问题 强制更改时,这两个git命令有什么区别? git push -f origin branch和git push origin +branch 回答1 TL; DR 如果只推一个分支,就没有区别。 git push -f origin branch 和 git push origin +branch 是完全等效的。 当您通过一次git push推送多个分支时,就会出现差异。 简而言之,与-f相比,可选的+可为您提供更好的控制:如果您一次推送多个引用,则+可让您指定要强制推送的是哪些推送的引用,而--force (或-f )适用于所有推送的引用。 更多细节 git-push手册页告诉您什么 涉及一个或多个refspec的git push最基本形式是 git push <repository> <refspec>... <refspec>...参数必须满足的形式在git-push手册页中进行了描述: <refspec>... Specify what destination ref to update with what source object. The format of a `<refspec>` parameter is an optional plus `+`, followed by the source object `<src>`, followed by a
  • Git,如何将原点/主节点重置为提交?(Git, How to reset origin/master to a commit?)
    问题 我通过以下命令将本地主服务器重置为提交: git reset --hard e3f1e37 当我输入$ git status命令时,终端说: # On branch master # Your branch is behind 'origin/master' by 7 commits, and can be fast-forwarded. # (use "git pull" to update your local branch) # nothing to commit, working directory clean 由于我也想重置原点/标头,因此我签出到原点/原版: $ git checkout origin/master Note: checking out 'origin/master'. You are in 'detached HEAD' state. You can look around, make experimental changes and commit them, and you can discard any commits you make in this state without impacting any branches by performing another checkout. If you want to create a new
  • 通过1次提交回滚本地和远程git存储库(Rolling back local and remote git repository by 1 commit)
    问题 我已经阅读过有关该主题的类似文章,并且终生无法找出如何正确执行此操作的方法。 我检入了大约1000个我不想要的文件,而我不想不必经过1by1并将其全部从存储库中删除。 我有一个远程master分支。 我有当地的master 。 他们都是在同一修订版。 我想通过1次提交来回滚我的遥控器。 假设我在master历史是A--B--C--D--E 。 我想将我的本地回滚到D 然后将其推送到远程,这样我当前的哈希值将同时为远程和本地D。 我在执行此操作时遇到问题。 我正在使用Git Tower,但对命令行感到满意。 有什么帮助吗? 更新:很棒的评论在下面。 似乎不鼓励使用重置,尤其是在与其他用户共享存储库的情况下。 取消上一次提交的更改而不使用硬重置的最佳方法是什么? 有办法吗? 回答1 如果还没有人拉过您的远程存储库,则可以更改分支HEAD并将其强制推送到所述远程存储库: git reset --hard HEAD^ git push -f (或者,如果您可以直接访问远程存储库,即使它是裸存储库,也可以更改其HEAD引用) 请注意,正如外来技术在下面的评论中所评论的那样,在Windows(CMD会话)上,您将需要^^ : git reset --hard HEAD^^ git push -f 自2011年以来的更新: 使用git push --force-with-lease
  • 为什么我不能推送此最新的Git子树?(Why can't I push this up-to-date Git subtree?)
    问题 我正在将Git子树与正在处理的几个项目一起使用,以便在它们之间共享一些基本代码。 基本代码会经常更新,并且升级可以在任何项目中进行,并且最终所有项目都将进行更新。 我遇到了一个问题,其中git报告我的子树是最新的,但是推送被拒绝了。 例如: #! git subtree pull --prefix=public/shared project-shared master From github.com:**** * branch master -> FETCH_HEAD Already up-to-date. 如果我进行推送,我应该收到一条消息,即没有任何内容可以推送...对吗? 对? :( #! git subtree push --prefix=public/shared project-shared master git push using: project-shared master To git@github.com:*** ! [rejected] 72a6157733c4e0bf22f72b443e4ad3be0bc555ce -> master (non-fast-forward) error: failed to push some refs to 'git@github.com:***' hint: Updates were rejected
  • 如何从git push -force中恢复?(How to recover from a git push -force?)
    问题 这是发生了什么: 我有两个远程git分支: master和feature1 。 出于某种原因,我必须对feature1分支使用git push --force ,但是我不知道何时使用git push --force也会推动master分支。 然后,当我将本地master分支推送到远程存储库时,发生了灾难。 幸运的是,我的本地分支机构离远程站点不太远。 基本上,我的远程master在我的本地master之前合并了两个拉取请求。 所以我的问题是:我可以重新打开拉取请求并重新合并吗? 我注意到有用于合并请求的提交版本,所以我担心如果我仅仅提出新的请求,就会搞砸吗? 理想情况下,我只想重做两个请求的合并。 还有其他方法可以从这场灾难中恢复过来吗? 我了解到--force是一个非常非常糟糕的选择。 :( 更新,发生的事示例: 我有以下分支: master feature1 origin/master origin/feature1 我通过使用GitHub的Auto merge pull requests集成了两个拉Auto merge pull requests 。 然后,我没有在本地计算机上获取master分支。 因此,我认为我的origin/master比远程主服务器落后两个版本。 然后我不小心使用了git -f push ,它覆盖了远程分支
  • 在github上找到强制推送的提交者(Find committer of a force push on github)
    问题 在我们的项目(该项目托管在GitHub上)中,偶尔有人不时地强制推送master。 没有人知道是否这样做,我想找出是谁做的,以及背后隐藏着哪种错误配置的工具或不良习惯。 因此,问题是,如何识别推动力量的用户? 当我拉动时,我看到这样的事情: # git pull --prune (.....) + 4c0d44c...138b9ed master -> origin/master (forced update) 但是138b9ed只是源/主138b9ed中的最新提交,任何人在强行推动后都可能已经提交过; 推力推销器自己甚至可能没有做任何事情,只是改头换面,因此他的名字甚至在作者的原著/大师历史的改写部分中也没有出现。 我也尝试了git reflog origin/master ,但是它只提供了相同的信息:有一条记录说git pull --prune (forced update)的提交ID为138b9ed ,但这又将最后一个提交者提供给master,而不是一位用力推动的人。 在原始服务器上运行git reflog master可能会有所帮助,但是GitHub并没有为您提供这种访问AFAIK的权限。 有没有可靠的方法来找出推送的来源(以及何时)? 回答1 您可以将一个Webhook添加到您的Github存储库,并使其将推送通知提交到某些服务器或诸如requestb
  • How to recover from a git push -force?
    Here is what happened: I have two remote git branches: master and feature1. For some reason I have to use git push --force for the feature1 branch, but I didn't know when I use git push --force it will also push the master branch. Then, a disaster happened, as I pushed my local master branch to the remote repository. Luckily, my local branch is not too far away from the remote. Basically, my remote master has two pull requests merged ahead of my local master. So my problem is: can I reopen the pull request and remerge? I noticed that there is commit version for merge request, so I am worried
  • 推送后如何压缩git中的提交?(How to squash commits in git after they have been pushed?)
    问题 这很好地解释了压缩多个提交: http://git-scm.com/book/en/Git-Branching-Rebasing 但不适用于已被推送的提交。 如何在本地和远程存储库中压缩最近的几次提交? 当我执行git rebase -i origin/master~4 master ,将第一个保留为pick ,将其他三个保留为squash ,然后退出(通过emacs中的cx cc),我得到: $ git rebase -i origin/master~4 master # Not currently on any branch. nothing to commit (working directory clean) Could not apply 2f40e2c... Revert "issue 4427: bpf device permission change option added" $ git rebase -i origin/master~4 master Interactive rebase already started 其中2f40是pick提交。 现在这4个提交都没有出现在git log 。 我希望我的编辑器可以重新启动,以便我可以输入提交消息。 我究竟做错了什么? 回答1 壁球本地提交 git rebase -i origin/master~4
  • 将当前的Git分支设为master分支(Make the current Git branch a master branch)
    问题 我在Git中有一个存储库。 我做了一个分支,然后对母版和分支进行了一些更改。 然后,在数十次提交之后,我意识到分支的状态要比主服务器好得多,因此我希望分支“成为”主服务器,而忽略主服务器上的更改。 我无法合并它,因为我不想将更改保留在主文件上。 我应该怎么办? 附加:在这种情况下,“旧”母版已经push送到另一个存储库,例如GitHub。 这如何改变事情? 回答1 其他两个答案的问题在于,新主人没有老主人的祖先,因此当您按下它时,其他所有人都会陷入困境。 这是您要执行的操作: git checkout better_branch git merge --strategy=ours master # keep the content of this branch, but record a merge git checkout master git merge better_branch # fast-forward master up to the merge 如果您想更清楚地了解历史记录,建议您向合并提交消息中添加一些信息,以使您清楚自己所做的事情。 将第二行更改为: git merge --strategy=ours --no-commit master git commit # add information to the template merge message
  • 解决git push报错: hint: Updates were rejected because the tip of your current branch is behind和各种其它小报错
    文章目录 报错原因解决方案一解决方案二解决方案三 报错原因 ! [rejected] master -> master (fetch first) error: failed to push some refs to ‘https://github.com/fang0jun/myLeetCode.git’ hint: Updates were rejected because the remote contains work that you do hint: not have locally. This is usually caused by another repository pushing hint: to the same ref. You may want to first integrate the remote changes hint: (e.g., ‘git pull …’) before pushing again. hint: See the ‘Note about fast-forwards’ in ‘git push --help’ for details. 这本地仓库与线上仓库不一致产生的报错! 解决方案一 产生的原因是本地仓库与线上仓库的内容不匹配,或者说本地相对于远程不是最新,先pull更新本地,再把自己的push上去。
  • 推送后更改git commit消息(假设没有人从远程拉出)(Changing git commit message after push (given that no one pulled from remote))
    问题 我做了一个git commit和随后的推送。 我想更改提交消息。 如果我理解正确,那么这是不可取的,因为在进行此类更改之前,可能有人从远程存储库中拉出了。 如果我知道没人拉怎么办? 有没有办法做到这一点? 回答1 改变历史 如果这是最近的提交,则只需执行以下操作: git commit --amend 这将使编辑器显示最后的提交消息,并允许您编辑消息。 (如果要清除旧消息并使用新消息,则可以使用-m 。) 推动 然后,当您按下按钮时,请执行以下操作: git push --force-with-lease <repository> <branch> 或者,您可以使用“ +”: git push <repository> +<branch> 或者您可以使用--force : git push --force <repository> <branch> 使用这些命令时要小心。 如果其他人将更改推送到同一分支,则可能要避免破坏这些更改。 --force-with-lease选项是最安全的,因为如果上游有任何更改,它将终止。 如果您未明确指定分支,则Git将使用默认的推送设置。 如果您的默认推送设置为“匹配”,则您可以同时销毁多个分支上的更改。 之后拉/取 现在,任何已经拉出的人都会收到一条错误消息,并且他们需要通过执行以下操作来更新(假设他们自己没有进行任何更改): git
  • Git说本地分支位于远程分支后面,但不是(Git says local branch is behind remote branch, but it's not)
    问题 设想: 我做了一个新的分支骇客提交推它黑客更多再次提交尝试再次推动 Git回应: 由于当前分支的尖端位于其远程对应的后面,因此更新被拒绝。 等等。 我是该分支上唯一的黑客-没有其他人在触摸它。 远程分支实际上位于本地分支之后。 我根本不用拉 (如果我确实拉了,Git会报告两者之间的冲突,并迫使我将分支合并到自身中) 为什么(可能)发生这种情况? 我该如何诊断/修复它? 需要明确的是,我没有分支到任何地方,也没有其他人对此进行研究: Remote: Commit A -------- Commit B Local: Commit A -------- Commit B -------- Commit C C是B的直接延续,不涉及分支。 但是git认为C是A的一个分支: Remote: Commit A -------- Commit B ------- Commit C / Local: Commit A -------- Commit B 不是; 这是B的直接延续。 回答1 您可能重写了一些历史记录? 您的本地分支与服务器上的分支不同。 运行以下命令以更好地了解发生了什么: gitk HEAD @{u} 我强烈建议您尝试了解此错误的来源。 要修复它,只需运行: git push -f -f使其成为“强制推送”,并覆盖服务器上的分支。 当您在团队中工作时,这是非常危险的。
  • Updates were rejected because the tip of your current branch is behind its remote counterpart
    Our workflow is such. We have a branch called dev which I can reach at origin/dev. When we do changes, we create a branch off dev: git checkout -b FixForBug origin/dev Now I have a branch called FixForBug which is tracking (I think that's the right word) origin/dev. Thus, if I do a git pull it'll bring in new changes from origin/dev which is great. Now, when I'm finished with my fix, I push to a remote branch called the same thing. First I pull down any changes from origin/dev and do a rebase: git pull --rebase Then I push the changes to a remote branch of the same name: git push origin
  • git:“由于当前分支的尖端不在后面,所以更新被拒绝了。”但是如何看到差异呢?(git: “Updates were rejected because the tip of your current branch is behind..” but how to see differences?)
    问题 我刚刚完成了一段代码。 想要推动并获得知名度: 提示:更新被拒绝,因为当前分支的提示位于提示:远程对应的提示之后。 在再次推送之前,集成远程更改(例如提示:'git pull ...')。 现在,我已经看到此问题在此处多次发布,例如 更新被拒绝,因为当前分支的提示位于提示之后:它的远程对应。 集成远程更改(例如, 由于您当前分支的尖端不在后面,因此更新被拒绝 根据具体情况,解决方案是 git pull ,因此远程更改将合并到我的本地工作中,或者 git push -f ,强制推送以更新远程(原始)分支。 现在,已经有一段时间我没有在这个分支上工作了。 我不一定要将远程更改合并到我当前的工作中! 我也不知道我是否可以安全地在origin分支上强制进行更新... 我如何才能看到差异并确定最适合我的情况? 回答1 为了查看差异,首先需要从原始存储库中获取提交: git fetch origin 现在您可以看到差异(假设您位于master分支上) git diff HEAD..origin/master 现在你是武装与您寻求决定知识merge或rebase前push荷兰国际集团更改。 回答2 最近,当我使用git checkout -b feature/abc创建一个新分支时,发生了这种情况,提交了一些更改,然后尝试git push --set-upstream origin
  • How do I force a subtree push to overwrite remote changes?
    We use a subtree deployment a lá this Gist to deploy a subdirectory of our Yeoman project. In our case, the branch is called production, not gh-pages. This worked perfectly until yesterday when the Git server rejected the command git subtree push --prefix dist origin production, saying ! [rejected] 9fe1683aa574eae33ee6754aad702488e0bd37df -> production (non-fast-forward) error: failed to push some refs to 'git@gitlab.sdstate.edu:web-and-new-media/graduation2015.git' hint: Updates were rejected because a pushed branch tip is behind its remote hint: counterpart. If I switch to the production
  • Find committer of a force push on github
    In our project (which is hosted on GitHub), someone accidentally force-pushes master every once in a while. No one is aware if doing so, and I would like to find out who does it and what sort of misconfigured tool or bad habit is behind it. So the question is, how to identify the user who made the force push? When I pull I see something like this: # git pull --prune (.....) + 4c0d44c...138b9ed master -> origin/master (forced update) but 138b9ed is just the latest commit in origin/master, and anyone might have committed after the force push; it is even possible that the force pusher himself did