我需要将某个提交从git的提交历史中彻底删除。我希望能够删除提交 abc123...
,使得执行 git checkout abc123...
时返回 error: pathspec 'abc123...' did not match any file(s) known to git.
QA 删除Git分支中的提交 部分回答了如何在HEAD中删除对提交的引用,但它并未涵盖查找所有包含特定提交的分支,也没有涵盖一旦特定提交成为悬空提交后如何使其失效和清除。
我应该如何实现这个目标?
我需要将某个提交从git的提交历史中彻底删除。我希望能够删除提交 abc123...
,使得执行 git checkout abc123...
时返回 error: pathspec 'abc123...' did not match any file(s) known to git.
QA 删除Git分支中的提交 部分回答了如何在HEAD中删除对提交的引用,但它并未涵盖查找所有包含特定提交的分支,也没有涵盖一旦特定提交成为悬空提交后如何使其失效和清除。
我应该如何实现这个目标?
List all branches that contain the commit:
git branch --contains COMMITSHA
Remove commit from these branches:
git checkout BRANCH
git rebase -i COMMITSHA^
# delete line with commit and save
If a changed branch is tracked in any remote, push it there with override:
git push --force REMOTE BRANCH
e.g:
git push --force origin master
(Note that, depending on your development process, the commit may appear in untracked remote branches as well.)
Purge the commit, so it can not be restored from your local repo:
git reflog expire --all BRANCH1 BRANCH2 # list all branches you changed
git prune --expire now
Note that you must also run this command on all remote repositories that had this commit. If you have no access to the remote repo, you have to cross your fingers — commit will eventually expire by itself and will be purged by git gc
.
Be warned that above commands will remove all dangling objects from Git repo and all the history of branch changes — so you wouldn't be able to restore (by non-forensic means) anything lost prior to its run.
Tell all collaborators to fetch changed branches and update any work they might have based on them. They should do as follows:
git fetch REMOTE
For each branch that is based on a branch you changed above (including the branch itself if they have it locally):
git checkout BRANCH
git rebase REMOTE/BRANCH
git reflog expire --all BRANCH
After they're done:
git prune --expire now
git rebase -i --preserve-merges COMMITSHA^
来避免提交图的平坦化吗? - Harry.git/objects
删除对象(它将位于以哈希的前两个字符命名的文件夹中,并且文件名将是其余的哈希)。.git/objects
可能不是个好主意,你可以使用git prune
命令完成这项任务。 - Alexander Gladyshgit prune
包括更多步骤以确保对象实际上被删除(例如确保清除 reflogs 等)。直接删除对象文件不需要这些步骤,并且通常是安全的,只要您不依赖该提交进行任何操作。 - Ambergit reflog expire --all BRANCH
应该可以做到这一点,不是吗? - Alexander Gladysh