这个项目只有一个master
分支,所以所有工作都在那里完成。
我错误地犯了一个拼写错误,虽然我可以撤消撤消,但我认为我会尝试完全删除提交。
提交哈希是dbcbf96b
,ded82215
是它之前的提交。所以,在these instructions工作,我这样做了:
git rebase -i ded82215
这会在编辑器中显示“todo”列表,只包含以下内容,如预期的那样:
pick dbcbf96 Writer update.
大概按照生成文件的注释中的说明,我将该行更改为:
drop dbcbf96 Writer update.
我保存了文件并关闭了编辑器。然后说:
Successfully rebased and updated refs/heads/master.
然后我检查了GitLab(我正在使用它来托管这个),期望看到提交消失,但事实并非如此,它仍然存在。
我做git status
看看它推荐了什么动作并且它产生了:
On branch master
Your branch is behind 'origin/master' by 1 commit, and can be fast-forwarded.
(use "git pull" to update your local branch)
nothing to commit, working tree clean
这有点道理,但就篮板而言,我不确定发生了什么。现在我做git pull
来更新本地仓库,但它刚刚回到我开始的地方,回到dbcbf96b
,当地文件仍然包含更改,本地仓库更新,GitLab仍在显示修订版。 pull
命令产生了:
Updating ded8221..dbcbf96
所以我的rebase尝试什么也没做。我在这里想念的是什么?
所以我按照下面的答案建议在第4步和第5步之间尝试git push -f
,但它失败了,产生了:
Total 0 (delta 0), reused 0 (delta 0)
remote: GitLab: You are not allowed to force push code to a protected branch on this project.
To https://gitlab.com/...
! [remote rejected] master -> master (pre-receive hook declined)
error: failed to push some refs to 'https://gitlab.com/...'
然后我尝试git push
只是因为笑容而且它也失败了,产生了:
To https://gitlab.com/...
! [rejected] master -> master (non-fast-forward)
error: failed to push some refs to 'https://gitlab.com/...'
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 fast-forwards' in 'git push --help' for details.
这也是有道理的,我想这就是-f
的用途。第二位中的提示再次推荐git pull
,我已经知道这不是正确的操作。
答案 0 :(得分:4)
所以我的rebase尝试什么也没做。我在这里想念的是什么?
这不是真的,它确实做了一些事情。
你重新设置了你的本地仓库,它对GitLab上的远程仓库没有任何作用。所以远程的那个仍然有不需要的提交,当你git pull
你获取它并将它合并回你的本地仓库时。
在rebase之后,您需要执行git push -f
强制将更改的本地存储推送到GitLab,以删除两个存储库中的错误提交。
答案 1 :(得分:3)
Git是为添加新内容而构建的(其中"东西"意味着"提交")而不是带走东西 。这就是为什么你必须使用强制推动:你的推动会带走东西",即放弃你的提交。
你给了你的rebase一个明确的指示,"放弃这个提交",所以它做了(用一堆安全气囊和安全带让你恢复它,通常至少30天)。常规的git push
不会让你放弃提交;只能用力推动。
因为强制推送可能会丢失提交,一些服务器会提供一个受保护的分支"模式,其中一些/许多/所有人都被禁止强迫推动。这就是你现在遇到的。要成功强制推送,您必须将自己设置为允许执行 - 通常是通过暂时取消保护分支,然后在推送后重新保护它。
确保您不会同时删除任何 else&#39> 提交内容!实际上,分支名称只是提交上的标签。它是提交本身,它们构成了存储库中的提交历史。每个提交本身都有其父提交的ID。我们说每次提交都会回到"它的父母:
... <- commit 1234567 <-- branch
要添加新的提交,Git只是推进分支&#34;转发&#34; (即使所有内部Git箭头指向&#34;向后&#34;)到较新的提交。例如,如果我们从:
开始... <-B <-C <--branch
我们通过制作指向D
的{{1}},然后将名称D
指向C
来添加新提交branch
:
D
要删除... <- B <- C <- D <--branch
,我们会再次D
指向branch
,但如果其他人出现并进行了新的提交C
,则图片现在看起来像这样:
E
当我们现在强制...--B--C--D--E <-- branch
指向branch
时, C
和 D
都会丢失:
E
使用...--B--C <-- branch
\
D--E [abandoned]
,这几乎是你所能做的。 (有一个安全带可用,称为&#34;强制租赁&#34;,你让Git告诉他们的Git:&#34;我相信你的名字git push
指向提交{{1如果是这样,强迫它指向branch
。如果没有,请给我一个错误。&#34;但是没有什么比这更好的了,因为它们在你自己的存储库中。在您自己的存储库,D
提供了复制所选提交到新但能提交不同的提交的功能,以便您可以删除中间产品。 C
只有强制选项。)
由于这些原因,Git还提供了“反转”的能力。一个提交:拿一些现有的提交,弄清楚它做了什么,并完全相反 - 放回任何被删除的文件;删除任何已添加的文件;删除添加的行并添加删除的行 - 作为 new 提交。因此,您可以在较新的提交中撤消任何较旧的提交,而这只是将添加到历史记录中。例如,如果,在:
git rebase -i
序列,我们发现git push
不好,我们可以告诉Git&#34;创建一个与A--B--C--D--E
&#34;相反的新提交B
,给出:
F
&#34;做同样的事情&#34;好像我们从未在序列中有B
或 A--B--C--D--E--F
,但这样做不必打扰B
到F
。通过添加其反转来回退整个提交的命令是C
。
您自己的Git存储库就是:您的。您可以执行任何您想要的操作,包括在链的末尾删除(放弃)提交,或者通过复制过去的所有提交来复制提交(通过E
)以删除中间件点。这样,您就可以编辑历史记录&#34;。
但是,每个提交都有一个唯一的ID。这是Git不时向您展示的丑陋哈希ID。唯一ID是进入提交的所有内容的加密校验和,以及#34;编辑历史记录&#34;导致全新的ID。通过 ID 进行交换(推送和提取)提交,因此一旦您将提交提供给另一个 Git实例 - 例如使用git revert
- 您就拥有< em>发布这些提交。您可以尝试取消发布&#34;他们,但谁知道什么是成功。这有点像试图删除推文:有人可能已经捕获了它。
这并不代表&#34;永远不会尝试更改已发布的历史记录&#34;只是&#34;请注意,如果您确实尝试更改已发布的历史记录,则可能无效,而且#&#34 39; s开始使用发布的历史可能会烦恼。&#34;