在 GitLab 上删除提交

75

我如何在GitLab上删除我所做的提交?这个提交现在不是HEAD。

如果我不能删除它,那么能否编辑它?

当它还是HEAD的时候,我尝试过:

git reset  --soft HEAD

git reset  --soft HEAD^1

git revert HEAD

git rebase -i HEAD

git rebase -i HEAD~1

git reset --hard HEAD

git reset --hard Id-Code

我已经尝试过变基,但它仍然停留在分支上。现在我刚从HEAD中删除了它,但它仍然存在。

还有其他命令吗?


你把提交推到了你的GitLab服务器上吗? - marcusshep
正如@Álvaro-p在下面的回答中提到的评论中所述,当您进行推送时,需要强制使用(-f),并确保该分支在GitLab中未受保护。 - user12345
大多数解决方案并不意味着在本地repo更改后进行强制推送。即使具有维护者权限,我也无法在GitLab上执行--force push。git push origin master --force 计数对象:5,完成。 使用最多4个线程的Delta压缩。 正在压缩对象:100%(5/5),完成。 写入对象:100%(5/5),1.02 KiB | 131.00 KiB/s,完成。 总共5个(delta 0),重用0个(delta 0) 远程:GitLab:您不被允许向此项目的受保护分支强制推送代码。因此,GitLab仍然没有解决方案。 - Roman Shishkin
1
@RomanShishkin,你的GitLab项目已配置为防止在受保护分支上进行强制推送。只需暂时允许它执行强制推送,然后再将其禁用即可。 - Didier L
4个回答

99
  1. git reset --hard CommitId
  2. git push -f origin master

第一个命令将重置您的当前分支到指定的CommitId,第二个命令将强制删除主分支上该提交以及之后的所有提交。

注意:在 push 命令中加入 -f 参数,否则会被拒绝。


记得在 push 命令中加上 -f 参数,否则会被拒绝。 - ABHAY JOHRI
10
这个回复没有解决OP所提出的问题。你的解决方案会移除任意提交后的所有提交,但不会仅移除一个不再分支顶端上的提交。 - Álvaro P.
注意!!这将会删除所有的更新和提交。 - yan
7
请注意,如果Gitlab上的主分支受到保护,则您可能需要暂时取消其保护才能使(2)起作用。 - Mario Orlandi
我同意回答并没有真正解决问题,但它解决了我的问题(尝试还原到以前的提交)。 :-) - Alek Davis

69

假设您有以下情况:

* 1bd2200 (HEAD, master) another commit
* d258546 bad commit
* 0f1efa9 3rd commit
* bd8aa13 2nd commit
* 34c4f95 1st commit

如果您想要删除d258546(即“坏提交”),您可以尝试交互式变基:git rebase -i 34c4f95,然后您的默认编辑器将弹出类似于以下内容:

 pick bd8aa13 2nd commit
 pick 0f1efa9 3rd commit
 pick d258546 bad commit
 pick 1bd2200 another commit

 # Rebase 34c4f95..1bd2200 onto 34c4f95
 #
 # Commands:
 #  p, pick = use commit
 #  r, reword = use commit, but edit the commit message
 #  e, edit = use commit, but stop for amending
 #  s, squash = use commit, but meld into previous commit
 #  f, fixup = like "squash", but discard this commit's log message
 #  x, exec = run command (the rest of the line) using shell
 #
 # These lines can be re-ordered; they are executed from top to bottom.
 #
 # If you remove a line here THAT COMMIT WILL BE LOST.
 #
 # However, if you remove everything, the rebase will be aborted.
 #
 # Note that empty commits are commented out

只需删除包含您想要剥离的提交的行,并保存+退出编辑器:

 pick bd8aa13 2nd commit
 pick 0f1efa9 3rd commit
 pick 1bd2200 another commit
 ...

Git将从您的历史记录中删除此提交,留下类似以下内容(请注意,从已删除的提交后代开始哈希值已发生更改):

 * 34fa994 (HEAD, master) another commit
 * 0f1efa9 3rd commit
 * bd8aa13 2nd commit
 * 34c4f95 1st commit

现在,由于我假设您已经将错误提交推送到gitlab,因此您需要重新将图形推送到存储库(但使用-f选项防止由于不可快速转发的历史记录而被拒绝,即git push -f <your remote> <your branch>)。

请格外小心,并确保没有同事已经在他们的分支中使用包含“坏提交”的历史记录。

备选方案:

与其重写历史记录,不如创建一个新提交,以抵消您的错误提交引入的更改,只需键入git revert <your bad commit hash>。这个选项可能不是很干净,但是更加安全(如果您不完全了解交互式变基的操作)。


1
@mhery,那么第一种选项就是你想要的。在推送之前,请确保仔细检查所有提交是否有序,因为git push -f是永久性的且不可逆转的。 - tcooc
6
从 GitLab 服务器上删除它,您需要推送您的分支。记得设置 -f(即强制)选项,否则它会被拒绝。(由于您正在使用 GitLab,请确保您的分支未受到强制推送的保护;在这种情况下,您或您的存储库管理员应在强制推送之前在存储库设置中取消“受保护分支”开关)。 - Álvaro P.
9
这将从分支的历史图中删除提交,有效地孤立它,但不会完全删除提交 - 如果您知道提交哈希值,即使在没有包括在任何分支或标签中,您仍可以通过Gitlab的Web界面找到提交。这至少是在打开合并请求记住在强制推送之前它曾包括该提交的情况下成立的。我不确定如果提交在没有合并请求的情况下是否会保留在分支中,但我不想冒险。 - Zeust the Unoobian
7
Zeust the Unoobian 是正确的。该提交仍然在 GitLab 中。即使运行“Housekeeping”,也无法将其删除。“Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects.”我怀疑这是因为它仍然与 Pipeline 相关联,所以它并不是真正的不可访问状态。 - John Vandenberg
1
看起来现在可以在GitLab中删除一些不再需要的提交记录列表了,详见减小Git仓库大小 - l0b0
显示剩余5条评论

20

我们曾经遇到过类似的问题,仅仅删除提交并强制推送到GitLab是不够的。
使用URL在GitLab界面上仍然可以访问它:

https://gitlab.example.com/<group>/<project>/commit/<commit hash>
我们不得不从GitLab中删除该项目并重新创建它,以便在GitLab UI中摆脱这个提交。

即使运行了他们的清理工具,这里仍然是同样的情况。我决定保持原样,因为如果不知道正确的哈希值,它就无法被找到。让我来到这个页面的有趣的事情是:在升级MacOS后,对于我的第一个提交,我必须通过IntelliJ框设置我的git用户名和电子邮件。我太快了,出于习惯输入了我的用户名和...我的密码,这是我用于其他帐户(但未启用2FA)和解锁我的MacBook的密码...所以在GitLab UI中,您可以在与我的提交相关的图标上悬停并看到"mailto:MYPASSWORD"。嘿嘿嘿 - lboix
这个问题还有其他解决方案吗? - Charalamm
1
根据 Álavro P. 的另一条评论,现在可以删除一系列的提交(尽管我自己没有尝试过)。你可以参考这个链接了解如何进行清理存储库 - Didier L

3
我假设您想编辑所有提交以从中删除某些字符串,例如泄露的凭据。
真正从Gitlab服务器中清除旧提交是一项棘手的任务,如 Gitlab清除文档所述,因为它涉及从服务器中删除所有内部引用。这在Gitlab 11.6版本以上是可能的(请参阅该文档)。
以下是主要步骤:
  • 安装git-filter-repo
  • 通过导出项目从Gitlab下载所有git引用
  • 然后循环执行以下步骤:
    • 使用 git filter-repo 更新存储库内容
    • 上传修改后的内容
    • 清理悬空引用
    当这些操作完成时,Gitlab项目将清除所有对那些旧提交的引用。

    警告

    注意,此前制作的任何本地副本仍将包含已删除的提交。此外,尝试从那些旧本地副本中拉取的用户将会陷入困境。
    详细过程:
    • 安装 git-filter-repo
    • 按照Gitlab导出文档从Gitlab导出项目:进入设置->高级,点击导出项目按钮,按照通过电子邮件收到的链接下载导出文件
    • 创建一个临时文件夹并跳转到它:mkdir tmp && cd tmp
    • 解压缩导出的存档:tar xf path/to/downloaded...export.tar.gz
    • 克隆项目捆绑包:git clone --bare --mirror export.bundle
    • 将要更改的所有表达式复制到expressions.txt

    示例内容:

    a_sample_password==>DELETED
    
    • 跳转到克隆的仓库:cd project.git
    • 更新源远程地址:git remote set-url origin YOUR_REMOTE_ORIGIN
    • 运行git filter-repo --replace-text ../expressions.txt
    • 进入Gitlab 设置->仓库->受保护的分支并取消保护任何受保护的分支
    • 使用git push origin --force 'refs/heads/*'上传结果
    • 使用git push origin --force 'refs/replace/*'删除悬空提交
    • 等待30分钟
    • 在Gitlab 设置->仓库中,使用文件filter-repo/commit-map运行仓库清理
    • 重新保护Gitlab 设置->仓库->受保护的分支中未受保护的分支

    请查看git-filter-repo示例获取更多示例。有关Gitlab清理的详细信息,请参见Gitlab文档中的repo cleanup。我创建了一个示例存储库以说明该过程。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接