Alrighty, you want to get compiling. We love you already. Your parents raised you right. Let's get started.
- Overview
- CLI-only development
- The Basics
- Debugging
- Troubleshooting
- Building
- Design
- Contributing
- Some Other Random Notes
- Development mode OAuth login
- Joining the GitButler Team
So how does this whole thing work?
It's a Tauri app, which is basically like an Electron app, in that we can develop a desktop app from one source with multiple OS targets and write the UI in HTML and Javascript. Except instead of Node for the filesystem access part, Tauri uses Rust.
So everything that hits disk is in Rust, everything that the user sees is in HTML/JS. Specifically we use Svelte in Typescript for that layer.
For a deep dive into the architecture, see DEEPWIKI.
The easiest way to get started is by hacking on the but CLI.
You only need Rust installed…1
$ cd gitbutler-repo
$ curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh…to build and run the CLI:
$ cargo build -p but
$ cargo run -p but -- --help
$ cargo run -p but -- -C /path/to/git-repo statusTo test only the CLI:
$ cargo test -p butUseful locations in the source tree:
crates/but/src/argsfor CLI argument parsing and help textcrates/but/src/commandfor command implementationscrates/but/testsfor integration tests
OK, let's get it running.
First of all, this is a Tauri app, which uses Rust for the backend and Javascript for the frontend. So let's make sure you have all the prerequisites installed.
- Tauri Dev Deps (https://tauri.app/start/prerequisites/#system-dependencies)
On Mac OS, ensure you've installed XCode and cmake. On Linux, if you're on Debian or one of its derivatives like Ubuntu, you can use the following command.
Linux Tauri dependencies
$ sudo apt update
$ sudo apt install libwebkit2gtk-4.1-dev \
build-essential \
curl \
wget \
file \
libxdo-dev \
libssl-dev \
libayatana-appindicator3-dev \
librsvg2-dev \
cmake- Rust
For both Mac OS and Linux, you can use the following rustup quick install script to get all the necessary tools.
$ cd gitbutler-repo
$ curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh- Node
Next, ensure you've got at least Node 20 installed. If you're on Mac OS or Linux and you're missing node, you can use your favorite package manager like brew or apt.
Alternatively, you can use the following Node installer from Vercel to get the latest version.
$ curl https://install-node.vercel.app/latest > install_node.sh
$ sudo ./install_node.sh- pnpm
Finally, we use pnpm as our javascript package manager. You can leverage corepack, which comes shipped with node, to install and use the pnpm version we defined in our package.json.
$ cd gitbutler-repo
$ corepack enableNext, install the app dependencies.
I hope you have some disk space for 300M of node_modules, because this bad
boy will fill er up:
$ pnpm install # This should now ask you to confirm the download, installation, and use of pnpm via corepackYou'll have to re-run this occasionally when our deps change.
Note
We use turborepo as our monorepo tooling and by default Vercel collects some basic telemetry. If you'd like to disable this, please run pnpm exec turbo telemetry disable once in the project's root directory after installing dependencies.
First, run cargo build such that supplementary bins such as gitbutler-git-askpass are created (Note the default folder (target) will be used for the build):
$ cargo buildNow you should be able to run the app in development mode:
$ pnpm dev:desktopBy default it will not print debug logs to console. If you want debug logs, set LOG_LEVEL environment variable:
$ LOG_LEVEL=debug pnpm dev:desktopIn order to have a PR accepted, you need to make sure everything passes our Linters, so make sure to run these before submitting. Our CI will shame you if you don't.
Javascript:
$ pnpm lint
$ pnpm formatRust:
$ cargo clippy # see linting errors
$ cargo fmt # format codeNow that you have the app running, here are some hints for debugging whatever it is that you're working on.
The app writes logs into:
stdoutin development mode- The Tauri logs directory
One can get performance log when launching the application locally as follows:
GITBUTLER_PERFORMANCE_LOG=1 LOG_LEVEL=debug pnpm tauri devFor more realistic performance logging, use local release builds with --release.
GITBUTLER_PERFORMANCE_LOG=1 LOG_LEVEL=debug pnpm tauri dev --releaseOften the behaviour depends on the current context: the repository being displayed. Next to logs, it's useful to learn how it's structured.
To do that, launch the application from a terminal as shown in the paragraph above this one, or right below, but with graphviz installed.
The dot program should be available in PATH so it can run from the terminal.
Doing so can look like this on MacOS, for example:
GITBUTLER_PERFORMANCE_LOG=1 /Applications/GitButler/Contents/MacOS/gitbutler-tauriGITBUTLER_PERFORMANCE_LOG=1 /Applications/GitButler\ Nightly.app/Contents/MacOS/gitbutler-tauriThen, within the application, type dot in any non-editable portion of the GUI, like the cheat code that it is.
This will pop open an SVG version of the graph that GitButler uses to create the workspace projection.
We are also collecting tokio's runtime tracing information that could be viewed using tokio-console:
- development:
$ tokio-console
- nightly:
$ tokio-console http://127.0.0.1:6668
- production:
$ tokio-console http://127.0.0.1:6667
Common issues and solutions when developing GitButler.
If you're experiencing issues with the dev:desktop target failing to start, especially on macOS with case-sensitive filesystems, this may be related to Turborepo's handling of case-sensitive volumes.
Solution: See the related issue at vercel/turborepo#8491 for current workarounds.
If builds are hanging or behaving unexpectedly:
# Stop the turbo daemon
pnpm exec turbo daemon stop
# Clear turbo cache
pnpm exec turbo daemon clean
# Restart development
pnpm dev:desktopIf you're seeing stale builds or unexpected behavior:
rm -rf .turbo node_modules
pnpm install
# Optional (Rust artifacts):
cargo cleanUse the Node version pinned by .nvmrc (currently LTS “jod” / Node 22):
nvm install
nvm use
node -vUse pnpm via Corepack (avoid global installs):
corepack enable
corepack pnpm -v
# optionally pin a major:
corepack prepare pnpm@10 --activateFor issues specific to our toolchain components:
If none of these solutions work, please check our GitHub Issues or create a new issue with detailed information about your system and the error you're encountering.
To build the app in production mode, run:
$ pnpm tauri build --features devtools,builtin-but,disable-auto-updates --config crates/gitbutler-tauri/tauri.conf.nightly-local.jsonThis will make an asset similar to our nightly build.
Building on Windows is a bit of a tricky process. Here are some helpful tips.
We use pnpm, which requires a relatively recent version of Node.js.
Make sure that the latest stable version of Node.js is installed and
on the PATH, and then npm install -g pnpm.
Sometimes npm's prefix is incorrect on Windows, we can check this via:
npm config get prefixIf it's not C:\Users\<username>\AppData\Roaming\npm or another folder that is
normally writable, then we can set it in Powershell:
mkdir -p $APPDATA\npm
npm config set prefix $env:APPDATA\npmAfterwards, add this folder to your PATH.
A Perl interpreter is required to be installed in order to configure the openssl-sys
crate. We've used Strawberry Perl without issue.
Make sure it's installed and perl is available on the PATH (it is by default
after installation, just make sure to restart the terminal after installing).
Scoop users can install this via scoop install perl.
Note that it might appear that the build has hung or frozen on the openssl-sys crate.
It's not, it's just that Cargo can't report the status of a C/C++ build happening
under the hood, and openssl is large. It'll take a while to compile.
To build it, one needs to export the path to the perl installation to use. The line below will do the trick in a git-bash.
export OPENSSL_SRC_PERL="c:/Strawberry/perl/bin/perl.exe"To make this change permanent, one would one can add this change (and others) to the ~/.bash_profile.
echo 'export OPENSSL_SRC_PERL="c:/Strawberry/perl/bin/perl.exe"' >> ~/.bash_profileThis paragraph is about crosscompilation to x86_64-MSVC from ARM Windows, a configuration typical for people with Apple Silicon and Parallels VMs, which only allow ARM Windows to be used.
The windows dependency on gitbutler-git doesn't currently compile on ARM,
which means cross-compilation to x86-64 is required to workaround that. Besides,
most users will probably still be on INTEL machines, making this capability
a common requirement.
In a Git bash, with MSVC for x86-64 installed on the system, run the following
to prepare the environment.
export TRIPLE_OVERRIDE=x86_64-pc-windows-msvc
export CARGO_BUILD_TARGET=x86_64-pc-windows-msvc
# for good measure
export OPENSSL_SRC_PERL="c:/Strawberry/perl/bin/perl.exe"Here is how to produce a nightly release build:
pnpm tauri build --features windows,devtools --config crates/gitbutler-tauri/tauri.conf.nightly.json
And this is how to get a local developer debug build:
pnpm tauri dev --features windows --target x86_64-pc-windows-msvcNote that it's necessary to repeat the --target specification as otherwise the final copy operation doesn't work,
triggered by tauri itself.
We use Figma for our design work. If you're a designer (and even if you're not), you want to contribute to the design of GitButler, or your work involves UI, you could duplicate our design file.
GitButler design: Figma file 🎨
Now that you're up and running, if you want to change something and open a PR for us, make sure to read CONTRIBUTING.md to make sure you're not wasting your time.
Most of this is for internal GitButler use, but maybe everyone else will find it interesting too.
I always forget how to do this, but when we update our app icon, run this to import it.
$ pnpm tauri icon path/to/icon.pngBuilding is done via GitHub Action.
Go to the link and select Run workflow from the desired branch.
When running the release action,
you will have to choose one of major, minor, or patch release type. Action will generate a new version based on your input and current
version found at https://app.gitbutler.com/releases.
To publish a version that you've just build, use Release Manager.
By default, you will not be able to log into GitButler using Github/Google because the base url does not match. To be able to do this add ( or update ) the following line to your .env.development file. You will need to create the file if it does not exist.
PUBLIC_API_BASE_URL=https://app.gitbutler.com/
If you are interested in joining our small but tightly knit engineering team, we are currently looking for the following roles:
- Senior Rust developer (SF, Berlin or Remote)
- Senior TypeScript developer (SF, Berlin or Remote)
- Gerrit developer (SF, Berlin or Remote)
This is a list of crates/modules that we want to eliminate or split into smaller crates:
- gitbutler-reference (just bad)
- gitbutler-branch-actions (contains functionality outside of the virtual branch domain (e.g. commit actions etc.))
- gitbutler-branch (contains
diffandbranchcontexts due to a cyclic dependency) - gitbutler-url (this is a huge mess and ideally we need none of it)
- gitbutler_repo::config (seems like the wrong abstraction)
Footnotes
-
In practice,
cargo build -p butalso builds native dependencies such asgit2with vendoredopensslandlibgit2, so you still need a working C toolchain. On Linux, that commonly means tools such asbuild-essential,make,perl,cmake, andpkg-config; on macOS, install Xcode Command Line Tools. On Windows, you’ll need a working MSVC-based toolchain and related native dependencies; see Building on Windows below for details (includingperlforopenssl-sys). If you already completed the desktop prerequisites in The Basics, you already have the stricter setup. If you already completed the desktop prerequisites in The Basics below, you already have the stricter setup. ↩