Skip to main content

Efficiently manage Git branches without leaving your local branch

Project description

git branchless

PyPi

Efficiently manage topic branches without leaving your local branch

Motivation

Sometimes, I am working on multiple changes to a Git repository. I want to add all of my changes to a single branch, but send them upstream in small, reviewable chunks.

Git already supports this workflow via git format-patch and git send-email, however, many projects prefer to receive patches as pull requests. To make proposed changes easy to review, you'll want to submit a separate pull request for each independent change. With a branchless workflow, the sole local branch typically contains multiple independent changes. To submit those upstream as pull requests, you need to create a separate branch for each change. Running git branchless creates the desired branches without requiring you to switch back and forth between branches. 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-run git branchless.

Installation

$ pip install --user git-branchless

Usage

Create some commits with commit messages starting with [<topic>] where <topic> is a valid branch name. Then run git branchless to create a branch for each of those topics among commits in the range @{upstream}..HEAD. Each topic branch is the result of applying the topic's commits on top of the common ancestor of your branch and the upstream branch, that is, git merge-base @{upstream} HEAD.

For example, if you have a history like

$ git log --graph --oneline
* 2708e12 [my-awesome-feature] Initial support for feature
* c6dd3ab [my-awesome-feature] Some more work on feature
* 683de4b [some-unrelated-fix] Unrelated fix
* 3eee379 Local commit without topic tag
* 2ec4d51 Initial commit

Then this command will create or update two branches that branch away from HEAD:

$ git branchless
$ git log --graph --oneline --all
* 2708e12 (HEAD) [my-awesome-feature] Initial support for feature
* c6dd3ab [my-awesome-feature] Some more work on feature
* 683de4b [some-unrelated-fix] Unrelated fix
* 3eee379 Local commit without topic tag
| * 7645890 (my-awesome-feature) Initial support for feature
| * e420fd6 Some more work on feature
|/
| * d5f4bb2 (some-unrelated-fix) Unrelated fix
|/
* 2ec4d51 Initial commit

git branchless ignores commits whose subject does not start with a topic tag.

To avoid conflicts, you can specify dependencies between branches. For example use [child:parent1:parent2] to base child off both parent1 and parent2. The order here does not matter because it will be determined by which topic occurs first in the commit log.

By default, when dependencies are added to generated branches, the commit message will include their topic tags. You can turn this off for all branches with the --trim-subject option, or for a single dependency by adding the + character before a dependency specification (like [child:+parent]).

If there is a merge conflict when trying to apply a commit, you will be shown potentially missing dependencies. You can either add the missing dependencies, or resolve the conflict. You can tell Git to remember your conflict resolution by enabling git rerere (use git config rerere.enabled true; git config rerere.autoUpdate true).

Instead of the default topic tag delimiters ([ and ]), you can set Git configuration values branchless.subjectPrefixPrefix and branchless.subjectPrefixSuffix, respectively.

Integrating Commits from Other Branches

You can use git-branchless-pick to integrate other commit ranges into your branch:

$ ln -s $PWD/git-branchless-pick ~/bin/
$ git branchless-pick ..some-branch 

This starts an interactive rebase, prompting you to cherry-pick all missing commits from some-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:

$ git config --add remote.origin.fetch '+refs/pull/*/head:refs/remotes/origin/pr-*'
$ git fetch origin
$ git branchless-pick $(git merge-base origin/pr-123 HEAD)..origin/pr-123

Tips

You can use git revise to efficiently modify your commit messages to contain the [<topic>] tags. This command lets you edit all commit messages in @{upstream}..HEAD.

$ git revise --interactive --edit

Like git revise, you can use git branchless during an interactive rebase.

Related Articles

Related Projects

  • Stacked Git implements a similar workflow. It provides a comprehensive set of commands to manage commit metadata, whereas git branchless only offers one command and requires the user to use standard Git tools for everything else.

Contributing

Submit feedback at https://github.com/krobelus/git-branchless/ or at the public mailing list by sending email to mailto:~krobelus/git-branchless@lists.sr.ht.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

git-branchless-0.0.5.tar.gz (11.0 kB view hashes)

Uploaded Source

Built Distribution

git_branchless-0.0.5-py3-none-any.whl (11.3 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page