блокировка push тривиального слияния на git server - PullRequest
24 голосов
/ 09 ноября 2010

Некоторое время назад я попросил наших разработчиков использовать rebase вместо слияния, прежде чем нажать . Исключение тривиальных слияний значительно упрощает отслеживание графика фиксации (т. Е. Gitk, git log).

Иногда люди все еще случайно делают тривиальные слияния, а затем толкают. У кого-нибудь есть под рукой или есть советы по написанию серверной ловушки, которая блокирует тривиальные слияния?

Под «тривиальным слиянием» я подразумеваю слияние без конфликтов. Вот пример , а - лучшее объяснение тривиального слияния в git .

Обновление Ср 10 ноября 01:26:41 UTC 2010 : отличные комментарии, все! Спасибо.

  • Примите во внимание следующее: все, чего я действительно прошу, это сделать следующее:
    • если git pull --ff-only завершится неудачно, вместо git pull
  • У git.git есть только один или два коммиттера, верно? Теоретически, следовать графику коммитов должно быть легко, но для меня это выглядит довольно грязно.

Обновление четверг, 11 ноября 23:49:35 UTC 2010 :

Обновление ср 15 дек 18:34:52 UTC 2010 :

  • адымитрук уже близко! Только один случай до сих пор не решен: нетривиальные слияния все еще должны работать.
  • Доступен довольно полный набор тестов , посмотрите его.
  • Я попросил помощи в (10) * списке рассылки git .

Ответы [ 2 ]

8 голосов
/ 20 января 2012

Я наткнулся на этот кусок кода, пытаясь найти решение. Он не делает именно то, что вы хотите, но это должно быть ez, чтобы добавить дополнительные имена ветвей в операторе if.

Пока у меня работает. он вынуждает тянуть --rebase для той же ветки и позволяет регулярным слияниям с другими ветвями проходить.

Все кредиты переходят к первоначальному автору.

#!/bin/bash
#
# This git update hook will refuse unnecessary merge commits caused by pulling
# from being pushed to a shared repository. These commits make following the
# history of a project difficult and are always avoidable with rebasing.
#
# by Scott Kyle (appden)
# modified by Olivier Refalo (orefalo)

refname="$1"
oldrev="$2"
newrev="$3"

# if this is not run as a hook, you may have messed up
if [ -z "$GIT_DIR" -o -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
    echo "Usage: GIT_DIR=<path> $0 <ref> <oldrev> <newrev>" >&2
    exit 1
fi

# if the new revision is all 0's then it's a commit to delete a ref
zero="0000000000000000000000000000000000000000"
# also check if the new revision is not a commit or is not a fast forward
# detect branch deletion, branch creation... and more
if [ "${refname#refs/heads/}" = "master" ] || [ "$newrev" = "$zero" ] || [ "$oldrev" = "$zero" ] || [ $(git cat-file -t $newrev) != "co
mmit" ] || [ $(git merge-base $oldrev $newrev) != "$oldrev" ]; then
    exit 0
fi

# loop through merges in the push only following first parents
for merge in $(git rev-list --first-parent --merges $oldrev..$newrev --); do
    # lazily create the revision list of this branch prior to the push
    [ -z "$revlist" ] && revlist=$(git rev-list $oldrev)
    # check if the second parent of the merge is already in this branch
    if grep -q $(git rev-parse $merge^2) <<< "$revlist"; then
        cat >&2 <<-EOF
            *** PUSH REJECTED ***
            *** TRIVIAL merge detected on local branch ${refname#refs/heads/}
            *** To fix: git rebase origin/${refname#refs/heads/}
            ***
            *** Next time use: git pull --rebase
            ***
            *** Permanent fix: git config [--global] branch.autosetuprebase always
            *** Then for existing branches: git config branch.<name>.rebase true
        EOF
        exit 1
    fi
done

echo -Info- Clean history successfully preserved!
exit 0
4 голосов
/ 09 ноября 2010

Этот update hook проверит, нажимаете ли вы на определенные ветки (он допускает тривиальные слияния в wip, topic и других ветках).

Это не беспокоит остальныхРодители осьминога сливаются, так как он ссылается только на 2-го родителя в каждом выдвигаемом коммите слияния.Пожалуйста, не стесняйтесь обновлять скрипт.

ОБНОВЛЕНИЕ: Зарезервированные ветви должны существовать на удаленном.

#!/bin/bash
refname="$1"
oldrev="$2"
newrev="$3"
branches="refs/heads/hotfixes refs/heads/dev refs/heads/qa refs/heads/master"
cont="no"
for branch in $branches ; do
  if [[ $refname == $branch ]] ; then
    cont="yes"
  fi
done
if [[ $cont == "no" ]] ; then
  exit 0
fi
echo "inspecting branch $refname for trivial merges" >&2
hashes="$(git log --format=%H --merges $oldrev..$newrev)"
for hash in $hashes ; do
  echo "checking merge commit $hash" >&2
  cont="no"
  for branch in $branches ; do
    if [[ $refname == $branch ]] ; then
      continue
    fi
    # if [[ "$(git log --format=%H $hash^2 ^$branch | wc -l)" == "0" ]] ; then
    if [[ "$(git log --format=%H $hash^2 ^$branch | wc -l)" == "    0" ]] ; then
      cont="yes"
    fi
  done
  if [[ $cont == "no" ]] ; then
    echo "No trivial merges allowed. Please rebase and push again." >&2
    exit 1
  fi
done
exit 0
...