Developing the Git Town source code
May 21, 2026 ยท View on GitHub
This page provides guidance for contributing to the Git Town codebase. For a comprehensive understanding of the architecture, refer to ARCHITECTURE.md.
Folders
This monorepo contains a number of codebases:
- internal and pkg: Git Town, a CLI application written in Go
- website: the Git Town website, an mdBook application
- features: end-to-end tests for Git Town
- installer: the Windows installer for Git Town
- tools: custom-made linters for the Git Town codebase
- source code for tool
Setup
- install Go version 1.26
- install Make
- Mac and Linux users have this out of the box
- Windows users can install
Make for Windows or
run
choco install makeif Chocolatey is available.
- If you want to use the Git Town executable compiled from source,
add
~/go/bin(or wherevergo installputs executables on your machine) to your $PATH environment variable. - run all CI tests locally:
make test - faster smoke test during development:
make test-go - install Git Town locally into
~/go/bin:make install - To auto-format changes when committing,
run
make setup-githooks.
Dependencies
Add an external Go dependency:
- run
go get [dependency]inside the Git Town folder to register the dependency - use the new dependency somewhere in the code
- run
go mod vendorto vendor it - run
go mod tidyto clean up
Update an external Go module:
go get <path>
Update all external Go modules:
make update
Unit tests
Run unit tests for packages containing changes:
make unit
Run all unit tests no matter what has changed:
make unit-all
Run all unit tests with race detection:
make unit-race
Run an individual unit test:
go test src/cmd/root_test.go
go test src/cmd/root_test.go -v -run TestIsAcceptableGitVersion
End-to-end tests
Git Town uses an extensive end-to-end test suite that models a wide variety of situations in which Git Town can be used. This helps ensure Git Town behaves correct in these situations and debug Git Town when it doesn't.
Run all E2E tests
Run the end-to-end tests during development (nicer output):
make cuke
Run the end-to-end tests as they run on CI:
make cukeall
Run a subset of E2E tests
Run all tests in the features/append folder or file:
go test -- features/append
To run individual Cucumber scenarios,
add a @this flag to the scenario you want to run.
Example:
@this
Scenario: my awesome scenario
Then run only the scenarios that have a @this tag:
make cukethis
Run all files named es.feature:
find . -name es.feature | xargs go test --
Stubbing out forges in E2E tests
Certain tests require that the Git remote points to an actual GitHub, Gitea,
GitLab, Bitbucket, or Forgejo address.
An example is using this value to determine the forge type.
Using such a setting would cause git push operations in this test to also go
to GitHub.
We want to avoid this, because it's slow, brittle,
and stresses the external forges.
To prevent this, keep the actual setting pointed to the local remote.
Set an environment variable GIT_TOWN_REMOTE with the desired value of the
development remote.
Git Town will use that value for internal calculations,
instead of what is configured in the repo.
Running on Windows
If Cucumber tests produce garbled output on Windows, try running them inside Git Bash. See this issue for details.
Pausing end-to-end tests
To pause an end-to-end test so
that you have time to inspect the status of the Git repository created by the
test, add the step And inspect the repo.
The test runner will pause and print the path of the test workspace.
You can cd into that path in a separate terminal window
and inspect the repos there.
The developer's repo is in the repo folder.
The remote repo (that would normally be on GitHub) is in the origin folder.
Finding the right SHAs
Some end-to-end tests contain placeholders for commit SHAs.
To find the correct placeholder, add the step And inspect the commits.
This displays all SHAs in the repo, together with the placeholder to be used.
Possible placeholders are defined in here.
Inspecting variables
Inspect basic variables in a unit test:
fmt.Printf("%#v\n", variable)
Inspect more complex variables:
import "github.com/davecgh/go-spew/spew"
spew.Dump(variable)
- or -
pretty.Ldiff(t, var1, var2)
Debug an E2E test on the CLI
To see the CLI output of the shell commands in a Cucumber test,
as well as the Git commands that the Git Town test suite runs under the hood,
add a tag @debug above the feature or scenario you want to debug:
@debug @this
Scenario: my awesome scenario
To see all Git commands that the test runner and the Git Town command execute,
run the Git Town command with the --verbose option.
As an example, if the step When I run "git-town append new" mysteriously
fails, you could change it to When I run "git-town append new -v".
Also add the tags @debug @this to see the CLI output on the console.
To get a quick glance of which status the repo is at any point in time,
insert the step And display "<command_>" running whatever command you want to
execute in the Git repo under test.
Example: And display "git status".
To manually inspect the local
and remote Git repositories used in an end-to-end test,
insert the step And inspect the repo.
This step will make Cucumber print the path of the workspace and wait
until you hit ENTER.
Debug an E2E test in VSCode
Debug a Godog Cucumber feature in VSCode:
- open
main_test.go - change the path of the test to execute
- set a breakpoint in your test code
- run the
debug a testconfiguration in the debugger
Locate a hanging end-to-end test
End-to-end tests sometimes hang.
To find the hanging test,
you can execute subsets of tests using go test -- features/<path>
where path is either a subfolder or file inside the "features" folder.
Alternatively, open main_test.go,
change Format to pretty and Concurrency to 1,
and run the entire test suite.
The detailed output will give you hints at which test fails.
Automatically update E2E test files
Our E2E tests act as golden files: they embody the expected output that all future test runs must match. When we intentionally change Git Town's behavior, we also need to update possibly hundreds of E2E tests.
To streamline this, run:
make cuke-update
When running in this mode, and an E2E test fails,
the test runner updates the .feature file, rather than failing the test.
You must then inspect the test files to verify
whether the updated tests are correct.
If needed, run make fix to format the
recorded Gherkin code.
Configure the Cucumber IDE extension
To configure the official
Cucumber extension
add this to your settings.json file:
"cucumber.features": [
"features/**/*.feature",
],
"cucumber.glue": [
"internal/test/cucumber/steps.go"
]
This enables useful functionality:
- auto-complete steps in
.featurefiles go to definitionon a step in a feature file to see the code that runs when this step executes
Run linters
Quick and efficient linter during development:
make lint
Run all linters reliably like on CI:
make lint-all
If the linter complains about formatting issues, run the formatters:
make fix
The Git Town codebase relies heavily on automation like linters to find as many code smells as possible. If a linter creates false positive warnings, it is okay to disable it for that line.
Debug the dialogs
Run git town debug to see the commands to manually test Git Town's dialogs.
Learn about the code and test architecture
See file ARCHITECTURE.md.
Website
The source code for the website is in the website folder. This folder contains its own Makefile for activities related to working on the website.
To work on the website, cd into the website folder
and run make serve to start a
local development server.
The production site auto-updates on changes to the main branch.
The site hoster is Netlify.
Netlify configuration is in netlify.toml.