G. *_*ies 30 git merge git-merge
foxtrot合并是一种合并,其中'origin/master'作为第二个(或更晚的)父级合并,如下所示:
提交'D'是foxtrot合并,因为'origin/master'是它的第二个父级.注意此时来自"origin/master"的第一父历史如何包含提交"B".
但是在我的git repo中,我需要所有涉及'origin/master'的合并来保持'origin/master'作为第一个父级.不幸的是,git在评估提交是否符合快进条件时并不关心父级.这会导致我的主分支上的第一个父历史记录有时会丢失曾经存在的提交(例如,输出"git log --first-parent").
以下是推送前面图表中提交"D"时发生的情况:
我怎样才能防止这种推动?推送foxtrot合并后,'origin/master'的第一父历史不再包含提交'B'!
显然没有提交或工作实际上丢失,只是在我的环境中我真的需要"git log --first-parent"作为一个稳定的提交累积记录 - 如果你愿意,一种"一次写入读 - 许多"(WORM)数据库.我有脚本和进程使用"git log --first-parent"来生成更改日志和发行说明,以及管理我的票证系统(JIRA)中的票证转换.Foxtrot合并破坏了我的脚本!
是否有某种预接收挂钩我可以安装在我的git存储库中以防止foxtrot合并被推送?
ps使用http://bit-booster.com/graph.html生成此stackoverflow问题中的提交图.
G. *_*ies 16
以下预接收挂钩将阻止这些:
#/bin/bash
# Copyright (c) 2016 G. Sylvie Davies. http://bit-booster.com/
# Copyright (c) 2016 torek. http://stackoverflow.com/users/1256452/torek
# License: MIT license. https://opensource.org/licenses/MIT
while read oldrev newrev refname
do
if [ "$refname" = "refs/heads/master" ]; then
MATCH=`git log --first-parent --pretty='%H %P' $oldrev..$newrev |
grep $oldrev |
awk '{ print \$2 }'`
if [ "$oldrev" = "$MATCH" ]; then
exit 0
else
echo "*** PUSH REJECTED! FOXTROT MERGE BLOCKED!!! ***"
exit 1
fi
fi
done
Run Code Online (Sandbox Code Playgroud)
如果您正在使用Github/Gitlab/Bitbucket Cloud,您可能需要考虑在其提交状态apis中创建某种调用(这里的api文档为:bitbucket,github ;不确定gitlab是否有),因为你不喜欢可以访问预接收挂钩,即使你这样做了,你仍然需要处理直接在这些产品的web ui中点击"合并"按钮的人(在这种情况下没有"推送") .
使用Bitbucket Server,您可以安装我创建的附加组件.
安装完毕后,在给定存储库的"挂钩"设置中单击"保护第一个父挂钩"上的"启用":
它将通过推送和Bitbucket Server UI中的"合并"按钮来阻止foxtrot合并.它即使其许可证已过期也会这样做,使"保护第一父钩"成为更大附加组件的免费组件.
以下是我的Bit-Booster "保护第一父母"预接收挂钩的示例:
$ ?git pull
$ git push
remote: *** PUSH REJECTED BY Protect-First-Parent HOOK ***
remote:
remote: Merge [1f70043b34d3] is not allowed. *Current* master must appear
remote: in the 'first-parent' position of the subsequent commit. To see how
remote: master is merging into the wrong side (not as 1st parent), try this:
remote:
remote: git show --graph -s --pretty='%h %d%n' \
remote: 1f70043b34d3 1f70043b34d3~1 origin/master
remote:
remote: To fix, there are two traditional solutions:
remote:
remote: 1. (Preferred) rebase your branch:
remote:
remote: git rebase origin/master
remote: git push origin master
remote:
remote: 2. Redo the merge in the correct direction:
remote:
remote: git checkout master
remote: git reset --hard origin/master
remote: git merge --no-ff 1f70043b34d3eaedb750~1
remote: git push origin master
remote:
Run Code Online (Sandbox Code Playgroud)
有关foxtrot合并的更多背景,我写了一篇博文.
这是一个钩子代码,可以满足您的要求:
pre-receive hook
#!/bin/sh
# Check to see if this is the first commit in the repository or not
if git rev-parse --verify HEAD >/dev/null 2>&1
then
# We compare our changes against the previous commit
against=HEAD^
else
# Initial commit: diff against an empty tree object
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi
# Redirect output to screen.
exec 1>&2
# Check to see if we have updated the master branch
if [ "$refname" eq "refs/heads/master" ];
then
# Output colors
red='\033[0;31m';
green='\033[0;32m';
yellow='\033[0;33m';
default='\033[0;m';
# personal touch :-)
echo "${red}"
echo " "
echo " |ZZzzz "
echo " | "
echo " | "
echo " |ZZzzz /^\ |ZZzzz "
echo " | |~~~| | "
echo " | |- -| / \ "
echo " /^\ |[]+ | |^^^| "
echo " |^^^^^^^| | +[]| | | "
echo " | +[]|/\/\/\/\^/\/\/\/\/|^^^^^^^| "
echo " |+[]+ |~~~~~~~~~~~~~~~~~~| +[]| "
echo " | | [] /^\ [] |+[]+ | "
echo " | +[]+| [] || || [] | +[]+| "
echo " |[]+ | || || |[]+ | "
echo " |_______|------------------|_______| "
echo " "
echo " "
echo " ${green}You have just committed code ${red} "
echo " Your code ${yellow}is bad.!!! "
echo " ${red} Do not ever commit again "
echo " "
echo "${default}"
fi;
# set the exit code to 0 or 1 based upon your needs
# 0 = good to push
# 1 = exit without pushing.
exit 0;
Run Code Online (Sandbox Code Playgroud)