Git: Comment puis-je empêcher foxtrot de fusionner dans ma branche 'master'?

une fusion foxtrot est une fusion où 'origin / master' fusionne en tant que second (ou plus tard) parent, comme ceci:

Commit 'D' is a foxtrot merge because 'origin/master' is its 2nd parent.

Commit " D " est un fox-trot de fusion parce que 'origin/master' est sa 2ème mère. Remarquez comment l'histoire du premier parent de' origin/master 'contient' B ' en ce moment.

mais dans mon git repo j'ai besoin de tout Fusion impliquant ' origine / master 'pour conserver' origine/master ' comme premier parent. Malheureusement git ne se soucie pas de parent-order quand il évalue si un commit est admissible pour fast-forward. Cela fait que la première histoire parent de ma branche principale est parfois perdue par des propagations qui étaient là (par exemple, sortie de "git log --first-parent").

voici ce qui se passe lorsque commit 'D' du diagramme précédent est poussé:

How can I prevent this push? First-parent history of 'origin/master' no longer contains commit 'B' after the foxtrot merge is pushed!

Comment puis-je empêcher cette poussée? L'histoire du premier parent de 'origin / master'ne contient plus de commit' B ' après la fusion de foxtrot!

évidemment pas de commits ou de travail sont réellement perdus, c'est juste que dans mon environnement, j'ai vraiment besoin de "git log --first-parent" pour être un enregistrement accumulatif stable de commits - si vous voulez, une sorte de "écrire-une fois lu-beaucoup" (ver) la base de données. J'ai des scripts et des processus qui utilisent "git log --first-parent" pour générer des listes de modifications et des notes de publication, ainsi que pour gérer les transitions de tickets dans mon système de billetterie (JIRA). Foxtrot merges casse mes scripts!

est-ce qu'il y a une sorte de précepte que je pourrais installer dans mes dépôts git pour empêcher les fusions foxtrot d'être poussées?

p. S. Les graphiques d'engagement de cette question sur les flux stackoverflow sont les suivants: généré en utilisant http://bit-booster.com/graph.html .

26
demandé sur G. Sylvie Davies 2016-03-12 23:12:54

3 réponses

le crochet pré-réception suivant bloque ceux:

#/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

si vous utilisez Github / Gitlab / Bitbucket Cloud, vous pouvez avoir besoin d'examiner la création d'une sorte d'appel dans leur commit status apis (voici les docs api pour: bitbucket , GitHub ; pas sûr si gitlab en a un), parce que vous n'avez pas accès aux crochets de pré-réception, et même si c'était le cas, vous auriez quand même affaire avec les gens qui cliquent sur le bouton" Fusionner "directement dans l'interface Web de ces produits (dans ce cas, il n'y a pas de"push").

avec Bitbucket Server vous pouvez installer le add-on j'ai créé .

une fois installé, vous cliquez sur" Activer "sur" Protéger le premier crochet Parent "dans les paramètres" hook "d'un dépôt donné:

enter image description here

il va bloquer foxtrot fusionne via push et via le bouton" merge " dans L'interface utilisateur Bitbucket Server. Il le fait même si sa licence est Expirée, faisant du "Crochet De Protection du premier Parent" un composant libre de l'add-on plus grand.

Voici un exemple de mon Bit-Booster "d'Abord Protéger les Parent" avant de recevoir le crochet dans l'action:

$ ​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: 

Pour plus d'information sur foxtrot fusionne j'ai écrit un post de blog .

16
répondu G. Sylvie Davies 2016-03-22 15:43:30

voici un code hook qui fera ce que vous demandez:

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='3[0;31m';
    green='3[0;32m';
    yellow='3[0;33m';
    default='3[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;
8
répondu CodeWizard 2016-04-13 23:08:06

j'ai écrit ceci pour fournir une rétroaction tôt ( pre-receive crochet est également nécessaire). J'utilise pour cela des crochets post-merge et pre-push . Il n'est pas possible d'empêcher une fusion foxtrot dans commit-msg hook car les informations pour en détecter une ne sont disponibles qu'après. Dans post-merge crochet, je préviens simplement. Dans le crochet pre-push , je lance et bloque la poussée. Voir d3f1821 ("foxtrot: Ajouter des sous-crochets pour détecter foxtrot fusionne", 2017-08-05).

~/.git-crochets/helpers/foxtrot-fusion-détecteur:

#!/bin/sh

#usage:
#   foxtrot-merge-detector [<branch>]
#
# If foxtrot merge detected for branch (current branch if no branch),
# exit with 1.

# foxtrot merges:
# See http://bit-booster.blogspot.cz/2016/02/no-foxtrots-allowed.html
# /q/git-how-can-i-prevent-foxtrot-merges-in-my-master-branch-59236/""@{u} 2>/dev/null)
# no remote tracking branch, exit
if [[ -z "$remoteBranch" ]]; then
    exit 0
fi
branch=$(git rev-parse --abbrev-ref "${1-@}" 2>/dev/null)
# branch commit does not cover remote branch commit, exit
if ! $(git merge-base --is-ancestor $remoteBranch $branch); then
    exit 0
fi
remoteBranchCommit=$(git rev-parse $remoteBranch)
# branch commit is same as remote branch commit, exit
if [[ $(git rev-parse $branch) == $remoteBranchCommit ]]; then
    exit 0
fi
# remote branch commit is first-parent of branch, exit
if [[ $(git log --first-parent --pretty='%P' $remoteBranchCommit..$branch | \
    cut -d' ' -f1 | \
    grep $remoteBranchCommit | wc -l) -eq 1 ]]; then
    exit 0
fi
# foxtrot merge detected if here
exit 1

et ensuite l'utiliser comme

pré-poussoir crochet:

#!/bin/sh

remote=""
url=""
z40=0000000000000000000000000000000000000000
while read local_ref local_sha remote_ref remote_sha
do
    if [ "$local_sha" = $z40 ]; then
        # handle delete, do nothing
        :
    else
        # ex $local_ref as "refs/heads/dev"
        branch=$(git rev-parse --abbrev-ref "$local_ref")
        ~/.git-hooks/helpers/foxtrot-merge-detector "$branch"
        # check exit code and exit if needed
        exitcode=$?
        if [ $exitcode -ne 0 ]; then
            echo 1>&2 "fatal: foxtrot merge detected, aborting push"
            echo 1>&2 "fatal: branch $branch"
            exit $exitcode
        fi
    fi
done

post-fusion:

#!/bin/sh

~/.git-hooks/helpers/foxtrot-merge-detector
# check exit code and exit if needed
exitcode=$?
if [ $exitcode -ne 0 ]; then
    echo -e "  ${Yellow}WARNING:${None} foxtrot merge detected"
    # swallow exit code
fi
2
répondu hIpPy 2017-08-10 20:35:55