Skip to content

geofflamrock/stack

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

stack

A tool to help manage multiple Git branches and pull requests that build on top of each other.

When you are working on a change to your software, breaking down and shipping your work in smaller, iterative chunks using separate branches and pull requests that build on each other brings a number of benefits:

  • It's easier to understand and reason about a smaller set of changes.
  • Getting someone to review your changes is easier if they are smaller and well contained. You are also more likely to get a high quality review that could catch issues compared to a massive pull request with a large number of changes which will often get skimmed.
  • Integration into long-lived branches such as main is easier and less prone to unintended issues.
  • It's easier to revert or fix if there is an issue.
  • Iterating on a change promotes getting feedback early and adjusting if you need to as you understand and complete the work.

This approach is not without it's tradeoffs though:

  • It can be hard to get the overall context or scope of a change across multiple branches and pull requests.
  • Keeping branches up to date with the latest changes in main is difficult, time-consuming and can easily be done incorrectly, leading to needing to untangle a mess of conflicts.
  • Getting reviews from other team members or other teams can take time.
  • Incorporating feedback from reviews across branches is difficult.

This is where stack comes in: It lets you manage multiple branches that form together into a stack, along with their associated pull requests, helping you to overcome the tradeoffs and gain the benefits of small, iterative changes.

Note: This project is under active development and is likely to have rough edges, bugs and missing things. Until it reaches v1.0.0 it also might change at any time.

Contents

Getting started

Prerequisites

In order to use stack you'll need the following:

  • The git CLI installed, added to your path and configured to access your repository.
  • (optional) The gh CLI installed, added to your path and authenticated if you want to use some of the GitHub integration points.

Installing stack

To install stack download the relevant binary for your OS from the latest GitHub release, unarchive it and (optionally) add stack to your path.

Run stack to get a list of the available commands.

How does it work?

Multiple branches are managed in a stack. This is an explicit set of branches that you want to manage and keep updated as you work. stack doesn't try and automatically work out which branches were first created from other ones, it takes the opinion that you are in control of which branches you to manage together. Every stack has a source branch which it starts from, this is likely to be the default branch of your repository.

stack operates using the git and (optionally) gh CLI to perform the branch actions that you likely would do if you were trying to manage branches yourself. As a result it doesn't need to store any specific credentials, and inherits any defaults you might have for your Git configuration.

All commands can be run from anywhere inside the Git repository you are working with, or optionally using the --working-dir option.

Data is stored inside a config file in {user}/stack/config.json. You can open the config file by running stack config open.

Creating a stack

To create a stack:

  • In your terminal, change to your Git repository.
  • Run stack new.
  • Give your stack a name.
  • Select a branch to start your stack from.
  • Optionally either create a new branch from the source branch, or add an existing branch to the stack.

If a new branch was not able to be pushed to the remote, you can use the stack push command to push the branch to the remote later.

Working within a stack

Working within a stack is the same as working with Git as per normal, make your changes on the branch, commit them and push them to the remote. You likely have your own tooling and workflows for this, you can continue to use them.

Adding a new branch

Once you've done some work on the first branch within the stack, at some point you'll likely want a second branch. To do this:

  • Run stack branch new.
  • Select the stack to create the branch in.
  • Give the branch a name.

The new branch will be created from the branch at the bottom of the stack and the current branch will be changed so you can make more changes.

If a new branch was not able to be pushed to the remote, you can use the stack push command to push the branch to the remote later.

Incorporating changes from the remote repository

After working on a stack of branches for a while, you might need to incorporate changes that have happened to your source branch from others. To do this:

  • Run stack sync
  • Select the stack you wish to sync
  • Confirm the sync

Branches in the stack will be updated by:

  • Fetching changes to the repository, pruning remote branches that no longer exist, the equivalent of running git fetch --prune.
  • Pulling changes for all branches in the stack, including the source branch, the equivalent of running stack pull.
  • Updating branches in order in the stack, the equivalent of running stack update.
  • Pushing changes for all branches in the stack, the equivalent of running stack push.

Specifying an update strategy

There are two strategies that can be used to update branches in a stack.

The Git configuration key stack.update.strategy can be used to control the default update strategy on a global or per-repository basis.

You will be asked to select an update strategy if none is supplied or configured.

Merge

When using the merge update strategy, each branch in the stack is merged into the one directly below it, starting with the source branch.

To use the merge strategy, either:

  • Supply the --merge option to the sync or update command.
  • Configure stack.update.strategy to be merge in Git configuration using git config stack.update.strategy merge.

Rough edges

Updating a stack using merge, particularly if it has a number of branches in it, can result in lots of merge commits.

If you merge a pull request using "Squash and merge" then you might find that the first update to a stack after that results in merge conflicts that you need to resolve. This can be a bit of a pain.

Rebase

When using the rebase update strategy, each branch in the stack is rebased on it's parent branch.

To use the rebase strategy, either:

  • Supply the --rebase option to the sync or update command.
  • Configure stack.update.strategy to be rebase in Git configuration using git config stack.update.strategy rebase.

To push changes to the remote after rebasing you'll need to use the --force-with-lease option.

Rough edges

If you merge a pull request using "Squash and merge" then you might find that the first update to a stack after that results in merge conflicts that you need to resolve. This can be a bit of a pain, however for each commit that existed on the branch that was merged if you select to take the new single commit that now exists generally it isn't too bad.

Creating pull requests

When you've made your changes you can create a set of pull requests that build off each other. This requires that you have the gh CLI installed on your path and authenticated (run gh auth login).

To do this:

  • Run stack pr create.
  • Confirm that you want to create pull requests for the stack.
  • For each branch you'll be asked for the title of the pull request.
  • The pull request will then be created, targeting the previous branch in the stack.

When all the pull requests have been created set of links to all pull requests in the stack will be put into the body of each pull request. This is optional and is controlled by the presence of the <!-- stack-pr-list --> comment in the body of the pull request. To opt-out just remove the comment.

You can then open each pull request if the stack if you want to view them.

stack pr create can be run multiple times, if there are new branches in the stack that don't have an associated pull request these will be created and the list updated on each pull request.

Commands

Stack commands

stack new

Create a new stack.

Usage:
  stack new [options]

Options:
  --working-dir        The path to the directory containing the git repository. Defaults to the current directory.
  --verbose            Show verbose output.
  -n, --name           The name of the stack. Must be unique within the repository.
  -s, --source-branch  The source branch to use for the new stack. Defaults to the default branch for the repository.
  -b, --branch         The name of the branch to create within the stack.
  -?, -h, --help       Show help and usage information

stack list

List stacks.

Usage:
  stack list [options]

Options:
  --working-dir   The path to the directory containing the git repository. Defaults to the current directory.
  --verbose       Show verbose output.
  --json          Output results as JSON.
  -?, -h, --help  Show help and usage information

stack status

Show the status of the current stack or all stacks in the repository.

Usage:
  stack status [options]

Options:
  --working-dir   The path to the directory containing the git repository. Defaults to the current directory.
  --verbose       Show verbose output.
  --json          Output results as JSON.
  -s, --stack     The name of the stack.
  --all           Show status of all stacks.
  --full          Show full status including pull requests.
  -?, -h, --help  Show help and usage information

stack delete

Delete a stack.

Usage:
  stack delete [options]

Options:
  --working-dir   The path to the directory containing the git repository. Defaults to the current directory.
  --verbose       Show verbose output.
  -s, --stack     The name of the stack.
  -y, --yes       Confirm the command without prompting.
  -?, -h, --help  Show help and usage information

Branch commands

stack update

Update the branches in a stack.

Usage:
  stack update [options]

Options:
  --working-dir   The path to the directory containing the git repository. Defaults to the current directory.
  --verbose       Show verbose output.
  -s, --stack     The name of the stack.
  --rebase        Use rebase when updating the stack. Overrides any setting in Git configuration.
  --merge         Use merge when updating the stack. Overrides any setting in Git configuration.
  -?, -h, --help  Show help and usage information

stack switch

Switch to a branch in a stack.

Usage:
  stack switch [options]

Options:
  --working-dir   The path to the directory containing the git repository. Defaults to the current directory.
  --verbose       Show verbose output.
  -b, --branch    The name of the branch.
  -?, -h, --help  Show help and usage information

stack cleanup

Clean up branches in a stack that are no longer needed.

Usage:
  stack cleanup [options]

Options:
  --working-dir   The path to the directory containing the git repository. Defaults to the current directory.
  --verbose       Show verbose output.
  -s, --stack     The name of the stack.
  -y, --yes       Confirm the command without prompting.
  -?, -h, --help  Show help and usage information

stack branch new

Create a new branch in a stack.

Usage:
  stack branch new [options]

Options:
  --working-dir   The path to the directory containing the git repository. Defaults to the current directory.
  --verbose       Show verbose output.
  -s, --stack     The name of the stack.
  -b, --branch    The name of the branch.
  -p, --parent    The name of the parent branch to put the branch under.
  -?, -h, --help  Show help and usage information

stack branch add

Add an existing branch to a stack.

Usage:
  stack branch add [options]

Options:
  --working-dir   The path to the directory containing the git repository. Defaults to the current directory.
  --verbose       Show verbose output.
  -s, --stack     The name of the stack.
  -b, --branch    The name of the branch.
  -p, --parent    The name of the parent branch to put the branch under.
  -?, -h, --help  Show help and usage information

stack branch remove

Remove a branch from a stack.

Usage:
  stack branch remove [options]

Options:
  --working-dir   The path to the directory containing the git repository. Defaults to the current directory.
  --verbose       Show verbose output.
  -s, --stack     The name of the stack.
  -b, --branch    The name of the branch.
  -y, --yes       Confirm the command without prompting.
  -?, -h, --help  Show help and usage information

Remote commands

stack pull

Pull changes from the remote repository for a stack.

Usage:
  stack pull [options]

Options:
  --working-dir   The path to the directory containing the git repository. Defaults to the current directory.
  --verbose       Show verbose output.
  -s, --stack     The name of the stack.
  -?, -h, --help  Show help and usage information

stack push

Push changes to the remote repository for a stack.

Usage:
  stack push [options]

Options:
  --working-dir       The path to the directory containing the git repository. Defaults to the current directory.
  --verbose           Show verbose output.
  -s, --stack         The name of the stack.
  --max-batch-size    The maximum number of branches to process at once. [default: 5]
  --force-with-lease  Force push changes with lease.
  -?, -h, --help      Show help and usage information

stack sync

Sync a stack with the remote repository. Shortcut for git fetch --prune, stack pull, stack update and stack push.

Usage:
  stack sync [options]

Options:
  --working-dir     The path to the directory containing the git repository. Defaults to the current directory.
  --verbose         Show verbose output.
  -s, --stack       The name of the stack.
  --max-batch-size  The maximum number of branches to process at once. [default: 5]
  --rebase          Use rebase when updating the stack. Overrides any setting in Git configuration.
  --merge           Use merge when updating the stack. Overrides any setting in Git configuration.
  -y, --yes         Confirm the command without prompting.
  --no-push         Don't push changes to the remote repository
  -?, -h, --help    Show help and usage information

GitHub commands

stack pr create

Create pull requests for a stack.

Usage:
  stack pr create [options]

Options:
  --working-dir   The path to the directory containing the git repository. Defaults to the current directory.
  --verbose       Show verbose output.
  -s, --stack     The name of the stack.
  -?, -h, --help  Show help and usage information

stack pr open

Open pull requests for a stack in the default browser.

Usage:
  stack pr open [options]

Options:
  --working-dir   The path to the directory containing the git repository. Defaults to the current directory.
  --verbose       Show verbose output.
  -s, --stack     The name of the stack.
  -?, -h, --help  Show help and usage information

Advanced commands

stack config open

Open the configuration file in the default editor.

Usage:
  stack config open [options]

Options:
  --working-dir   The path to the directory containing the git repository. Defaults to the current directory.
  --verbose       Show verbose output.
  -?, -h, --help  Show help and usage information

stack config migrate

Migrate the configuration file from v1 to v2 format (preview).

Usage:
  stack config migrate [options]

Options:
  --working-dir   The path to the directory containing the git repository. Defaults to the current directory.
  --verbose       Show verbose output.
  -y, --yes       Confirm the command without prompting.
  -?, -h, --help  Show help and usage information

About

A tool to help manage multiple Git branches and pull requests that build on top of each other

Resources

License

Stars

Watchers

Forks

Contributors 4

  •  
  •  
  •  
  •  

Languages