GIT:我怎样才能阻止foxtrot在我的'master'分支中合并?

G. *_*ies 30 git merge git-merge

foxtrot合并是一种合并,其中'origin/master'作为第二个(或更晚的)父级合并,如下所示:

提交'D'是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'!

我怎样才能防止这种推动?推送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合并的更多背景,我写了一篇博文.

  • 很好,虽然我使用,例如,'awk'{print $ 2}'`而不是`cut`来避免列计数(例如,如果git曾经切换到SHA-256,那么潜在的破坏,尽管很多*其他*东西会打破这可能不值得担心...). (3认同)
  • 我会试试的!你是否可以根据麻省理工学院许可证更改我的许可? (3认同)

Cod*_*ard 7

这是一个钩子代码,可以满足您的要求:

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)