Cra*_*g J 4 git merge git-merge
在将origin/develop合并到本地开发时,滥用"-s ours"合并选项基本上会丢弃自上次开发更新以来所完成的工作.我通过故意查看我知道丢失的文件的历史记录,在git历史记录中手动找到了这两个实例.
有没有办法找到使用"-s ours"合并选项完成的所有提交?
我想通过比较合并提交与他们的父母,并检查是否只有一个父母分支内容实际上被采取,但我不知道如何将这个理论转换为git命令.我甚至从什么命令开始?
作为shell脚本:
git rev-list --merges HEAD |
while read rev; do
thistree=$(git rev-parse $rev^{tree})
p1tree=$(git rev-parse $rev^1^{tree})
if [ $thistree = $p1tree ]; then
echo "commit $rev has the effect of -s ours"
fi
done
Run Code Online (Sandbox Code Playgroud)
直接答案是"不"(但继续阅读).使用的实际策略不会自动记录.(如果进行所有合并的人都非常自律,也许他们会在每个合并提交消息中记录这些信息.基于你的问题描述,这显然没有发生......)但这不一定是有趣的问题无论如何.这可能是有人创建具有合并效果的-s ours不实际使用的ours策略.
更有趣的问题是自动查找具有效果的合并-s ours,无论是否使用该选项; 这很容易实现自动化.
问题减少到:
git rev-list.-s ours:此工具是...嗯,请参阅下文; 有几种可能性.一旦你知道如何git rev-list枚举提交,找到合并提交是微不足道的.比如git log,你给出git rev-list了一个起点,然后Git 从那一点开始向后工作,通过可以从该提交到达的历史记录,直到它耗尽历史记录或遇到你告诉它用作停止点的提交.
通常,一个很好的起点是HEAD,你现在已经检查过的提交,这可能是分支的提示.您甚至可以给出多个起始点,例如--branches(每个分支的每个提示)或--all(每次提交带有标签,该标签是分支名称,标记名称,远程跟踪名称,甚至是特殊名称之一)喜欢refs/stash藏匿处).
然后,您希望将输出限制为仅列出合并提交.合并提交是指至少有两个父母的任何提交:--min-parents=2.不过,你可能更喜欢这个的同义词,所以我们得到了,例如:
git rev-list --merges HEAD
Run Code Online (Sandbox Code Playgroud)
从你现在的位置开始,然后通过所有可以通过的提交向后工作HEAD.(有关此可达性概念的更多信息,请参阅Think Like(a)Git.)
输出来自git rev-list满足rev-list条件的提交哈希ID流,在这种情况下,--merges(每个可达到的合并提交):对人类不是很有用,但对计算机程序非常有用.现在我们只需要编写识别有趣合并的程序.
我们已经看到合并提交是一个至少有两个父项的提交.什么-s ours或等价的告诉Git新合并提交的快照(其存储的树)应该与两个父节点中的一个匹配,特别是第一个父节点.您可能想要放松您的条件并检查树是否与第二个父项的匹配(一个策略theirs合并,除了没有内置-s theirs),或者章鱼合并,任何父项,但"匹配第一个父项"可能做,而且稍微容易一些.
这样做的两个显而易见的方法是:
git diff(或其管道等效物)与两个特定提交或树哈希进行比较.git diff如果需要,使用完整或等效的将允许您稍微放宽匹配标准.我们将编写第二个代码 - 比较tree合并中存储的哈希值和第一个父内置shell脚本,因为它可能更快,并且在任何情况下都演示了更多的各种Git工具.我们从泛型"read every commit hash"循环开始:
while read rev; do ...; done
Run Code Online (Sandbox Code Playgroud)
每个版本都将在循环内提供$rev.
现在我们只需将$rev(提交)转换为自己的树:
git rev-parse $rev^{tree}
Run Code Online (Sandbox Code Playgroud)
它使用gitrevisions语法来查找指定的提交树的哈希ID.我们必须将其保存在变量中:
thistree=$(git rev-parse $rev^{tree})
Run Code Online (Sandbox Code Playgroud)
然后我们想找到第一个父树的树.第一个父级是gitrevisions语法${rev}^1.这里的括号在技术上是不必要的,所以我会省略它们.然后我们想要那个提交的树,我们需要将它保存在另一个变量中:
p1tree=$(git rev-parse $rev^1^{tree})
Run Code Online (Sandbox Code Playgroud)
如果两棵树匹配,犯$rev有效果的-s ours,它是否与制作-s ours,所以我们应打印其散列ID,甚至运行git show就可以了.
这个循环的最终版本(将所有部分放在一起)是这个答案的顶部.