Skip to content

Stacked PRs (stacked commits, stacked diffs) for GitHub

License

Notifications You must be signed in to change notification settings

dimikot/git-grok

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

35 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Git-grok: stacked PRs and stacked diffs for GitHub

Git-grok is the simplest stacked commits (stacked PRs, stacked diffs — you name it) solution for GitHub.

One idempotent command to rule 'em all:

git grok

No arguments. No configuration. No interactivity. On intent.

If you frequently write code and find it tedious to manage interdependent branches (like when "branch A depends on branch B which itself depends on branch C"), there's an approach that avoids the use of branches entirely. This method, known as "stacked PRs", is used in Meta, Google and other leading companies.

The central idea is that every individual commit in your local working copy becomes an individual pull request. Commits can be stacked on top of each other, reordered, and edited right on your computer using the standard git features. Then, run git-grok to sync the changes in local commits out to their corresponding PRs.

When you want to make changes based on feedback in some PR, just go to the local commit in your stack, make the change ("edit a commit in the middle of the stack"), and rerun git grok to get it propagated to the PRs at GitHub.

Installation

git clone https://github.com/dimikot/git-grok.git
sudo ln -s $(pwd)/git-grok/git-grok /usr/local/bin/git-grok

brew install gh
gh auth login

Important

Don't forget to run gh auth login, it won't work otherwise.

Usage Examples

cd your-repository
git pull --rebase

# Create a PR from the topmost commit you've just made.
touch commit1
git add . && git commit -m "your commit message here"
git grok

# Create more commits on top of each other, all on top of main.
touch commit2
git add . && git commit -m "your commit message here"
touch commit3
git add . && git commit -m "your commit message here"
touch commit4
git add . && git commit -m "your commit message here"

# This turns each individual commit on top of main into individual PRs
# (one commit = one PR) and keeps the PRs in sync with local commits.
git grok

Now comes the beauty of stacked PRs workflow. At any time you can edit a local commit in the middle of the stack in your working copy and rerun git grok to update all the PRs automatically:

git rebase -i
# Now choose a commit which you want to edit. Edit the code, then run:
git add .
git commit --amend
git rebase --continue

# This auto-updates all of the related PRs, so they will be in sync with
# your local working copy.
git grok

You can also reorder the commits freely in case a PR in the middle got accepted earlier than the previous one, and you want to merge it now. As usual, git rebase -i, reorder, run git grok.

With stacked PRs workflow, there is no need in branches and git push anymore.

Here is how a pull request managed by git-grok looks like. Notice the block "PRs in the Stack" at the bottom of the description: it's added by the tool automatically, and it will also be kept in sync with your stack of local commits as you go. (It is also fully compatible with pull_request_template.md GitHub feature in case you use it.)

How to Merge

If your repository enforces code reviews on the main branch (so the only way to push there is through GitHub UI), the process is following.

You "Create a merge commit" or "Squash and merge" or "Rebase and merge" the 1st PR in the stack by clicking the button in GitHub UI (it will go to the main branch).

Then, after the PR is merged, GitHub is smart enough to update the base of the next PR in the stack to point to the main branch (hooray!). So you just switch to the 2nd PR in the stack and merge it.

Rinse.

Repeat.

Warning: pay attention to only merge (or rebase) into the main branch in GitHub UI. GitHub is smart, so it automatically changes the base of the next PR to main once its old branch is auto-deleted when you merge, but if you see something unusual, just rerun git pull --rebase && git grok

What if my GitHub Actions are slow, so they take minutes to execute?

(First of all, you'd better make them fast, because you're wasting the time/money of the entire company otherwise.)

But if you cannot, and you want to use "Squash and merge" or "Rebase and merge" button with stacked PRs, I have bad news for you. When you merge a bottom PR in the stack using any of those two options (note: the 3rd option, "Create a merge commit", works fine), you'll have to wait until GitHub Actions finish running the checks for all other PRs above. It's a GitHub limitation.

There are 2 workarounds here though:

  1. Recommended: use "Create a merge commit" option on the PR button. It doesn't have this problem with re-running GitHub Actions checks when some bottom PR gets merged.
  2. If you don't want merge commits, and you ran git pull --rebase before git grok, and all GitHub Actions checks in all PRs have succeeded, and there are no other commits added on top of the main branch by someone else... then, you can merge the entire stack from your local machine with the following snippet:
    for c in $(git log --reverse --pretty=format:%h origin/main...HEAD); do
      git push origin $c:main
      sleep 5
    done
    Notice that "Squash and merge"/"Rebase and merge" button in GitHub UI won't work in this case still, because it amends the commit message implicitly, so it will still rerun the checks for the PRs above.

About

Stacked PRs (stacked commits, stacked diffs) for GitHub

Resources

License

Stars

Watchers

Forks