This question begins where this one left off: 就像那里一样,情况是,在一次提交中,文件
A
被重命名为 B
并且新内容被写入名为 A
. 的文件
链接的问题询问是否有一种方法可以在提交中表示此重命名,并且接受的答案正确地指出提交对重命名一无所知,并且重命名信息是在需要时即时计算的,例如在 diffs 或 rebases 期间。
给定如上所述的提交,
git diff
使用默认设置将更改显示为对 A
的修改和创建新文件 B
,无论差异有多大。
我的问题是:
git diff
的设置,以便它更准确地了解情况,这可以通过更小的差异来证明?A
→B
重命名*,另一个用于创建新的A
(至少有助于一个理解如果他们一个一个提交会发生什么的人类审阅者)?* 请注意,我将使用“对
A
→ B
重命名的提交”作为“树不再包含 A
但包含 B
以及 A
的旧内容的提交”的简写
.
一些提示/我尝试过的事情:
对于第一个问题,使用
git diff
的-C
/--find-copies
开关可以获得一些改进。这将使它表示更改为 A
已被复制到 B
,然后 A
已被修改,使其内容被新内容替换。这将差异的“不必要”部分的大小减半,然后只是删除A
的“旧内容”。不过,这并不理想。
对于第二个问题,我猜“蛮力”的做法是:
HEAD
回到有问题的提交之前,同时将修改保留在工作树中,或者如果它不是最新的提交,则在该提交时使用 e
进行交互式 rebase,然后在 rebase 期间重置 HEAD
。 git add B
将 B
添加到暂存区。git rm --cached A
将 A
的删除添加到暂存区。git commit ...
这两个更改,将 A
作为工作树中的未暂存文件。git add A
和 git commit ...
承诺创建新的 A
.这非常麻烦,我不喜欢必须在两次提交之间将
A
作为工作树中的未暂存文件。但是尝试做一些“聪明”的事情,例如仅使用 A
→ B
重命名或隐藏更改后的 A
手动重做提交会使事情变得更糟,因为 Git 的重命名检测会在这两种情况下启动只是在没有警告的情况下完全摆脱A
。我在这里取得的最大成功是使用旧的 recursive
合并策略和 no-renames
选项进行变基,这至少会引发冲突,而不是默默地摆脱 A
.
您可以通过将重命名和副本拆分到它们自己的提交中来显示 Git 的重命名/复制检测您在做什么。与其在一次提交中重命名和双关语,不如重命名,提交,在旧瓶子所在的地方创建新酒,提交,现在 Git 看到了序列(并且您足够关心记录它;事实上基本上没有人这样做,尽管它花了大约五秒钟,但在这里可能是相关的)。
否则,将提交分成两个单独的提交的最惯用的方法是什么,一个用于 A → B 重命名*,另一个用于创建新的 A(至少帮助人工审阅者理解如果他们一个一个地经历提交)?
如果您熟悉 Git,将提交分成两部分很容易。说你有
X---ABA---*---Y topic
并且您想将
ABA
拆分为重命名和重新创建的序列。
git checkout X # no need for a branch name here
git mv A B # make the AB-rename-only commit
git commit # ...
git replace --graft ABA @ # make ABA's parent be that locally
git filter-branch -- @..topic # bake it in