High-level CLI for Git

Git Town provides additional Git commands that make creating, synchronizing, shipping, and cleanup of Git branches more efficient. Supports mono-repos and stacked changes.


screencast


Git is a very flexible source code management system. The Git CLI (rightfully) supports all possible ways of using Git equally well. Git commands are generic building blocks for implementing your specific Git workflow. This generic design can make using the vanilla Git CLI repetitive in real life. As the screencast above demonstrates, typical development activities like creating, synchronizing, or shipping a feature branch can require running dozens of Git commands.

Git Town adds commands to Git that implement these activities in one step. Git Town's commands are compatible with most common branching models like GitHub Flow, Git Flow, GitLab Flow, trunk-based development and even committing straight into the main branch. See also this external review.

What our users say

Supercharge your workflow with Git by relying on this surprisingly powerful and quite useful plugin that provides you with a series of extra Git commands.

Softpedia article about Git Town

Q & A

Does this force me into any conventions for my branches or commits?

No. Git Town doesn’t require or enforce conventions for naming or set up of branches and commits. It works with a wide variety of Git branching models and workflows. If it doesn't work with your workflow: contact us

Which Git branching models are supported by Git Town?

Git Town is so generic that it supports the most widely used branching models including GitHub Flow, Git Flow, GitLab Flow, trunk-based development. Git Town is even useful if you commit straight into the main branch!

How is this different from the git-flow tool?

git-flow is a Git extension that provides specific and opinionated support for the powerful Git branching model with the same name. It doesn’t care too much about how you keep your work in sync with the rest of the team. Git Town doesn’t care which branching model you use. It focusses on keeping your team synchronized and your code repository clean from old branches. You can use the two tools together.

Is Git Town compatible with my other Git tools?

Yes, we try to be good citizens in the Git ecosystem. If you run into any issues with your setup, please let us know!

Does my whole team have to use Git Town?

No. Git Town is already useful even if you are the only person using it. It simply executes the Git commands that you would (should) run.

Installation

Git Town ships as a single self-contained binary. It calls the Git executable that is already installed on your machine.

Packaging status

macOS

You can install Git Town on macOS via Homebrew:

brew install git-town

Installation via MacPorts is also supported:

sudo port install git-town

Windows

You can install Git Town on Windows using:

If you use the Windows Subsystem for Linux, please install wsl-open to allow the commands git town repo and git town propose to open a browser window for you.

Linux

On Debian-based systems, download the .deb file matching your CPU architecture and run:

sudo apt-get install git-town_linux_intel_64.deb

On RedHat-based systems download the .rpm file matching your CPU architecture and run

rpm -i git-town_linux_intel_64.rpm

On Arch Linux, install the git-town package from the AUR. Or download the matching .pkg.tar.zst file for your architecture and run:

sudo pacman -U <filename>

You can also install Git Town on Linux via Homebrew for Linux:

brew install git-town

You can also install Git Town manually or compile from source.

BSD

You can install Git Town on BSD via freshports or by downloading the matching binaries from the GitHub release.

manual installation

curl https://git-town.com/install.sh | sh

For a fully custom installation, download the archive matching your CPU architecture, extract it, and move the git-town executable into a directory listed in your $PATH, for example /usr/local/bin.

compile from source

If you have the Go compiler installed, you can compile the latest version of Git Town from source by running:

go get github.com/git-town/git-town

New releases

Subscribe to the Git Town release feed to get notifications about new releases.

Uninstall

To remove Git Town from your system:

  1. Remove the Git Town configuration from your repositories: in each repo, run git town config remove
  2. If your operating system or package manager provides an uninstaller for Git Town, run it. If you installed Git Town manually, delete the binary.

Configuration

If your repository already contains a .git-branches.toml file, you are good to go. If not or something doesn't work, run Git Town's setup assistant. It walks you through every configuration option and give you a chance to adjust it.

git town config setup

More information about the configuration file including how to create one manually is here.

Commands

Run git town for an overview of all Git Town commands and git town help <command> for help with individual commands. You can call each Git Town command like git town <command>. This user manual displays the commands in the shorter form available after enabling aliases through the setup assistant.

Basic workflow

Commands to create, work on, and ship features.

  • git hack - create a new feature branch
  • git sync - update the current branch with all ongoing changes
  • git switch - switch between branches visually
  • git propose - propose to ship a branch
  • git ship - deliver a completed feature branch

Additional workflow commands

Commands to deal with edge cases.

Stacked changes

Commands to develop, review, and ship parts of a larger feature as multiple connected branches.

Dealing with errors

Commands to deal with merge conflicts.

  • git continue - continue after you resolved the merge conflict
  • git skip - when syncing all branches, ignore the current branch and continue with the next one
  • git town status - display available commands
  • git undo - undo the last completed Git Town command

Git Town installation

Commands that help install Git Town on your computer.

  • git town aliases - add or remove shorter aliases for Git Town commands
  • git town completion - generate completion scripts for Bash, zsh, fish & PowerShell.
  • git town version - display the installed version of Git Town

Git Town configuration

Commands that help adapt Git Town's behavior to your preferences.

Typical development workflow

The following four Git Town commands automate the typical development workflow:

  • You start hacking by running git hack to create a feature branch.
  • While coding you run git sync to keep your feature branch up to date with commits that you or other developers make into the main branch. This prevents your feature branch from deviating too much from the main code line.
  • If your team does pull requests, you can run git propose to create a new pull request.
  • git ship delivers the feature branch.

git hack <branch>

The hack command ("let's start hacking") creates a new feature branch with the given name off the main branch and brings all uncommitted changes over to it.

When running without uncommitted changes in your workspace, it also syncs the main branch to ensure you develop on top of the current state of the repository. If the workspace contains uncommitted changes, git hack does not perform this sync to let you commit your open changes first and then sync manually.

Configuration

If the repository contains a remote called upstream, it also syncs the main branch with its upstream counterpart. You can control this behavior with the sync-upstream flag.

If push-new-branches is set, git hack creates a remote tracking branch for the new feature branch. This behavior is disabled by default to make git hack run fast. The first run of git sync will create the remote tracking branch.

git sync [--all]

The sync command ("synchronize this branch") updates the local Git workspace with what happened in the rest of the repository.

  • pulls new commits for the current branch from its tracking and ancestor branches
  • downloads new Git tags
  • deletes the local branch if its tracking branch was deleted at the remote and the local branch doesn't contain unshipped changes
  • checks out the previously checked out Git branch in case the current branch got removed as part of the sync
  • local branches checked out in other Git worktrees don't get synced

Arguments

The --all parameter makes Git Town sync all local branches instead just the current one.

The --dry-run parameter allows to test-drive this command. It prints the Git commands that would be run but doesn't execute them.

Configuration

sync-perennial-strategy configures whether perennial branches merge their tracking branch or rebase against it.

sync-feature-strategy configures whether feature branches merge their parent and tracking branches or rebase against them.

If the repository contains a Git remote called upstream and the sync-upstream setting is enabled, Git Town also downloads new commits from the upstream main branch.

git town switch

The switch command displays the branch hierarchy on your machine and allows switching the current Git workspace to another local Git branch. Unlike git-switch, Git Town's switch command uses a more ergonomic visual UI and supports VIM motion commands.

git town switch does not allow switching to branches that are checked out in other worktrees and notifies you about uncommitted changes in your workspace in case you forgot to commit them to the current branch.

Arguments

The --merge or -m flag has the same effect as the git checkout -m flag.

git propose

The propose command helps create a new pull/merge request for the current feature branch. It opens your code hosting platform's website to create a new proposal in your browser and pre-populates information like branch and source/target repository. It also syncs the branch to merge before opening the pull request.

You can create new pull requests for repositories hosted on:

Configuration

You can configure the hosting platform type with the hosting-platform setting.

When using SSH identities, this command uses the hostname in the hosting-origin-hostname setting.

Error handling

Sometimes Git Town commands encounter problems that require the human user to make a decision. When this happens, the command stops and prints an error message. When you have resolved the issue, you can either:

  • run git continue to continue executing the interrupted command, starting with the operation that failed,
  • run git undo to undo the Git Town command and go back to where you started.

You can also run git undo after a Git Town command finished to undo the changes it made. Run git town status to see the status of the running Git Town command and which Git Town commands you can run to continue or undo it.

git continue

When a Git Town command encounters a problem that it cannot resolve, for example a merge conflict, it stops to give the user an opportunity to resolve the issue. Once you have resolved the issue, run the continue command to tell Git Town to continue executing the failed command. Git Town will retry the failed operation and execute all remaining operations of the original command.

git skip

The skip command allows to skip a Git branch with merge conflicts when syncing all feature branches.

git town status

The status command indicates whether Git Town has encountered a merge conflict and which commands you can run to continue, skip, or undo it.

git undo

The undo command reverts the last fully executed Git Town command. It performs the opposite activities that the last command did and leaves your repository in the state it was before you ran the problematic command.

Stacked Changes

Stacked changes implement and review a complex change as a series of smaller feature branches that build on top of each other. Benefits of stacked changes are:

  • developer and reviewer maintain momentum and block less on each other
  • breaking up the problem of developing/reviewing a complex problem into developing/reviewing many smaller problems
  • minimize merge conflicts by shipping parts of a complex change that are already approved separately from parts still under review

The single responsibility principle applies to feature branches the same way it applies to functions, classes, and methods. Feature branches should also perform only one change. Implementing, refactoring, reviewing, and resolving merge conflicts on such single-responsibility branches is easier than with branches that combine unrelated changes.

Git Town supports stacked changes naturally as part of its bigger picture about branch ancestry.

Example

Let's say we want to add a new feature to an existing codebase. Before we can do that cleanly, we need to get the code base ready:

  1. Make the architecture more flexible so that we can add the new feature in a clean way.
  2. Clean up some technical drift: improve the names of variables and functions.
  3. Build the feature on top of this modernized codebase

Implementing all these changes in a single feature branch is risky. Some changes like the refactor in (1) touch a lot of files that other people might change as well. We want to review and merge them as fast as possible to minimize merge conflicts. Other changes like building the actual feature in (3) will take a while to build. We should therefore make both changes in separate branches. At the same time, the feature (3) depends on the changes in (1) and (2) and drives the changes in (2). We want to develop these changes together. The solution is a stack of feature branches.

Branch 1: refactor

The first feature branch contains the refactor. We create a feature branch named 1-refactor off the main branch to contain it.

git hack 1-refactor

git hack creates a new feature branch off the main branch. We perform the refactor and commit it.

Branch 2: rename foo

With the refactored architecture in place, we can update the names of some variables, functions, and files whose role has changed as the code base has evolved. Since these changes require the refactor, we perform them on top of branch 1-refactor:

git append 2-rename-foo

git append creates a new feature branch on top of the currently checked out branch (which is 1-refactor). We now have this lineage:

main
 \
  1-refactor
   \
    2-rename-foo

Branch 2-rename-foo builds on top of 1-refactor and thereby contains all the changes made there. We commit the changes that rename the foo variable. Because we used git append to create the new branch, Git Town knows about the lineage and creates the proposal (aka pull request) for branch 2-rename-foo against branch 1-refactor. This way, the proposal for branch 2-rename-foo shows only the changes made in that branch (renaming the variable) and not the refactor made in branch 1.

Branch 3: rename bar

This is a different change from renaming foo and has different reviewers. Let's perform it in a different branch. Some of these changes might happen on the same lines on which we also renamed foo earlier. We don't want to deal with merge conflicts coming from that. So let's make this change on top of the change we made in step 2:

git append 3-rename-bar

The lineage is now:

main
 \
  1-fix-typos
   \
    2-rename-foo
     \
      3-rename-bar

Extend the refactoring

While renaming bar, we discover another improvement for the architecture. Let's add it to the refactoring branch.

git checkout 1-refactor
# make the changes and commit them
git checkout 3-rename-bar

Back on branch 3-rename-bar, the additional refactor we just added isn't visible because the commit for it exists only in branch 1-refactor right now. Let's propagate these changes through the entire branch chain so that they become visible in branches 2 and 3 as well:

git sync

Because we created the branches with git append, Git Town knows about the branch lineage and git sync can update all branches in the right order. It updates the main branch, merges main into branch 1. Then it merges branch 1 into branch 2 and branch 2 into branch 3.

Shipping the refactor

We got the approval for the refactor from step 1. Let’s ship it!

git ship 1-refactor

You have to use the git ship command here because it updates the lineage that Git Town keeps track of. With branch 1-refactor shipped, our lineage now looks like this:

main
 \
  2-rename-foo
   \
    3-rename-bar

If you ship feature branches via the code hosting API or web UI, run git sync --all, or git sync on the youngest child branch, to update the lineage.

Synchronizing our work with the rest of the world

We have been at it for a while. Other developers on the team have made changes to the codebase as well. We don't want our branches to deviate too much from the main branch since that leads to more severe merge conflicts later. Let's get all our branches in sync with the rest of the world!

git sync --all

This pulls updates for the main branch, then merges it into 2-rename-foo, then 2-rename-foo into 3-rename-bar.

Branch 4: building the new feature

We can now add the new feature on top of the code base we prepared:

git append 4-add-feature

Let’s stop here and review what we have done.

  • Each change happens in its own feature branch.
  • Our feature branches build on top of each other and see changes in their parent branches.
  • We review and ship each feature branch in the chain in isolation.
  • git hack creates a feature branch as a child of the main branch.
  • git append creates a feature branch as a child of the current feature branch.
  • git sync keeps a feature branch chain up to date with the rest of the world
  • git ship ships the oldest feature branch in a branch chain.

Single-responsibility branches are easier to reason about and faster to implement, debug, review, and ship than branches performing multiple changes. They encounter fewer and smaller merge conflicts which are easier to resolve than merge conflicts on branches that implement many different changes. You can review and ship parts of your complex change before the entire change is finished. You can still make different changes in parallel, just commit them to the correct branch.

Best Practices

Branch discipline: when you have an idea that is different from what you currently work on, resist the urge to code it in the current feature branch. Implement it in its own feature, parent, or child branch.

Keep the entire branch chain in sync: Make sure you run git sync --all or git sync on the youngest child branch to keep the entire chain of feature branches synced.

Avoid unnecessary chaining: If your feature branches don't depend on each other, put them in (independent) top-level feature branches. This way you can ship them in any order.

Organize branch chains in the order you want to ship: You always have to ship the oldest branch first. You can use git prepend to insert a feature branch as a parent of the current feature branch or set parent to change the order of branches.

git append <branch>

The append command creates a new feature branch with the given name as a direct child of the current branch and brings over all uncommitted changes to the new branch.

When running without uncommitted changes in your workspace, it also syncs the current branch to ensure your work in the new branch happens on top of the current state of the repository. If the workspace contains uncommitted changes, git append does not perform this sync to let you commit your open changes first and then sync manually.

Example

Consider this branch setup:

main
 \
  feature-1

We are on the feature-1 branch. After running git append feature-2, our repository will have this branch setup:

main
 \
  feature-1
   \
    feature-2

Configuration

If push-new-branches is set, git append also creates the tracking branch for the new feature branch. This behavior is disabled by default to make git append run fast. The first run of git sync will create the remote tracking branch.

git prepend <branch>

The prepend command creates a new feature branch as the parent of the current branch. It does that by inserting the new feature branch between the current feature branch and it's old parent.

When running without uncommitted changes in your workspace, it also syncs the current feature branch to ensure commits into the new branch are on top of the current state of the repository. If the workspace contains uncommitted changes, git prepend does not perform this sync to let you commit your open changes first and then sync manually.

Example

Consider this branch setup:

main
 \
  feature-2

We are on the feature-2 branch. After running git prepend feature-1, our repository has this branch setup:

main
 \
  feature-1
   \
    feature-2

Configuration

If push-new-branches is set, git hack creates a remote tracking branch for the new feature branch. This behavior is disabled by default to make git hack run fast. The first run of git sync will create the remote tracking branch.

git set-parent

The set-parent command changes the parent branch for the current branch. It prompts the user for the new parent branch. Ideally you run git sync when done updating parent branches to pull the changes of the new parent branches into their new child branches.

Example

Let's say we have this branch hierarchy:

main
 |
 + feature-1
   |
   + feature-2

"feature-2" is a child branch of "feature-1". Let's make "feature-2" a child of "main":

  • run git town set-parent
  • select main in the dialog

Now we have this branch hierarchy:

main
 |
 + feature-1
 |
 + feature-2

git diff-parent

The diff-parent command displays the changes made on a feature branch, i.e. the diff between the current branch and its parent branch.

Advanced Branch Syncing

Git branches can be used in many different ways. When properly configured, you can run git sync or git sync --all at any time and each of your local branches will get synced in the specific ways it's supposed to get synced or not synced.

Contribution branches

Contribution branches are for people who contribute commits to somebody else's branch. You cannot propose or ship contribution branches because those are responsibilities of the person owning the branch you contribute to. For the same reason git sync does not pull updates from the parent branch of a contribution branch and always rebases your local commits. Syncing removes contribution branches from your machine as soon as their tracking branch is gone, even if you have unpushed local commits. Killing a contribution branch only deletes your local copy and not the tracking branch.

You can make any feature branch a contribution branch by running git contribute on it. Convert a contribution branch back to a feature branch by running git hack on it.

Observed branches

Observed branches are for people who want to observe the work of somebody else without contributing commits to it. Similar to contribution branches, you cannot propose or ship observed branches, kill only deletes your local copy and not the tracking branch, git sync always uses the rebase sync-feature-strategy and will remove a local observed branch as soon as its tracking branch is gone, even if there are unmerged local commits.

Unlike with contributing branches, git sync does not push your local commits made to an observed branch to its tracking branch.

You can make any feature branch an observed branch by running git observe on it. Convert an observed branch back to a feature branch by running git hack on it.

Parked Branches

Parked branches don't get synced at all unless you run git sync directly on a parked branch. You might want to park a branch if you

  • want to intentionally keep the branch at an older state
  • don't want to deal with merge conflicts on this branch right now
  • reduce load on your CI server by syncing only your actively developed local branches

You can park any feature branch by running git park on it. Unpark a parked branch by running git hack on it.

git contribute [branches]

The contribute command makes some of your branches contribution branches.

Examples

Make the current branch a contribution branch:

git contribute

Make branches "alpha" and "beta" contribution branches:

git contribute alpha beta

Check out a remote branch (that exists at origin but not on your local machine) and make it a contribution branch:

git contribute somebody-elses-branch

Convert the current contribution branch back to a feature branch:

git hack

Convert the contribution branches "alpha" and "beta" back to a feature branch:

git hack alpha beta

git observe [branches]

The observe command makes some of your branches observed branches.

Examples

Observe the current branch:

git observe

Observe branches "alpha" and "beta":

git observe alpha beta

Check out a remote branch (that exists at origin but not on your local machine) and make it observed:

git observe somebody-elses-branch

Convert the current observed branch back to a feature branch:

git hack

Convert the observed branches "alpha" and "beta" back to feature branches:

git hack alpha beta

git park [branches]

The park command parks some of your branches.

Examples

Park the current branch:

git park

Park branches "alpha" and "beta":

git park alpha beta

Convert the current parked branch back to a feature branch:

git hack

Convert the parked branches "alpha" and "beta" back to feature branches:

git hack alpha beta

Additional commands

These Git Town commands allow handling edge cases beyond of the basic development workflow outlined earlier.

git compress [branches]

The compress command squashes all commits on a branch into a single commit. Git Town compresses feature branches and parked branches if they are currently checked out. It doesn't compress perennial, observed, and contribution branches.

Branches must be in sync to compress them, so run git sync and resolve possible merge conflicts before running this command.

Configuration

By default the compressed commit uses the commit message of the first commit in the branch. You can provide a custom commit message for the squashed commit with the -m <message> flag, which works similar to the -m flag for git commit.

To compress all branches in a branch stack provide the --stack switch.

Example: compressing commits on a branch

Assuming you have a feature branch with these commits:

$ git log --pretty=format:'%s'
commit 1
commit 2
commit 3

Let's compress these three commits into a single commit:

git compress

Now your branch has these commits:

$ git log --pretty=format:'%s'
commit 1

The new commit 1 now contains the changes from the old commit 1, commit 2, and commit 3.

Example: compressing using a custom commit message

Assuming you have a feature branch with these commits:

$ git log --pretty=format:'%s'
commit 1
commit 2
commit 3

Let's compress these three commits into a single commit:

git compress -m "compressed commit"

Now your branch has these commits:

$ git log --pretty=format:'%s'
compressed commit

The new compressed commit now contains the changes from the old commit 1, commit 2, and commit 3.

Example: Compressing all branches in a stacked change

Assuming you have a stacked change consisting of two feature branches. Each branch contains three commits.

main
 \
  branch-1
  |  * commit 1a
  |  * commit 1b
  |  * commit 1c
  branch-2
     * commit 2a
     * commit 2b
     * commit 2c

Let's compress the commits in all branches of this stack:

git compress --stack

Now your stack contains these branches and commits:

main
 \
  branch-1
  |  * commit 1a
  branch-2
     * commit 2a

As usual, the new commit 1a contains the changes made in branch 1, i.e. the changes from the old commit 1a, commit 1b, and commit 1c. The new commit 2a contains the changes made in branch 2, i.e. the changes from the old commit 2a, commit 2b, and commit 2c.

git kill [branch]

The kill command deletes the feature branch you are on including all uncommitted changes from the local and remote repository. It does not delete perennial branches.

When killing the currently checked out branch, you end up on the previously checked out branch. If that branch also doesn't exist, you end up on the main development branch.

Arguments

If you provide an argument, git kill removes the branch with the given name instead of the current branch.

git rename-branch [old name] <new name>

The rename-branch command changes the name of the current branch in the local and origin repository. It aborts if the new branch name already exists or the tracking branch is out of sync.

Arguments

Provide the additional old_name argument to rename the branch with the given name instead of the currently checked out branch.

Renaming perennial branches requires confirmation with the --force/-f option.

git repo

The repo command ("show the repository") opens the homepage of the current repository in your default browser. Git Town can display repositories hosted on GitHub, GitLab, Gitea, and Bitbucket.

Configuration

Git Town automatically identifies the hosting platform type through the origin remote. You can override the type of hosting server with the hosting-platform setting.

Set the hosting-origin-hostname setting to tell Git Town about the hostname when using ssh identities.

git ship [branch name] [-m message]

Notice: Most people don't need to use the ship command. The recommended way to merge your feature branches is to use the web UI or merge queue of your code hosting service, as you already do. git ship is for edge cases like developing in offline mode.

The ship command ("let's ship this feature") squash-merges a completed feature branch into the main branch and removes the feature branch. After the merge it pushes the main branch to share the new commit on it with the rest of the world.

Git ship opens the default editor with a prepopulated commit message that you can modify. You can submit an empty commit message to abort the shipping process.

This command ships only direct children of the main branch. To ship a child branch, you need to first ship or kill all its ancestor branches.

Arguments

Similar to git commit, the -m parameter allows specifying the commit message via the CLI.

Configuration

If you have configured the API tokens for GitHub, GitLab, or Gitea and the branch to be shipped has an open proposal, this command merges the proposal for the current branch on your origin server rather than on the local Git workspace.

If your origin server deletes shipped branches, for example GitHub's feature to automatically delete head branches, you can disable deleting remote branches.

If sync-before-ship is enabled, Git Town syncs the current branch before executing the ship. This allows you to resolve merge conflicts on the feature branch instead of on the main branch. This helps keep the main branch green, but can delay shipping.

Installation commands

These commands help set up Git Town on your machine.

git town completions [bash|zsh|fish|powershell]

The completions command outputs shell scripts that enable auto-completion for Git Town in Bash, Zsh, Fish, or PowerShell. When set up, typing git-town <tab key> in your terminal will auto-complete subcommands.

Bash

To load autocompletion for Bash, run this command:

source <(git-town completions bash)

To load completions for each session, add the above line to your .bashrc.

Zsh

To load autocompletions for Zsh, run this command:

source <(git-town completions zsh)

To load completions for each session, add the above line to your .zshrc.

Fish

To load autocompletions for Fish, run this command:

git-town completions fish | source

To load completions for each session, add the above line to your ~/.config/fish/config.fish.

Powershell

To install autocompletions for Powershell, run this command:

git-town completions powershell | Out-String | Invoke-Expression

To load completions for each session, add the above line to your PowerShell profile.

git town --version

Running git town --version displays the installed version of Git Town.

Configuration commands

Git Town prompts for required configuration information during usage. Git Town stores its configuration data inside Git configuration data. You can store configuration values in the local or global Git configuration depending on whether you want to share config settings between repositories or not. To see your entire Git configuration, run git config -l. To see only the Git Town configuration entries, run git config --get-regexp git-town. The following commands read and write the configuration entries for you so that you don't have to run Git configuration commands manually:

  • git town config - display or update your Git Town configuration
  • git town config setup - setup assistant for all config settings
  • git town offline - enable/disable offline mode
  • git town config sync-perennial-strategy - display or set the strategy to update perennial branches
  • git town config sync-feature-strategy - display or set the strategy to sync via merges or rebases

git town config [subcommand]

The config command displays and updates the local Git Town configuration.

Arguments

  • Running without a subcommand shows the current Git Town configuration.
  • The reset subcommand deletes all Git Town configuration entries.
  • The setup subcommand deletes all Git Town configuration entries and interactively prompting for new values.

git town config setup

This command launches Git Town's setup assistant. The setup assistant walks you through all configuration options for Git Town and gives you a chance to adjust them.

git town offline <yes|no>

The offline configuration command displays or changes Git Town's offline mode. Git Town skips network operations in offline mode.

Arguments

  • without an argument, displays the current offline status
  • when given yes, 1, on, or true enables offline mode
  • when given no, 0, off, or false disables offline mode

Preferences

You can see all preferences via the config command and change them via the setup assistant.

Git Town can store preferences in two places:

Git Town Configuration File

Git Town can be configured through a configuration file with named .git-branches.toml. To create one, execute:

git town config setup

Here is an example configuration file with the default settings:

push-new-branches = false
ship-delete-tracking-branch = true
sync-upstream = true

[branches]
main = ""             # must be set by the user
perennials = []
perennial-regex = ""

[hosting]
platform = ""         # auto-detect
origin-hostname = ""  # use the hostname in the origin URL

[sync-strategy]
feature-branches = "merge"
perennial-branches = "rebase"

hosting.platform

To talk to the API of your code hosting platform, Git Town needs to know which platform (GitHub, Gitlab, Bitbucket, etc) you use.

By default, Git Town determines the code hosting platform by looking at the URL of the origin remote. If that's not successful, for example when using private instances of code hosting platforms, you can tell Git Town through this configuration setting which code hosting platform you use.

The best way to change this setting is via the setup assistant.

values

You can use one of these values for the hosting platform setting:

  • remove the entry or leave it empty for auto-detection
  • github
  • gitlab
  • gitea
  • bitbucket

config file

In the config file the hosting platform is part of the [hosting] section:

[hosting]
platform = "<value>"

Git metadata

To configure the hosting platform in Git, run this command:

git config [--global] git-town.hosting-platform <value>

The optional --global flag applies this setting to all Git repositories on your machine. Without it, this setting applies to the current Git repo.

hosting.origin-hostname

If you use SSH identities, you can define the hostname of your source code repository with this setting. The given value should match the hostname in your SSH config file.

The best way to change this setting is via the setup assistant.

config file

In the config file the hosting platform is part of the [hosting] section:

[hosting]
origin-hostname = "<hostname>"

Git metadata

To configure the origin hostname in Git, run this command:

git config [--global] git-town.hosting-origin-hostname <hostname>

The optional --global flag applies this setting to all Git repositories on your local machine. When not present, the setting applies to the current repo.

github-token

Git Town can interact with GitHub in your name, for example to update pull requests as branches get created, shipped, or deleted. To do so, Git Town needs a personal access token with the repo scope. You can create one in your account settings.

The best way to enter your token is via the setup assistant.

config file

Since your API token is confidential, you cannot add it to the config file.

Git metadata

You can configure the API token manually by running:

git config [--global] git-town.github-token <token>

The optional --global flag applies this setting to all Git repositories on your local machine. When not present, the setting applies to the current repo.

gitlab-token

Git Town can interact with GitLab in your name, for example to update pull requests as branches get created, shipped, or deleted. To do so, Git Town needs a personal access token with api scope. You can create one in your account settings.

The best way to enter your token is via the setup assistant.

config file

Since your API token is confidential, you cannot add it to the config file.

Git metadata

You can configure the API token manually by running:

git config [--global] git-town.gitlab-token <token>

The optional --global flag applies this setting to all Git repositories on your local machine. When not present, the setting applies to the current repo.

main-branch

This setting stores the name of the main branch. The main branch is the default parent branch for new feature branches created with git hack and the default branch into which Git Town ships finished feature branches.

The best way to change this setting is via the setup assistant. Git Town commands also prompt for this setting if needed.

config file

In the config file the main branch is part of the [branches] section:

[branches]
main = "config-main"

Git metadata

To configure the main branch in Git, run this command:

git config [--global] git-town.main-branch <value>

The optional --global flag applies this setting to all Git repositories on your local machine. When not present, the setting applies to the current repo.

offline

git-town.offline=<true|false>

If you have no internet connection, certain Git Town commands that perform network requests will fail. Enabling offline mode omits all network operations and thereby keeps Git Town working.

This setting applies to all repositories on your local machine.

set via CLI

To put Git Town into offline mode, execute the git town offline command.

Git metadata

git config --global git-town.offline <true|false>

push-hook configuration setting

The "push-hook" setting determines whether Git Town allows or prevents Git hooks while pushing branches. Hooks are enabled by default. If your Git hooks are slow, you can disable them to speed up branch syncing.

When disabled, Git Town pushes using the --no-verify option. This omits the pre-push hook.

The best way to change this setting is via the setup assistant.

config file

To configure the push hook in the configuration file:

push-hook = false

Git metadata

To configure the push hook manually in Git, run this command:

git config [--global] git-town.push-hook <true|false>

The optional --global flag applies this setting to all Git repositories on your local machine. When not present, the setting applies to the current repo.

push-new-branches

By default, Git Town does not push new feature branches to the origin remote since that would make creating branches slower and triggers an unnecessary CI run for a branch containing no changes. Running git sync or git propose later will push the branch to origin. If you prefer to push new branches upon creation, enable this configuration option.

in config file

push-new-branches = true

in Git metadata

To enable pushing new branches in Git, run this command:

git config [--global] push-new-branches <true|false>

The optional --global flag applies this setting to all Git repositories on your machine. Without it, this setting applies to the current Git repo.

Branch lineage

Configuration entries of the form git-town-branch.<branch>.parent=<branch> store the parents of Git branches. You can ignore these configuration entries, Git Town maintains them as it creates and removes feature branches.

perennial-branches

Perennial branches are long-lived branches. They have no parent and are never shipped. Typical perennial branches are main, master, development, production, staging, etc.

You can see the configured perennial branches via the config command and change them via the setup assistant.

configure in config file

In the config file the perennial branches are defined as part of the [branches] section:

[branches]
perennials = [ "branch", "other-branch" ]

configure in Git metadata

You can configure the perennial branches manually by running:

git config [--global] git-town.perennial-branches "branch other-branch"

The optional --global flag applies this setting to all Git repositories on your local machine. When not present, the setting applies to the current repo.

bulk-define perennial branches

If you have many perennial branches that follow the same naming schema, like release-v4.0-rev.1, release-v4.0-rev.2, etc, you can define a regular expression for them instead of listing them one by one.

pererennial-regex

All branches matching this regular expression are considered perennial branches.

configure in config file

In the config file the perennial regex exists inside the [branches] section:

[branches]
perennial-regex = "release-*"

configure in Git metadata

You can configure the perennial branches manually by running:

git config [--global] git-town.perennial-regex 'release-.*'

The optional --global flag applies this setting to all Git repositories on your local machine. When not present, the setting applies to the current repo.

ship-delete-tracking-branch

Some code hosting platforms like GitHub and GitLab can delete the tracking branch when shipping via their API. In this case the tracking branch is already gone when git ship tries to delete it, resulting in an error. To prevent this error, set the ship-delete-tracking-branch setting to false so that Git Town does not try to delete the tracking branch.

The best way to change this setting is via the setup assistant.

in config file

ship-delete-tracking-branch = false

in Git metadata

To configure this setting in Git, run this command:

git config [--global] git-town.ship-delete-tracking-branch <true|false>

The optional --global flag applies this setting to all Git repositories on your local machine. When not present, the setting applies to the current repo.

sync-before-ship

Syncing before shipping allows you to resolve merge conflicts and any associated problems on the feature branch instead of the main branch. This helps keep the main branch green. The downside of syncing before shipping is that it will trigger another CI run and might block shipping until CI is green again. Syncing before shipping therefore makes the most sense when shipping locally on your machine.

The best way to change this setting is via the setup assistant.

values

When set to true, git ship syncs the branch to ship before shipping. When set to false (the default value), git ship does not sync the branch before shipping.

in config file

To configure sync-before-ship in the configuration file:

sync-before-ship = false

in Git metadata

To manually configure sync-before-ship in Git, run this command:

git config [--global] git-town.sync-before-ship <true|false>

The optional --global flag applies this setting to all Git repositories on your local machine. When not present, the setting applies to the current repo.

sync-feature-strategy

The sync-feature-strategy setting specifies how to update local feature branches with changes from their parent and tracking branches.

options

merge

When using the "merge" sync-feature-strategy, git sync merges the parent and tracking branches into local feature branches.

merge is the default value because it is the safest and easiest option.

rebase

When set to rebase, git sync rebases local feature branches against their parent branches and then does a safe force-push of your rebased local commits to the tracking branch. This safe force-push uses Git's --force-with-lease and --force-if-includes switches to guarantee that the force-push will never overwrite commits on the tracking branch that haven't been integrated into the local Git history.

If the safe force-push fails, Git Town rebases your local branch against its tracking branch to pull in new commits from the tracking branch. If that leads to conflicts, you have a chance to resolve them and continue syncing by running git town continue.

When continuing the sync this way, Git Town tries again to safe-force-push and rebase until the safe-force-push succeeds without removing commits from the tracking branch that aren't part of the local Git history.

This can lead to an infinite loop if you do an interactive rebase that removes commits from the tracking branch while syncing it. You can break out of this infinite loop by doing a less aggressive rebase that doesn't remove the remote commits. Finish the git sync command and then clean up your commits via a separate interactive rebase after the sync. At this point another sync will succeed because the commits you have just cleaned up are now a part of your local Git history.

The rule of thumb is that pulling in new commits via git sync and cleaning up old commits must happen separately from each other. Only then can Git guarantee that the necessary force-push happens without losing commits.

change this setting

The best way to change this setting is via the setup assistant.

config file

In the config file the sync-feature-strategy is part of the [sync-strategy] section:

[sync-strategy]
feature-branches = "merge"

Git metadata

To manually configure the sync-feature-strategy in Git, run this command:

git config [--global] git-town.sync-feature-strategy <merge|rebase>

The optional --global flag applies this setting to all Git repositories on your local machine. When not present, the setting applies to the current repo.

sync-perennial-strategy

The sync-perennial-strategy setting specifies how to update local perennial branches with changes from their tracking branches.

options

When set to rebase (the default value), Git Town rebases local perennial branches against their tracking branch. When set to merge, it merges the tracking branch into the local perennial branch.

The best way to change this setting is via the setup assistant.

in config file

In the config file the sync-perennial-strategy is part of the [sync-strategy] section:

[sync-strategy]
perennial-branches = "rebase"

in Git metadata

To manually configure the sync-perennial-strategy in Git, run this command:

git config [--global] git-town.sync-perennial-strategy <merge|rebase>

The optional --global flag applies this setting to all Git repositories on your local machine. When not present, the setting applies to the current repo.

sync-upstream

The sync-upstream setting configures whether to pull in updates from the upstream remote. This is intended for codebases that are forks of other codebases and want to stay in sync with the codebase they are forked from.

options

When set to true (the default value), git sync also updates the local main-branch with changes from its counterpart in the upstream remote. When set to false, git sync does not pull in updates from upstream even if that remote exists.

The best way to change this setting is via the setup assistant.

in config file

In the config file the sync-upstream setting can be set like this:

sync-upstream = true

in Git metadata

To manually configure sync-upstream in Git, run this command:

git config [--global] git-town.sync-upstream <true|false>

The optional --global flag applies this setting to all Git repositories on your local machine. When not present, the setting applies to the current repo.