Git стратегия слияния поддеревьев или команда поддеревьев? - PullRequest
5 голосов
/ 06 июля 2011

Я начинаю новый проект Zend Framework, в котором я буду сотрудничать с дизайнером.Я собираюсь поддерживать этот код проекта, используя git, и обычно дизайнеры не говорят на git (или на любом другом языке программирования), поэтому я хочу упростить ему задачу, иначе я боюсь, что он вообще не будет использовать git.Мой план состоит в том, чтобы дать ему немного Git GUI, и при этом он должен использовать только основные функции Git, такие как commit, diff, fetch, merge, push и pull.

Я использую gitolite для поддержки общей копиинаш репозиторий git и так как он имеет детализированную систему разрешений, я предоставлю разработчику RW доступ только для отдельной ветки (дизайн) и доступ для чтения к другим ветвям.

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

Сокращенная структура его ветви должна быть такой:

<project name>/
    application/
        layouts/
            scripts/
        views/
            scripts/
    public/
        css/
        images/
        js/

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

Некоторые ссылки, которые я уже прочитал, заставляют меня думать, что то, что я спрашиваю, возможно:

Вот мой вопрос:

  1. Как создать уменьшенную ветку design (git checkout -b design и git mv/rm?)
  2. Как настроить git для отслеживания изменений в ветвях (чтобы я мог git merge design из главной ветви и наоборот)Версия)

Обновление:

Я обнаружил другой возможный подход к проблеме, заданный этими двумя вопросами SO

Я попытался реализовать первый после git rm all-unneeded-stuff в ветви проектирования, я делаю коммит в ветке master, которая включает файл в whiпути в списках и другие файлы в путях, занесенных в черный список, но git merge завершается ошибкой со следующим сообщением

CONFLICT (delete/modify): application/Bootstrap.php deleted in HEAD and modified in master. Version master of application/Bootstrap.php left in tree.

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

Я не пробовал второй подход (.gitignore)пока, но если я понял, что подход не соответствует моим потребностям, потому что он будет игнорировать только занесенные в черный список файлы в ветви дизайна, но они будут проверены в ветви дизайна, что нарушит мои требования.

Iподтолкнул свои эксперименты на GitHub

Обновление 2:

Я думаю, что в настоящее время нет решения для этого.С текущей реализацией git это просто недостижимо.

Я бы хотел получить противоречие, но боюсь, что этого не произойдет.

1 Ответ

6 голосов
/ 26 сентября 2011

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

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

Репозитории

Общее решение включает как минимум три варианта одного и того же репозитория:Один авторитетный репозиторий, который координирует два или более делегата репозиториев.Пользователи никогда не клонируют хранилище полномочий;клонируются только репозитории делегатов.

Делегаты отвечают за пересылку входящих коммитов в репозиторий полномочий.Хранилище полномочий отвечает за надлежащую фильтрацию входящих коммитов для каждого репозитория делегатов.Затем результаты передаются другим делегатам.

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

Репозитории делегатов

Каждый репозиторий делегатов содержит подмножество данных всего проекта (например, отфильтровано ноль или более подкаталогов).Все репозитории делегатов идентичны друг другу, за исключением того, что каждый делегат имеет свой набор отфильтрованных файлов.Все они имеют один и тот же граф истории коммитов, но коммиты будут иметь разное содержимое файла и, следовательно, разные идентификаторы SHA1.Они имеют одинаковый набор ветвей и тегов (другими словами, если у проекта есть ветвь master, то в каждом репозитории делегатов также есть ветвь master), но поскольку идентификаторы SHA1 для эквивалентных коммитов различны,ссылки будут указывать на разные идентификаторы SHA1.

Например, ниже приведены графики содержимого двух репозиториев делегатов.В репозитории everything.git ничего не отфильтровано, но в репозитории no-foo.git все в подкаталоге foo отфильтровано.

$ cd ~git/repositories/everything.git
$ git log --graph --oneline --decorate --date-order --all
* 2faaad9 (HEAD, master) barbaz
| * c3eb6a9 (release) foobar
* |   8b56913 Merge branch 'release'
|\ \  
| |/  
| * b8f899c qux
* | aad30f1 baz
|/  
* f4acd9f put a new file in subdirectory bar
* 2a15586 put a new file in subdirectory foo

$ cd ~git/repositories/no-foo.git
$ git log --graph --oneline --decorate --date-order --all
* 81c2189 (HEAD, master) barbaz
| * 6bbd85f (release) foobar
* |   c579c4b Merge branch 'release'
|\ \  
| |/  
| * 42c45c7 qux
* | 90ecdc7 baz
|/  
* 4d1cd8d put a new file in subdirectory bar
* 9cc719d put a new file in subdirectory foo

Обратите внимание, что два графика выглядят одинаково, имеют одинаковыйфиксировать сообщения, одни и те же имена веток и т. д. Единственное отличие - это идентификаторы SHA1 из-за различий в содержимом файла.

(Примечание: коммиты также могут быть отфильтрованы, чтобы не допустить пользователей другогоделегат даже не знает, что был сделан коммит в отфильтрованном каталоге. Однако, коммит можно отфильтровать, только если он касается только файлов в отфильтрованном каталоге. В противном случае могут возникнуть конфликты слияния, которые не могут быть разрешены автоматическивсеми правдами и неправдами.)

Хранилище полномочий

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

Репозиторий полномочий также будетиметь версию каждой ветви проекта от каждого делегата с префиксом имени делегата.Продолжая приведенный выше пример, репозиторий делегатов everything.git имеет ветку master, указывающую на фиксацию 2faaad9, а делегат no-foo.git имеет ветку master, указывающую на отфильтрованный, но в остальном эквивалентный коммит 81c2189.В этом сценарии authority.git будет иметь две основные ветви: everything/master, указывающие на 2faaad9 и no-foo/master, указывающие на 81c2189.Следующий график иллюстрирует это.

$ cd ~git/repositories/authority.git
$ git log --graph --oneline --decorate --date-order --all
* 2faaad9 (everything/master) barbaz
| * 81c2189 (no-foo/master) barbaz
| | * c3eb6a9 (everything/release) foobar
| | | * 6bbd85f (no-foo/release) foobar
* | | |   8b56913 Merge branch 'release'
|\ \ \ \  
| | |/ /  
| |/| |   
| | * |   c579c4b Merge branch 'release'
| | |\ \  
| | | |/  
| * | | b8f899c qux
| | | * 42c45c7 qux
* | | | aad30f1 baz
|/ / /  
| * | 90ecdc7 baz
| |/  
* | f4acd9f put a new file in subdirectory bar
| * 4d1cd8d put a new file in subdirectory bar
* | 2a15586 put a new file in subdirectory foo
 /  
* 9cc719d put a new file in subdirectory foo

Обратите внимание, что существует две версии каждого коммита, по одному для каждого делегата. Также обратите внимание на названия филиалов.

Крючки

Репозитории делегатов

Каждый фид делегата фиксирует в хранилище полномочий.

Когда пользователь обновляет ссылку (через git push) в репозитории делегатов, хук update этого репозитория автоматически делает git push в репозитории полномочий. Однако вместо использования стандартного push-refspec он использует refspec, в результате чего ссылка в репозитории органа префиксируется именем репозитория делегата (например, если репозиторий делегата имеет имя foo.git, тогда он будет использовать push refspecs, например +refs/heads/master:refs/heads/foo/master и +refs/tags/v1.0:refs/tags/foo/v1.0).

Хранилище полномочий

Хранилище полномочий фильтрует входящие коммиты и помещает их в другие репозитории делегатов.

Когда репозиторий делегатов помещается в репозиторий полномочий, перехват update полномочий:

  1. Проверяет, пытается ли пользователь создать файл в одном из отфильтрованных каталогов. Если это так, он завершается с ошибкой (в противном случае могут возникнуть конфликты слияния, которые не могут быть разрешены автоматически).
  2. Возвращает обратно в подкаталоги, которые изначально были отфильтрованы, с образованием дерева, в котором ничего не отфильтровано.
  3. Для каждого другого делегата отфильтруйте нефильтрованное дерево, чтобы сделать эквивалентный коммит с соответствующим удаленным содержимым.
  4. Нажмите эквивалентные коммиты в репозитории делегатов.

Необходимо соблюдать осторожность, чтобы избежать расы между репозиториями делегатов и правильно обрабатывать ошибки.

Ваш случай

В вашем примере у вас будет два репозитория делегатов, подобных этому:

  • everything.git (для вас)
  • zend-project.git (для вашего дизайнера)

Ветвям в authority.git будет предшествовать everything и zend-project, соответствующие двум репозиториям делегатов.

Когда вы нажимаете master в everything.git, происходит следующее:

  1. Хук update в everything.git будет толкать входящие коммиты в ветку everything/master в authority.git.
  2. Для каждой входящей фиксации хук update в authority.git будет:
    1. Создайте новый объект дерева, который на 100% идентичен дереву коммита, но удалите все, что находится вне подкаталогов application и public.
    2. Создайте новый объект фиксации, используя новое дерево и эквивалентные родительские элементы, но повторно используйте исходное сообщение фиксации, автора и метку времени.
    3. Обновление zend-project/master, чтобы указывать на новый коммит.
  3. Нажмите zend-project/master в authority.git в master в zend-project.git.

Когда ваш дизайнер нажимает master в zend-project.git, происходит следующее:

  1. Хук update в zend-project.git будет толкать входящие коммиты в ветку zend-project/master в authority.git.
  2. Для каждой входящей фиксации хук update в authority.git будет:
    1. Проверьте, не были ли созданы какие-либо новые файлы за пределами подкаталогов application или public. Если это так, вернитесь с сообщением об ошибке.
    2. Создайте новый объект дерева, который на 100% идентичен дереву коммита, за исключением того, что в него вложены другие подкаталоги из everything/master.
    3. Создайте новый объект фиксации, используя новое дерево и эквивалентные родительские элементы, но повторно используйте исходное сообщение фиксации, автора и метку времени.
    4. Обновление everything/master для указания нового коммита.
  3. Нажмите everything/master в authority.git до master в everything.git.

Примечания

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

Я надеюсь, что смог объяснить это достаточно ясно.

...