GitHub Pages

Documentation Tool

GitHub Pages

Overview

GitHub Pages is a free static site hosting service provided by GitHub. It allows you to deploy HTML, CSS, and JavaScript files directly from GitHub repositories and publish websites through Jekyll's build process.

Details

GitHub Pages was launched by GitHub in 2008 and revolutionized the simplicity of publishing documentation for developers and projects. Based on Jekyll, a static site generator, it automatically generates high-quality websites from Markdown files and HTML/CSS. Content can be version-controlled as Git repositories, enabling collaborative editing through pull requests. It supports custom domains and SSL encryption, allowing you to build professional websites. As of 2025, deep integration with GitHub Actions has enhanced automated builds and deployments. It's available for free with public repositories and can be used with private repositories on paid plans. The Liquid templating language enables dynamic content display, and rich Jekyll plugins provide feature extensions. It supports beautiful code block display with Rouge syntax highlighter, optimized for developer documentation. You can build publication-quality documentation sites from simple Markdown syntax, and it provides change history management and rollback functionality through Git integration.

Advantages and Disadvantages

Advantages

  • Completely Free: Unlimited hosting for public repositories
  • Git Integration: Version control and collaboration features
  • Jekyll Auto-build: Automatic conversion from Markdown to HTML
  • Custom Domain: Custom domain support with SSL certificates
  • GitHub Actions Integration: Automated deployment and workflows through CI/CD
  • Fast Delivery: High performance through static sites
  • Security: High security without server-side processing requirements

Disadvantages

  • Static Sites Only: No dynamic features or database usage
  • Jekyll Dependency: Requires understanding of Ruby-based build system
  • Limitations: File size, repository size, and bandwidth restrictions
  • Plugin Restrictions: Limited plugin usage for security reasons
  • Public Requirement: Free version requires public source code
  • Build Time: Increased Jekyll build time for large sites

Key Links

Usage Examples

Repository Setup and Initialization

# Create and clone new repository
git clone https://github.com/username/username.github.io.git
cd username.github.io

# Initialize Jekyll site
echo "Hello GitHub Pages!" > index.html
git add .
git commit -m "Initial commit"
git push origin main

# Repository Pages site structure example
username.github.io/
├── _config.yml          # Jekyll configuration file
├── _layouts/            # Layout templates
│   ├── default.html
│   ├── post.html
│   └── page.html
├── _includes/           # Reusable partials
│   ├── header.html
│   ├── footer.html
│   └── navigation.html
├── _posts/              # Blog posts
│   └── 2025-06-20-welcome.md
├── _data/               # Data files
│   └── navigation.yml
├── assets/              # CSS, JS, images
│   ├── css/
│   ├── js/
│   └── images/
├── docs/                # Documentation pages
├── index.md             # Home page
└── README.md

Jekyll Configuration File (_config.yml)

# _config.yml - GitHub Pages Jekyll configuration
title: "Project Documentation"
description: "Comprehensive documentation for technical project"
baseurl: "" # Set only for subdirectory
url: "https://username.github.io"
author: "Developer Name"
email: "[email protected]"

# Build settings
markdown: kramdown
highlighter: rouge
theme: minima

# Jekyll plugins (GitHub Pages compatible)
plugins:
  - jekyll-feed
  - jekyll-sitemap
  - jekyll-seo-tag
  - jekyll-redirect-from
  - jekyll-mentions
  - jekyll-relative-links
  - jekyll-optional-front-matter
  - jekyll-readme-index
  - jekyll-default-layout
  - jekyll-titles-from-headings

# Kramdown configuration
kramdown:
  input: GFM
  syntax_highlighter: rouge
  syntax_highlighter_opts:
    css_class: 'highlight'
    span:
      line_numbers: false
    block:
      line_numbers: true

# Collection configuration
collections:
  docs:
    output: true
    permalink: /:collection/:name/
  api:
    output: true
    permalink: /api/:name/

# Default front matter
defaults:
  - scope:
      path: ""
      type: "posts"
    values:
      layout: "post"
      comments: true
  - scope:
      path: ""
      type: "docs"
    values:
      layout: "page"
  - scope:
      path: ""
      type: "api"
    values:
      layout: "api"

# Exclude from processing
exclude:
  - Gemfile
  - Gemfile.lock
  - node_modules
  - vendor/
  - .sass-cache/
  - .jekyll-cache/
  - gemfiles/

# Navigation configuration
navigation:
  - title: Home
    url: /
  - title: Documentation
    url: /docs/
  - title: API
    url: /api/
  - title: Blog
    url: /blog/
  - title: About
    url: /about/

# SEO and social
twitter:
  username: username
  card: summary

facebook:
  app_id: 1234567890
  publisher: 1234567890

logo: /assets/images/logo.png

social:
  name: Project Name
  links:
    - https://twitter.com/username
    - https://github.com/username
    - https://linkedin.com/in/username

# Analytics
google_analytics: G-XXXXXXXXXX

# Comments (GitHub Issues)
github:
  repository_url: https://github.com/username/project

Layout Template Creation

<!-- _layouts/default.html -->
<!DOCTYPE html>
<html lang="{{ page.lang | default: site.lang | default: 'en' }}">
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  
  {%- seo -%}
  <link rel="stylesheet" href="{{ '/assets/css/style.css' | relative_url }}">
  <link rel="shortcut icon" type="image/png" href="{{ '/assets/images/favicon.png' | relative_url }}">
  
  {%- feed_meta -%}
  {%- if jekyll.environment == 'production' and site.google_analytics -%}
    {%- include google-analytics.html -%}
  {%- endif -%}
</head>

<body>
  {%- include header.html -%}
  
  <main class="page-content" aria-label="Content">
    <div class="wrapper">
      {{ content }}
    </div>
  </main>
  
  {%- include footer.html -%}
  
  <script src="{{ '/assets/js/main.js' | relative_url }}"></script>
</body>
</html>
<!-- _layouts/post.html -->
---
layout: default
---
<article class="post h-entry" itemscope itemtype="http://schema.org/BlogPosting">
  
  <header class="post-header">
    <h1 class="post-title p-name" itemprop="name headline">{{ page.title | escape }}</h1>
    <p class="post-meta">
      <time class="dt-published" datetime="{{ page.date | date_to_xmlschema }}" itemprop="datePublished">
        {%- assign date_format = site.minima.date_format | default: "%b %-d, %Y" -%}
        {{ page.date | date: date_format }}
      </time>
      {%- if page.modified_date -%}
        ~ 
        <time class="dt-modified" datetime="{{ page.modified_date | date_to_xmlschema }}" itemprop="dateModified">
          Updated: {{ page.modified_date | date: date_format }}
        </time>
      {%- endif -%}
      {%- if page.author -%}
        • {% for author in page.author %}
            <span itemprop="author" itemscope itemtype="http://schema.org/Person">
              <span class="p-author h-card" itemprop="name">{{ author }}</span>
            </span>
            {%- if forloop.last == false %}, {% endif -%}
          {% endfor %}
      {%- endif -%}
    </p>
  </header>

  <div class="post-content e-content" itemprop="articleBody">
    {{ content }}
  </div>

  {%- if site.disqus.shortname -%}
    {%- include disqus_comments.html -%}
  {%- endif -%}

  <a class="u-url" href="{{ page.url | relative_url }}" hidden></a>
</article>

Navigation and Header

<!-- _includes/header.html -->
<header class="site-header" role="banner">
  <div class="wrapper">
    {%- assign default_paths = site.pages | map: "path" -%}
    {%- assign page_paths = site.header_pages | default: default_paths -%}
    
    <a class="site-title" rel="author" href="{{ "/" | relative_url }}">
      <img src="{{ '/assets/images/logo.png' | relative_url }}" alt="{{ site.title }}" class="site-logo">
      {{ site.title | escape }}
    </a>

    {%- if page_paths -%}
      <nav class="site-nav">
        <input type="checkbox" id="nav-trigger" class="nav-trigger" />
        <label for="nav-trigger">
          <span class="menu-icon">
            <svg viewBox="0 0 18 15" width="18px" height="15px">
              <path d="M18,1.484c0,0.82-0.665,1.484-1.484,1.484H1.484C0.665,2.969,0,2.304,0,1.484l0,0C0,0.665,0.665,0,1.484,0 h15.032C17.335,0,18,0.665,18,1.484L18,1.484z M18,7.516C18,8.335,17.335,9,16.516,9H1.484C0.665,9,0,8.335,0,7.516l0,0 c0-0.82,0.665-1.484,1.484-1.484h15.032C17.335,6.031,18,6.696,18,7.516L18,7.516z M18,13.516C18,14.335,17.335,15,16.516,15H1.484 C0.665,15,0,14.335,0,13.516l0,0c0-0.82,0.665-1.483,1.484-1.483h15.032C17.335,12.031,18,12.695,18,13.516L18,13.516z"/>
            </svg>
          </span>
        </label>

        <div class="trigger">
          <a class="page-link" href="{{ '/' | relative_url }}">Home</a>
          {%- for path in page_paths -%}
            {%- assign my_page = site.pages | where: "path", path | first -%}
            {%- if my_page.title -%}
              <a class="page-link" href="{{ my_page.url | relative_url }}">{{ my_page.title | escape }}</a>
            {%- endif -%}
          {%- endfor -%}
          
          <!-- Dropdown menu -->
          <div class="dropdown">
            <button class="dropbtn">Documentation</button>
            <div class="dropdown-content">
              <a href="{{ '/docs/getting-started/' | relative_url }}">Getting Started</a>
              <a href="{{ '/docs/installation/' | relative_url }}">Installation</a>
              <a href="{{ '/docs/configuration/' | relative_url }}">Configuration</a>
              <a href="{{ '/docs/api/' | relative_url }}">API Reference</a>
            </div>
          </div>
        </div>
      </nav>
    {%- endif -%}
  </div>
</header>

GitHub Actions Auto-deployment Configuration

# .github/workflows/pages.yml
name: Build and Deploy to GitHub Pages

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

# GitHub token permissions
permissions:
  contents: read
  pages: write
  id-token: write

# Concurrency to prevent multiple deployments
concurrency:
  group: "pages"
  cancel-in-progress: false

jobs:
  build:
    runs-on: ubuntu-latest
    
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Setup Ruby
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: '3.1'
          bundler-cache: true
          cache-version: 0

      - name: Setup Pages
        id: pages
        uses: actions/configure-pages@v3

      - name: Build with Jekyll
        run: bundle exec jekyll build --baseurl "${{ steps.pages.outputs.base_path }}"
        env:
          JEKYLL_ENV: production

      - name: Upload artifact
        uses: actions/upload-pages-artifact@v2

  deploy:
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    runs-on: ubuntu-latest
    needs: build
    if: github.ref == 'refs/heads/main'
    
    steps:
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v2

Custom Domain Configuration

<!-- CNAME file for custom domain -->
docs.example.com
# _config.yml - Additional custom domain configuration
url: "https://docs.example.com"
enforce_ssl: true

# Custom domain redirect settings
plugins:
  - jekyll-redirect-from

# Redirect rules
redirect_from:
  - /old-url/
  - /another-old-url/

redirect_to: https://docs.example.com/new-location/

Markdown Content Creation

---
layout: post
title: "Getting Started with Project Documentation"
date: 2025-06-20 10:00:00 +0900
categories: [documentation, tutorial]
tags: [github-pages, jekyll, markdown]
author: "Developer"
description: "How to create project documentation with GitHub Pages"
image: "/assets/images/documentation-guide.png"
toc: true
---

# Getting Started with Project Documentation

Learn how to create project documentation using GitHub Pages.

## Table of Contents
{:.no_toc}

* toc
{:toc}

## Introduction

GitHub Pages is a powerful tool for easily publishing project documentation.

### Required Knowledge
- Basic Git usage
- Markdown syntax
- Basic HTML/CSS (for customization)

## Project Setup

### 1. Repository Preparation

```bash
# Clone repository
git clone https://github.com/username/project.git
cd project

# Create docs directory (for project documentation)
mkdir docs
cd docs

2. Jekyll Initialization

# Create Gemfile
cat > Gemfile << EOF
source "https://rubygems.org"
gem "github-pages", group: :jekyll_plugins
gem "jekyll-feed"
gem "jekyll-sitemap"
gem "jekyll-seo-tag"
EOF

# Install dependencies
bundle install

# Initialize Jekyll site
bundle exec jekyll new . --force

Content Creation

Utilizing Markdown

## API Reference

### `getUserData(userId)`

API function to retrieve user data.

**Parameters:**
- `userId` (string): User ID

**Returns:**
- Promise<UserData>: Promise of user data

**Usage:**

```javascript
const userData = await getUserData('user123');
console.log(userData.name);

Response Example:

{
  "id": "user123",
  "name": "John Doe",
  "email": "[email protected]",
  "created_at": "2025-01-01T00:00:00Z"
}

### Enhanced Code Blocks

```markdown
## Syntax Highlighting

```python
def calculate_fibonacci(n):
    """Function to calculate Fibonacci sequence"""
    if n <= 1:
        return n
    return calculate_fibonacci(n-1) + calculate_fibonacci(n-2)

# Usage example
for i in range(10):
    print(f"F({i}) = {calculate_fibonacci(i)}")
# _config.yml configuration example
title: "Project Name"
description: "Project description"
highlighter: rouge
markdown: kramdown

kramdown:
  syntax_highlighter: rouge
  syntax_highlighter_opts:
    css_class: 'highlight'
    line_numbers: true

## Utilizing Includes and Layouts

```liquid
<!-- API endpoint documentation include -->
<!-- _includes/api-endpoint.html -->
<div class="api-endpoint">
  <div class="method {{ include.method | downcase }}">{{ include.method }}</div>
  <div class="url">{{ include.url }}</div>
  <div class="description">{{ include.description }}</div>
</div>

<!-- Usage example -->
{% include api-endpoint.html method="GET" url="/api/users" description="Retrieve user list" %}
{% include api-endpoint.html method="POST" url="/api/users" description="Create new user" %}

Search Function Implementation

// assets/js/search.js
class SimpleSearch {
  constructor() {
    this.searchInput = document.getElementById('search-input');
    this.searchResults = document.getElementById('search-results');
    this.searchData = [];
    
    this.loadSearchData();
    this.bindEvents();
  }
  
  async loadSearchData() {
    try {
      const response = await fetch('/search.json');
      this.searchData = await response.json();
    } catch (error) {
      console.error('Search data loading failed:', error);
    }
  }
  
  bindEvents() {
    this.searchInput.addEventListener('input', (e) => {
      this.performSearch(e.target.value);
    });
  }
  
  performSearch(query) {
    if (query.length < 2) {
      this.searchResults.innerHTML = '';
      return;
    }
    
    const results = this.searchData.filter(item => 
      item.title.toLowerCase().includes(query.toLowerCase()) ||
      item.content.toLowerCase().includes(query.toLowerCase())
    );
    
    this.displayResults(results);
  }
  
  displayResults(results) {
    if (results.length === 0) {
      this.searchResults.innerHTML = '<p>No search results found.</p>';
      return;
    }
    
    const html = results.map(result => `
      <div class="search-result">
        <h3><a href="${result.url}">${result.title}</a></h3>
        <p>${this.truncateText(result.content, 150)}</p>
      </div>
    `).join('');
    
    this.searchResults.innerHTML = html;
  }
  
  truncateText(text, length) {
    return text.length > length ? text.substring(0, length) + '...' : text;
  }
}

// Initialize
document.addEventListener('DOMContentLoaded', () => {
  new SimpleSearch();
});

Development and Deployment Commands

# Start local development server
bundle exec jekyll serve --port 4000 --livereload

# Production build
JEKYLL_ENV=production bundle exec jekyll build

# Deploy (for GitHub Pages)
git add .
git commit -m "Update documentation"
git push origin main

# Check with custom domain
curl -I https://docs.example.com

# Check SSL configuration
openssl s_client -connect docs.example.com:443 -servername docs.example.com

# Debug build issues
bundle exec jekyll build --verbose
bundle exec jekyll doctor

# Update dependencies
bundle update
bundle outdated

# Clear cache
bundle exec jekyll clean
rm -rf _site .jekyll-cache