如何将文档与Github Pages同步?

81
我和几个人一起做一个项目,我们有一个包含大量GitHub风格Markdown的README.md文件,可以在我们的GitHub页面上进行渲染。我们还设置了一个GitHub Pages分支,它托管在我们的GitHub组织的子域名下,并使用Automatic Page Generator来加载我们的README.md文件来创建我们的页面。但是,当我更新我们的README.md文件时,它不会更新项目页面。相反,我们必须转到GitHub设置选项卡并重新创建项目页面,在重新加载README.md文件时才能更新页面。
此外,在阅读了关于在GitHub项目目录页面上文档文件之间工作的相对链接的内容后,我非常喜欢Markdown,因为它可以节省大量时间来手动编写我们的文档所需的所有HTML。然而,我希望能够有一个README.md文件,能够包含到位于docs/*.md的其他文档文件的相对链接。我希望有一个简单的解决方案,使我的其他文档文件也可以包含在我的gh-pages分支中,并在我的GitHub Pages子域名下托管,并被渲染和/或主题化。
换句话说,我的问题是:
  • 有没有一种方法可以让我的README.md文件在Github页面子域名上自动更新?
    • [编辑]:如果使用自动页面生成器,似乎没有办法实现这个功能。您必须进入存储库的设置页面,并在每次更改时重新加载它才能更新它。
       
  • 有没有办法让我在我的README.md文件中的相对链接在我的Github页面上工作,也许是通过将我的/docs/*.md与我的Github页面同步并以某种方式呈现和/或主题化它们?
    • [编辑]:从我撰写这篇问题以来所学到的知识来看,似乎只有通过静态网站生成器(如ruby gem Jekyll)才能在GitHub页面上实现此功能,可能还需要使用下面评论中提到的Github支持的Webhooks。我目前正在寻找最佳解决方案。
       
  • 更好的方法是,有没有更简单的方法可以做到这一点,也许只有一个README.md和文档的副本,可以在gh-pages和我的主分支上使用,并使所有内容变得更容易?
    • [编辑]:看起来这个几乎肯定不行。我在考虑GitHub内置的可能性,以允许这种情况发生。似乎未来GitHub Pages可能会有更好的支持,或者至少我真的希望会有。
       

3
GitHub支持后置Webhook。你是否考虑添加一个钩子来调用某个远程脚本,将新的 README.md 版本推送到GitHub Pages中? - ubik
7
感谢您的出色编辑和发现。在这个网站上,做到这一点的人并不多。 - Matt Kantor
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - iled
1
GitHub 刚刚启用了 任何分支和目录作为文档源。您不再需要使用 gh-pages - Dan Dascalescu
10个回答

36

我将发布一个解决方案,利用GitHub Pages已经使用自动页面生成器的Jekyll的事实。

  1. git checkout gh-pages
  2. mkdir _layouts
  3. mv index.html _layouts
  4. git checkout master -- README.md
  5. mv README.md index.md
  6. index.md前面添加以下文本

 

---
layout: index
---
你还需要打开index.html文件并进行以下更改:
  1. 从你的README.md文件中删除渲染的HTML。这通常位于<section><article>标签之间。用文本{{content}}替换此HTML,这将使我们能够将此文件用作jekyll。我们应用布局的文件将放置在内容标记所在的位置。

  2. 找到项目页面主题的CSS。对我来说,这是一行类似于以下内容的代码:

    <link rel='stylesheet' href='stylesheets/stylesheet.css' />

    这需要改为:

    <link rel='stylesheet' href='{{ site.path }}/stylesheets/stylesheet.css' />

  3. 存储在您的站点上将在此布局中使用的任何其他资产也需要以{{ site.path }}为前缀。

通过执行这些步骤,Jekyll将把markdown文件呈现为_layouts目录中index.html布局的内容。为了自动化这个过程,不仅针对README.md文件,还包括您可能在主分支中拥有的其他文档,我已经采取了以下步骤:

创建名为post-commit的文件,其中包含以下内容:

 

#!/bin/bash
###
### The following block runs after commit to "master" branch
###
if [ `git rev-parse --abbrev-ref HEAD` == "master" ]; then

    # Layout prefix is prepended to each markdown file synced
    ###################################################################
    LAYOUT_PREFIX='---\r\nlayout: index\r\n---\r\n\r\n'

    # Switch to gh-pages branch to sync it with master
    ###################################################################
    git checkout gh-pages

    # Sync the README.md in master to index.md adding jekyll header
    ###################################################################
    git checkout master -- README.md
    echo -e $LAYOUT_PREFIX > index.md
    cat README.md >> index.md
    rm README.md
    git add index.md
    git commit -a -m "Sync README.md in master branch to index.md in gh-pages"

    # Sync the markdown files in the docs/* directory
    ###################################################################
    git checkout master -- docs
    FILES=docs/*
    for file in $FILES
    do
        echo -e $LAYOUT_PREFIX | cat - "$file" > temp && mv temp "$file"
    done

    git add docs
    git commit -a -m "Sync docs from master branch to docs gh-pages directory"

    # Uncomment the following push if you want to auto push to
    # the gh-pages branch whenever you commit to master locally.
    # This is a little extreme. Use with care!
    ###################################################################
    # git push origin gh-pages

    # Finally, switch back to the master branch and exit block
    git checkout master
fi

编辑:我已更新上述脚本,使得README.md文件和docs/*中的markdown都使用相同的布局文件。这比之前好多了。该脚本需要放在.git/hooks/目录下,并且bash必须在您的路径中。

创建文件_config.yml并添加以下内容。

markdown: redcarpet
path: http://username.github.io/reponame
上述脚本还同步了位于主分支docs/*目录中的markdown文件,以便它们也可以在GitHub Pages网站上查看。如果您包含以下jQuery函数以从gh-pages分支上的锚点中去掉.md扩展名,则可以相对链接到这些文档。您可以将以下脚本添加到_layouts目录中的index.html文件中:
$(document).on('ready', function () {
    $('a').each(function (i, e) {
        var href = e.href;
        if (href.search('.md') > 0)
            $(this).attr('href', href.split('.md')[0]);
    });
});

编辑: 我在我的代码库中更改了上面的代码,这只是一种快速脏方式,但如果你知道我指的是什么,它不会在所有情况下正常工作。例如,markdown文件company.mdata.md将无法正确处理。为了解决这个问题,我更新了以下脚本,它更仔细地检查href并在找到扩展名时删除它。我还使脚本更加通用,允许通过更改ext变量来删除其他扩展名。以下是代码:

$(function () {
    $('a').each(function () {
        var ext = '.md';
        var href = $(this).attr('href');
        var position = href.length - ext.length;
        if (href.substring(position) === ext)
            $(this).attr('href', href.substring(0, position));
    });
});

我在CoryG89/docsync设置了一个示例仓库,其中包含一个项目页面,如果您想看看所有这些是如何协同工作的,请访问该页面。


4
我因为你提供了详尽的答案而授予你我的奖励,但我仍然希望有人能想出一个更简单的解决方案。 - Matt Kantor
1
我非常感谢你的建议,Matt。我打算使用50个声望来再次发布赏金,希望可以找到另一种更简单易行的解决方案。这种解决方案非常好,因为它允许相对链接在您的README和其他标记文件以及存储库中正常工作。 - Cory Gross
1
难道在提交后钩子中删除 .md 扩展名不是更容易吗?或者甚至可以使用 Jenkins 自身来完成这个操作? - jjmerelo
我认为你必须将文件以 .md 扩展名存储,否则它不会被渲染为 Markdown。但我不是100%确定。 - Cory Gross
2
2016年有更简单的东西吗? - Peter Krauss
显示剩余3条评论

6

我对将README与Github页面同步的解决方案与上述略有不同。不需要使用单独的JavaScript Markdown引擎,可以使用Github API返回Markdown文件并呈现为HTML。

  1. Fetch the README.md from https://api.github.com/repos/<owner>/<repo>/contents/README.md.
  2. Decode the Base64 response: window.atob( JSON.parse( blob ).content );
  3. Post the decoded README to https://api.github.com/markdown in a JSON body

     {
       "text": "<README>",
       "mode": "markdown",
       "context": "<owner>/<repo>"
     }
    
  4. Insert the rendered HTML into a DOM element, as done by Brad Rhodes.

这种方法有两个注意事项:

  1. 进行两次连续请求会减慢页面加载速度。
  2. 访问Github API时可能会遇到速率限制。

对于流量较低、加载时间不是关键问题的页面(大约1-2秒),上述方法已经足够好用了。


atob() 在 Chrome 和 FF 中运行良好,但在 IE 11 中无法正常工作。显示无效字符。网站如下:http://joymon.github.io/joyful-visualstudio/ - Joy George Kunjikkuru

4
您可以使用DocumentUp来渲染您的README.md文件。

3

我有几个想法可以在文档站点和主Github存储库之间共享单个readme文件:

  1. 您可以仅使用一个包含代码和jekyll文档站点的gh-pages分支。您的仓库可能会变得有些混乱,您需要将YAML标头放在自述文件顶部。它几乎支持相对链接。问题在于,如果要让jekyll呈现您的markdown,它将为其提供.html扩展名。也许有一种配置方式。 这是我组合起来看看是否有效的示例。

  2. 您可以在文档站点中使用AJAX调用从主要分支读取readme,然后使用JavaScript Markdown渲染器进行呈现。这将需要更长时间才能加载,并且如果没有编写一些聪明的Javascript,它将不支持相对链接。实施比第一种想法更需要工作。


3
考虑的另一种方法是设置 pre-commit hook 来构建相关页面。我在 我的一个存储库中 这样做。你可能需要放弃自动页面生成器并自己推送到 gh-pages 分支,同时对你的文档进行一些特殊处理,使其变成 HTML 或 Jekyll 网站,如 Nathan 建议的那样
在那个存储库中,我像这样推送,以保持 gh-pagesmaster 相同。当然还有很多其他方式来实现这一点。但这可能并不适用于你的情况(你可能不希望它们相同)。
无论如何,我提出这个问题的原因是希望有人能提供更好的工作流程。这种方法有点复杂和不灵活,并且需要每个人保持他们的钩子同步。

2
另一种我比较成功地使用的方法是使用Ajax通过Github API获取文档,并使用Javascript Markdown引擎将其渲染为HTML(就像Nathan建议的那样)。
  1. 使用Github API和JSONP从Github获取文档
  2. 解码Github API响应中的base64内容
  3. 使用Javascript Markdown引擎呈现Markdown
  4. 显示呈现的HTML
Nathan对性能表示了一些担忧,但在我的经验中,它似乎会立即加载,因此我认为这实际上不是问题。
优点是设置简单,并且即使您直接在Github浏览器中编辑Markdown,它也会始终更新您的文档。
我在Github页面上设置了一个示例http://bradrhodes.github.io/GithubDocSync/以展示其工作原理。

我将该方法与 克隆 结合起来,以展示我的 project.wikiGitHub pages 上。 - eQ19

2
Nathan和Brand Rhodes所描述的方法的另一个可能性是使用一个很棒的工具:FlatDoc,由Rico Sta.Cruz创建。
FlatDoc将通过ajax加载文档(README.md或任何其他markdown文件),解析并显示所有好处,甚至还有侧边栏菜单进行导航!
它在其api中构建了一个帮助方法,可以从GitHub repo master加载文件(但也可以从Web的任何其他位置加载)。 说明 首先将以下html模板复制到您的gh-pages分支的index.html中。然后继续执行以下操作:
  • 用您的GitHub用户名替换“USER”
  • 用您的GitHub repo名称替换“REPO”
  • 用您的项目名称替换“Your Project”
在文件中。在浏览器中本地尝试一下。然后提交并推送更改。现在,您的github页面将始终更新您主分支中的README.md文件。
如果默认主题对您不满意,则可以使用自己的css重新设计它。

1
我还希望在主分支中编辑文档并在gh-pages上发布——我喜欢将文档与源代码保持最新,这似乎是最好的方法。这对我来说是一个正在进行的工作,但我以Cory's script为起点,稍微扩展了一下,使其可以直接使用,只要有一个带有_layouts(即jekyll站点)的gh-pages分支。它将反引号样式的围栏(用于代码块)转换回适合在github源浏览中使用的样式,但在gh-pages中不适用。我使用一个index.md,其中包含项目README.md,以便我可以添加标题和其他装饰。此版本还处理名为“docs”的任何嵌套目录中的文档,我发现这在具有多个模块的项目中非常有用(不是git子模块,只是子目录):

.git/hooks/post-commit

#!/bin/bash
###
### The following block runs after commit to "master" branch
###
if [ `git rev-parse --abbrev-ref HEAD` == "master" ]; then

    # function to convert a plain .md file to one that renders nicely in gh-pages
    function convert {
        # sed - convert links with *.md to *.html (assumed relative links in local pages)
        # awk - convert backtick fencing to highlights (script from bottom of file)
        sed -e 's/(\(.*\)\.md)/(\1.html)/g' "$1" | awk -f <(sed -e '0,/^#!.*awk/d' $0) > _temp && mv _temp "$1"
    } 

    if ! git show-ref --verify --quiet refs/heads/gh-pages; then
        echo "No gh-pages, so not syncing"
        exit 0
    fi

    # Switch to gh-pages branch to sync it with master
    ###################################################################
    git checkout gh-pages

    mkdir -p _includes

    # Sync the README.md in master to index.md adding jekyll header
    ###################################################################
    git checkout master -- README.md
    if [ -f README.md ]; then
        cp README.md _includes/
        convert _includes/README.md
        git add README.md
        git add _includes/README.md
    fi

    # Generate index if there isn't one already
    ###################################################################
    if [ ! -f index.md ]; then
        echo -e '---\ntitle: Docs\nlayout: default\n---\n\n{% include README.md %}' > index.md
        git add index.md
    fi

    # Generate a header if there isn't one already
    ###################################################################
    if [ ! -f _includes/header.txt ]; then
        echo -e '---\ntitle: Docs\nlayout: default\nhome: \n---\n\n' > _includes/header.txt
        git add _includes/header.txt
    fi

    # Sync the markdown files in all docs/* directories
    ###################################################################
    for file in `git ls-tree -r --name-only master | grep 'docs/.*\.md'`
    do
        git checkout master -- "$file"
        dir=`echo ${file%/*} | sed -e "s,[^/]*,..,g"`
        cat _includes/header.txt | sed -e "s,^home: .*$,home: ${dir}/," > _temp
        cat "$file" >> _temp && mv _temp "$file"
        convert "$file"
        git add "$file"
    done

    git commit -a -m "Sync docs from master branch to docs gh-pages directory"

    # Uncomment the following push if you want to auto push to
    # the gh-pages branch whenever you commit to master locally.
    # This is a little extreme. Use with care!
    ###################################################################
    # git push origin gh-pages

    # Finally, switch back to the master branch and exit block
    git checkout master
fi

exit $?

#!/usr/bin/awk
{
   # Replace backtick fencing (renders well when browsing github) with jekyll directives
   if (/```/) {
      IN = IN?0:1 # Are we already in a fenced section? Toggle.
      if (IN) { # If we are starting a fenced section
         if (/```\s*$/) {
           $0 = $0"text" # empty language is OK for backticks but not for jekyll
         }
         gsub(/```/, "{% highlight ")
         print $0" %}"
      } else { # ending a fenced section
        print "{% endhighlight %}" 
      }
    } else { # not a fencing line
      if (IN) { # but in a fenced section, so add indent to make sure code is rendered with <pre>
        print "    "$0
      } else {
        print
      }
    }
}

与原始版本的另一个变化是它在所有页面中设置一个变量page.home。这可以用于定位根目录的相对路径,因此可以用于定位静态资源,例如css。在_layouts/.default.html中我有:

<link rel="stylesheet" href="{{ page.home }}css/main.css">

通过这种方式,我可以编辑CSS,在本地构建Jekyll网站,并在浏览器中查看结果,而不必等待GitHub在服务器上构建它。


0

这很简单,只需将两个复制粘贴到终端中,就可以完成设置。

Jekyll 允许您导入您的 markdown 文件,然后它会负责将它们转换为 HTML。诀窍是使用 {% include_relative README.md %} 将您的 README.md 导入到您的 index.md 文件中。以下是我们如何实现:

值得一看的是 如何在 Github 上设置一个超级简单的 Jekyll 站点(仅有两个文件!

设置

您可以通过运行此一次性设置复制整个代码块并粘贴到终端中),复制这两个文件并使用当前的 readme 来启动您的页面:

# Copy our two files to the gh-pages branch
git checkout -b gh-pages &&
wget https://raw.githubusercontent.com/lazamar/barebones-jekyll-project-readme/master/_config.yml &&
wget https://raw.githubusercontent.com/lazamar/barebones-jekyll-project-readme/master/index.md &&
#
# Commit and publish our page on github
git add -A && git commit -m "Create project github page" &&
git push --set-upstream origin gh-pages |
#
git checkout master # go back to master branch

自动化

然后我们只需要自动化从master分支复制所有更改到gh-pages分支的任务,在每次推送之前。我们可以通过运行这个脚本来实现(您可以将其复制并粘贴到终端中

$(cat > .git/hooks/pre-push << EOF
#!/bin/sh
we_are_in_gh_pages="\$(git branch | grep -G "* gh-pages")"

if [ ! "\$we_are_in_gh_pages" ];
  then
    git checkout gh-pages &&
    git rebase master &&
    git push -f &&
    git checkout master # go back to master branch
fi
EOF
) && chmod 775 .git/hooks/pre-push

它将创建一个推送钩子,每次运行git push时都会将master分支的所有更改复制到gh-pages

就是这样。完成了。


0
我最近制作了一个名为gh-pages-generator的软件包来解决这个问题 - 它使用多个MD文件和一个配置文件生成多页网站。
它可以正确更新页面之间的所有链接。将其作为CI的一部分,将更改提交回gh-pages分支相对容易。
我正在这里这里使用它。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接