Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,35 @@ docs: update documentation
chore: maintenance tasks
```

## Stacked PRs

When creating stacked PRs, use `gh-stack` to manage and annotate them:

1. Create branches that build on each other:
```bash
git checkout -b feat/my-feature-part1
# make changes, commit
git checkout -b feat/my-feature-part2
# make changes, commit
```

2. Push branches and create PRs with proper base branches:
```bash
git push origin feat/my-feature-part1 feat/my-feature-part2
gh pr create --base master --head feat/my-feature-part1 --title "[STACK-ID] part 1"
gh pr create --base feat/my-feature-part1 --head feat/my-feature-part2 --title "[STACK-ID] part 2"
```

3. Annotate PRs with stack info:
```bash
gh-stack annotate 'STACK-ID' -r 'luqven/gh-stack' --ci
```

4. After rebasing, update the stack:
```bash
gh-stack autorebase 'STACK-ID' -r 'luqven/gh-stack' -C . --ci
```

## Function Signatures

Pass primitives directly, keep arg count low:
Expand Down
23 changes: 17 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@ This tool assumes that:
- All PRs in a single "stack" all have a unique identifier in their title (I typically use a Jira ticket number for this).
- All PRs in the stack live in a single GitHub repository.
- All remote branches that these PRs represent have local branches named identically.
- Your PRs are publicly viewable by all GitHub users.
- This assumption is due to how the Markdown table is uses https://shields.io to render badges that auto-update based on your PR status.
- example URL: https://img.shields.io/github/pulls/detail/state/{{your-user-or-org}}/{{your-repository}}/{{the-pr-number}}

It then looks for all PRs containing this identifier and builds a dependency graph in memory.

Expand Down Expand Up @@ -107,9 +104,10 @@ $ gh-stack annotate 'stack-identifier' -r '<some/repo>' --prefix '#'
# contents of `filename.txt`.
$ gh-stack annotate 'stack-identifier' -p filename.txt

# Same as above, but precede the markdown table with the
# contents of `filename.txt`.
$ gh-stack annotate 'stack-identifier' -p filename.txt
# Same as above, but with shields.io status badges (requires public repo).
# By default, annotations use GitHub's native PR autolinking which works
# with both public and private repositories.
$ gh-stack annotate 'stack-identifier' --badges

# Automatically update the entire stack, both locally and remotely.
# WARNING: This operation modifies local branches and force-pushes.
Expand Down Expand Up @@ -195,6 +193,19 @@ _This is a quick overview of the ways this tool could be used in practice._
```

This (idempotently) adds a table like this to the description of every PR in the stack:

```markdown
### Stacked PR Chain: EXAMPLE-13799
| PR | Title | Merges Into |
|:--:|:------|:-----------:|
|#1|[EXAMPLE-13799] PR for branch `first`|-|
|#2|[EXAMPLE-13799] PR for branch `second`|#1|
|#3|[EXAMPLE-13799] PR for branch `third`|#2|
```

GitHub automatically converts `#1`, `#2`, `#3` to clickable links. Hovering over them shows PR details including current status.

For public repositories, you can use `--badges` to add shields.io status badges:
<img src="img/annotate.png" width="700" />

7. Make changes to a branch that rewrites commits in some way (amend, remove a commit, combine commits):
Expand Down
16 changes: 14 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ fn clap<'a, 'b>() -> App<'a, 'b> {
.takes_value(true)
.help("PR title prefix identifier to remove from the title");

let badges = Arg::with_name("badges")
.long("badges")
.takes_value(false)
.help("Use shields.io badges for PR status (requires public repo visibility)");

let annotate = SubCommand::with_name("annotate")
.about("Annotate the descriptions of all PRs in a stack with metadata about all PRs in the stack")
.setting(AppSettings::ArgRequiredElseHelp)
Expand All @@ -49,6 +54,7 @@ fn clap<'a, 'b>() -> App<'a, 'b> {
.arg(repository.clone())
.arg(ci.clone())
.arg(prefix.clone())
.arg(badges.clone())
.arg(Arg::with_name("prelude")
.long("prelude")
.short("p")
Expand Down Expand Up @@ -219,8 +225,14 @@ async fn main() -> Result<(), Box<dyn Error>> {
build_pr_stack_for_repo(&identifier, repository, &credentials, get_excluded(m))
.await?;

let table =
markdown::build_table(&stack, &identifier, m.value_of("prelude"), repository);
let use_badges = m.is_present("badges");
let table = markdown::build_table(
&stack,
&identifier,
m.value_of("prelude"),
repository,
use_badges,
);

for (pr, _) in stack.iter() {
println!("{}: {}", pr.number(), pr.title());
Expand Down
Loading