Kam*_*her 6 git github git-rewrite-history
你能提供一个(全部或最常见的)操作或命令列表,这些操作或命令会危害git中的历史记录吗?
什么应该绝对避免?
git commit
/ git push
/ git commit --amend
)我希望这个问题(如果它还没有在其他地方之前提出过)成为关于git上常见的可避免操作的某种参考.
此外,我使用git reset
了很多,但我还没有完全意识到我可以对存储库(或其他贡献者副本)造成的损害.可能git reset
有危险吗?
Von*_*onC 10
请注意,从 Git 2.24(2019 年第四季度)开始,上面的列表可能不再需要包含在内git filter-branch
。
git filter-branch
正在被弃用(BFG也是)见提交483e861,提交9df53c5,提交7b6ad97(2019年9月4日)通过以利亚Newren( )newren
。
(由Junio C gitster
Hamano合并-- --在提交 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
尽管有其他更多信息,但仍将about用作示例。现在存在众所周知的例子。
重新编写这些部分以解决这些问题并避免推荐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
namedbfg-ish
,它提供了相同的用户界面,BFG
但有几个错误修正和新功能,BFG
由于其技术基础而难以实现。虽然我仍然可以提到这两个工具,但似乎我需要提供某种比较,我最终只会说
filter-repo
可以做任何事情BFG
,所以最终似乎最好完全删除该部分。
哪些操作或命令会破坏 git 中的历史记录?
至少,它newren/git-filter-repo
可以从因使用而受损的任何历史记录中恢复。
在其既定目标中:
更智能的安全
将原始引用的副本写入 repo 中的特殊命名空间并不能提供用户友好的恢复机制。许多人会很难使用它来恢复。
我见过的几乎所有执行存储库过滤操作的人都使用新的克隆来执行此操作,因为在出现错误时清除克隆是一种非常容易的恢复机制。
如果我们不是新的克隆,则通过检测和保释来强烈鼓励该工作流程,除非用户使用--force
.
git filter-repo
正如文档中提到的,通过运行大致可以工作:
Run Code Online (Sandbox Code Playgroud)git fast-export <options> | filter | git fast-import <options>
并且git fast-export
/git fast-import
对 git 2.24(2019 年第四季度)进行了一些改进
见提交941790d,提交8d7d33c,提交a1638cf,提交208d692,提交b8f50e5,提交f73b2ab,提交3164e6b(2019年10月3日),并提交af2abd8(2019年9月25日)通过以利亚Newren( )newren
。
(由Junio C gitster
Hamano合并-- --在commit 16d9d71,2019 年 10 月 15 日)
例如:
fast-import
: 允许通过标记标签来识别标签签字人: Elijah Newren
标记标识符用于
fast-export
并fast-import
提供标签以引用较早的内容。Blob 被赋予标签,因为它们需要在首次出现时使用给定文件名的提交中被引用,并且提交被赋予标签,因为它们可以是其他提交的父项。
标签从未被赋予标签,可能是因为它们被认为是不必要的,但这会带来两个问题:
- 如果我们想创建一个标签(或更高的嵌套)的标签,它让我们无法引用以前的标签。
- 它让我们无法记录在使用
--export-marks
和时已经导入了标签--import-marks
。通过允许标签的可选标记标签来解决这些问题。
脱离我的头顶:
git commit --amend
将重写前一次提交git rebase
可以重写多次提交(衍合使用时也被称为git pull
用--rebase
标志或branch.$name.rebase
配置选项)git filter-branch
可以重写多个提交git push -f
可以更改分支指向的提交(git push origin +branch
语法相同)git reset
可以更改分支指向的提交git branch -f
可以更改分支指向的提交(通过重新创建具有相同名称的分支)git checkout -B
可以更改分支指向的提交(通过重新创建具有相同名称的分支)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
在服务器上设置,禁用删除位于远程存储库上的分支的能力。此外,我使用
git reset
了很多,但我并不完全意识到我可能对存储库(或其他贡献者的副本)造成的损害。可以git reset
是危险的?
git-reset
,正如knittl所提到的,通常会改变分支参考点的位置。此命令可能很危险,因为它会使可访问的提交变得不可访问。因为一张图千言万语,请考虑以下情况:
你在master
分支上,它指向 commit D
。现在,假设你跑,例如,
git reset master~2
Run Code Online (Sandbox Code Playgroud)
软重置被认为是最良性的重置形式,因为它“仅”更改当前分支指向的位置,但不会影响暂存区或您的工作树。也就是说,仅以这种方式更改分支指向的位置会产生后果:在软重置之后,您最终会得到
在重置之前可以访问的提交C
和现在变得无法访问;换句话说,它们不是任何引用(分支、标签或 HEAD)的祖先。您可以说它们处于“存储库边缘”;它们仍然存在于您的 Git 存储库的对象数据库中,但它们将不再列在.D
master
git log
如果您确实在重置之前发现这些提交有价值,您应该通过使一些引用(例如另一个分支)指向D
再次提交来使它们再次可访问。否则,承诺C
和D
最终会死于真正的死亡时的Git运行其自动垃圾收集并删除不可达的对象。
理论上,您可以D
从reflog 中取出提交,但始终存在忘记那些无法访问的提交或无法识别 reflog 的哪个条目对应于 commit 的风险D
。
总之,是的,这git-reset
可能很危险,最好确保您要重置的分支的当前提示在重置后仍然可以访问。如果需要,在重置之前在那里创建另一个分支,以防万一,作为备份;如果您确定要忘记这些提交,您可以随时删除该分支。
归档时间: |
|
查看次数: |
1472 次 |
最近记录: |