Jit is an alternative "porcelain" (wrapper/interface) for Git. It is intentionally opinionated, and aims to push the user to use Git in a very particular way, which the developer, at least, believes to be a superior way.
Some of the ways Jit differs from vanilla Git include:
- Worktrees as the standard workflow
- Baked-in support for triangular workflows (new branches are pushed to the user's fork by default)
- There are no special remote names such as "origin" or "upstream" - all remotes are named after the corresponding GitHub user.
It also includes some convenience commands, such as being able to apply a patch
directly from GitHub using jit apply
.
At the same time, Jit works within the language of Git - its repos are Git repos, its branches Git branches, and so on. This means you can still run standard Git commands in any repo or branch set up using Jit.
NB: although I use Jit extensively, it is still in development, and may naturally contain bugs and incomplete features. Please report issues here, or even better, open a PR.
- Git
- GitHub CLI (
gh
, for certain commands)
go install github.com/barrettj12/jit@latest
Jit uses the JIT_DIR
environment variable to determine where/how to store
Git repos. Inside this directory, it uses the following file structure:
${JIT_DIR}
├─ user1
│ ├─ repo1
│ │ ├─ branch1
│ │ ├─ branch2
│ │ ├─ ...
│ ├─ repo2
│ │ ├─ ...
├─ user2
│ ├─ repo3
│ ├─ ...
├─ ...
For example, say we have a repo located at
https://github.com/johnsmith/foo-app
with branches main
, stable
and exp
. When you run
jit clone https://github.com/johnsmith/foo-app
Jit will create the following file structure:
${JIT_DIR}
└─ johnsmith
└─ foo-app
├─ main
├─ stable
└─ exp
Each subdirectory of foo-app
is a worktree (see below) with the corresponding
branch checked out.
Worktrees are a great feature of Git added in later versions. They allow you to
check out multiple branches at once. Jit uses worktrees as the default workflow.
This makes it easy to work on multiple things simultaneously - just move to a
different directory, instead of fiddling around with git stash
, git switch
,
etc.
Modern software development (in teams) often uses a "triangular workflow" with three copies of the source code:
- A central "source" copy
- A remote fork
- A local copy
Developers pull changes from the source copy to their local copy, then push changes to their fork. After this, a pull request is opened to merge changes from their fork into the central source.
Git does support this kind of workflow, but it can be a lot of work to set it up and maintain it. Jit makes it easy by automatically setting up the remotes - Jit commands are designed to use a triangular workflow.
All remotes are named after the GitHub user by default. So, when you clone
https://github.com/ecma/gizmo
, the "origin" remote will be named ecma
,
while your personal fork will be the same as your GitHub username.
Clone a GitHub repository. Jit sets up the local repository with a bare/worktree structure, so that other Jit commands can use it.
jit clone <user> <repo>
jit clone <user>/<repo>
jit clone https://github.com/<user>/<repo>
Create a new worktree/branch. There are three different modes:
jit new <branch>
- create a new worktree for an existing branchjit new <branch> <base>
- create a new branch based on an existing branchjit new <remote>:<branch>
- check out a branch from someone else's remote
Update a given branch.
jit pull <branch>
Remove a given branch/worktree and its upstream remote.
jit rm <branch>
Squash all commits in the current branch into one. Requires a GitHub PR to be open on the branch.
Rebase the current branch against the latest version of the base branch. Requires a GitHub PR to be open on the branch.
Jit started from a series of Bash scripts I wrote to automate my Git workflow. At some point, I realised these scripts could be turned into a fully-fledged CLI tool.