如何在 git 的“master”分支中自动修复 foxtrot-merges?
Posted
技术标签:
【中文标题】如何在 git 的“master”分支中自动修复 foxtrot-merges?【英文标题】:How to automatically fix foxtrot-merges in my the 'master' branch in git? 【发布时间】:2022-01-22 23:25:29 【问题描述】:foxtrot 合并的问题在this question 中有详细解释。 简而言之: 在同一个分支(远程和本地)上工作时,简单的git merge
命令将远程合并提交隐藏在第二个父级下,并替换远程的第一父级历史记录(在常规情况 - “起源”)。我们认为这很糟糕。
上面链接的问题要求一种方法来检测这种情况,并拒绝推送。我的问题是如何自动修复它。
我不真的关心完整的树历史的整洁,但我希望第一父母树是完美的。并且不要打扰其他用户很重要,因此问题应该会自动解决。
目标:当 git origin 钩子检测到 foxtrot 提交推送时,它会在 old-HEAD 和 new-HEAD 之上添加另一个 merge-commit,将 old-HEAD 作为第一父级。
实现它最安全的方法是什么?
【问题讨论】:
你不能简单地禁止在 origin/master 上的快进吗?总是需要合并提交? @LasseV.Karlsen 我不明白如何做你的建议,或者它会有什么帮助。 (a) new-HEAD is 合并提交。 (b) 我不想阻止用户。我希望用户按自己的意愿推送,并且服务器会修复它。拉取请求过程(如在 TFS 中)实际上做了我想要的(他们创建新的合并提交,具有正确的第一父级)。我的问题是我们没有 PR(这对用户来说是一个额外的步骤),而且 - 我们不在 TFS 上工作。 【参考方案1】:在the mentioned above question 和this question(在裸仓库中合并)的答案的启发下,我提出了以下解决方案。
这个脚本应该放在post-receive
挂钩文件中。根据要求,脚本会创建不隐藏旧 HEAD 的新合并提交。
脚本也是:
-
收集new-HEAD第一父行的所有commit-msgs,并将其设置为new-merge-commit msg。
将 new-merge-commit 的作者和提交者伪装成 new-HEAD 的作者(同时注意名称中“或”的情况)。
命令说明:
git read-tree
命令暂存 new-HEAD 提交的确切内容。 new-merge-commit 应该具有完全相同的内容。
git log
命令收集所需的提交消息。
git ... commit-tree
命令使用作者姓名/电子邮件、暂存数据、2 个父项和组合提交消息创建 new-merge-commit。
git update-ref
命令更新相关 ref(在本例中为 master
)以指向新合并提交。
如果此脚本有问题,如果您能发现它们,我们将不胜感激。 :)
脚本:
#!/bin/sh
while read oldrev newrev refname
do
if [ "$refname" = "refs/heads/master" ]; then
echo "Fix Foxtrot-Merges Hook..."
MATCH=`git log --first-parent --pretty='%H %P' $oldrev..$newrev | grep $oldrev | awk ' print \$2 '`
if [ "$oldrev" = "$MATCH" ]; then
echo "...All is OK"
else
echo "...Fixing"
authorName=`git log --first-parent --pretty='%an' $newrev^..$newrev`
authorEmail=`git log --first-parent --pretty='%ae' $newrev^..$newrev`
authorName=$authorName//"/\\"
authorEmail=$authorEmail//"/\\"
git read-tree -i --reset $newrev
git log --first-parent --pretty='%B' $oldrev..$newrev > COMMIT_EDITMSG
newCommitHash=$(git -c user.name="$authorName" -c user.email="$authorEmail" commit-tree $(git write-tree) -p $oldrev -p $newrev < COMMIT_EDITMSG)
git update-ref $refname $newCommitHash
fi
fi
done
【讨论】:
这将主要适用于最常见的情况,这可能已经足够好了。但是,这里真正的问题是它无法修复,因为您无法更改现有提交。您可以简单地不接受它(Git 可以很好地使用它),或者您可以像您在这里所做的那样pseduo-accept-it-and-rewrite-it。但是当你做伪接受时,sending Git 认为你做了一个正常的完全接受,并错误地更新了他们的远程跟踪名称。这可能会让其他人感到惊讶。如果可以的话,最好让人们一开始就停止这样做。 同时,作为一个小改进,考虑使用现有的合并提交树 (git rev-parse $rev^tree
) 而不是将树读入索引然后写出索引。此外,您可以使用git log -1
或git log --no-walk
更轻松地提取作者姓名、电子邮件和正文。不幸的是,git log
在技术上是瓷器而不是管道,因此它患有用户配置综合症,但没有管道相当于使用。
最后:注意进行多次 foxtrot 合并的用户,然后用一个 git push
推送所有这些用户。这就是您在这里缺少的情况:您只重写了提示提交。
@torek 非常感谢您的 cmets!关于第一个,我明白你的观点。就我而言,它已经足够好了。如果出现一些需要特别管理的危机——我们可以暂时禁用它。关于第二个:好主意!我试试看。
@torek 关于最后一点,我认为你是不正确的,或者我没有理解你。 old-HEAD(= 任何其他程序员和构建服务器都知道的最新origin/master
,直到当前用户推送)将始终是自动创建提交的第一步(即现在头部)。无论用户git pull
多少次,用户从哪个提交中提取都无关紧要;在底线 - old-HEAD 提交不会被隐藏。以上是关于如何在 git 的“master”分支中自动修复 foxtrot-merges?的主要内容,如果未能解决你的问题,请参考以下文章