git-stack-cli

module
v0.0.0-...-40952a8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 4, 2025 License: MIT

README ยถ

git stack

git stack is a small CLI that makes working with stacked branches in Git easier.

TL;DR โ€“ What can it do?
  • ๐Ÿš€ git stack push โ€” push a whole stack of branches and open PRs/MRs
  • ๐Ÿงฑ git stack branch โ€” view branches in your current stack
  • ๐Ÿ“‹ git stack list โ€” view all active stacks
  • ๐Ÿงฐ Integrates with GitHub and GitLab

What is stacking?

Stacking lets you break big changes into smaller, easier-to-review pull requests. Each branch in the stack builds on top of the last. See this intro for a helpful overview.

Why use git stack?

Git supports stacking out of the box, but it's tedious:

  • You have to manually track which branches are stacked together - and in what order
  • There's no built-in way to push a full stack of PRs
  • Target branches in GitHub/GitLab need to be set by hand

git stack makes stacking much easier, while aiming to feel like a natural extension of the Git CLI - not a replacement.

Quickstart

You'll need Go 1.22+ installed. On macOS:

brew install go 

Install git stack:

go install github.com/raymondji/git-stack-cli/cmd/git-stack@0.39.0

In your Git repo:

git stack init  # Set up with your GitHub/GitLab token
git stack learn # Launch interactive CLI tutorial

Sample usage

This sample output is taken from git stack learn --chapter=1 --mode=exec.

โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚                                                  โ”‚
โ”‚ Welcome to git stack!                            โ”‚
โ”‚ Here is a quick tutorial on how to use the CLI.  โ”‚
โ”‚                                                  โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚                                                  โ”‚
โ”‚ Let's start things off on the default branch:    โ”‚
โ”‚                                                  โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
> git checkout main
Your branch is up to date with 'origin/main'.
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚                                                  โ”‚
โ”‚ Next, let's create our first branch:             โ”‚
โ”‚                                                  โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
> git checkout -b myfirststack
> echo 'hello world' > myfirststack.txt
> git add .
> git commit -m 'hello world'
[myfirststack eb4a6fe] hello world
 1 file changed, 1 insertion(+)
 create mode 100644 myfirststack.txt
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚                                                  โ”‚
โ”‚ Now let's stack a second branch on top of our    โ”‚
โ”‚ first:                                           โ”‚
โ”‚                                                  โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
> git checkout -b myfirststack-pt2
> echo 'have a break' >> myfirststack.txt
> git commit -am 'break'
[myfirststack-pt2 e3579cb] break
 1 file changed, 1 insertion(+)
> echo 'have a kitkat' >> myfirststack.txt
> git commit -am 'kitkat'
[myfirststack-pt2 7c3f014] kitkat
 1 file changed, 1 insertion(+)
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚                                                  โ”‚
โ”‚ So far we've only used standard Git commands.    โ”‚
โ”‚ Let's see what git stack can do for us already.  โ”‚
โ”‚                                                  โ”‚
โ”‚ Our current stack has two branches in it, which  โ”‚
โ”‚ we can see with:                                 โ”‚
โ”‚                                                  โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
> git stack branch
* myfirststack-pt2 (top)
  myfirststack
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚                                                  โ”‚
โ”‚ Our current stack has 3 commits in it, which we  โ”‚
โ”‚ can see with:                                    โ”‚
โ”‚                                                  โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
> git stack log
7c3f014 kitkat
e3579cb break
eb4a6fe hello world
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚                                                  โ”‚
โ”‚ We can easily push all branches in the stack and โ”‚
โ”‚ open PRs.                                        โ”‚
โ”‚ git stack automatically sets the target branches โ”‚
โ”‚ for you.                                         โ”‚
โ”‚                                                  โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
> git stack push --open
[?25l[?2004h
โฃฝ Pushing stack...โฃป Pushing stack...โขฟ Pushing stack...โกฟ Pushing stack...โฃŸ Pushing stack...โฃฏ Pushing stack...โฃท Pushing stack...โฃพ Pushing stack...โฃฝ Pushing stack...โฃป Pushing stack...โขฟ Pushing stack...โกฟ Pushing stack...โฃŸ Pushing stack...โฃฏ Pushing stack...โฃท Pushing stack...โฃพ Pushing stack...โฃฝ Pushing stack...โฃป Pushing stack...โขฟ Pushing stack...โกฟ Pushing stack...โฃŸ Pushing stack...โฃฏ Pushing stack...โฃท Pushing stack...โฃพ Pushing stack...โฃฝ Pushing stack...โฃป Pushing stack...โขฟ Pushing stack...โกฟ Pushing stack...โฃŸ Pushing stack...โฃฏ Pushing stack...โฃท Pushing stack...โฃพ Pushing stack...โฃฝ Pushing stack...โฃป Pushing stack...โขฟ Pushing stack...โกฟ Pushing stack...โฃŸ Pushing stack...โฃฏ Pushing stack...โฃท Pushing stack...โฃพ Pushing stack...โฃฝ Pushing stack...โฃป Pushing stack...
[?2004l[?25h[?1002l[?1003l[?1006lPushed branches:
* myfirststack-pt2 (top)
  โ””โ”€โ”€ https://github.com/raymondji/git-stack-cli/pull/209

  myfirststack
  โ””โ”€โ”€ https://github.com/raymondji/git-stack-cli/pull/208
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚                                                  โ”‚
โ”‚ We can quickly view the PRs at any point using:  โ”‚
โ”‚                                                  โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
> git stack branch --prs
[?25l[?2004h
โฃฝ Fetching prs...โฃป Fetching prs...โขฟ Fetching prs...โกฟ Fetching prs...โฃŸ Fetching prs...
[?2004l[?25h[?1002l[?1003l[?1006l* myfirststack-pt2 (top)
  โ””โ”€โ”€ https://github.com/raymondji/git-stack-cli/pull/209

  myfirststack
  โ””โ”€โ”€ https://github.com/raymondji/git-stack-cli/pull/208
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚                                                  โ”‚
โ”‚ To sync the latest changes from the default      โ”‚
โ”‚ branch into the stack, you can run:              โ”‚
โ”‚ git rebase main --update-refs                    โ”‚
โ”‚ Or to avoid having to remember --update-refs,    โ”‚
โ”‚ you can do:                                      โ”‚
โ”‚                                                  โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
> git stack rebase main
Successfully rebased myfirststack-pt2 on main
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚                                                  โ”‚
โ”‚ Great, we've got the basics down for one stack.  โ”‚
โ”‚ How do we deal with multiple stacks?             โ”‚
โ”‚ Let's head back to our default branch and create โ”‚
โ”‚ a second stack.                                  โ”‚
โ”‚                                                  โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
> git checkout main
Your branch is up to date with 'origin/main'.
> git checkout -b mysecondstack
> echo 'buy one get one free' > mysecondstack.txt
> git add .
> git commit -m 'My second stack'
[mysecondstack dd16f86] My second stack
 1 file changed, 1 insertion(+)
 create mode 100644 mysecondstack.txt
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚                                                  โ”‚
โ”‚ To view all the stacks:                          โ”‚
โ”‚                                                  โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
> git stack list
  myfirststack-pt2 (2 branches)
* mysecondstack (1 branch)
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚                                                  โ”‚
โ”‚ Nice! All done chapter 1 of the tutorial.        โ”‚
โ”‚                                                  โ”‚
โ”‚ In chapter 2 we'll see how to make changes to    โ”‚
โ”‚ earlier branches in the stack.                   โ”‚
โ”‚ Once you're ready, continue the tutorial using:  โ”‚
โ”‚ git stack learn --chapter 2                      โ”‚
โ”‚                                                  โ”‚
โ”‚ To cleanup all the branches/PRs that were        โ”‚
โ”‚ created, run:                                    โ”‚
โ”‚ git stack learn --chapter 1 --mode=clean         โ”‚
โ”‚                                                  โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

How does it work?

When working with Git we often think in terms of branches as the unit of work, and Gitlab/Github both tie pull requests to branches. Thus, git stack presents stacks as "stacks of branches".

However, branches in Git don't inherently make sense as belonging to a "stack", i.e. where one branch is stacked on top of another branch. Branches in Git are just pointers to commits, so:

  • Multiple branches can point to the same commit
  • Branches don't inherently have a notion of parent branches or child branches

Under the hood, git stack therefore walks the commit graph and parses stacking relationships between branches. Commits serve this purpose well because:

  • Each commit is a unique entity
  • Commits do inherently have a notion of parent commits and child commits

git stack uses the commit relationships to try and establish a total order between branches in a stack, i.e. where each branch i contains branch i-1. If such an order exists, the stack is valid. If such an order doesn't exist, the stack is invalid and git stack prints a helpful error message so you can resolve the bad state.

Attribution

Some code is adapted from sections of https://github.com/aviator-co/av (MIT license). A copy of av's license is included at attribution/aviator-co/av/LICENSE.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL