Most of my workflow centers around the terminal, and a big part of that is git. I’ve been using lazygit for a while and it’s been great for most of my daily tasks.

For me, CLI tools need to be customizable or able to interact with other tools using pipes, redirects, or plugins. One tool will never solve everything, so they need to work together or let me make them do so.

I don’t use just lazygit though. In NeoVim I have GitSigns and Git Fugitive plugins installed that give me git stats in the editor, let me edit hunks, and perform git commands without leaving the editor. I use these for small, granular changes in the files I’m currently working on.

With GitSigns I can press <leader>gr to reset the hunk below the cursor or <leader>gR to reset the entire file.

I use Git Fugitive mainly for browsing git history. With <leader>gL I can see the history of the current file, which is extremely useful for understanding what changed and why.

The default lazygit diff is useful but not very pleasant to look at, so I customized its appearance and diff output. I use delta for a better diff experience. Here’s my ~/.config/git configuration:

[alias]
	pf = push --force-with-lease
[pull]
	rebase = false
[fetch]
	prune = true

[diff]
    colorMoved = default
    algorithm = histogram

[merge]
    conflictstyle = zdiff3

[core]
    pager = delta

[include]
    path = /home/cacarico/ghq/github.com/catppuccin/delta/catppuccin.gitconfig

[delta]
	features = catppuccin-frappe
    keep-plus-minus-markers = true
    paging = never
    line-numbers = true
    file-style = bold "#A855F7"
    hunk-header-style = file line-number syntax

    minus-style = syntax normal
    plus-style = syntax normal

    minus-marker-style = "red bold"
    plus-marker-style  = "green bold"

And ~/.config/lazygit/config.yml:

git:
  overrideGpg: true
  pagers:
    - colorArg: always
      pager: delta --dark --paging=never --line-numbers --hyperlinks
  log:
    showGraph: always
    order: topo-order

This transforms the default view to something much more readable:

Before: Default lazygit diff

After: Customized lazygit diff with delta

The improved syntax highlighting and line numbers make it way easier to read diffs. Beyond configuration, I also have some custom keybinds in lazygit to speed up common workflows.

In all repos I contribute to, I have pre-commit installed so linting and testing run before I commit. This prevents a lot of failed pipelines on GitHub and saves money on CI runs.

After making changes and committing, I use scripts to run and watch GitHub workflows. I have a fish function called ghrv (github run view) that opens a floating terminal with fzf, letting me select which workflow run to watch.

function ghrv --description 'Pick a workflow run with fzf and watch it (floating window)'
    if not set -q _GH_FLOATING
        alacritty -T floating60 -e fish -c "cd $(pwd); set -x _GH_FLOATING 1; ghrv" &
        return
    end

    # If a run ID was passed directly, skip fzf
    if test (count $argv) -gt 0
        gh run watch $argv
        return
    end

    set -l selected (
        gh run list --limit 30 --json databaseId,displayTitle,status,conclusion,workflowName 2>/dev/null |
        jq -r '.[] | [
            (.databaseId | tostring),
            .workflowName,
            .status,
            (.conclusion // "-"),
            .displayTitle
        ] | @tsv' |
        fzf --prompt="Run> " \
            --height=20 \
            --border \
            --layout=reverse \
            --delimiter='\t' \
            --with-nth=2,3,4,5
    )
    test -z "$selected" && return 0

    set -l run_id (string split \t $selected)[1]
    set -l run_status (string split \t $selected)[3]

    if test "$run_status" = "completed"
        set -l job_ids (
            gh run view "$run_id" --json jobs 2>/dev/null |
            jq -r '.jobs[].databaseId'
        )
        for job_id in $job_ids
            gh run view "$run_id" --job="$job_id"
            echo ""
        end
    else
        gh run watch "$run_id"
        set -l conclusion (gh run view "$run_id" --json conclusion -q '.conclusion' 2>/dev/null)
        notify-send "GitHub Actions" "Run finished: $conclusion" --icon=dialog-information
    end

    echo ""
    read -P "Press enter to close..."
end

Chosiing a workflow to watch: Selecting workflow with fzf

Watching workflow execution: Workflow run output

This is extremely useful for checking if a run is passing or failing, and if it fails, I can check the logs right away to see what went wrong.

For reviewing PRs, I use gh-dash, an extension for the gh CLI that gives me a dashboard of all PRs assigned to me or where I’m a reviewer. I can filter by repo or label without opening the browser.

So the entire workflow lives in my terminal. From coding to PR review to merging to watching workflow runs, I never have to switch contexts.

That said, I still use the web interface when it makes sense. I don’t subscribe to the hardcore philosophies like “the mouse is evil when using Vim.” It’s about balance. A browser will always be better for certain things, and for those I’ll use it. But for many tasks I’m faster and more efficient in the terminal, so I stay there.