Last active
July 21, 2025 00:42
-
-
Save SolomonHD/ff209f45c80f1ec0068f6b39203a302d to your computer and use it in GitHub Desktop.
GitHub Pages Setup Script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# jekyll-ghpages-setup | |
# Script to initialize gh-pages branch with docs folder for GitHub Pages | |
# Run this script from the root of your repository | |
# | |
# Documentation: https://gist.github.com/SolomonHD/1391d973b86c0aeb3e901cceeb34650f | |
set -euo pipefail # Exit on error, undefined vars, pipe failures | |
# Configuration | |
readonly BRANCH_NAME="gh-pages" | |
readonly DOCS_FOLDER="docs" | |
readonly REMOTE_NAME="origin" | |
# Colors for output | |
readonly RED='\033[0;31m' | |
readonly GREEN='\033[0;32m' | |
readonly YELLOW='\033[1;33m' | |
readonly BLUE='\033[0;34m' | |
readonly CYAN='\033[0;36m' | |
readonly NC='\033[0m' # No Color | |
# Helper functions | |
log_info() { | |
echo -e "${BLUE}[INFO]${NC} $1" | |
} | |
log_success() { | |
echo -e "${GREEN}[SUCCESS]${NC} $1" | |
} | |
log_warning() { | |
echo -e "${YELLOW}[WARNING]${NC} $1" | |
} | |
log_error() { | |
echo -e "${RED}[ERROR]${NC} $1" | |
} | |
log_step() { | |
echo -e "${CYAN}[STEP]${NC} $1" | |
} | |
# Check if we're in a git repository | |
check_git_repo() { | |
if ! git rev-parse --git-dir > /dev/null 2>&1; then | |
log_error "Not in a git repository. Please run this script from the root of your git repository." | |
exit 1 | |
fi | |
log_info "Git repository detected" | |
} | |
# Check if remote exists | |
check_remote() { | |
if ! git remote get-url "$REMOTE_NAME" > /dev/null 2>&1; then | |
log_error "Remote '$REMOTE_NAME' not found. Please ensure your repository has a remote configured." | |
exit 1 | |
fi | |
log_info "Remote '$REMOTE_NAME' found: $(git remote get-url $REMOTE_NAME)" | |
} | |
# Check if branch exists on remote | |
check_remote_branch() { | |
log_info "Checking if '$BRANCH_NAME' branch exists on remote..." | |
# Fetch latest remote information | |
git fetch "$REMOTE_NAME" > /dev/null 2>&1 || true | |
if git ls-remote --heads "$REMOTE_NAME" "$BRANCH_NAME" | grep -q "$BRANCH_NAME"; then | |
log_info "Branch '$BRANCH_NAME' exists on remote" | |
return 0 | |
else | |
log_info "Branch '$BRANCH_NAME' does not exist on remote" | |
return 1 | |
fi | |
} | |
# Create gh-pages branch with docs folder | |
create_ghpages_branch() { | |
log_info "Creating '$BRANCH_NAME' branch with '$DOCS_FOLDER' folder..." | |
# Save current branch | |
local current_branch | |
current_branch=$(git branch --show-current) | |
log_info "Current branch: $current_branch" | |
# Create orphan branch (no history) | |
git checkout --orphan "$BRANCH_NAME" | |
# Remove all files from staging | |
git rm -rf . > /dev/null 2>&1 || true | |
# Create docs folder and basic structure | |
mkdir -p "$DOCS_FOLDER" | |
# Create basic index.html in docs folder | |
cat > "$DOCS_FOLDER/index.html" << 'EOF' | |
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>GitHub Pages Site</title> | |
<style> | |
body { | |
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; | |
max-width: 800px; | |
margin: 2rem auto; | |
padding: 0 1rem; | |
line-height: 1.6; | |
} | |
.header { | |
text-align: center; | |
padding: 2rem 0; | |
border-bottom: 1px solid #eee; | |
margin-bottom: 2rem; | |
} | |
.status { | |
background: #d4edda; | |
border: 1px solid #c3e6cb; | |
padding: 1rem; | |
border-radius: 4px; | |
margin: 1rem 0; | |
} | |
</style> | |
</head> | |
<body> | |
<div class="header"> | |
<h1>🚀 GitHub Pages Site</h1> | |
<p>Successfully deployed to GitHub Pages!</p> | |
</div> | |
<div class="status"> | |
<strong>Status:</strong> Site is live and ready for content. | |
</div> | |
<h2>Next Steps</h2> | |
<ul> | |
<li>Replace this file with your actual content</li> | |
<li>Configure Jekyll if using Markdown</li> | |
<li>Set up your CI/CD pipeline</li> | |
<li>Configure custom domain (if needed)</li> | |
</ul> | |
<h2>Deployment Info</h2> | |
<ul> | |
<li><strong>Branch:</strong> gh-pages</li> | |
<li><strong>Source:</strong> /docs folder</li> | |
<li><strong>Generated:</strong> <script>document.write(new Date().toISOString())</script></li> | |
</ul> | |
</body> | |
</html> | |
EOF | |
# Create README for the gh-pages branch | |
cat > README.md << 'EOF' | |
# GitHub Pages Branch | |
This branch contains the built/deployed version of the site for GitHub Pages. | |
## Structure | |
- `/docs/` - Contains the actual site files served by GitHub Pages | |
- This branch is automatically managed by CI/CD | |
## Configuration | |
- **Source:** `gh-pages` branch | |
- **Folder:** `/docs` | |
- **Build:** Automated via Jenkins/CI | |
## DO NOT EDIT MANUALLY | |
This branch is automatically updated by the build process. | |
All changes should be made to the source branch and deployed via CI/CD. | |
EOF | |
# Create .gitignore | |
cat > .gitignore << 'EOF' | |
# Logs | |
*.log | |
# Temporary files | |
*.tmp | |
*.temp | |
# OS generated files | |
.DS_Store | |
.DS_Store? | |
._* | |
.Spotlight-V100 | |
.Trashes | |
ehthumbs.db | |
Thumbs.db | |
EOF | |
# Add all files | |
git add . | |
# Commit initial structure | |
git commit -m "Initial gh-pages setup with docs folder | |
- Created basic index.html in docs folder | |
- Added README with branch information | |
- Configured for GitHub Pages deployment | |
- Ready for CI/CD integration" | |
log_success "Created '$BRANCH_NAME' branch with initial structure" | |
} | |
# Configure GitHub Pages via API | |
configure_pages_api() { | |
log_step "Configuring GitHub Pages via API..." | |
# Get repository info from remote URL | |
local repo_url | |
repo_url=$(git remote get-url "$REMOTE_NAME") | |
local repo_owner repo_name api_base | |
# Parse repository owner and name from different URL formats | |
if [[ $repo_url =~ github\.com[:/]([^/]+)/([^/]+)(\.git)?$ ]]; then | |
repo_owner="${BASH_REMATCH[1]}" | |
repo_name="${BASH_REMATCH[2]%.git}" | |
api_base="https://api.github.com" | |
elif [[ $repo_url =~ ([^/:]+)[:/]([^/]+)/([^/]+)(\.git)?$ ]]; then | |
# For GHES instances | |
local ghes_host="${BASH_REMATCH[1]}" | |
repo_owner="${BASH_REMATCH[2]}" | |
repo_name="${BASH_REMATCH[3]%.git}" | |
api_base="https://$ghes_host/api/v3" | |
else | |
log_warning "Could not parse repository URL for API configuration" | |
show_manual_setup_instructions | |
return 1 | |
fi | |
log_info "Repository: $repo_owner/$repo_name" | |
# Try GitHub CLI first (easier authentication) | |
if command -v gh &> /dev/null; then | |
log_info "Using GitHub CLI for API configuration..." | |
# Check if we're authenticated | |
if gh auth status &> /dev/null; then | |
if configure_with_gh_cli "$repo_owner" "$repo_name"; then | |
return 0 | |
else | |
log_warning "GitHub CLI configuration failed, trying manual methods..." | |
fi | |
else | |
log_info "GitHub CLI not authenticated, trying manual methods..." | |
fi | |
fi | |
# Try with curl and environment token | |
if configure_with_curl "$api_base" "$repo_owner" "$repo_name"; then | |
return 0 | |
fi | |
# Fall back to manual instructions | |
log_warning "Automatic API configuration not available" | |
show_manual_setup_instructions | |
return 1 | |
} | |
# Configure using GitHub CLI | |
configure_with_gh_cli() { | |
local owner="$1" | |
local repo="$2" | |
# First check if Pages is already configured | |
if gh api "repos/$owner/$repo/pages" &> /dev/null; then | |
log_info "GitHub Pages already exists, updating configuration to use /docs folder..." | |
if gh api "repos/$owner/$repo/pages" \ | |
--method PUT \ | |
--field source.branch="$BRANCH_NAME" \ | |
--field source.path="/$DOCS_FOLDER" &> /dev/null; then | |
log_success "GitHub Pages configuration updated to use /$DOCS_FOLDER folder via GitHub CLI" | |
return 0 | |
fi | |
else | |
log_info "Creating new GitHub Pages configuration with /docs folder..." | |
if gh api "repos/$owner/$repo/pages" \ | |
--method POST \ | |
--field source.branch="$BRANCH_NAME" \ | |
--field source.path="/$DOCS_FOLDER" &> /dev/null; then | |
log_success "GitHub Pages configured to use /$DOCS_FOLDER folder via GitHub CLI" | |
return 0 | |
fi | |
fi | |
return 1 | |
} | |
# Configure using curl with token | |
configure_with_curl() { | |
local api_base="$1" | |
local owner="$2" | |
local repo="$3" | |
# Check for GitHub token in environment | |
local token="" | |
if [[ -n "${GITHUB_TOKEN:-}" ]]; then | |
token="$GITHUB_TOKEN" | |
elif [[ -n "${GH_TOKEN:-}" ]]; then | |
token="$GH_TOKEN" | |
else | |
log_info "No GitHub token found in environment (GITHUB_TOKEN or GH_TOKEN)" | |
return 1 | |
fi | |
log_info "Using curl with GitHub token for API configuration..." | |
# Check if Pages already exists | |
local pages_exists=false | |
if curl -s -f \ | |
-H "Accept: application/vnd.github+json" \ | |
-H "Authorization: Bearer $token" \ | |
-H "X-GitHub-Api-Version: 2022-11-28" \ | |
"$api_base/repos/$owner/$repo/pages" > /dev/null 2>&1; then | |
pages_exists=true | |
fi | |
local method="POST" | |
local action="Creating" | |
if [[ "$pages_exists" == true ]]; then | |
method="PUT" | |
action="Updating" | |
fi | |
log_info "$action GitHub Pages configuration to use /$DOCS_FOLDER folder..." | |
# Configure Pages with API to use /docs folder | |
local response http_code | |
response=$(curl -s -w "%{http_code}" \ | |
-X "$method" \ | |
-H "Accept: application/vnd.github+json" \ | |
-H "Authorization: Bearer $token" \ | |
-H "X-GitHub-Api-Version: 2022-11-28" \ | |
"$api_base/repos/$owner/$repo/pages" \ | |
-d "{\"source\":{\"branch\":\"$BRANCH_NAME\",\"path\":\"/$DOCS_FOLDER\"}}") | |
http_code="${response: -3}" | |
if [[ "$http_code" =~ ^(200|201)$ ]]; then | |
log_success "GitHub Pages configured to use /$DOCS_FOLDER folder via API" | |
return 0 | |
else | |
log_warning "API request failed with HTTP $http_code" | |
return 1 | |
fi | |
} | |
# Show manual setup instructions | |
show_manual_setup_instructions() { | |
echo | |
log_info "Manual GitHub Pages configuration required:" | |
echo "1. Go to your repository Settings → Pages" | |
echo "2. Under 'Build and deployment' → 'Source', select 'Deploy from a branch'" | |
echo "3. Set Branch to: '$BRANCH_NAME'" | |
echo "4. Set Folder to: '/$DOCS_FOLDER' (NOT root /)" | |
echo "5. Click 'Save'" | |
echo | |
echo -e "${YELLOW}⚠️ Important: Make sure to select '/$DOCS_FOLDER' folder, not root (/)${NC}" | |
} | |
# Push branch to remote and configure Pages | |
push_and_configure() { | |
log_info "Pushing '$BRANCH_NAME' branch to remote..." | |
if git push "$REMOTE_NAME" "$BRANCH_NAME"; then | |
log_success "Successfully pushed '$BRANCH_NAME' branch to remote" | |
# Configure GitHub Pages via API | |
configure_pages_api | |
else | |
log_error "Failed to push '$BRANCH_NAME' branch to remote" | |
return 1 | |
fi | |
} | |
# Return to original branch | |
return_to_original_branch() { | |
local current_branch | |
current_branch=$(git branch --show-current) | |
if [[ "$CURRENT_BRANCH" != "$current_branch" ]]; then | |
log_info "Returning to original branch: $CURRENT_BRANCH" | |
git checkout "$CURRENT_BRANCH" | |
fi | |
} | |
# Display success message with next steps | |
show_completion_message() { | |
echo | |
log_success "GitHub Pages setup completed successfully!" | |
echo | |
echo -e "${BLUE}🌐 Your site will be available at:${NC}" | |
# Get repository URL for Pages URL construction | |
local repo_url | |
repo_url=$(git remote get-url "$REMOTE_NAME") | |
if [[ $repo_url =~ github\.com[:/]([^/]+)/([^/]+)(\.git)?$ ]]; then | |
local user_org="${BASH_REMATCH[1]}" | |
local repo_name="${BASH_REMATCH[2]%.git}" | |
echo " https://$user_org.github.io/$repo_name" | |
elif [[ $repo_url =~ ([^/:]+)[:/]([^/]+)/([^/]+)(\.git)?$ ]]; then | |
# For GHES instances | |
local ghes_host="${BASH_REMATCH[1]}" | |
local user_org="${BASH_REMATCH[2]}" | |
local repo_name="${BASH_REMATCH[3]%.git}" | |
echo " https://$ghes_host/pages/$user_org/$repo_name" | |
fi | |
echo | |
echo -e "${BLUE}📁 Repository Structure:${NC}" | |
echo " • Source: '$BRANCH_NAME' branch" | |
echo " • Folder: '/$DOCS_FOLDER' (configured via API)" | |
echo " • Branch: '$CURRENT_BRANCH' (your working branch)" | |
echo | |
echo -e "${BLUE}🚀 Next Steps:${NC}" | |
echo "1. Your Jekyll source files go in the 'src/' directory" | |
echo "2. Run 'jekyll-ghpages-deploy' to build and deploy your site" | |
echo "3. Check repository Settings → Pages to verify /$DOCS_FOLDER is selected" | |
echo | |
echo -e "${BLUE}🔧 Authentication Methods Detected:${NC}" | |
if command -v gh &> /dev/null && gh auth status &> /dev/null; then | |
echo " ✅ GitHub CLI (gh) - authenticated" | |
else | |
echo " ❌ GitHub CLI (gh) - not available/authenticated" | |
fi | |
if [[ -n "${GITHUB_TOKEN:-}" ]] || [[ -n "${GH_TOKEN:-}" ]]; then | |
echo " ✅ Environment token - available" | |
else | |
echo " ❌ Environment token - not set" | |
fi | |
echo | |
echo -e "${BLUE}💡 For automatic API configuration in the future:${NC}" | |
echo " • Install GitHub CLI: https://cli.github.com/" | |
echo " • Or set GITHUB_TOKEN environment variable" | |
echo | |
} | |
# Main execution | |
main() { | |
log_info "Starting GitHub Pages setup..." | |
echo | |
# Perform checks | |
check_git_repo | |
check_remote | |
# Save current branch for later | |
CURRENT_BRANCH=$(git branch --show-current) | |
# Check if branch already exists | |
if check_remote_branch; then | |
log_warning "Branch '$BRANCH_NAME' already exists on remote" | |
echo | |
read -p "Do you want to recreate it? This will DELETE the existing branch! (y/N): " -n 1 -r | |
echo | |
if [[ ! $REPLY =~ ^[Yy]$ ]]; then | |
log_info "Aborted by user" | |
exit 0 | |
fi | |
log_warning "Deleting existing '$BRANCH_NAME' branch on remote..." | |
git push "$REMOTE_NAME" --delete "$BRANCH_NAME" || true | |
fi | |
# Create and setup branch | |
create_ghpages_branch | |
push_and_configure | |
return_to_original_branch | |
# Show completion message | |
show_completion_message | |
} | |
# Run main function | |
main "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment