Как я могу предотвратить небыстрые нажатия на выбранные ветки в git?

Я хотел бы защитить свой репозиторий git, чтобы можно было перезаписать только неосновные ветки. Есть ли способ защитить только выбранные ветки?


person Community    schedule 16.07.2012    source источник


Ответы (7)


Вы можете использовать GitEnterprise для настройки разрешений для каждой ветки (администратора) для блокировки не-fastforward push-уведомлений с использованием детального разрешения доступа. .

И git config --system receive.denyNonFastForwards true просто выполнит эту работу, если вам нужно заблокировать изменение истории для всех веток.

person Sergey K.    schedule 16.07.2012
comment
denyNonFastForwards — это не «разрешение», которое вам следует использовать. Установите хук git, чтобы запретить принудительное нажатие... Это правильный способ сделать это. - person Eric; 02.09.2016
comment
@Eric Отказ от push-уведомлений без быстрой перемотки на самом деле является способом пойти на GitHub/BitBucket . Новых велосипедов не придумали. - person Sergey K.; 02.09.2016
comment
Если вы запретите все не fastforward в каждой ветке, то как бы вы объединили ветки своих функций? - person Eric; 03.09.2016
comment
@Eric, перебазируйте ветку функций local поверх удаленного мастера и объедините ее с мастером. Всегда вперед. - person Sergey K.; 03.09.2016
comment
Даже для больших команд? Я думал, что rebase следует использовать экономно. Просто потому, что они являются физическим переписыванием истории. Вы меняете исходный коммит. - person Eric; 04.09.2016
comment
@Eric Где можно переписать в этом случае? - person Sergey K.; 04.09.2016
comment
Сделайте коммит и отследите идентификатор коммита. Перебазируйте, а затем сравните идентификатор фиксации. Идентификатор фиксации уже не тот. Это новый коммит. Переписать. - person Eric; 06.09.2016
comment
@ Эрик, это происходит только в вашем локальном репо. Если вы теперь объедините эту перебазированную ветку обратно в мастер и отправите ее в удаленное репо, это будет безопасный быстрый толчок вперед с кристально чистой историей. - person Sergey K.; 06.09.2016
comment
Хорошо, я думаю, что понимаю контекст, в котором следует применять переписывание коммитов — плохая идея. Это не тотальное покрытие всего переписывания коммитов — это плохо. Вернее, переписывать только те коммиты, которые находятся на удаленке. Я понял это еще до того, как меня проинформировали о том, что следует избегать любого переписывания коммитов. Когда изначально неверно истолковали, почему переписывание коммитов — это плохо. Просто другой способ читать между строк! Спасибо!! - person Eric; 17.10.2016

Вот хук обновления (копировать в хуки/обновление), который я написал для собственного использования. Этот сценарий по умолчанию запрещает все обновления без быстрой перемотки вперед, но разрешает их для явно настроенных ветвей. Должно быть достаточно легко инвертировать его, чтобы обновления без быстрой перемотки вперед были разрешены для всех, кроме главной ветки.

#!/bin/sh
#
# A hook script to block non-fast-forward updates for branches that haven't
# been explicitly configured to allow it. Based on update.sample.
# Called by "git receive-pack" with arguments: refname sha1-old sha1-new
#
# Config
# ------
# hooks.branch.<name>.allownonfastforward
#   This boolean sets whether non-fast-forward updates will be allowed for
#   branch <name>. By default they won't be.

# --- Command line
refname="$1"
oldrev="$2"
newrev="$3"

# --- Safety check
if [ -z "$GIT_DIR" ]; then
        echo "Don't run this script from the command line." >&2
        echo " (if you want, you could supply GIT_DIR then run" >&2
        echo "  $0 <ref> <oldrev> <newrev>)" >&2
        exit 1
fi

if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
        echo "Usage: $0 <ref> <oldrev> <newrev>" >&2
        exit 1
fi

# --- Check types
# if $newrev is 0000...0000, it's a commit to delete a ref.
zero="0000000000000000000000000000000000000000"
if [ "$newrev" = "$zero" ]; then
        newrev_type=delete
else
        newrev_type=$(git cat-file -t $newrev)
fi

case "$refname","$newrev_type" in
        refs/tags/*,commit)
                # un-annotated tag
                ;;
        refs/tags/*,delete)
                # delete tag
                ;;
        refs/tags/*,tag)
                # annotated tag
                ;;
        refs/heads/*,commit)
                # branch
                # git rev-list doesn't print anything on fast-forward updates
                if test $(git rev-list "$newrev".."$oldrev"); then
                        branch=${refname##refs/heads/}
                        nonfastforwardallowed=$(git config --bool hooks.branch."$branch".allownonfastforward)

                        if [ "$nonfastforwardallowed" != "true" ]; then
                                echo "hooks/update: Non-fast-forward updates are not allowed for branch $branch"
                                exit 1
                        fi
                fi
                ;;
        refs/heads/*,delete)
                # delete branch
                ;;
        refs/remotes/*,commit)
                # tracking branch
                ;;
        refs/remotes/*,delete)
                # delete tracking branch
                ;;
        *)
                # Anything else (is there anything else?)
                echo "hooks/update: Unknown type of update to ref $refname of type $newrev_type" >&2
                exit 1
                ;;
esac

# --- Finished
exit 0
person Tanu Kaskinen    schedule 02.04.2013
comment
Было бы полезно, если бы вы могли изменить сценарий, чтобы обновления без быстрой перемотки вперед были разрешены для всех, кроме главной ветки. - person Ren; 02.04.2013
comment
См. мой пост ниже для небольшой модификации этого скрипта, которая позволяет использовать подстановочные знаки для разрешенных ветвей. - person jomofrodo; 16.03.2020

Вы можете предотвратить обновления без быстрой перемотки вперед, настроив denyNonFastForwards

git config --system receive.denyNonFastForwards true

Но это относится ко всем отраслям. Для получения дополнительной информации см. ProGit.

person Karthik Bose    schedule 16.07.2012

Я думаю, это зависит от того, что вы используете на стороне сервера для доступа к вашему репозиторию. Некоторые серверные приложения поддерживают разрешения для каждой ветки, например Gerrit или Gitlab (однако я не уверен, поддерживает ли Gitlab ваш вариант использования). Gerrit поддерживает это, так как я использую аналогичный рабочий процесс в своей компании.

Возможно, Gitolite также поддерживает его (это то, что Gitlab использует под капотом), который проще в настройке, но не нет веб-интерфейса, такого как Gerrit или Gitlab.

Дополнительный комментарий: GitEnterprise, как было предложено, также является хорошим решением, однако мои предложения подходят, если у вас есть собственный сервер (что распространено во многих компаниях).

person dunni    schedule 16.07.2012

Если вам будет разрешено изменить свой сервер, это позволит выполнять быструю перемотку на сервере.

ssh ip 'echo $"[receive]
    denyDeletes = false
    denyNonFastForwards = false" >> /path/to/repo/config'
#then git push -f origin master
person test30    schedule 08.04.2014

Этот ответ SO даст вам то, что вы ищете. Просто отредактируйте его, чтобы применить его к основной ветке:

#!/bin/sh
# lock the master branch for pushing
refname="$1"

if [ "$refname" = "refs/heads/master" ]
then
    echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
    echo "You cannot push to the master branch."
    echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
    exit 1
fi
exit 0

Обновление:
Это предотвратит все отправки в основную ветку, включая ускоренную перемотку вперед.

person redhotvengeance    schedule 16.07.2012
comment
Это предотвратит любые нажатия на выбранную ветку. Должна быть разрешена быстрая перемотка вперед. - person Sergey K.; 16.07.2012
comment
Здесь кто-то понял, как обнаружить принудительность в сценариях обновления. Длинное объяснение, последний фрагмент еще нужно сделать. .. - person Frank Nocke; 24.02.2016

Вот модификация сценария Tanu Kaskinen, позволяющая использовать подстановочные знаки для имен ветвей. Мы используем ветки с именами, начинающимися с «d/», для обозначения веток «разработки». Я хотел разрешить обновления без перемотки вперед для этих веток d/:

   refs/heads/*,commit)
            # branch
            # git rev-list doesn't print anything on fast-forward updates

            if [[ $(git rev-list "$newrev".."$oldrev") ]]; then
                    branch=${refname##refs/heads/}
                    if [[ "$branch" =~ ^d/ ]] ; then
                      echo "Non-fast-forward update allowed on d/ branch"
                      nonfastforwardallowed="true";
                    else
                      #look for a specific config setting
                      nonfastforwardallowed=$(git config --bool  hooks.branch."$branch".allownonfastforward)
                    fi


                    if [ "$nonfastforwardallowed" != "true" ]; then
                            echo "hooks/update: Non-fast-forward updates are not allowed for branch $branch"
                            exit 1
                    fi
            fi
person jomofrodo    schedule 16.03.2020