Package: git-branchstack
git branchstackMotivationWhen I am working on multiple changes to aGitrepository, I usually want to
combine all of my changes in a single branch, but send them upstream in small,
reviewable chunks. As stated inthe related articlesone advantage is that you can base new work on previous changes, and test
them in combination.Git already supports this workflow viagit format-patchandgit send-email,
however, many projects prefer to receive patches via pull requests.  To make
proposed changes easy to review, you'll want to submit a separate pull request
for each independent change on your worktree's branch.  This means that you
want to create branches containing those independent changes and nothing else.git branchstackcreates the desired branches without requiring you to switch
back and forth between branches (and invalidating builds). This allows you
to submit small pull requests, while enjoying the benefits of a branchless
workflow. After making any changes to your worktree's branch you can easily
update the generated branches: just re-rungit branchstack.InstallationVia pip$pipinstall--usergit-branchstackInstead of the last command you can also run./git-branchstackdirectly, provided you havegit-revise>=0.7.0.ViapipxUse this instead to avoid breakage when your Python installation is upgraded.$pipxinstallgit-branchstackUsageCreate some commits with commit messages starting with a topic tag[...].
The topic name,<topic>, inside the square bracket tag markers[<topic>],
must be an unused valid branch name.  Then rungit branchstackto create
the branch<topic>with the given commits.For example, if you have created a commit history like$ git log --graph --oneline
* 9629a6c (HEAD -> local-branch) [some-unrelated-fix] Unrelated fix
* e764f47 [my-awesome-feature] Some more work on feature
* a9a811f [my-awesome-feature] Initial support for feature
* 28fcf9c Local commit without topic tag
* 5fb0776 (master) Initial commitThen this command will (re)create two branches:$ git branchstack
$ git log --graph --oneline --all
* 9629a6c (HEAD -> local-branch) [some-unrelated-fix] Unrelated fix
* e764f47 [my-awesome-feature] Some more work on feature
* a9a811f [my-awesome-feature] Initial support for feature
* 28fcf9c Local commit without topic tag
| * 7d4d166 (my-awesome-feature) Some more work on feature
| * fb0941f Initial support for feature
|/
| * 1a37fd0 (some-unrelated-fix) Unrelated fix
|/
* 5fb0776 (master) Initial commitBy default,git branchstacklooks only at commits in the range@{upstream}..HEAD.  It ignores commits whose subject does not start with
a topic tag.Created branches are based on the common ancestor of your branch and the
upstream branch, that is,git merge-base @{upstream} HEAD.To avoid conflicts, you can specify dependencies between branches.
For example use[child:parent1:parent2]to basechildoff bothparent1andparent2. The order of parents does not matter: the one that occurs
first in the commit log will be added first.Pass--keep-tagsto mark dependency commits by keeping the commits'
topic tags. Usekeep-tags=allto keep all topic tags. To only keep topic
tags of select dependencies, prefix them with the+character (like[child:+parent]).If a commit cannot be applied cleanly,git branchstackwill show topics
that would avoid the conflict if added as dependencies. You can either
add the missing dependencies, or resolve the conflict in your editor. You
can tell Git to remember your conflict resolution by enablinggit rerere(usegit config rerere.enabled true; git config rerere.autoUpdate true).Instead of the default topic tag delimiters ([and]), you can
set Git configuration valuesbranchstack.subjectPrefixPrefixandbranchstack.subjectPrefixSuffix, respectively.Integrating Commits from Other BranchesYou can usegit-branchstack-pickto integrate
other commit ranges into your branch:$gitbranchstack-pick..some-branchThis behaves likegit rebase -iexcept it prefills the rebase-todo list to
cherry-pick all missing commits fromsome-branch, prefixing their commit
subjects with[some-branch].  Old commits with such a subject are dropped,
so this allows you to quickly update to the latest upstream version of a
ref that has been force-pushed.Here's how you would use this to cherry-pick GitHub pull requests:$gitconfig--addremote.origin.fetch'+refs/pull/*/head:refs/remotes/origin/pr-*'$gitfetchorigin
$gitbranchstack-pick..origin/pr-123TipsYou can usegit reviseto efficiently modify your commit messages
to contain the[<topic>]tags. This command lets you edit all commit
messages in@{upstream}..HEAD.$gitrevise--interactive--editLikegit revise, you can usegit branchstackduring an interactive rebase.git-autofixupcan eliminate
some of the busywork involved in creating fixup commits.Related ArticlesInStacked Diffs Versus Pull Requests, Jackson Gabbard
describes the advantages of a patch-based workflow (usingPhabricator)
over the one-branch-per-reviewable-change model;git branchstackcan be used
to implement the first workflow, even when you have to use pull-requests.InMy unorthodox, branchless git workflow, Drew
DeVault explains some advantages of a similar workflow.Peer ProjectsWhilegit branchstackonly offers one command and relies on standard Git
tools for everything else, there are some tools that offer a more comprehensive
set of commands to achieve a similar workflow:Stacked Gitgit psgh-stackgit machetegit-stackdepot-toolsUnlike its peers,git branchstacknever modifies any worktree files,
since it usesgit reviseinternally.  This makes it faster, and avoids
invalidating builds.ContributingSubmit feedback athttps://github.com/krobelus/git-branchstack/or to thepublic mailing listby
sending email tomailto:~krobelus/git-branchless@lists.sr.ht.