Как добавить git-репо как подмодуль? (Или: Как сгенерировать GitHub Pages программно?) - PullRequest
20 голосов
/ 14 марта 2011

Я хочу начать использовать GitHub Pages для веб-сайта моего проекта. Для этого просто требуется ветвь (поддерево) с именем gh-pages в репо и его содержимое. Проблема в том, что часть сайта (руководство, журнал изменений, страница загрузки ...) автоматически генерируется системой сборки, поэтому я хочу найти лучший способ зафиксировать эти изменения в ветке gh-pages во время основного репо остается на master (или где-либо еще).

Чтобы зафиксировать ветку gh-pages, я мог бы написать сценарий, который клонирует репо во временный каталог, вносит изменения, фиксирует их и затем возвращает их в основное репо. Но это звучит как склонный к ошибкам процесс, поэтому я надеюсь, что есть более простой способ.

Друг предложил мне добавить ветку gh-pages в качестве подмодуля в основной репозиторий. Я провел небольшой эксперимент, но он не совсем работает:

$ git init main
Initialized empty Git repository in /tmp/main/.git/
$ cd main
$ touch main.txt
$ git add .
$ git commit -m'Initial commit in main branch.'
[master (root-commit) 1c52a4e] Initial commit in main branch.
 0 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 main.txt
$ git symbolic-ref HEAD refs/heads/gh-pages
$ rm .git/index
$ git clean -fdx
Removing main.txt
$ touch index.html
$ git add .
$ git commit -m'Initial commit in website branch.'
[gh-pages (root-commit) 94b10f2] Initial commit in website branch.
 0 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 index.html
$ git checkout master
Switched to branch 'master'
$ git submodule add -b gh-pages . gh-pages
repo URL: '.' must be absolute or begin with ./|../
$ git submodule add -b gh-pages ./ gh-pages
remote (origin) does not have a url defined in .git/config

Я новичок в подмодулях; Конечно, я немного читал, но я не понимаю этого поведения. Зачем ему нужен origin пульт? В идеале я хочу, чтобы субмодуль всегда ссылался на репо, в котором он находится, поэтому он не должен ссылаться на origin или любые другие пульты. Если кто-то клонирует репо и запускает git submodule init ; git submodule update, в идеале он должен извлечь из вновь клонированного репо.

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

Ответы [ 2 ]

8 голосов
/ 14 марта 2011

В этом случае поведение выглядит так, что git пытается установить источник исходного репозитория в качестве источника подмодуля. Это подтверждается справочной страницей git submodule, где написано [мой акцент]:

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

Обходной путь, который мне подходит, это сделать следующее:

# Define origin to be the absolute path to this repository - we'll remove
# this later:
$ cd /tmp/main/
$ git remote add origin /tmp/main/

# Now add the submodule:
$ git submodule add -b gh-pages ./ gh-pages
Initialized empty Git repository in /tmp/main/gh-pages/.git/
Branch gh-pages set up to track remote branch gh-pages from origin.

# Now .gitmodules looks sensible:
$ cat .gitmodules 
[submodule "gh-pages"]
    path = gh-pages
    url = ./

# However, the origin for the submodule isn't what we want:
$ cd gh-pages
$ git remote -v
origin  /tmp/main/ (fetch)
origin  /tmp/main/ (push)

# So remove it and add the right origin (just ".."):
$ git remote rm origin
$ git remote add origin ..

# Change back to the main repository and commit:
$ cd ..
$ git commit -m "Added the gh-pages branch as a submodule of this repository"
[master 6849d53] Added the gh-pages branch as a submodule of this repository
 2 files changed, 4 insertions(+), 0 deletions(-)
 create mode 100644 .gitmodules
 create mode 160000 gh-pages

Кажется, это работает нормально - если я перехожу в другой каталог и делаю:

$ cd /var/tmp
$ git clone --recursive /tmp/main/

... подмодуль обновлен и правильно инициализирован. (Обновление: хотя, как вы указали в комментарии ниже, origin в подмодуле будет иметь вместо URL-адреса, клонированного вами, ..)

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

Однако для вашего случая использования я думаю, что это довольно изящное решение:)

6 голосов
/ 10 октября 2013

Альтернативой использованию Git подмодулей для генерации страниц GitHub является использование Git поддерева стратегии слияния, Есть много сайтов , которые показывают, как это сделать и , которые утверждают плюсы и минусы из Подмодулей против Subtree-Merge . Существует даже новая команда git-subtree , которая может или не может быть установлена ​​с вашей версией Git. ИМО единственное, что вам действительно нужно знать, это два момента.

  • Стратегия слияния поддеревьев соответствует деревьям (понятие git дерева каталогов) двух репозиториев / ветвей при слиянии, так что посторонние файлы и папки не объединяются, только соответствующие деревья. Это именно то, что вам нужно для Github Pages, так как оно находится в ветке-сироте, у нее совершенно другое дерево - ваша основная ветвь.

  • Как правило, объединение поддеревьев имеет упрощенный рабочий процесс и меньше шансов на потерю ревизий, чем подмодули.

Вот как использовать стратегию слияния поддеревьев с Github Pages:

  1. Если у вас нет ветки с именем gh-pages в локальных или удаленных репозиториях, то создайте ветку, используя флаг --orphan, чтобы она была пустой. Github содержит инструкции по созданию страниц Github вручную. . Если вы использовали Automatic Page Generation , то вы можете пропустить этот шаг, но заменить локальную ветку gh-pages на удаленную ветку origin/gh-pages везде в этом посте, в противном случае получить удаленную ветку локально . ПРИМЕЧАНИЕ. Вы можете пропустить создание файла .nojekyll, но вы должны удалить все файлы из сиротской ветви и зафиксировать его, иначе он не будет создан.

    . $ (master) git checkout --orphan gh-pages
    . $ (gh-pages) git rm -rf. 
    . $ (gh-pages) echo >> .nojekyll
    . $ (gh-pages) git add .nojekyll
    . $ (gh-pages) git commit -m "create github pages, ignore jekyll"
    

    Если у вас уже есть документация в поддереве в вашей основной ветке, вы могли бы извлечь ее и зафиксировать, используя git-read-tree прямо сейчас, но вы должны знать древовидную структуру. Предположительно, вы могли бы сначала использовать git-write-tree , который выведет SHA-1 дерева, названного флагом --prefix в текущем индексе. Затем используйте флаг -u, чтобы обновить ветку gh-pages с изменениями из основной ветви и зафиксировать изменения.

    . $ (master) git write-tree --prefix=docs/_build/html master
    abcdefghijklmnopqrstuvwxyz1234567890abcd
    . $ (master) git checkout gh-pages
    . $ (gh-pages) git read-tree abcdefghijklmnopqrstuvwxyz1234567890abcd
    . $ (gh-pages) git commit -m "update gh-pages html from master docs"
    
  2. Оформить заказ master и использовать git-read-tree, чтобы скопировать рабочую копию ветви gh-pages по какому-либо пути в master, например: ./docs/_build/html. Флаг -u обновляет файлы в рабочей копии, если слияние прошло успешно. Этот шаг может быть ненужным, если в ветви gh-pages нет файлов, которые вы хотите объединить с master, но если они есть, это может помочь стратегии объединения поддеревьев выяснить, в каком дереве находятся ваши файлы. Как обычно, Git не позволит вам объединять файлы, которые уже существуют, или если в вашем репо есть незафиксированные изменения. Используйте этот шаг, если вы хотите объединить страницы, созданные с помощью автоматического создания страниц, в другое дерево, например: docs в вашей ветви master. Не забудьте отправить новые файлы в ветку master.

    . $ (gh-pages) git checkout master
    . $ (master) git read-tree --prefix=docs/_build/html -u gh-pages
    . $ (master) git commit -m "read gh-pages tree into master at ./docs/_build/html"
    
  3. Внесите изменения в свою документацию и сгенерируйте html любым удобным для вас способом. Например: Джекилл , Пеликан или Сфинкс . ПРИМЕЧАНИЕ. Если вы не используете Jekyll и нуждаетесь в подчеркивании папок / файлов, например, для *.css или *.js файлов, то обязательно добавьте файл с именем .nojekyll в каталог html.

    ./docs $ (master) sphinx-quickstart
    ...
    ./docs $ (master) make html
    ./docs/_build/html $ (master) echo >> .nojekyll
    
  4. Обновите ветку gh-pages, используя стратегию слияния поддеревьев (-s subtree), раздавите все коммиты, чтобы история страниц Github не была загрязнена (--squash), и дождитесь завершения слияния, чтобы зафиксировать так что вы можете просмотреть (--no-commit). ПРИМЕЧАНИЕ. Когда вы извлекаете ветку gh-pages, файлы и папки от мастера, вероятно, останутся как Без отслеживания , просто проигнорируйте их и сконцентрируйтесь на том, что на самом деле находится в индексе. ПРИМЕЧАНИЕ: Git будет не извлекать gh-pages, если в master.

    есть какие-либо неснятые или несвязанные изменения.
    . $ (master) git checkout origin/gh-pages
    . $ (gh-pages) git merge --no-commit --squash -s subtree master
    

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

    . $ (gh-pages) git merge --no-commit --squash -s recursive -Xsubtree=docs/_build/html/ master
    
  5. Просмотрите ваши изменения и зафиксируйте. Merge генерирует для вас сообщение, содержащее краткий журнал всех коммитов слияния.

    . $ (gh-pages) git commit
    
  6. При нажатии на ветку gh-pages развертывается веб-сайт GitHub Pages.

    . $ (gh-pages) git push origin gh-pages
    
  7. Возврат к master.

    . $ (gh-pages) git checkout master
    
  8. Если по какой-либо причине вам необходимо получить изменения из вашего gh-pages, используйте стратегию слияния поддерева в противоположном направлении. EG git merge --squash --no-commit -s subtree gh-pages

  9. Чтобы сделать diff из двух ветвей, соответствующих деревьям, используйте diff-tree

    . $ git diff-tree master gh-pages
    
  10. Поместите это в скрипт или ловушку после фиксации, которая запускается всякий раз, когда вы редактируете свои документы или добавляете его в Makefile, который вы используете для генерации html и вуаля! программно сгенерированных страниц GitHub .

...