DEVELOPMENT.md
Alrighty, you want to get compiling. We love you already. Your parents raised you right. Let's get started.
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 status
To test only the CLI:
$ cargo test -p but
Useful locations in the source tree:
crates/but/src/args for CLI argument parsing and help textcrates/but/src/command for command implementationscrates/but/tests for integration testsOK, 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.
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.
$ 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
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
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
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 enable
Next, 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 corepack
You'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 runpnpm exec turbo telemetry disableonce 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 build
Now you should be able to run the app in development mode:
$ pnpm dev:desktop
By default it will not print debug logs to console. If you want debug logs, set LOG_LEVEL environment variable:
$ LOG_LEVEL=debug pnpm dev:desktop
In 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 format
Rust:
$ cargo clippy # see linting errors
$ cargo fmt # format code
Now 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:
stdout in development modeOne can get performance log when launching the application locally as follows:
GITBUTLER_PERFORMANCE_LOG=1 LOG_LEVEL=debug pnpm tauri dev
For more realistic performance logging, use local release builds with --release.
GITBUTLER_PERFORMANCE_LOG=1 LOG_LEVEL=debug pnpm tauri dev --release
Often 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-tauri
GITBUTLER_PERFORMANCE_LOG=1 /Applications/GitButler\ Nightly.app/Contents/MacOS/gitbutler-tauri
Then, 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:
$ tokio-console
$ tokio-console http://127.0.0.1:6668
$ 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:desktop
If you're seeing stale builds or unexpected behavior:
rm -rf .turbo node_modules
pnpm install
# Optional (Rust artifacts):
cargo clean
Use the Node version pinned by .nvmrc (currently LTS “jod” / Node 22):
nvm install
nvm use
node -v
Use pnpm via Corepack (avoid global installs):
corepack enable
corepack pnpm -v
# optionally pin a major:
corepack prepare pnpm@10 --activate
For 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.json
This 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 prefix
If 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\npm
Afterwards, 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_profile
This 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-msvc
Note 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.png
Building 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:
This is a list of crates/modules that we want to eliminate or split into smaller crates:
diff and branch contexts due to a cyclic dependency)In practice, cargo build -p but also builds native
dependencies such as git2 with vendored openssl and libgit2, so you
still need a working C toolchain. On Linux, that commonly means tools such
as build-essential, make, perl, cmake, and pkg-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 (including
perl for openssl-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. ↩