High-level CLI for Git

Git Town adds Git commands that make software development more efficient by keeping Git branches better in sync with each other. This reduces merge conflicts and the number of Git commands you need to run.


screencast


Git is a flexible source code management system. The Git CLI (correctly) supports all possible ways of using Git equally well. It provides basic commands out of which Git users can implement their particular Git workflows. This generic design can make using the Git CLI repetitive in real life. As the screencast above demonstrates, typical development activities like creating, synchronizing, or shipping a feature branch require running multiple, sometimes dozens of Git commands.

Git Town adds a high-level layer of Git commands for these activities. These 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.

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 and even committing 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. It is possible to 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. But please make sure that all feature branches get squash-merged, for example by running git merge --squash or enabling them in your GitHub settings. If you don't know what squash-merges are, you probably want to learn about them and use them.

Installation

Git Town ships as a single self-contained binary. It doesn't bundle a Git client but uses the native Git installation on your machine.

macOS

The easiest way to install Git Town on macOS is via Homebrew:

brew install git-town

Git Town is available via MacPorts. You can also install Git Town manually or compile from source.

Windows

The easiest way to install Git Town on Windows is to download the Windows installer and run it. You can also install Git Town via scoop:

scoop bucket add org https://github.com/git-town/scoop.git
scoop install git-town

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

If you use the Windows Subsystem for Linux, please install wsl-open to allow the commands git town repo and git town new-pull-request 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_7.7.0_linux_intel_64.deb

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

rpm -i git-town_7.7.0_linux_intel_64.rpm

On Arch Linux, install the git-town package from the AUR.

You can install Git Town via Homebrew for Linux:

brew install git-town

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

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 our release feed to never miss a new release!

Uninstall

To remove Git Town from your system:

  1. remove Git Town's aliases: git town alias false
  2. remove the Git Town configuration from your repositories: in each repo, run git town config reset
  3. uninstall the program or manually delete the binary

Quick configuration

Git Town prompts for all the configuration information it needs. The commands below set additional configuration options that might be helpful in your use case. We will cover the full list of options later.

Shorter commands

Having to type git town <command> gets old. Git Town can install aliases for its commands that make them feel like native Git commands, i.e. allow you to run for example git hack instead of git town hack. To enable this feature:

git town alias true

To remove these aliases, run git town alias false.

API access to your hosting provider

Git Town can ship branches that have an open pull request by merging this pull request via your code hosting service's API. This feature is currently implemented for GitHub and Gitea only. To enable it, create an API token for your account at your code hosting provider.

Then run this command inside the folder that contains your Git repository to provide this API token to Git Town.

git config --add git-town.github-token <your api token>

Delete remote branches

Some code hosting providers automatically delete feature branches after merging them. This is a very useful feature that you should enable if possible. It can interfere with Git Town's attempts to also delete this branch after shipping it. To make Git Town play along, run:

git config git-town.ship-delete-remote-branch false

Shell autocompletion

Follow the instructions given by git-town help completions to install the autocompletions for your shell.

Commands

Run git town for an overview of all Git Town commands and git town help <command> for help with individual commands. Each Git Town command can be called like git town <command>. This user manual displays the commands in the shorter form available after running git town alias.

Typical development commands

Advanced development commands

Nested feature branches

Git Town configuration

Git Town setup

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 new-pull-request 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. Before it does that, it syncs the main branch to ensure commits into the new branch are on top of the current state of the repository.

Variations

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 new-branch-push-flag 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 current branch and its remote and parent branches with each other. When run on the main or a perennial branch, it pulls and pushes updates and tags to the tracking branch. When run on a feature branch, it additionally updates all parent branches and merges the direct parent into the current branch.

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.

Variations

With the --all parameter this command syncs all local branches and not just the branch you are currently on. This is more comprehensive but takes longer.

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

git new-pull-request

The new-pull-request command helps create a new pull request for the current feature branch. It does that by opening a browser window showing the new pull request page of your code hosting service. The form is prepopulated with the current branch and it's parent branch. This command syncs the current branch before opening the pull request.

Variations

You can create new pull requests for repositories hosted on GitHub, GitLab, Gitea and Bitbucket. When using self-hosted versions of these services, you can configure the hosting service type with the code-hosting-driver setting.

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

git ship [branch name] [-m message]

The ship command ("let's ship this feature") merges a completed feature branch into the main branch and removes the feature branch. Before the merge it syncs the branch to be shipped. 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 nested feature branch, you need to first ship or kill all its ancestor branches.

Variations

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

If you use GitHub or Gitea, have enabled API access to your hosting provider, and the branch to be shipped has an open pull request, this command merges pull requests via the API of the hosting service.

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

Advanced development commands

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

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 the main or perennial branches.

Variations

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

git prune-branches

The prune-branches command deletes all local branches whose tracking branch no longer exists. This usually means the branch was shipped or deleted on another machine.

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.

Variations

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 -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.

Variations

Git Town identifies the hosting service type by looking at the origin remote. You can override this detection with the code-hosting-driver setting.

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

Feature branch chains

The single responsibility principle applies to feature branches the same way it applies to code architecture. Like classes and functions, feature branches should also do only one thing. Implementing, refactoring, reviewing, and resolving merge conflicts on such single-responsibility branches is more straightforward than on branches that combine unrelated changes.

Git Town's branch chain feature automates working with multiple single-responsibility feature branches that form a chain in which changes from parent branches are visible in their child branches. This helps make complex changes as a series of smaller steps. As an 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 chain of connected 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 branch hierarchy:

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 branch hierarchy and creates the pull request for branch 2-rename-foo against branch 1-fix-typos. This way, that the pull request 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 branch hierarchy 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 ancestry 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 branch hierarchy that Git Town keeps track of. With branch 1-refactor shipped, our branch hierarchy now looks like this:

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

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 branch 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. Before it does that, it syncs the current branch to ensure commits into the new branch are on top of the current state of the repository.

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

Variations

If new-branch-push-flag is set, git append creates a remote 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. Before it does that, it syncs the current feature branch to ensure commits into the new branch are on top of the current state of the repository.

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

Variations

If the new-branch-push-flag 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-branch

The set-parent-branch 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 resolve merge conflicts between this branch and its new parent.

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 [subcommand]

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

Variations

  • 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 new-branch-push-flag [(true|false)]

The new-branch-push-flag command displays or updates the new-branch-push-flag configuration setting. If set to true, hack, append, and prepend push newly created feature branches to the origin remote. Defaults to false.

Variations

  • the --global flag displays or sets the "new-branch-push-flag" globally

git town main-branch [branch]

The main-branch command displays or sets the main development branch for a repository.

Variations

Without an argument, displays the main branch. With an argument, sets the main branch to the given value.

git town offline <true|false>

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

Variations

  • without an argument, displays the current offline status
  • when given true, enables offline mode
  • when given false, disables offline mode

git town perennial-branches [subcommand]

The perennial-branches command displays your perennial branches. Perennial branches are long-lived branches that are never shipped. Examples for perennial branches are master, main, development, production, or staging.

Variations

  • without a subcommand, displays the currently configured perennial branches
  • the update subcommand displays UI to set the perennial branches

git town pull-branch-strategy <rebase|merge>

The pull-branch-strategy command displays or sets your pull branch strategy. The pull branch strategy specifies which strategy to use when merging remote tracking branches into local branches for the main branch and perennial branches.

Variations

  • without an argument, displays the current branch strategy
  • with rebase, set the pull branch strategy to rebase
  • with merge, set the pull branch strategy to merge

Setup commands

These commands help install parts of Git Town.

git town alias (true|false)

The alias command adds or removes default global aliases. Global aliases make Git Town commands feel like native Git commands. When enabled, you can run git hack instead of git town hack. Please note that this can conflict with other tools that also define Git aliases. This command does not overwrite existing aliases. If you encounter issues, you can also set this manually for individual commands:

git config --global alias.hack 'town hack'

Variations

  • when given true, creates the aliases
  • when given false, removes the aliases

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

The completion command generates auto-completion scripts for Bash, Zsh, Fish, and PowerShell. With shell completions set up, typing git-town <tab key> in your terminal will auto-complete subcommands.

Bash

To install autocompletion for Bash, run this command:

source <(git-town completion bash)

Zsh

To install autocompletions for Zsh, run this command:

source <(git-town completion zsh)

Fish

To install autocompletions for Fish, run this command:

git-town completion fish | source

Powershell

To install autocompletions for Powershell, run this command:

git-town completion powershell | source

git town version

The version command displays the installed version of Git Town.

Preferences

Git Town uses these configuration settings:

code-hosting-driver

git-town.code-hosting-driver=<github|gitlab|bitbucket|gitea>

To talk to the API of your code hosting service, Git Town needs to know which code hosting service (GitHub, Gitlab, Bitbucket, etc) you use. Git Town can automatically figure out the code hosting driver by looking at the URL of the origin remote. In cases where that's not successful, for example when using private instances of code hosting services, you can tell Git Town which code hosting service you use via the code-hosting-driver preference. To set it, run

git config [--global] git-town.code-hosting-driver <driver>

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. <driver> can be "github", "gitlab", "gitea", or "bitbucket".

code-hosting-origin-hostname

git-town.code-hosting-origin-hostname=<hostname>

When using SSH identities, you can use this configuration setting to define the hostname of your source code repository by running:

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

<hostname> should match the hostname in your ssh config file. 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.github-token=<token>

To interact with the GitHub API in your name, Git Town needs a personal access token. After your create your token, run git config git-town.github-token <token> inside your code repository to store it in the Git Town configuration for the current repository.

main-branch-name

git-town.main-branch-name=<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.

Git Town automatically asks for this setting if needed. You can run the git town main-branch command to see or update the configured main branch.

new-branch-push-flag

git-town.new-branch-push-flag=<true|false>

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 new-pull-request will push the branch to origin later. If you prefer to push new branches upon creation, set this option to true by running:

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

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

offline

git-town.offline=<true|false>

If you have no internet connection, certain Git Town commands will fail trying to keep the local repository in sync with it's remote counterparts. Enabling offline mode via the git town offline command prevents this. In offline mode, Git Town omits all network operations. This setting applies to all repositories on your local machine.

parent

git-town-branch.<branch>.parent=<parent>

Configuration entries of this format store the name of the parent branch for each feature branch. You can ignore these configuration entries, Git Town maintains them as it creates and removes feature branches.

pererennial-branch-names

git-town.perennial-branch-names=<branch 1> <branch 2>

The perennial-branch-names setting lists the names of all perennial branches. Perennial branches are long-lived branches. They are never shipped. Examples for perennial branches are master, main, development, production, or staging.

You can see and update the configured perennial branches via the git town perennial-branches command.

pull-branch-strategy

git-town.pull-branch-strategy <rebase|merge>

The pull-branch-strategy setting specifies which strategy to use when merging the remote of the main branch and perennial branches into their local counterpart. If set to rebase (the default value), it updates local perennial branches by rebasing them against their remote branch. If set to merge, it merges the respective tracking branch into its local branch.

ship-delete-remote-branch

git-town.ship-delete-remote-branch=<true|false>

If set to true (default value), git ship deletes the remote tracking branch of shipped branches. Some code hosting services like GitHub also delete the remote branch when merging a pull request. In this case, change this setting to false so that Git Town skips deleting the tracking branch.

sync-upstream

git-town.sync-upstream=<true|false>

If your Git repository contains an upstream remote, git sync syncs the main branch with its upstream counterpart. You can disable this behavior by running git config git-town.sync-upstream false.