如何添加git repo作为自身的子模块?(或者:如何以编程方式生成GitHub页面?)

Tho*_*mas 21 git github git-submodules

我想开始在我的项目网站上使用GitHub Pages.这只需要gh-pages在repo中命名的分支(子树),并提供其内容.问题是网站的一部分(手动,更改日志,下载页面......)是由构建系统自动生成的,所以我想找到gh-pages在主要仓库保持打开时将这些更改提交到分支的最佳方法master(或任何地方).

为了提交gh-pages分支,我可以编写一个脚本,将repo克隆到一个临时目录中,进行修改,提交它们,然后将它们推回到主repo.但这听起来像一个容易出错的过程,所以我希望有一个更简单的方法.

一位朋友建议我可以将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
Run Code Online (Sandbox Code Playgroud)

我是子模块的新手; 当然,我已经做了一些阅读,但我不明白这种行为.为什么需要origin遥控器?理想情况下,我希望子模块始终引用它所驻留的repo,因此它不应该引用origin或任何其他遥控器.如果某人克隆了回购并运行git submodule init ; git submodule update,理想情况下应该从新克隆的回购中获取.

是否可以将repo添加为自身的子模块?这是可取的吗?我需要注意哪些陷阱?有没有更好的方法来实现我想要的?

Mar*_*air 8

在这种情况下,行为似乎是git试图将原始存储库的原点设置为子模块的原点.这一点由git submodule手册页确认,该手册说[我的重点]:

<repository>是新子模块的原始存储库的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
Run Code Online (Sandbox Code Playgroud)

这似乎工作正常 - 如果我切换到另一个目录并执行:

$ cd /var/tmp
$ git clone --recursive /tmp/main/
Run Code Online (Sandbox Code Playgroud)

...子模块已正确更新和初始化. (更新:虽然正如您在下面的评论中指出的那样,origin在子模块中将设置为您克隆的URL而不是..)

至于这是否是一个好主意:我曾经做过一个项目,过去使用类似的设置,后来放弃了它.然而,其原因是:(a)主存储库中的替代分支是巨大的,并且即使对于不需要子模块的人也会使存储库膨胀,以及(b)它对不确定的人造成了混乱.发生了什么事.

但是,对于您的用例,我认为这是一个相当简洁的解决方案:)


Mar*_*ski 6

到使用替代GIT中 子模块产生的GitHub页是使用GIT中子树 合并策略.有许多网站 展示了如何做到这一点,并争辩的 利弊子模块VS子树,合并.甚至还有一个新的git-subtree命令可能会或可能不会与您的Git版本一起安装.IMO唯一需要知道的是这两点.

  • 子树合并策略在合并时匹配两个存储库/分支的树(git的目录树的概念),以便不合并无关的文件和文件夹,仅合并相关的树.这正是你想要的Github Pages,因为它在一个孤儿分支中,它有一个完全不同的树你的主分支.

  • 通常,子树合并具有简化的工作流程,并且丢失修订的机会少于子模块.

以下是如何在Github Pages中使用子树合并策略:

  1. 如果您没有gh-pages在本地或远程repos中调用的分支,则使用该--orphan标志创建一个分支,以使其为空.Github有关于手动创建Github页面的说明..如果您使用自动页面生成,则可以跳过此步骤,但在本文中的其他位置替换本地分支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"
    
    Run Code Online (Sandbox Code Playgroud)

    如果你的主分支中的子树中有文档,你可以将其拉入并立即使用git-read-tree进行提交,但你必须知道树形.据推测,您可以先使用git-write-tree,它将输出--prefix当前索引中标志所命名的树的SHA-1 .然后使用该-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"
    
    Run Code Online (Sandbox Code Playgroud)
  2. 签出master并用于git-read-treegh-pages分支的工作副本复制到masterEG中的某个路径./docs/_build/html.-u如果合并成功,该标志将更新工作副本中的文件.如果gh-pages分支中没有要与主服务器合并的文件,则此步骤可能是不必要的,但如果存在,则可能有助于子树合并策略以确定您的文件在哪个树中.像往常一样,Git不允许您合并已存在的文件或您的仓库中有未提交的更改.如果要将使用"自动页面生成"创建的页面合并回另一个树EG:docsmaster分支中,请使用此步骤.不要忘记将新文件提交到您的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"
    
    Run Code Online (Sandbox Code Playgroud)
  3. 对您的文档进行更改,并通过您喜欢的任何方式生成一些HTML.EG:Jekyll,PelicanSphinx.注意:如果您不使用Jekyll,并且需要下划线文件夹/文件,EG:for *.css*.jsfiles,那么请务必添加一个名为.nojekyllhtml目录的文件.

    ./docs $ (master) sphinx-quickstart
    ...
    ./docs $ (master) make html
    ./docs/_build/html $ (master) echo >> .nojekyll
    
    Run Code Online (Sandbox Code Playgroud)
  4. gh-pages使用子树合并策略(-s subtree)更新您的分支,压缩所有提交,以便您的Github页面历史记录不被污染(--squash)并等到合并后提交,以便您可以查看(--no-commit).注意:当你签出你的gh-pages分支时,master中的文件和文件夹可能会保持为Untracked,只需忽略它们并专注于索引中的实际内容.注意:Git 不会检查gh-pages是否有任何未经修改或未安装的修改master.

    . $ (master) git checkout origin/gh-pages
    . $ (gh-pages) git merge --no-commit --squash -s subtree master
    
    Run Code Online (Sandbox Code Playgroud)

    Git使用子树合并策略对你想要合并的树进行最好的猜测,但是,如果没有太多可继续下去的话,你可能会更好地明确告诉Git要合并哪个树.

    . $ (gh-pages) git merge --no-commit --squash -s recursive -Xsubtree=docs/_build/html/ master
    
    Run Code Online (Sandbox Code Playgroud)
  5. 检查您的更改并提交.Merge为您生成一条消息,其中包含所有要合并的提交的短日志.

    . $ (gh-pages) git commit
    
    Run Code Online (Sandbox Code Playgroud)
  6. 推动您的gh-pages分支部署您的GitHub Pages网站.

    . $ (gh-pages) git push origin gh-pages
    
    Run Code Online (Sandbox Code Playgroud)
  7. 回到master.

    . $ (gh-pages) git checkout master
    
    Run Code Online (Sandbox Code Playgroud)
  8. 如果您gh-pages因任何原因需要从中提取更改,请使用相反方向的子树合并策略.例如git merge --squash --no-commit -s subtree gh-pages

  9. 要对与树匹配的两个分支进行差异,请使用diff-tree

    . $ git diff-tree master gh-pages
    
    Run Code Online (Sandbox Code Playgroud)
  10. 将它放入脚本或后提交钩子中,无论何时编辑文档或将其添加到Makefile用于生成html的文件中,它都会运行!以编程方式生成的GitHub页面.