ghstack

0.14.0 · active · verified Sun Apr 12

ghstack provides command-line utilities to manage and submit a stack of Git commits as individual GitHub Pull Requests for review. It simplifies the workflow for projects that rely on sequential, dependent changes. The current version is 0.14.0, and it is actively maintained with a moderate release cadence.

Warnings

Install

Imports

Quickstart

This quickstart demonstrates how to set up a dummy Git repository, create a stack of commits, and then attempt to use `ghstack submit`. It highlights the requirement for a `GH_TOKEN` environment variable (a GitHub Personal Access Token with 'repo' scope) and a configured Git remote. The `ghstack` command is executed via `subprocess.run`, as it is primarily a CLI tool. The example includes error handling for when the token or remote is not properly configured.

import subprocess
import os
import shutil
from pathlib import Path

# --- Setup for demonstration --- 
# Create a temporary directory and initialize a Git repository
repo_dir = Path("ghstack_test_repo")
if repo_dir.exists():
    shutil.rmtree(repo_dir)
repo_dir.mkdir()
os.chdir(repo_dir)

subprocess.run(["git", "init", "-b", "main"], check=True)
subprocess.run(["git", "config", "user.email", "test@example.com"], check=True)
subprocess.run(["git", "config", "user.name", "Test User"], check=True)
subprocess.run(["git", "commit", "--allow-empty", "-m", "Initial commit"], check=True)

# Create a dummy commit stack
(repo_dir / "file1.txt").write_text("Hello from commit 1")
subprocess.run(["git", "add", "file1.txt"], check=True)
subprocess.run(["git", "commit", "-m", "feat: Add file1"], check=True)

(repo_dir / "file2.txt").write_text("Hello from commit 2")
subprocess.run(["git", "add", "file2.txt"], check=True)
subprocess.run(["git", "commit", "-m", "feat: Add file2"], check=True)

# --- ghstack usage (requires GH_TOKEN and a configured Git remote) ---
# IMPORTANT: This part will attempt to interact with GitHub.
# For a successful run, set a valid GitHub Personal Access Token (PAT)
# with 'repo' scope as the GH_TOKEN environment variable, and configure
# a remote named 'origin' pointing to a GitHub repository.
# For this example, we use a dummy token if not set.

github_token = os.environ.get("GH_TOKEN", "dummy_token_for_quickstart_only")
os.environ["GH_TOKEN"] = github_token # ghstack requires this env var

print("\n--- Running ghstack submit (requires valid GH_TOKEN and an upstream remote) ---")
print("If GH_TOKEN is not valid or no upstream is configured, the command will fail.")

try:
    # This command attempts to push commits as GitHub Pull Requests.
    # In a real scenario, the output would include URLs to the created PRs.
    print(f"Attempting to submit stack with GH_TOKEN set: {github_token[:5]}...")
    result = subprocess.run(
        ["ghstack", "submit"],
        check=True, # Will raise CalledProcessError if ghstack fails
        capture_output=True, 
        text=True
    )
    print("ghstack submit command executed successfully.")
    print("Output:\n" + result.stdout)
    if result.stderr:
        print("Errors (if any):\n" + result.stderr)
except subprocess.CalledProcessError as e:
    print(f"ghstack submit failed (expected if GH_TOKEN/remote is not set up):")
    print(f"Stderr: {e.stderr}")
    print(f"Stdout: {e.stdout}")
    print("Please configure GH_TOKEN and a Git remote to run ghstack submit successfully.")
finally:
    # Clean up dummy token and repository
    if github_token == "dummy_token_for_quickstart_only":
        del os.environ["GH_TOKEN"]
    os.chdir("..")
    shutil.rmtree(repo_dir)

print("\n--- ghstack demo finished ---")
print("To use ghstack effectively, ensure a valid GH_TOKEN and a configured git remote.")

view raw JSON →