Lazygit is a Go-powered terminal UI for git. It makes complex git operations simple and visual.
· 4 min read

Lazygit: The terminal UI that makes git actually usable


I have a confession. I’ve been using git for over a decade and I still forget the syntax for interactive rebase. Every single time.

That’s why I use Lazygit, a terminal UI for git written in Go. It turns the operations I always have to look up into single keystrokes.

What is Lazygit?

Lazygit gives you a visual interface for git without leaving your terminal. Run lazygit in any repo and you get a panel-based view of your files, branches, commits and stash, all in one place. No switching to a GUI app. No Googling “git rebase onto” for the hundredth time.

It’s written entirely in Go, which is a big part of why it’s fast, portable and trivial to install. One binary, no dependencies.

Why Go is perfect for CLI tools

Go has become the default language for CLI tools, and Lazygit is a good demonstration of why.

The binary compiles to a single executable. No runtime, no dependency hell, just download and run. Cross-compilation means you can build for Linux, macOS and Windows from one machine, and Lazygit ships for all three. Startup is instant too. Go binaries launch in milliseconds, where Python or Node-based CLIs first have to spin up an interpreter.

If you’re building your own CLI tools, check out Cobra and Bubble Tea. Lazygit uses a custom TUI approach, but those two libraries power many popular Go CLIs.

Getting started with Lazygit

Installation is straightforward. On macOS with Homebrew:

brew install lazygit

On most Linux distros, use your package manager or download the binary directly from GitHub releases.

Once installed, navigate to any git repo and run:

lazygit

The layout puts status, files, branches, commits and stash on the left, diffs and details on the right, and command feedback along the bottom. Press ? for help at any time. That help screen is how I learned most of what follows.

Common operations made simple

Here’s where Lazygit earns its place. Operations that normally take several commands and a syntax check become single keystrokes.

Interactive rebase is the standout for me. Navigate to a commit, then press e to edit it, d to drop it, or s to squash it. That’s the whole workflow. Cherry-picking is similar: press c on the commits you want, switch to the target branch, and press v to paste them in.

Merge conflicts get the same treatment. Lazygit shows them inline, b takes both sides, and < or > picks one. Staging individual lines might be my favourite of the lot. Press enter on a file to open the diff, move to the lines you care about, and press space to stage just those. It makes the small, focused commits everyone claims to want actually easy to produce.

It’s the same instinct we apply to complex operations in Go code: break them into smaller, visible pieces. If you’ve worked with regex in Go, you know how much difference visual feedback makes when you’re debugging something opaque.

Customising Lazygit

Lazygit reads its config from ~/.config/lazygit/config.yml. Here’s a useful starter config:

gui:
  theme:
    selectedLineBgColor:
      - reverse
    selectedRangeBgColor:
      - reverse
  showIcons: true
  nerdFontsVersion: "3"

git:
  paging:
    colorArg: always
    pager: delta --dark --paging=never
  commit:
    signOff: true

keybinding:
  universal:
    quit: 'q'
    return: '<esc>'

The pager setting is the one to pay attention to. Piping diffs through delta gets you syntax highlighting, and it genuinely transforms the diff view.

Building your own TUI in Go

Lazygit’s codebase is worth studying if you fancy building a terminal UI yourself. It manages a surprising amount of state across those panels.

Here’s a stripped-down example of reading single keypresses for a TUI:

package main

import (
	"fmt"
	"os"
	"os/exec"
)

func main() {
	// Set terminal to raw mode for single keypress reading
	exec.Command("stty", "-F", "/dev/tty", "cbreak", "min", "1").Run()
	exec.Command("stty", "-F", "/dev/tty", "-echo").Run()
	defer exec.Command("stty", "-F", "/dev/tty", "echo").Run()

	var b []byte = make([]byte, 1)
	for {
		os.Stdin.Read(b)
		fmt.Printf("Key pressed: %s\n", string(b))
		if string(b) == "q" {
			break
		}
	}
}

That’s the crude version. Real TUI apps use libraries like tcell or tview for proper terminal handling: resizing, colours, mouse events, all the things the snippet above ignores.

The other thing a TUI forces you to take seriously is failure. A git operation can go wrong mid-flow and the UI has to recover gracefully, which is where Go’s approach to error handling does a lot of quiet work.

Tips for power users

A few of my favourite tricks once you’re past the basics. Custom commands let you add project-specific git aliases to your config and run them with @. Lazygit handles git worktrees too, so you can manage several branches checked out at once. z undoes almost anything, because Lazygit tracks your actions and can reverse them, which is very forgiving when a rebase goes sideways. / filters within any panel, handy for hunting down a specific commit or branch. And v selects multiple items so you can act on all of them in one go.

Wrapping up

Lazygit turned git from a frustration into something I actually enjoy using. The visual feedback means I understand what’s about to happen before it happens, and the shortcuts make me faster than raw git commands ever did for anything beyond the basics.

It’s also a great example of what Go is for: a fast, cross-platform terminal tool that solves a real problem and installs in one command.

Try it for a week. Then notice which git commands you’ve stopped typing.