Включение Bootstrap в репозиторий git с использованием слияния поддеревьев

Я работаю над проектом, в котором мы хотели бы отредактировать файлы LESS, поставляемые с Twitter Bootstrap. стандартный совет — оставить эти файлы нетронутыми, чтобы упростить обновление Bootstrap. Но этот совет не работает для нас; наш код становится хрупким и его трудно поддерживать.

Кажется, что это должно быть возможно решить с помощью слияния поддеревьев git: мы могли бы отредактировать LESS-файлы Bootstrap, чтобы получить четкий, поддерживаемый код, а затем использовать инструменты слияния git для добавления новых версий Bootstrap.

Мы придумали план использования слияния поддеревьев. Но прежде чем приступить к реализации плана, я хотел бы получить отзыв: Есть ли существенные недостатки, которые мы упустили из виду? Есть ли лучший/более простой подход?

Подходы с существенными недостатками

При самом простом подходе к слиянию поддерева все коммиты из поддерева ( т. е. Bootstrap) объединяются в ветку master вашего проекта. Недостаток в том, что в Bootstrap так много коммитов, что наши коммиты теряются в шуме. Мы бы хотели, чтобы их коммиты не попадали в нашу ветку master.

Теоретически мы могли бы использовать git rebase -i, чтобы объединить все коммиты Bootstrap в один коммит, который затем мы объединим в master. Но rebase -i не работает со слияниями.

@Sigi услужливо предложил использовать сквош-слияния для перехода от bootstrap-upstream к master. Захват начальной версии Bootstrap (v3.1.0) работал нормально. Но когда мы объединились в следующей версии (v3.1.1), у нас возникло более 100 конфликтов слияния. Каждое изменение Bootstrap между 3.1.0 и 3.1.1 помечалось как конфликт. (Наши точные шаги приведены в этой сути.)

План

Мы планируем использовать ветку merge-from-bootstrap для загрузки коммитов Bootstrap в наш репозиторий. При объединении изменений в merge-from-bootstrap (либо наших изменений в master, либо изменений Bootstrap) всегда записывайте слияние. При объединении из merge-from-bootstrap в master используйте git merge --squash, чтобы слияние не записывалось.

Наша надежда в том, что:

  1. master остается управляемым, потому что коммиты Bootstrap никогда не становятся частью этой ветки.
  2. Git имеет максимально возможное количество информации при слиянии с новой версией Bootstrap, поскольку ветка merge-from-bootstrap содержит полную историю наших изменений и изменений команды Bootstrap.

Доказательство концепции

На следующих шагах мы берем Bootstrap v3.1.0, вносим некоторые изменения, а затем обновляемся до v3.1.1. POC, кажется, работает хорошо (как и мои тесты с нашим реальным репо), но я хотел бы знать, не создадим ли мы себе проблемы в будущем.

Начните с нового репозитория, где единственным файлом является README.md (т. е. новый репозиторий, который вам дает GitHub).

# Add bootstrap as a remote
git remote add bootstrap https://github.com/twbs/bootstrap.git
# Only fetch the master branch; don't fetch tags
git config remote.bootstrap.fetch +refs/heads/master:refs/remotes/bootstrap/master
git config remote.bootstrap.tagopt --no-tags
git fetch bootstrap

# Start with Bootstrap v3.1.0
git checkout -b merge-from-bootstrap
# SHA is the commit tagged v3.1.0 from the bootstrap repo
git merge -s ours --no-commit 1409cde7e800ca83fd761f87e5ad8f0d259e38d1
git read-tree -u --prefix=bootstrap/ 1409cde7e800ca83fd761f87e5ad8f0d259e38d1
git commit -am "Bootstrap v3.1.0"

# Merge Bootstrap 3.1.0 to master
git checkout master
git merge --squash merge-from-bootstrap
git commit -am "Merge bootstrap v3.1.0 to master"

# Make some changes on master, so that we have something to
# be merged
sed -e 's/= space/= force-merge-conflict/g' -i '' bootstrap/.editorconfig
git commit -am "Force a merge conflict"
sed -e 's/"Helvetica Neue"/"Comic Sans"/g' -i '' bootstrap/less/variables.less 
git commit -am "Comic Sans"

# Get ready to upgrade to the new version of Bootstrap
git checkout merge-from-bootstrap
git merge -s recursive -Xtheirs master

# Merge in Bootstrap v3.1.1 from bootstrap/master to
# merge-to-bootstrap. (SHA is for v3.1.1 from the bootstrap repo)
git merge -s recursive -X subtree=bootstrap --no-commit a365d8689c3f3cee7f1acf86b61270ecca8e106d

# Fix the merge conflict, then do:
git commit -am "Merged in Bootstrap v3.1.1"

# Merge back to master
git checkout master
git merge --squash merge-from-bootstrap

person Evan    schedule 15.04.2014    source источник


Ответы (1)


Воспользуйтесь подходом, описанным в книге Pro Git:

В ветке Bootstrap объедините исходные изменения:

$ git checkout bootstrap-upstream
$ git pull

Затем в главной ветке объедините поддерево поддерево Bootstrap с параметром --squash:

$ git checkout master
$ git merge --squash -s subtree --no-commit bootstrap-upstream

Ключевым моментом здесь является использование стратегии слияния subtree, которая берет все изменения из Bootstrap оптом и помещает их на свое место (подкаталог).

Зафиксируйте и напишите сообщение о коммите:

$ git commit

Это позволит избежать хранения всей истории bootstrap-upstream в вашей ветке master, и вам не придется использовать git rebase.

person Sigi    schedule 28.04.2014
comment
Спасибо за ответ. Но когда я объединил bootstrap-upstream с master во второй раз, я получил массу конфликтов слияния. Все изменения в Bootstrap между версиями помечались как конфликт. Я отредактировал вопрос с более подробной информацией. - person Evan; 29.04.2014
comment
Вы использовали не стратегию слияния subtree, как рекомендуется в моем ответе, а стратегию рекурсивного. Не могли бы вы попробовать еще раз с опцией -s subtree, потому что это ключ к предложенному мной решению. - person Sigi; 29.04.2014
comment
Кстати, в самых последних версиях git есть подкоманда subtree, которая может упростить вам задачу. Пожалуйста, взгляните и на это тоже. Страница руководства для git-subtree на самом деле вполне читабельна (во всяком случае, для стандартов Git :) - person Sigi; 29.04.2014
comment
Спасибо за указатель на git-subtree; это выглядит многообещающе. Что касается стратегии слияния: я попробовал стратегию слияния поддерева (строка 46 суть) и удалил почти все файлы Bootstrap. Вторая попытка использовала аргумент поддерева для рекурсивной стратегии, что вызвало массовые конфликты слияния. Но я не думаю, что буду следовать ни одному из этих подходов, а вместо этого рассмотрю git-subtree. Ваше здоровье. - person Evan; 01.05.2014
comment
У меня нет опыта работы с git-subtree, так как он новый. Насколько я понимаю, однако, это будет очень похоже на ручной подход, описанный выше. Пожалуйста, вернитесь сюда и сообщите о своем опыте, мне было бы интересно. - person Sigi; 01.05.2014