我想开始为我的项目网站使用 GitHub Pages。这仅需要存储库中名为 gh-pages 的分支(子树),并提供其内容。问题是网站的一部分(手册、更改日志、下载页面...)是由构建系统自动生成的,所以我想找到将这些更改提交到 gh-pages 的最佳方法。 code> 分支,而主存储库保留在 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,理想情况下它应该从新克隆的存储库中提取。
是否可以添加存储库作为其自身的子模块?值得吗?有什么我需要注意的陷阱吗?有更好的方法来实现我想要的吗?
I want to start using GitHub Pages for my project's website. This simply requires a branch (subtree) named gh-pages
in the repo, and serves up its content. The problem is that part of the website (manual, changelog, download page...) is auto-generated by the build system, so I want to find the best way to commit these changes to the gh-pages
branch while the main repo remains on master
(or wherever).
To commit to the gh-pages
branch, I could write a script that clones the repo into a temporary directory, makes the modifications, commits them, and then pushes them back to the main repo. But this sounds like an error-prone process, so I'm hoping there is an easier way.
A friend suggested that I might add the gh-pages
branch as a submodule to the main repository. I ran a little experiment, but it doesn't quite work:
$ 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
I'm new to submodules; have done some reading, of course, but I don't understand this behaviour. Why does it need an origin
remote? Ideally, I want the submodule to always reference the repo that it resides in, so it should not reference origin
or any other remotes. If somebody clones the repo and runs git submodule init ; git submodule update
, it should ideally pull from the newly cloned repo.
Is it possible to add a repo as a submodule of itself? Is it desirable? Are there any pitfalls that I need to be aware of? Is there a better way to achieve what I want?
发布评论
评论(2)
在这种情况下,行为似乎是 git 试图将原始存储库的起源设置为子模块的起源。
git submodule
手册页证实了这一点,其中显示[我的重点]:对我来说似乎不错的解决方法是执行以下操作:
这似乎工作正常 - 如果我更改为另一个目录并执行以下操作:
...子模块已正确更新和初始化。 (更新:尽管正如您在下面的评论中指出的那样,子模块中的
origin
将设置为您克隆的 URL,而不是..
)至于这是否是一个好主意:我曾经参与过一个项目,该项目过去使用了类似的设置,但后来放弃了它。然而,这样做的原因是(a)主存储库中的替代分支非常巨大,即使对于不需要子模块的人来说,存储库也会变得臃肿;(b)它导致了混乱对于那些不确定发生了什么的人。
然而,对于您的用例,我认为这是一个相当简洁的解决方案:)
In this case, the behaviour seems to be that git is trying to set the origin of the original repository to be the origin of the submodule. This is confirmed by the
git submodule
man page, which says [my emphasis]:A workaround that seems fine for me is to do the following:
This seems to work OK - if I change into another directory and do:
... the submodule is updated and initialized correctly. (Update: although as you point out in a comment below,
origin
in the submodule will be set to the URL you cloned from rather than..
)As for whether this is a good idea or not: I've worked on a project which used a similar setup in the past and which subsequently abandoned it. The reasons for this, however, were (a) that the alternative branches in the main repository were huge and bloated the repository even for people who didn't need the submodule and (b) that it caused confusion for people who weren't sure what was going on.
For your use case, however, I think it's a rather neat solution :)
使用 Git 子模块 生成 GitHub Pages就是使用Git Subtree 合并策略。 有很多网站 展示了如何执行此操作 和 争论 /2012/04/28/why-your-company-shouldnt-use-git-submodules/" rel="nofollow noreferrer">子模块与子树合并。甚至还有一个新的 git-subtree 命令 可能会也可能不会随您的 Git 版本一起安装。 IMO 您真正需要了解的唯一事情就是这两点。
子树合并策略在合并时匹配两个存储库/分支的树(git 的目录树概念),以便无关的文件和分支被合并。文件夹不会被合并,只会合并相关的树。这正是您想要的 Github Pages,因为它位于一个孤立分支中,它与您的主分支具有完全不同的树。
一般来说,子树合并具有简化的工作流程,并且比子模块丢失修订的机会更少。
以下是如何在 Github Pages 中使用子树合并策略:
如果您在本地或远程存储库中没有名为
gh-pages
的分支,则使用-- 创建一个分支orphan
标志,使其为空。 Github 有手动创建 Github 页面的说明。。如果您使用自动页面生成,那么您可以可以跳过此步骤,但将本文其他地方的本地分支gh-pages
替换为远程分支origin/gh-pages
,否则本地获取远程分支。 注意:您可以跳过创建.nojekyll
文件,但必须从孤立分支中删除所有文件并提交它,否则不会创建该文件。<前><代码>。 $ (master) git checkout --orphan gh-pages
。 $ (gh-pages) git rm -rf.
。 $(gh-pages)回显>> .nojekyll
。 $ (gh-pages) git add .nojekyll
。 $ (gh-pages) git commit -m "创建 github 页面,忽略 jekyll"
如果您的主分支的子树中已经有文档,您可以将其拉入并使用 git-read-tree 现在,但你必须了解树。想必您可以首先使用 git-write-tree 它将输出当前索引中由
--prefix
标志命名的树的 SHA-1。然后使用-u
标志通过主分支的更改来更新gh-pages
分支并提交更改。<前><代码>。 $ (master) git write-tree --prefix=docs/_build/html master
abcdefghijklmnopqrstuvwxyz1234567890abcd
。 $ (主) git checkout gh-pages
。 $ (gh-pages) git 读取树 abcdefghijklmnopqrstuvwxyz1234567890abcd
。 $ (gh-pages) git commit -m "从主文档更新 gh-pages html"
签出
master
并使用git-read-tree
将gh-pages
分支的工作副本复制到中的某个路径>master
,EG:./docs/_build/html
。如果合并成功,-u
标志会更新工作副本中的文件。如果gh-pages
分支中没有您想要合并回 master 的文件,则此步骤可能是不必要的,但如果有,它可能有助于子树合并策略确定您在哪棵树中文件是。与往常一样,Git 不会让您合并已存在的文件或存储库中存在未提交的更改。如果您想将使用自动页面生成创建的页面合并回不同的树,例如master
分支中的docs
,请使用此步骤。不要忘记将新文件提交到您的master
分支。<前><代码>。 $(gh-pages)git checkout master
。 $ (master) git read-tree --prefix=docs/_build/html -u gh-pages
。 $ (master) git commit -m "将 gh-pages 树读入 master at ./docs/_build/html"
通过您喜欢的任何方式更改您的文档并生成一些 html。 EG:Jekyll,Pelican 或 Sphinx< /a>. 注意:如果您不使用 Jekyll,并且需要下划线文件夹/文件,例如:
*.css
或*.js
文件,然后确保添加一个名为.nojekyll
的文件到您的 html 目录。使用子树合并策略(
-s subtree
)更新您的gh-pages
分支,压缩所有提交,以便您的Github 页面历史记录未被污染 (--squash
),并等到合并后提交,以便您可以查看 (--no-commit
)。注意:当您签出gh-pages
分支时,文件和文件将被删除。主文件夹中的文件夹可能会保持为未跟踪,只需忽略它们并专注于索引中实际的内容即可。注意:如果master
中有任何未提交或未存储的修改,Git 将不会检出gh-pages
。<前><代码>。 $ (主) git checkout origin/gh-pages
。 $ (gh-pages) git merge --no-commit --squash -s 子树主控
Git 使用子树合并策略对要合并的树进行最佳猜测,但是,如果没有太多内容,你最好明确告诉 Git 要合并哪棵树。
<前><代码>。 $ (gh-pages) git merge --no-commit --squash -s recursive -Xsubtree=docs/_build/html/ master
检查您的更改并提交。合并会为您生成一条消息,其中包含正在合并的所有提交的简短日志。
<前><代码>。 $ (gh-pages) git 提交
推送您的
gh-pages
分支会部署您的 GitHub Pages 网站。<前><代码>。 $ (gh-pages) git Push 原点 gh-pages
返回
master
。<前><代码>。 $(gh-pages)git checkout master
如果您出于某种原因需要从
gh-pages
中提取更改,请以相反的方向使用子树合并策略。 EGgit merge --squash --no-commit -s subtree gh-pages
要对与树匹配的两个分支进行比较,请使用 diff-tree
<前><代码>。 $ git diff-tree master gh-pages git diff-tree master gh-pages
将其放入脚本或提交后挂钩中,该挂钩在您编辑文档或将其添加到
Makefile
用于生成 html,瞧! 以编程方式生成 GitHub 页面。An alternative to using Git Submodules to generate GitHub Pages is to use Git Subtree Merge Strategy. There are many sites that show how to do this and that argue the pros and cons of Submodules vs Subtree-Merge. There is even a newish git-subtree command that may or may not be installed with your version of Git. IMO the only things you really need to know are these two points.
The subtree merge strategy matches the trees (git's notion of a directory tree) of two repositories/branches when merging so that extraneous files & folders are not merged, only the relevant trees. This is exactly what you want for Github Pages, since it is in an orphan branch, it has a completely different tree your master branch.
In general, the subtree merge has a simplified workflow and less chance for losing revisions than submodules do.
Here's how to use subtree merge strategy with Github Pages:
If you don't have a branch called
gh-pages
in either local or remote repos, then create one using the--orphan
flag so that it will be empty. Github has instructions for creating Github pages manually.. If you used the Automatic Page Generation then you can can skip this step, but replace the local branchgh-pages
with the remote branchorigin/gh-pages
everywhere else in this post, otherwise fetch the remote branch locally. NOTE: You can skip creating the.nojekyll
file, but you must remove all files from the orphan branch and commit it or it will not be created.If you have documentation in a sub tree in your main branch already you could pull it in and commit it using git-read-tree right now, but you would have to know tree-ish. Presumably you could first use git-write-tree which will output the SHA-1 of the tree named by the
--prefix
flag in the current index. Then use the-u
flag to update thegh-pages
branch with changes form the main branch and commit the changes.Checkout
master
and usegit-read-tree
to copy the working copy of thegh-pages
branch to some path inmaster
, EG:./docs/_build/html
. The-u
flag updates files in the working copy if merge is successful. This step may be unnecessary if there are no files ingh-pages
branch that you want to merge back with master, but if there are, it may help the subtree merge strategy to figure out in what tree your files are. As usual, Git won't let you merge over files that already exist or if there are uncommitted changes in your repo. Use this step if you want to merge the pages you created using Automatic Page Generation back into a different tree, EG:docs
in yourmaster
branch. Don't forget to commit the new files to yourmaster
branch.Make changes to your documentation and generate some html by whatever means you prefer. EG: Jekyll, Pelican or Sphinx. NOTE: If you are not using Jekyll, and will need underscore folders/files, EG: for
*.css
or*.js
files, then be sure to add a file called.nojekyll
to your html directory.Update your
gh-pages
branch using the subtree merge strategy (-s subtree
), squash all of the commits so your Github pages history isn't polluted (--squash
) and wait till after the merge to commit so you can review (--no-commit
). NOTE: When you checkout yourgh-pages
branch, files & folders from master will probably remain as Untracked, just ignore them and concentrate on what is actually in the index. NOTE: Git will not checkoutgh-pages
if there are any uncommited or unstashed modifications inmaster
.Git makes its best guess as to what trees you want to merge using the subtree merge strategy, however, if there isn't much to go on, you might be better explicitly telling Git which tree to merge.
Review your changes and commit. Merge generates a message for you containing the short log of all of the commits being merged.
Pushing your
gh-pages
branch deploys your GitHub Pages website.Return to
master
.If you need to pull changes from your
gh-pages
for whatever reason, use the subtree merge strategy in the opposite direction. EGgit merge --squash --no-commit -s subtree gh-pages
To do a diff of the two branches matching the trees, use diff-tree
Put this into a script or a post-commit hook that runs whenever you edit your documents or add it to the
Makefile
you use to generate html and voila! programmatically generated GitHub pages.