{"id":4955,"library":"ghstack","title":"ghstack","description":"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.","status":"active","version":"0.14.0","language":"en","source_language":"en","source_url":"https://github.com/ezyang/ghstack","tags":["github","git","cli","code-review","development"],"install":[{"cmd":"pip install ghstack","lang":"bash","label":"Install ghstack"}],"dependencies":[],"imports":[{"note":"ghstack is primarily a command-line interface (CLI) tool. `ghstack_app` is the underlying Click application object, generally invoked via the `ghstack` command in the shell rather than directly imported and called programmatically by users.","symbol":"ghstack_app","correct":"from ghstack.app import ghstack_app"}],"quickstart":{"code":"import subprocess\nimport os\nimport shutil\nfrom pathlib import Path\n\n# --- Setup for demonstration --- \n# Create a temporary directory and initialize a Git repository\nrepo_dir = Path(\"ghstack_test_repo\")\nif repo_dir.exists():\n    shutil.rmtree(repo_dir)\nrepo_dir.mkdir()\nos.chdir(repo_dir)\n\nsubprocess.run([\"git\", \"init\", \"-b\", \"main\"], check=True)\nsubprocess.run([\"git\", \"config\", \"user.email\", \"test@example.com\"], check=True)\nsubprocess.run([\"git\", \"config\", \"user.name\", \"Test User\"], check=True)\nsubprocess.run([\"git\", \"commit\", \"--allow-empty\", \"-m\", \"Initial commit\"], check=True)\n\n# Create a dummy commit stack\n(repo_dir / \"file1.txt\").write_text(\"Hello from commit 1\")\nsubprocess.run([\"git\", \"add\", \"file1.txt\"], check=True)\nsubprocess.run([\"git\", \"commit\", \"-m\", \"feat: Add file1\"], check=True)\n\n(repo_dir / \"file2.txt\").write_text(\"Hello from commit 2\")\nsubprocess.run([\"git\", \"add\", \"file2.txt\"], check=True)\nsubprocess.run([\"git\", \"commit\", \"-m\", \"feat: Add file2\"], check=True)\n\n# --- ghstack usage (requires GH_TOKEN and a configured Git remote) ---\n# IMPORTANT: This part will attempt to interact with GitHub.\n# For a successful run, set a valid GitHub Personal Access Token (PAT)\n# with 'repo' scope as the GH_TOKEN environment variable, and configure\n# a remote named 'origin' pointing to a GitHub repository.\n# For this example, we use a dummy token if not set.\n\ngithub_token = os.environ.get(\"GH_TOKEN\", \"dummy_token_for_quickstart_only\")\nos.environ[\"GH_TOKEN\"] = github_token # ghstack requires this env var\n\nprint(\"\\n--- Running ghstack submit (requires valid GH_TOKEN and an upstream remote) ---\")\nprint(\"If GH_TOKEN is not valid or no upstream is configured, the command will fail.\")\n\ntry:\n    # This command attempts to push commits as GitHub Pull Requests.\n    # In a real scenario, the output would include URLs to the created PRs.\n    print(f\"Attempting to submit stack with GH_TOKEN set: {github_token[:5]}...\")\n    result = subprocess.run(\n        [\"ghstack\", \"submit\"],\n        check=True, # Will raise CalledProcessError if ghstack fails\n        capture_output=True, \n        text=True\n    )\n    print(\"ghstack submit command executed successfully.\")\n    print(\"Output:\\n\" + result.stdout)\n    if result.stderr:\n        print(\"Errors (if any):\\n\" + result.stderr)\nexcept subprocess.CalledProcessError as e:\n    print(f\"ghstack submit failed (expected if GH_TOKEN/remote is not set up):\")\n    print(f\"Stderr: {e.stderr}\")\n    print(f\"Stdout: {e.stdout}\")\n    print(\"Please configure GH_TOKEN and a Git remote to run ghstack submit successfully.\")\nfinally:\n    # Clean up dummy token and repository\n    if github_token == \"dummy_token_for_quickstart_only\":\n        del os.environ[\"GH_TOKEN\"]\n    os.chdir(\"..\")\n    shutil.rmtree(repo_dir)\n\nprint(\"\\n--- ghstack demo finished ---\")\nprint(\"To use ghstack effectively, ensure a valid GH_TOKEN and a configured git remote.\")","lang":"python","description":"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."},"warnings":[{"fix":"Generate a PAT on GitHub (Settings -> Developer settings -> Personal access tokens), set it as `GH_TOKEN` in your environment (e.g., `export GH_TOKEN=ghp_...`), and verify it has the necessary 'repo' scope.","message":"ghstack requires a GitHub Personal Access Token (PAT) to be set as the `GH_TOKEN` environment variable. Ensure this token has sufficient `repo` scope permissions for creating pull requests, comments, and interacting with repository contents.","severity":"gotcha","affected_versions":"All versions"},{"fix":"For programmatic integration, prefer executing `ghstack` commands via `subprocess.run(['ghstack', 'submit', ...])` rather than attempting to import and call internal functions.","message":"ghstack is primarily a Command Line Interface (CLI) tool. While its internal modules can be imported, there isn't a widely-used, stable public Python API for programmatic control. Most users interact with it by executing `ghstack` commands via `subprocess.run` or directly from the terminal.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Run `ghstack rebase` regularly, especially before submitting new changes or after the target branch has updated, to ensure your local stack is clean and conflicts are resolved early.","message":"Understanding and managing your Git commit stack with `ghstack rebase` is critical. Frequent rebasing is necessary to keep your stack updated with the target branch and to proactively resolve merge conflicts. Neglecting to rebase can lead to complex conflict resolution issues.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Commit or stash all local changes before running `ghstack` commands like `submit` or `rebase`. Familiarize yourself with `git reflog` and `git reset` for recovery in case of mistakes.","message":"ghstack modifies your local Git history. Always ensure you have a clean working directory and understand Git operations before using `ghstack` to prevent accidental data loss or difficult recovery situations.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-12T00:00:00.000Z","next_check":"2026-07-11T00:00:00.000Z"}