您能否提供可能危害git中历史记录的(全部或最常见)操作或命令的列表?
应该绝对避免什么?
git commit
/ git push
/ git commit --amend
)我希望这个问题(如果它还没有在其他地方提出过)在 git 上的常见的可避免操作上成为某种参考。
此外,我经常使用git reset
,但我并不完全了解我可以对存储库(或其他贡献者副本)造成的损害。 git reset
可能有危险吗?
答案 0 :(得分:5)
脱离我的头顶:
git commit --amend
将重写先前的提交git rebase
可以重写多次提交(使用带有git pull
标记的--rebase
或branch.$name.rebase
配置选项时也会调用rebase)git filter-branch
可以重写多次提交git push -f
可以更改分支指向的提交(git push origin +branch
语法也一样)git reset
可以将分支指向的提交更改为git branch -f
可以更改分支指向的提交(通过重新创建具有相同名称的分支)git checkout -B
可以更改分支指向的提交(通过重新创建具有相同名称的分支)答案 1 :(得分:3)
knittl已经编制了一个重写历史的命令列表,但我想以他的答案为基础。
您能否提供可能危害git历史记录的操作或命令列表?什么应该绝对避免?
首先,重写/删除历史本身没有错;毕竟,你可能经常创建功能分支,严格保持本地化,然后删除(合并后或意识到它们无处可去),而不考虑它。
但是,当您在本地重写/删除其他人已经访问过的历史记录然后将其推送到共享远程数据库时,您当然会遇到问题。
当然,有些愚蠢的方法可以破坏或删除历史记录(例如篡改.git/objects/
的内容),但这些方法超出了我的答案范围。
您可以通过各种方式重写本地仓库的历史记录。 Pro Git书中标题为Rewriting history的部分,提到了一些
git amend --commit
git rebase
git filter-branch
可以说,还有更多。任何有可能改变或以其他方式移动非符号引用(分支或标记)并使其指向不分支的当前提示的后代的提交的操作应该算作重写当地历史。这包括:
git commit --amend
:替换最后一次提交; git pull --rebase
); git reset
(请参阅下面的示例); git checkout -B
和git branch -f
:将现有分支重置为其他提交; git tag --force
:重新创建一个具有相同名称但可能指向另一个提交的标记。任何删除非符号引用(分支或标记)也可视为删除历史记录:
git branch -d
或git branch -D
git tag -d
可以说,删除已完全合并到另一个分支的分支应该只被视为一种温和的历史记录删除形式(如果有的话)。
但是,标签不同。删除轻量级标签并不是什么大问题,但删除带注释标签(真正的Git对象)应该算作删除本地历史记录。
据我所知,只有git push -f
(相当于git push --force
)才有可能在远程存储库中重写/删除历史记录。
那说,有可能
receive.denyNonFastForwards
,禁用强制更新远程分支到非快进参考的功能。receive.denyDeletes
,禁用删除生活在远程存储库中的分支的功能。如knittl所述,此外,我经常使用
git reset
,但我并不完全了解我可以对存储库(或其他贡献者副本)造成的损害。git reset
可能有危险吗?
git-reset
通常会更改分支参考所指向的位置。此命令可能很危险,因为它可以使可达提交变得无法访问。因为图片说千言万语,请考虑以下情况:
您位于master
分支上,该分支指向提交D
。现在,让我们说你跑了,例如,
git reset master~2
软复位被认为是最良性的复位形式,因为它只是"只有"更改当前分支指向的位置,但不会影响暂存区域或工作树。也就是说,仅仅改变一个分支指向的方式就会产生影响:在软复位之后,你最终会得到
提交C
和D
,在重置之前可以从master
到达,现在已无法访问;换句话说,它们不是任何引用的祖先(分支,标记或HEAD)。你可以说他们已经在" 知识库中设置&#34 ;;它们仍然存在于您的Git repo对象数据库中,但它们将不再列在git log
的输出中。
如果您在重置之前确实发现这些提交有价值,那么您应该通过再次提交D
一些引用(例如另一个分支)来使它们再次可访问。否则,当Git运行自动垃圾收集并删除无法访问的对象时,提交C
和D
将最终导致真正的死亡。
理论上,您可以从reflog中提交D
,但是您总是有可能忘记那些无法访问的提交或者无法确定哪些提交reflog的条目对应于commit D
。
总之,是的,git-reset
可能是危险的,确保您重置后的分支的当前提示在重置后仍然可以访问是个好主意。如果需要,在重置之前在那里创建另一个分支,以防万一,作为备份;如果你确定要忘记这些提交,你可以随时删除该分支。
答案 2 :(得分:2)
请注意,从Git 2.24(2019年第四季度)开始,上面的列表可能不再需要包含git filter-branch
。
git filter-branch
也已被弃用(BFG也是如此)请参见commit 483e861的commit 9df53c5,commit 7b6ad97,Elijah Newren (newren
)(2019年9月4日)。
(由Junio C Hamano -- gitster
--在commit 91243b0中合并,2019年9月30日)
推荐
git-filter-repo
而不是git-filter-branch
filter-branch
遭受大量变相的隐匿危险 历史记录会重写(即与故意更改有所不同)。许多这些问题并不引人注目,并且可以很容易地被发现,直到 新的存储库正在使用。
这可能会导致各种问题,从比最初导致filter-branch
的人们更混乱的历史到数据丢失或损坏。这些问题无法向后兼容解决,因此请向filter-branch
及其手册页添加警告 建议使用其他工具(例如filter-repo
)。此外,更新引用了
filter-branch
的其他手册页。
即使我们可以继续推荐一些这样的更新,filter-branch
,可能是由于暗示某事是唯一的filter-branch
在更广泛地应用于所有历史记录重写时 工具(例如BFG
,reposurgeon
,fast-import
,filter-repo
)或 以filter-branch
开头的内容为例, 现在存在众所周知的例子。
重命名这些部分以解决这些问题并避免推荐使用filter-branch
。最后,删除将
BFG Repo Cleaner
解释为 替代filter-branch
。
我对此感到有些难过,尤其是因为我觉得自己从BFG学到了很多东西,因此在filter-repo
中得到了很好的利用(这远远超出了我能说的范围)filter-branch
),但保留该部分存在一些问题:
- 为了建议人们使用
filter-branch
退出,我们需要为他们提供其他可以处理所有相同类型重写的建议。
据我所知,filter-repo
是唯一这样的工具。因此需要提及。- 我不想向用户提供有冲突的建议
- 如果我们推荐两种工具,那么我们不应该指望用户学习两种工具并选择使用哪一种。我们应该解释一个问题可以解决另一个问题不能解决的问题,或者一个问题比另一个问题快得多的问题。
BFG
和filter-repo
的性能相似BFG
可以执行的所有过滤类型,filter-repo
也可以执行的所有过滤类型。
实际上,filter-repo
带有名为BFG
的{{1}}的重新实现,它提供了与bfg-ish
相同的用户界面,但具有一些错误修复和新功能,这些功能难以在其中实现BFG
由于其技术基础。尽管我仍然可以提及这两种工具,但似乎我需要提供某种比较,而我最终只是说
BFG
可以filter-repo
所能做的一切,因此最终看来最好将其全部删除。
会破坏git历史记录的操作或命令吗?
至少,newren/git-filter-repo
可以恢复任何受其使用影响的历史记录。
在其既定目标中:
更智能的安全性
将原始引用的副本写入存储库中的特殊名称空间不会提供用户友好的恢复机制。许多人将很难恢复使用它。
我见过的几乎每个人都对存储库进行过滤操作,因为它是全新的克隆,因为万一出现错误,清除克隆是一种非常容易的恢复机制。
如果我们不在新的克隆中,则除非用户用BFG
覆盖,否则请通过检测并释放它来强烈鼓励该工作流。
--force
和mentioned in the documentation的运行方式大致相同:
git filter-repo
git fast-export
/ git fast-import
在git 2.24(2019年第四季度)中有一些改进
请参见commit 941790d,commit 8d7d33c,commit a1638cf,commit 208d692,commit b8f50e5,commit f73b2ab,commit 3164e6b(2019年10月3日) ,以及commit af2abd8的Elijah Newren (newren
)(2019年9月25日)。
(由Junio C Hamano -- gitster
--在commit 16d9d71中合并,2019年10月15日)
例如:
fast-import
:允许标签由标记标签标识签名人:伊利亚·纽伦
标记标识符用于
git fast-export <options> | filter | git fast-import <options>
和fast-export
中,以提供引用早期内容的标签。为Blob提供标签是因为它们需要在首次以给定文件名出现的提交中被引用,并且为提交赋予标签是因为它们可以是其他提交的父对象。
标签从未被赋予标签,可能是因为标签被认为是不必要的,但这带来了两个问题:
- 如果我们要创建标签的标签(或较高的嵌套),那么就无法引用以前的标签。
- 使用
fast-import
和--export-marks
时,我们无法记录已导入标签的情况。通过允许标签使用可选的标签来解决这些问题。
答案 3 :(得分:1)
根据经验,最危险的命令之一是
git push -f mirror
这会将您的本地存储库镜像到远程进程,从而删除除本地存储库上的分支机构之外的所有其他分支。