Блокировать ветку git от толкания - PullRequest
30 голосов
/ 11 июля 2011

Вот ситуация:

У меня есть общедоступный репозиторий для моего приложения с открытым исходным кодом на github.com. Однако теперь я хотел бы написать какой-то конкретный код, который не будет общедоступным (я мог бы использовать его в коммерческой версии моего приложения).

Я подумал, что мог бы использовать тот же репозиторий, и я бы создал "частную" ветвь в моем git-репозитории, которую я бы не помещал

Но ошибки случаются. Есть ли какой-нибудь способ запретить git отправлять ветки на удаленные серверы?

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

Ответы [ 7 ]

32 голосов
/ 27 мая 2015

Вот как работает подход pre-push ловушка с веткой с именем dontpushthis.

Создать этот файл как .git/hooks/pre-push:

if [[ `grep 'dontpushthis'` ]]; then 
  echo "You really don't want to push this branch. Aborting."
  exit 1
fi

Это работает, потому что списоквыдаваемые ссылки передаются на стандартный ввод.Так что это также поймает git push --all.

Сделайте его исполняемым.

Сделайте это в каждом локальном хранилище.

Когда вы попытаетесь перейти в эту ветку, высм .:

$ git checkout dontpushthis
$ git push
You really don't want to push this branch. Aborting.
error: failed to push some refs to 'https://github.com/stevage/test.git'

Очевидно, что это так просто, как кажется, и только предотвращает нажатие на ветку с именем "dontpushthis".Поэтому полезно, если вы пытаетесь избежать прямого перехода к важной ветке, такой как master.

. Если вы пытаетесь решить проблему предотвращения утечки конфиденциальной информации, этого может быть недостаточно.Например, если вы создали дочернюю ветку из dontpushthis, эта ветвь не будет обнаружена.Вам понадобится более сложное обнаружение - вы можете посмотреть, присутствуют ли какие-либо коммиты в ветви «dontpushthis», например, в текущей ветви.

Более безопасное решение

Lookingна вопрос снова, я думаю, что лучшее решение в этом случае было бы:

  1. Иметь одно репо, которое является публичным
  2. Клонировать это в новый рабочий каталог, который является приватным
  3. Удаление удаленного (git remote rm origin) из этого рабочего каталога.
  4. Чтобы объединить публичные изменения, просто выполните git pull https://github.com/myproj/mypublicrepo

Таким образом, рабочий каталог частного репо никогда не будетесть где угодноПо сути, у вас есть односторонний канал передачи публичной информации в частную, но не обратно.

27 голосов
/ 11 июля 2011

Немного хакерское решение: Создайте фиктивную ветку на GitHub с тем же именем, что и ваша реальная ветка, и убедитесь, что это не будет быстрое слияние.Таким образом, операция push завершится неудачей.

Вот пример.

$ git clone git@github.com:user/repo.git
$ cd repo
$ git checkout -b secret
$ echo "This is just a dummy to prevent fast-forward merges" > dummy.txt
$ git add .
$ git commit -m "Dummy"
$ git push origin secret

Теперь, когда фиктивная ветвь настроена, мы можем воссоздать ее локально, чтобы отличаться от той, что на GitHub.

$ git checkout master
$ git branch -D secret
$ git checkout -b secret
$ echo "This diverges from the GitHub branch" > new-stuff.txt
$ git add .
$ git commit -m "New stuff"

Теперь, если мы случайно попытаемся нажать, произойдет сбой с ошибкой слияния без ускоренной перемотки:

$ git push origin secret
To git@github.com:user/repo.git
! [rejected]        secret -> secret (non-fast forward)
error: failed to push some refs to ‘git@github.com:user/repo.git’
4 голосов
/ 11 ноября 2015

Исправление скрипта .git / hooks / pre-push от @ steve-bennett

    #!/usr/bin/bash

    branch_blocked=mine

    if grep -q "$branch_blocked"; then
        echo "Branch '$branch_blocked' is blocked by yourself." >&2
        exit 1
    fi
3 голосов
/ 13 мая 2016

Почему бы просто не использовать пример pre-push, предоставляемый с текущей версией git?

Идея состоит в том, чтобы начать сообщение о коммите первого коммита вашей частной ветви со словом PRIVATE:.

После установки сценария предварительного нажатия для каждого нажатия он проверяет сообщения о фиксации всего журнала отправленных ссылок.Если они начнутся с PRIVATE:, push будет заблокирован.

Вот шаги:

  • Создать файл в .git/hooks/pre-push
  • Дать ему права на выполнение
  • Пропустить следующий скриптв нем

    #!/bin/sh
    
    remote="$1"
    url="$2"
    
    z40=0000000000000000000000000000000000000000
    
    IFS=' '
    while read local_ref local_sha remote_ref remote_sha
    do
            if [ "$local_sha" = $z40 ]
            then
                    # Handle delete
                    :
            else
                    if [ "$remote_sha" = $z40 ]
                    then
                            # New branch, examine all commits
                            range="$local_sha"
                    else
                            # Update to existing branch, examine new commits
                            range="$remote_sha..$local_sha"
                    fi
    
                    # Check for WIP commit
                    commit=`git rev-list -n 1 --grep '^PRIVATE:' "$range"`
                    if [ -n "$commit" ]
                    then
                            echo "Error: Found PRIVATE commit in $local_ref."
                            echo "The commit is in the range $range."
                            echo "NOT pushing!"
                            exit 1
                    fi
            fi
    done
    
    exit 0
    
    remote="$1"
    url="$2"
    

Пример сбоя

$ git push origin private/old-kalman-filter 
Found PRIVATE commit in refs/heads/myforbiddenbranch, the commit is in the range 
a15c7948676af80c95b96430e4240d53ff783455. NOT PUSHING!
error: failed to push some refs to 'remote:/path/to/remote/repo'

Чтобы снова сделать ветвь пригодной для повторного использования, вы можете либо удалить ловушку, либо, что лучше, изменить сообщение фиксацииудалить запрещенное слово.

Этот сценарий можно изменить, чтобы он рассматривал только один запрещенный пульт, установив remote_ref.Но в этом случае не забудьте скопировать этот хук во все репозитории, разрешенные для получения этой ветки.

2 голосов
/ 11 июля 2011

Вы можете создать ветку, которая не существует в вашем удаленном хранилище.

Таким образом, если вы просто сделаете:

git push origin

, она будет выдвигать только те ветки, которые существуют в удаленном хранилище..

Также просмотрите файл .git/config (в каталоге локального репозитория) после создания ветви - вы увидите, что каждой локальной ветви может быть назначен отдельный удаленный репозиторий.Вы можете воспользоваться этим, назначив эту ветвь отдельному (частному) хранилищу, но это не универсальное решение (ветвь все еще может быть перенесена на удаленный источник, если явно заказано, или командой git push origin).

2 голосов
/ 11 июля 2011

Существует несколько решений:

  1. Не технически, просто измените лицензию на коммерческую для вашей отрасли
  2. Создайте частный репозиторий на github, содержащий ваш форк
  3. Сделать git-hook на сервере (afaik невозможен с github)
  4. Написать оболочку для git-push, чтобы предотвратить push с помощью git push
0 голосов
/ 28 июля 2018

Если вы используете GitHub, вы можете создать ветку на GitHub с тем же именем, что и ваша ветка. Нет необходимости выдвигать какие-либо коммиты на него, просто создайте пустую ветку вне master или чего-либо еще (вы можете сделать это в интерфейсе GitHub, набрав ветку во всплывающем окне «branch» и нажав create branch <branch-name>).

Затем перейдите к настройкам ветки для хранилища (например, https://github.com/<user>/<repo>/settings/branches/<branch-name>) и включите защиту ветки для своей ветки. Обязательно установите все флажки, в частности, поля «требовать проверки» или «проверки состояния», которые запрещают прямую передачу ветви (она должна быть выдвинута из запроса на извлечение), а также обязательно установите флажок, чтобы включить администраторы.

Тогда GitHub не позволит вам перейти в ветку, даже если вы используете -f. Вы получите сообщение типа

$ git push -f origin private
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 8 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 981 bytes | 981.00 KiB/s, done.
Total 3 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), completed with 2 local objects.
remote: error: GH006: Protected branch update failed for refs/heads/private.
remote: error: At least 1 approving review is required by reviewers with write access.
To github.com:<user>/<repo>.git
 ! [remote rejected] private -> private (protected branch hook declined)
error: failed to push some refs to 'git@github.com:<user>/<repo>.git'
...