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

发布于 2024-10-21 16:16:05 字数 1568 浏览 2 评论 0 原文

我想开始为我的项目网站使用 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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

一影成城 2024-10-28 16:16:05

在这种情况下,行为似乎是 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,而不是 ..

至于这是否是一个好主意:我曾经参与过一个项目,该项目过去使用了类似的设置,但后来放弃了它。然而,这样做的原因是(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]:

<repository> is the URL of the new submodule’s origin repository. This may be either an absolute URL, or (if it begins with ./ or ../), the location relative to the superproject’s origin repository.

A workaround that seems fine for me is to do the following:

# 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

This seems to work OK - if I change into another directory and do:

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

... 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 :)

活泼老夫 2024-10-28 16:16:05

使用 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 中使用子树合并策略:

  1. 如果您在本地或远程存储库中没有名为 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"

  2. 签出 master 并使用 git-read-treegh-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"

  3. 通过您喜欢的任何方式更改您的文档并生成一些 html。 EG:JekyllPelicanSphinx< /a>. 注意:如果您不使用 Jekyll,并且需要下划线文件夹/文件,例如:*.css*.js 文件,然后确保添加一个名为 .nojekyll 的文件到您的 html 目录。

    ./docs $ (master) sphinx-quickstart
    ...
    ./docs $ (master) 制作 html
    ./docs/_build/html $(master) echo >>> .nojekyll
    
  4. 使用子树合并策略(-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

  5. 检查您的更改并提交。合并会为您生成一条消息,其中包含正在合并的所有提交的简短日志。

    <前><代码>。 $ (gh-pages) git 提交

  6. 推送您的 gh-pages 分支会部署您的 GitHub Pages 网站。

    <前><代码>。 $ (gh-pages) git Push 原点 gh-pages

  7. 返回master

    <前><代码>。 $(gh-pages)git checkout master

  8. 如果您出于某种原因需要从 gh-pages 中提取更改,请以相反的方向使用子树合并策略。 EG git merge --squash --no-commit -s subtree gh-pages

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

    <前><代码>。 $ git diff-tree master gh-pages git diff-tree master gh-pages

  10. 将其放入脚本或提交后挂钩中,该挂钩在您编辑文档或将其添加到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:

  1. 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 branch gh-pages with the remote branch origin/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.

    . $ (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"
    

    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 the gh-pages branch with changes form the main branch and commit the changes.

    . $ (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. Checkout master and use git-read-tree to copy the working copy of the gh-pages branch to some path in master, 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 in gh-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 your master branch. Don't forget to commit the new files to your master branch.

    . $ (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. 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.

    ./docs $ (master) sphinx-quickstart
    ...
    ./docs $ (master) make html
    ./docs/_build/html $ (master) echo >> .nojekyll
    
  4. 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 your gh-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 checkout gh-pages if there are any uncommited or unstashed modifications in master.

    . $ (master) git checkout origin/gh-pages
    . $ (gh-pages) git merge --no-commit --squash -s subtree master
    

    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.

    . $ (gh-pages) git merge --no-commit --squash -s recursive -Xsubtree=docs/_build/html/ master
    
  5. Review your changes and commit. Merge generates a message for you containing the short log of all of the commits being merged.

    . $ (gh-pages) git commit
    
  6. Pushing your gh-pages branch deploys your GitHub Pages website.

    . $ (gh-pages) git push origin gh-pages
    
  7. Return to master.

    . $ (gh-pages) git checkout master
    
  8. If you need to pull changes from your gh-pages for whatever reason, use the subtree merge strategy in the opposite direction. EG git merge --squash --no-commit -s subtree gh-pages

  9. To do a diff of the two branches matching the trees, use diff-tree

    . $ git diff-tree master gh-pages
    
  10. 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文