# gh stack link vs submit: Understanding the Two Ways to Manage Stacked PRs

> Understand the difference between gh stack link and gh stack submit. Learn how to manage stacked PRs on GitHub using your local stack file for efficient workflow.

- Repository: [GitHub/gh-stack](https://github.com/github/gh-stack)
- Tags: deep-dive
- Published: 2026-08-03

---

**The `gh stack link` command creates or updates stacked PRs directly on GitHub without using local stack metadata, while `gh stack submit` synchronizes your local stack file (`.git/gh-stack`) with GitHub by pushing branches and managing PRs interactively.**

The `github/gh-stack` extension provides two distinct approaches for managing stacked pull requests. While both commands interact with GitHub's Stacks API, they serve opposite workflows—`link` operates purely against remote GitHub state, whereas `submit` orchestrates local Git operations, interactive editing, and remote synchronization. Understanding these differences ensures you choose the right tool for your branching strategy.

## Core Architectural Differences

### Remote-Only vs Local-First State Management

The fundamental distinction lies in where each command derives its source of truth. According to the command description in [`cmd/link.go`](https://github.com/github/gh-stack/blob/main/cmd/link.go) (lines 29-34), **`gh stack link` ignores the local stack file entirely**. It discovers pull requests from branch names, PR numbers, or URLs provided as CLI arguments, then calls the Stacks API to create or modify a remote stack directly.

In contrast, **`gh stack submit` relies on the local stack file** (`.git/gh-stack`) as its primary data source. As implemented in [`cmd/submit.go`](https://github.com/github/gh-stack/blob/main/cmd/submit.go) (lines 83-88), the command loads the stack using `stack.Load(gitDir)` and manipulates that local representation throughout the execution before syncing to GitHub.

### Source of Truth Operations

When you run `gh stack link`, GitHub serves as the source of truth. The command uses `upsertStack` (lines 42-48 in [`cmd/link.go`](https://github.com/github/gh-stack/blob/main/cmd/link.go)) to create or update the remote stack metadata without reading or writing local state.

Conversely, `gh stack submit` treats your local file system as authoritative. It pushes branches, potentially collects PR drafts through an interactive editor, and finally calls `syncStack` (line 95 in [`cmd/submit.go`](https://github.com/github/gh-stack/blob/main/cmd/submit.go)) to reflect the local state onto GitHub.

## Workflow Comparison

### How `gh stack link` Works

The link workflow is non-interactive and argument-driven:

1. Provide a list of branches, PR numbers, or URLs as CLI arguments
2. The command resolves each argument to a PR (or creates one)
3. It uses `detectAddMode` (lines 51-55 in [`cmd/link.go`](https://github.com/github/gh-stack/blob/main/cmd/link.go)) to determine whether to create a new remote stack or append to an existing one
4. It performs a push-only step (`pushBranchArgs` at line 23) before looking up PRs
5. Finally, it calls `upsertStack` to persist the stack on GitHub

This workflow uses `listStacksSafe` (lines 17-22) to safely query existing stacks before modification.

### How `gh stack submit` Works

The submit workflow is local-state-driven and optionally interactive:

1. Detect and load the current local stack (lines 97-104 in [`cmd/submit.go`](https://github.com/github/gh-stack/blob/main/cmd/submit.go))
2. Push all branches to the remote (lines 21-27)
3. Create new PRs or update existing ones using `ensurePR` and `createPR` functions
4. If the terminal is interactive and `--auto` is not set, launch the TUI (`submitview`) at lines 102-119 to collect PR drafts via `collectPRDrafts` (line 61)
5. Handle pending modify states and forked merged stacks
6. Call `syncStack` (lines 44-48) to update GitHub based on the local definition

## Implementation Details

### The Link Implementation ([`cmd/link.go`](https://github.com/github/gh-stack/blob/main/cmd/link.go))

The `runLink` function (line 96) serves as the entry point. Key implementation characteristics include:

- **Decision logic**: Uses `detectAddMode` (lines 51-55) to decide whether to create a new stack or add to an existing one
- **Safe querying**: Employs `listStacksSafe` (lines 17-22) to avoid errors when checking existing stacks
- **Remote-only operations**: Performs `upsertStack` calls without local file manipulation

### The Submit Implementation ([`cmd/submit.go`](https://github.com/github/gh-stack/blob/main/cmd/submit.go))

The submit command implementation reveals its local-first architecture:

- **State loading**: Calls `sf, err := stack.Load(gitDir)` (lines 83-88) to read the local stack file
- **Interactive capabilities**: Conditionally launches an interactive editor through `collectPRDrafts` (line 61) when drafting PR descriptions
- **Synchronization**: Uses `syncStack` to reconcile local state with GitHub, handling complex scenarios like merged stack forks

## When to Use Each Command

### Use `gh stack link` When:

- You manage branches with external tools (e.g., **jj**, **git-town**) and only need to group existing PRs on GitHub
- You do **not** want a `.git/gh-stack` file in your repository
- You need to link existing PRs or branches non-interactively via CLI arguments

### Use `gh stack submit` When:

- You want the full GH-Stack experience with local stack tracking
- You need interactive drafting of PR titles and descriptions
- You require automatic base-branch fixing and the ability to run subsequent stack commands (`gh stack view`, `gh stack modify`)
- You want to push branches and sync state in a single operation

## Command Examples

Link existing branches or PRs into a stack without local metadata:

```bash

# Create a new stack from three branches (no local .git/gh-stack created)

gh stack link auth-layer api-routes ui-components

# Add PRs to an existing stack #7

gh stack link 7 48 ui-polish

```

Submit local stack state to GitHub with optional interactivity:

```bash

# Open interactive TUI to draft PRs

gh stack submit

# Skip editor and auto-generate PR titles

gh stack submit --auto

# Mark all PRs as ready for review

gh stack submit --open

```

## Summary

- **`gh stack link`** is a remote-only command that operates directly against GitHub's Stacks API using `upsertStack`, ignoring local `.git/gh-stack` files
- **`gh stack submit`** is a local-first command that loads state via `stack.Load`, pushes branches, optionally launches an interactive TUI, and syncs via `syncStack`
- **Link** uses `detectAddMode` (lines 51-55) to decide between creating or appending to stacks, while **submit** uses local file detection (lines 97-104)
- **Link** accepts CLI arguments only; **submit** can run interactively (lines 102-119) when not using `--auto`
- Choose **link** for external workflow integration; choose **submit** for full stack lifecycle management

## Frequently Asked Questions

### Can I use `gh stack link` if I already have a local `.git/gh-stack` file?

Yes, but the command will ignore it. According to the implementation in [`cmd/link.go`](https://github.com/github/gh-stack/blob/main/cmd/link.go) (lines 29-34), `gh stack link` operates purely against GitHub's API using `listStacksSafe` and `upsertStack`, leaving your local stack file untouched. This makes it safe to use alongside other stack-tracking tools.

### Does `gh stack submit` work without a local stack file?

No. As implemented in [`cmd/submit.go`](https://github.com/github/gh-stack/blob/main/cmd/submit.go) (lines 83-88, 97-104), the command attempts to detect and load the local stack using `stack.Load(gitDir)`. If no stack exists in `.git/gh-stack`, the command cannot proceed with its local-first workflow of pushing branches and syncing state.

### Which command should I use with external git workflow tools like `jj` or `git-town`?

Use **`gh stack link`**. Since it ignores the local `.git/gh-stack` file and operates directly on GitHub via the Stacks API (using `upsertStack` at lines 42-48), it will not conflict with external systems that manage their own stack metadata. You can link your externally-managed branches into a GitHub stack without creating conflicting local state.

### Why does `gh stack submit` launch an interactive editor while `gh stack link` does not?

The submit command includes specific logic at lines 102-119 in [`cmd/submit.go`](https://github.com/github/gh-stack/blob/main/cmd/submit.go) to launch a TUI (`submitview`) when the terminal is interactive and the `--auto` flag is not set, allowing you to draft PR titles and descriptions via `collectPRDrafts` (line 61). In contrast, `gh stack link` (starting at `runLink`, line 96) is designed to accept all arguments via CLI and perform operations non-interactively, making it suitable for scripting and automation.