# Tutorial

> Fifteen minutes with grit. Create a repository, record some changes, work on a branch, and share it with a remote.

This walkthrough covers the commands you'll use every day. It assumes you have [installed grit](https://grit-scm.com/docs/install/index.md) and know roughly what a commit and a branch are. The output shown is what `grit` prints, minus the colors.

Regenerated on 2026-10-07 by running the listed commands with `grit` built from this repository (`cargo build --release -p grit-cli`), with `NO_COLOR=1` and author identity `Ada Lovelace <ada@example.com>`.

## Tell grit who you are

Every commit records an author. Set your name and email once, in your global config:

```console
$ grit config --global user.name "Ada Lovelace"
$ grit config --global user.email ada@example.com
```

`grit` reads and writes the same config files as Git, so if you've already set these up for Git, you can skip this step.

## Create a repository

```console
$ grit init project
Initialized empty repository in /workspace/project/.git
$ cd project
```

To work on an existing project instead, copy it with [`grit clone`](https://grit-scm.com/docs/clone/index.md) and skip ahead to the next section:

```console
$ grit clone https://github.com/gitbutlerapp/grit.git
```

## Your home base: grit status

Running `grit` with no arguments shows where you are and what's changed. Add a couple of files and look:

```console
$ echo "# Notes" > README.md
$ echo "fn main() {}" > main.rs
$ grit
On main — no commits yet

Untracked
  ?  untracked     README.md
  ?  untracked     main.rs

→ grit add <file> to stage
```

The last line always suggests the next step. You'll come back to this screen a lot; [`grit status`](https://grit-scm.com/docs/status/index.md) (or `grit st`) shows the same thing.

## Record a commit

[`grit commit`](https://grit-scm.com/docs/commit/index.md) stages every change in the working tree and records it in one step:

```console
$ grit commit "Start the project"
[main 310fdb0] Start the project
2 changes committed
```

There is no separate staging step to remember. [`grit add`](https://grit-scm.com/docs/add/index.md) exists for when you want to stage particular files and check them in `grit status` first, but `grit commit` always records every change.

Look at the history with [`grit log`](https://grit-scm.com/docs/log/index.md):

```console
$ grit log
  310fdb0  ada  just now  Start the project
```

## Work on a branch

Create a branch and switch to it with [`grit switch -c`](https://grit-scm.com/docs/switch/index.md):

```console
$ grit switch -c feature
Created and switched to branch feature
```

Make a change and look at it with [`grit diff`](https://grit-scm.com/docs/diff/index.md) before committing:

```console
$ printf 'fn main() {\n    println!("hi");\n}\n' > main.rs
$ grit diff

main.rs
@@ -1 +1 @@
 1    │ - fn main() {}
    1 │ + fn main() {
    2 │ +     println!("hi");
    3 │ + }
```

The two number columns are the old and new line numbers. Commit the change:

```console
$ grit commit "Say hi"
[feature 2e409e2] Say hi
1 change committed
```

[`grit show`](https://grit-scm.com/docs/show/index.md) displays a commit, its message and the files it changed. With no argument, it shows the latest commit:

```console
$ grit show
branch feature
commit 2e409e26f8b370ea1928a8fb93dcf2e025418e1f
Author: Ada Lovelace <ada@example.com>
Date:   2026-10-07 14:55:47 +0000

    Say hi

 main.rs |   4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
```

## Merge it back

Switch back to `main` and [merge](https://grit-scm.com/docs/merge/index.md) the branch in. Nothing else has happened on `main`, so `grit` just moves `main` forward:

```console
$ grit switch main
Switched to branch main
$ grit merge feature
Fast-forwarded feature → 2e409e2
```

The branch is done, so [delete it](https://grit-scm.com/docs/branch/index.md):

```console
$ grit branch -d feature
Deleted branch feature (was 2e409e2).
```

`grit branch -d` refuses to delete a branch whose commits haven't been merged into the branch you're on. Use `-D` when you really mean it.

## Share it with a remote

A remote is another copy of the repository, usually on a server. Add one called `origin` with [`grit remote add`](https://grit-scm.com/docs/remote/index.md), then [push](https://grit-scm.com/docs/push/index.md):

```console
$ grit remote add origin https://github.com/ada/project.git
Added remote origin → https://github.com/ada/project.git
$ grit push
  pushed main → origin refs/heads/main
```

`grit push` sends the current branch to a branch with the same name on `origin`, creating it if needed. There are no upstream flags to set. For GitHub over HTTPS, [`grit auth`](https://grit-scm.com/docs/auth/index.md) signs you in, and `grit` offers to run it if a push fails for lack of credentials.

To get other people's work, run [`grit pull`](https://grit-scm.com/docs/pull/index.md). It fetches from the remote and brings your branch up to date, fast-forwarding when it can and recording a merge commit when both sides have new commits:

```console
$ grit pull
Merged origin/main into the current branch (91275a2)
```

If someone pushed before you, `grit push` is rejected and tells you what to do:

```console
$ grit push
  rejected origin refs/heads/main: not a fast-forward — run `grit pull` first
```

## Tag a release

[`grit tag`](https://grit-scm.com/docs/tag/index.md) marks the current commit, and `grit push --tags` publishes your tags:

```console
$ grit tag v0.1
Created tag v0.1
$ grit push --tags
  pushed --tags → origin refs/tags/v0.1
```

## When things conflict

`grit merge`, `grit pull` and `grit pick` never leave a half-finished merge behind. If the two sides change the same lines, `grit` lists the conflicting files and leaves your branch and working tree as they were. To resolve the conflict, run the merge with `git`, fix the files and commit. Conflict resolution in `grit` itself is on the roadmap.

`grit` also refuses to switch branches, merge or pull while you have uncommitted changes, so work in progress can't get mixed into a merge. Commit first.

## Scripting

Every command takes `--json` and prints a single JSON object, which is handy for scripts and agents. `--filter` picks out the part you need:

```console
$ grit status --json --filter '{branch, clean}'
{
  "branch": "main",
  "clean": true
}
```

See [Scripting with grit](https://grit-scm.com/docs/scripting/index.md) for details, and each command's page for its JSON fields.

## Where to go next

Every command has a man page with its options and examples. Start from the [command list](https://grit-scm.com/docs/index.md#commands).
