diff --git a/README.md b/README.md index b250db9..310e556 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,82 @@ # gh-stack +I use this tool to help managed stacked pull requests on Github, which are notoriously difficult to manage manually. Here are a few examples of the kind of things I'm talking about: + +- https://unhashable.com/stacked-pull-requests-keeping-github-diffs-small +- https://stackoverflow.com/questions/26619478/are-dependent-pull-requests-in-github-possible +- https://gist.github.com/Jlevyd15/66743bab4982838932dda4f13f2bd02a + +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). It then looks for all PRs containing this containing this identifier and builds a dependency graph in memory. This can technically support a "branched stack" instead of a single chain, but I haven't really tried the latter style (which seems much more complex). + +With this graph built up, the tool can: + +- Add a markdown table to the PR description (idempotently) of each PR in the stack describing _all_ PRs in the stack. +- Log a simple list of all PRs in the stack (+ dependencies) to stdout. +- Emit a bash script that can update all PRs in the stack. + - This generally happens in the event of: + - The PR at the base of the stack is merged, leaving all the remaining PRs in a conflicted state. + - One of the PRs (not the top of the stack) has a commit added to it, leaving all dependent PRs in a conflicted state. + - The script requires two placeholders to be manually specified before execution. + +## Usage + +```bash +$ export GHSTACK_OAUTH_TOKEN='' + +# Idempotently add a markdown table summarizing the stack +# to the description of each PR in the stack. +$ gh-stack github 'stack-identifier' + +# Same as above, but precede the markdown table with the +# contents of `filename.txt`. +$ gh-stack github 'stack-identifier' filename.txt + +# Print a description of the stack to stdout. +$ gh-stack log 'stack-identifier' + +# Emit a bash script that can update a stack in the case of conflicts. +# WARNING: This script could potentially cause destructive behavior. +$ gh-stack rebase 'stack-identifier' ``` -gh-stack -``` + +## Strategy + +Here's a quick summary of the strategy that the bash script described above uses to keep the stack up-to-date. + +Let's use this stack as an example: + +![](img/initial.png) + +## Feature Changes + +In the first case, let's assume that "feature part 1" had some changes added to it in the form of a commit; this leaves parts 2 & 3 in a conflicted state: + +![](img/feature-1.png) + +The script requires that you pass in a `PREBASE` (which is essentially the boundary for the feature part you're operating on, the last/oldest commit in feature-part-2 in this case). +An initial `TO` ref is also required, which is the point upon which you want to rebase the rest of the stack. In this case, that ref is `remote/feature-part-1`). + +The script executes a single step, we now have this intermediate state: + +![](img/feature-2.png) + +The script completes execution, and we now have this final state with the entire stack updated/recreated: + +![](img/feature-3.png) + +## Feature Complete & Merged + +In the second case, let's assume that "feature part 2" is done and has been merged to `develop`: + +![](/img/complete-1.png) + +This immediately leaves feature parts 2 & 3 in a conflicted state. The script can fix this situation as well. +As before, pass a `PREBASE` (in this case the oldest commit in feature part 2) and an initial `TO` ref to rebase on (in this case `remote/develop`). + +Once the script executes a single step, we're left with: + +![](/img/complete-2.png) + +And once the script is done: + +![](img/complete-3.png) \ No newline at end of file diff --git a/img/complete-1.png b/img/complete-1.png new file mode 100644 index 0000000..8a35e1e Binary files /dev/null and b/img/complete-1.png differ diff --git a/img/complete-2.png b/img/complete-2.png new file mode 100644 index 0000000..6fc4619 Binary files /dev/null and b/img/complete-2.png differ diff --git a/img/complete-3.png b/img/complete-3.png new file mode 100644 index 0000000..0513720 Binary files /dev/null and b/img/complete-3.png differ diff --git a/img/feature-1.png b/img/feature-1.png new file mode 100644 index 0000000..3166414 Binary files /dev/null and b/img/feature-1.png differ diff --git a/img/feature-2.png b/img/feature-2.png new file mode 100644 index 0000000..f26c393 Binary files /dev/null and b/img/feature-2.png differ diff --git a/img/feature-3.png b/img/feature-3.png new file mode 100644 index 0000000..fa5ea3f Binary files /dev/null and b/img/feature-3.png differ diff --git a/img/initial.png b/img/initial.png new file mode 100644 index 0000000..7015078 Binary files /dev/null and b/img/initial.png differ