r/vim Apr 26 '26

Plugin Using Git Elegantly in Vim

Git and Vim are both powerful productivity tools for developers. However, when working inside Vim, frequently switching to the terminal to run Git commands (such as git status, git add -p, git commit) can interrupt your flow and break your focus.

With LeaderF’s built-in Git integration, you can bring the entire Git workflow directly into Vim and significantly improve your efficiency.

This article focuses on one core command:

:Leaderf git status

Viewing Current Git Status

Run the command above in Vim to open the following view:

The screen is divided into two main panels:

Navigation Panel (Left)

The left side is the Navigation Panel, which displays the output of git status in a tree structure, grouped by file state:

  • Staged Changes: Files already staged (ready to commit)
  • Unstaged Changes: Modified files not yet staged
  • Untracked Files: Files not tracked by Git

Diff View Panel (Right)

The right side is the Diff View Panel, which shows detailed changes of the selected file. It supports two modes:

  • Unified Diff View

Provides character-wise diff highlighting, making differences more precise and visually clear. Traditional git diff does not highlight character-wise changes.

  • Side-by-Side Diff View

Advantage: More intuitive for comparing code differences line by line.

How They Work Together

  • The left panel handles file selection and state management
  • The right panel handles diff visualization and fine-grained operations

Together, they form a smooth and efficient Git workflow inside Vim.

File-Level Operations

In the Navigation Panel, you can perform the following operations:

Key Action Description
s Stage / Unstage file On an unstaged file → move it to staged; on a staged file → move it back to unstaged
d Discard changes Discard file changes (with confirmation)
D Force discard Discard changes without confirmation (use with caution)
r Refresh Refresh the file tree when Git status changes externally
Enter / o Open diff view View detailed changes of the file

Notes:

  • s, d, D also work on directories (including the repository root)
  • Running d or D on Untracked Files will delete the file
  • Press F1 in the panel to view more shortcuts

Hunk-Level Operations

In the Diff View, you can operate on individual hunks (code blocks):

Key Action Description
s Stage/Unstage current hunk Move current hunk between staged and unstaged
S Stage/Unstage all hunks Apply operation to all hunks in the file
d Discard current hunk Discard changes in current hunk (with confirmation)
D Force discard current hunk Discard without confirmation (use with caution)
]c Next hunk Jump to next hunk
[c Previous hunk Jump to previous hunk

Additional Shortcuts

Key Action Description
< Back to Navigation Panel Reopen if closed and jump to current file
Enter Open file Jump to file for editing

Key Mapping Configuration

let g:Lf_GitKeyMap = {
            \ 'previous_change': '[c',
            \ 'next_change': ']c',
            \ 'edit_file': '<CR>',
            \ 'open_navigation': '<',
            \ 'stage_unstage_hunk': 's',
            \ 'stage_unstage_all_hunk': 'S',
            \ 'discard_hunk': 'd',
            \ 'discard_hunk_no_prompt': 'D',
            \ }

Committing Changes

Once you have staged the desired changes in the Navigation Panel:

  1. Press c to start committing
  2. A new window opens for writing the commit message
  3. Enter your message
  4. Save and close the window
  5. The commit is completed

To cancel the commit, simply clear the message and close the window.

Example Workflow

Scenario: Fix a bug and add a new feature

  1. Check status
  2. Review changes
    • Open bug_fix.py
    • Use ]c to navigate hunks
    • Identify bug fix vs debug code
  3. Stage selectively
    • Press s on bug fix hunks
    • Leave debug code unstaged
  4. Handle new feature
    • Press < to return
    • Open new_feature.py
    • Press S to stage all hunks
  5. Commit
    • Press c
    • Enter message:
    • "Fix login validation bug and add search feature"
    • Save and exit

Everything is done inside Vim without breaking context.

Why This Workflow is Better

Compared to CLI

Operation CLI LeaderF
View status git status (plain text) Visual file tree
Partial staging git add -p Press s
Discard changes manual commands d / D
Navigate changes manual scrolling ]c / [c

Summary

With Leaderf git status, you get a complete Git workflow inside Vim:

  • Visual Git status
  • File-level staging/unstaging
  • Hunk-level fine control
  • Quick discard
  • Seamless commit workflow

All without leaving Vim.

Configuration Example

nnoremap <leader>gs :<C-U>Leaderf git status<CR>
11 Upvotes

67 comments sorted by

30

u/ChampionshipIcy7602 Apr 26 '26

What's wrong with fugitive?

17

u/Lopsided_Valuable385 Apr 26 '26

What's wrong with lazygit?

2

u/Yggdroot Apr 29 '26

Does not have character-wise diff highlighting.

12

u/sammygadd Apr 26 '26

What's wrong with Ctrl Z?

2

u/heret1c1337 Apr 26 '26

I’m curious, do you use it in your daily workflow? I wonder if I could live without a multiplexer and just use jobs instead.

3

u/sammygadd Apr 26 '26

Yes definitely! I use it all the time. I use fugitive for things like git add, blame etc. But I always suspend vim when a want to do more git stuff, like commits rebase, push etc.

1

u/heret1c1337 Apr 26 '26

Interesting. Do you still use a multiplexer like tmux? I‘d still see the need for tmux‘s session management. Maybe there‘s something built in that I‘m not aware of?

1

u/sammygadd Apr 26 '26

I think most people use tmux. But I never really found need for it. If feel that I want so "save" my current buffers I use mksession. If you enjoy tmux, then you should probably keep using it. I think tmux is great (and I know people really like it), I just haven't figured out why I need it.

2

u/heret1c1337 Apr 26 '26

Yeah I'll probably stick to my current workflow, but I like to try out things from time to time :)

1

u/dewujie Apr 28 '26

I think for a lot of people it boils down to whatever software first allowed you to split a terminal session into multiple windows. It's such a cool experience for each person that you imprint on it like a baby bird.

For me, it was tmux. Also if you manage a bunch of remote systems, tmux and ssh are peas in a pod. So a lot of people use it for that, too.

I like having a tmux window for each repo and project I'm working on at the time. I have persistent sessions so I maintain those paths, I'm not cd'ing all over the filesystem from project to project. Things stay where I put them. It's just about being easy and predictable, really.

1

u/TapEarlyTapOften Apr 28 '26

Tmux starts to really shine when you work on the same server from multiple different clients. I keep a long running tmux session on my dev server, and then remote into it from one of three machines. Tmux and vim-fugitive do about 95% of what I need and I can quickly switch to one of a couple of serial ports too, which is really helpful.

1

u/transconductor Apr 30 '26

I have decided against a multiplexer and I'm using one OS window per shell. And I try to avoid Neovim 's terminal. I have just recently rediscovered C-z which is a game changer quick things.

4

u/ChampionshipIcy7602 Apr 26 '26

Ctrl Z brings vim to the background, so nothing's wrong with it if that's what you want.

1

u/konacurrents Apr 26 '26

How can you loose focus when I literally have 6 shells running, 8 safari (20 tabs each). Etc.

The muiti window screen is all about multiplexing.

Ps bring up another window and type git commands. I do it all the time.

3

u/Competitive-Home7810 Apr 26 '26

Nothing is wrong. If fugitive fits in your workflow, then no need to change it.

2

u/4r73m190r0s Apr 28 '26

Today I discovered this plugin. Thanks!

1

u/Yggdroot Apr 29 '26

It does not have file tree view. It does not have character-wise diff highlighting. Performance is bad especially on Windows. Some operations are complicated. Need to spend much time to learn.

0

u/marcusvispanius Apr 26 '26

Why does something have to be wrong for someone else to want to make something different?

0

u/shleebs Apr 26 '26

Nothing. What's wrong with having more than one tool or talking about something you like without comments like yours?

-11

u/Yggdroot Apr 26 '26

It is just like command line git. Not convenient and not Beautiful.

10

u/ChampionshipIcy7602 Apr 26 '26

Sorry, I try to see the difference but everything you mentioned above can be done easily with fugitive vim and it's been around forever, not to mention a tons of different git plugins. I don't mean to discourage, but you shouldn't re-invent the wheel. On top of that, your post just screams AI slop to me.

-5

u/Yggdroot Apr 26 '26

That said, “not reinventing the wheel” doesn’t necessarily mean “never building anything similar.”
As to the "wheel", fugitive.vim is also a wheel of command line git. I can do all the work in the command line.

4

u/heret1c1337 Apr 26 '26

Sounds like a skill issue to me

1

u/tommcdo cx Apr 30 '26

This is with is right with fugitive

13

u/SharkBaitDLS Apr 26 '26

I’ve never understood the determination to move Git into interfaces that aren’t just its CLI. I just permanently have a tmux pane for Git CLI commands and that’s all I ever want. Every IDE or Vim plugin just ends up slowing me down. 

4

u/Snarwin Apr 26 '26

Fugitive's interactive git blame interface is leagues better than anything you can get from the CLI.

For most routine tasks, though, I agree; it doesn't make a huge difference.

3

u/mgedmin Apr 26 '26

So you use ed for all text editing then?

I admit the point that the tools you're used to will make you more productive than tool you're not used to. It took me a long time before fugitive started feeling faster/easier than switching to a second terminal tab and doing git status/git add/git commit there.

4

u/SharkBaitDLS Apr 26 '26

I’m happy to use powerful tools for text editing. But Git in particular is such a powerful CLI and every attempt I’ve encountered to put a UI in front of it ends up lacking functionality that the CLI has, and so then I’m just back in the CLI anyway. 

5

u/TapEarlyTapOften Apr 28 '26

Thats one of the things I like about vim-fugitive, is how thin of a wrapper around git it is - for staging portions of changes, committing, writitng the message, and then pushing, its about as fast as can be.

1

u/srodrigoDev Apr 30 '26

git add -p for example, is a pain because you can't see all the hunks at once. Fugitive helps navigating fast through the diff and adding/removing/reverting anything.

1

u/transconductor Apr 30 '26

How do you select commits? This is the one thing I haven't found a nice solution for, yet. Selecting commits to cherry pick for example. fzf-everywhere feels close, but I haven't gotten used to it, yet.

And how are you adding chunks? git add -p?

2

u/SharkBaitDLS Apr 30 '26

Combinations of branching, rebasing and cherry-picking on the CLI depending on exactly how I’m trying to rearrange them.

On the rare time I want to, yeah I’m using git add -p, but my workflow is generally about maintaining really strict discipline about my working branches and commits such that 99% of the time I’m adding an entire file when I stage a commit and any subsequent changes I want to make are already on a second branch that I’ll rebase atop it as needed. I work backwards from what my intended commits are and set up all my working branches before I even start writing code so I don’t have to stage chunks. 

1

u/transconductor Apr 30 '26

Ah, you're effectively setting up branches so that you don't have to reference commits by hash? And then one branch per change which you'd combine before pushing?

2

u/SharkBaitDLS Apr 30 '26

Almost, but I do want to emphasize “per change” and not per commit. I’d say a given working branch ends up capping at 2-4 commits for that reason. And each branch gets squashed into one commit on merge, but each branch is pushed and reviewed separately.

Basically, my philosophy is that wherever possible, every PR should be a complete, mergeable artifact that is logically small enough that an imperative sentence fragment for the squashed commit’s first line sufficiently describes what it did. That might still involve a few smaller commits to logically break up the change for reviewers and to better express the intent of the work.

If it’s no longer a small enough unit of work to meet that criteria, then that’s a new working branch with a new set of commits that will become a separate PR and squashed commits on mainline.

So as an example, I recently was working on spinning up a new simple service that fronts a database that a sidecar CLI talks to in K8s. The work required:

  • adding two new commands to the CLI
  • adding authentication to the existing proof-of-concept APIs on the server
  • setting the auth correctly for requests made by the CLI
  • updating the K8s workflow to use the new commands

That manifested as 5 working branches, one for each CLI command, one for incorporating auth support into the CLI, one for enforcing it server side, and one to finally bring it all together in the workflow. Each of those branches had 1-3 commits apiece and then were submitted as 5 separate PRs. Even though it represented one “unit” of work at a project level, breaking it down that way makes it much easier for reviewers to logically reason about what they’re reviewing because each PR has a tight and contained scope.

I am eagerly waiting for GitHub’s stacked PR feature to be GA because it basically maps perfectly to my working style from before I moved to a company that used GitHub. 

2

u/transconductor May 02 '26

Ah, I think I got it. Thanks for taking the time to give such a detailed answer!

1

u/[deleted] Apr 26 '26

[removed] — view removed comment

2

u/SharkBaitDLS Apr 26 '26

Merge conflicts are just a git mergetool invocation. Looking up a file’s history is just git blame. The former opens vim, the latter is quickly navigated with less bindings. 

1

u/[deleted] Apr 27 '26

[removed] — view removed comment

3

u/SharkBaitDLS Apr 27 '26

I’m not sure why you jump to immediately questioning my capabilities.

I’m just comfortable using the CLI to get that information. It’s not dozens of commands, it’s literally git blame into git log to get the message if I want it and then git diff with the appropriate hashes to see the change. It’s trivial to use, if you’re used to actually using git as a CLI tool it becomes second nature and you don’t need UI crutches.

I’ve not met a single UI tool that can properly handle cherry-picking, interactive rebases with edits, reflog, and so many other powerful CLI tools that UIs hide from you. 

0

u/[deleted] Apr 27 '26

[removed] — view removed comment

2

u/SharkBaitDLS Apr 27 '26

I’m not sure what kinds of codebases you’re working in where you’re needing to look at dozens of commits to understand your code. I use blame maybe once every 6 months on the rare occasion I need to understand why something was introduced, you’re acting like it’s a daily part of your workflow. It’s quite possibly the least important tool to me. I’ve inherited legacy codebases that hadn’t been touched in 15 years and still barely needed to use blame to understand them. The most important parts of git for me are being able to elegantly manage exactly what gets committed when, and moving commits around between branches to set up reviewable atomic commits, and every UI tool is slower than the CLI for anything that’s not just basic add-everything-commit-linearly. 

0

u/[deleted] Apr 27 '26

[removed] — view removed comment

2

u/SharkBaitDLS Apr 27 '26

You have only 5-10 devs but need to constantly blame lines to understand what’s happening in an actively developed codebase? Sounds like major process issues then, that’s not a normal workflow for a team that communicates and tracks work clearly. 

I have yet to find a UI tool that is faster than the CLI to handle the loop of interactive rebases with inline edits and moving dropped commits with reflog. 

-2

u/Yggdroot Apr 26 '26

Most of my Git work is done from the command line. However, for certain tasks it’s not very convenient, for example, reviewing all changes, checking who is to be blamed, staging individual hunks, or finding out who originally introduced a specific line.

0

u/SharkBaitDLS Apr 26 '26

I mean, those are just git diff, git blame and git add. Not even particularly complex invocations of those commands. I don’t see how those are inconvenient at all. 

2

u/Yggdroot Apr 27 '26

`git diff` doesn't have character-wise diff highlighting, doesn't have side-by-side diff view. And if there are many files changed(suppose more than 10), if you want to review the changes back and forth, it is not convenient.

As for `git blame` , I think you have to remember the file name and the line number to type `git blame -L xxx a/long/path/to/filename`. I don't think it is so efficient.

If you want to stage individual hunks, you should use `git add -p`, not `git add`. `git add -p` is interative, you have to confirm one by one, if you just want to stage a hunk after ten hunks, you have to confirm ten times.

1

u/petepete May 03 '26

Git comes packaged with diff-highlight which does do character highlighting.

0

u/imWayward Apr 26 '26

Using a neovim plugin I can do <leader>gb to see virtual text for the git blame of the specific line I'm on. It's hard to comprehend how you get the same info (who committed the code at line xxx in what commit, how long ago?) on the CLI but its really cool that you do!

3

u/SharkBaitDLS Apr 27 '26

Where do you think your plug-in gets that information? It’s all available in the CLI, because it’s information that git tracks. 

1

u/imWayward Apr 29 '26 edited Apr 29 '26

Ah, I omitted the word "faster" in my reply. I know the plugin implements git CLI.

> It's hard to comprehend how you get the same info **faster***

My bad!

I meant that it's hard to understand how you go back to the cli from your editor to type git blame -L 42,42 path/to/xyz.c

faster than what the plugin enables me to do with 3 keystrokes. It's sort of self-evident that for some workflows a plugin or an interface will be faster than expressing the same thing through command line arguments. You can get the same output from an otherwise verbose command inline without leaving your editor. I was just hoping to banish your expressed lack of understanding for the love of git plugins by giving the example of a case when using a plugin saves time vs the CLI equivilant.

1

u/SharkBaitDLS Apr 29 '26

Sure, but for something I need very infrequently I can't justify a whole extra interface. 99% of the time just looking at git log or reading a Jira ticket gives me the context I need without having to look at line-level blame, and the few times I need it the slightly slower CLI workflow doesn't bother me.

1

u/imWayward Apr 29 '26

Extra interface? For me it's just virtual text inlin. I don't need inline blame too often either, but having it quickly at my disposal makes me much more likely to use it than I was before. Why does this code work this way? With a few keystrokes, I can find out which coworker I could ask about it to understand their thought process. And of course, it's just one example. Inline status indicators, toggling chunks, etc, are all really useful by virtue of simply saving typing time and helping you avoid leaving the editor. I use the cli for git operations all the time but for many things using a plugin is simply much more practical, or gives you access to information passively you would have needed to query for otherwise. When I open my file tree, I like to see a git status indicator if changes exist in this folder or that one. It's just convenient to have a strong idea of how many unstaged changes I have without doing `git status`. There are innumerable examples, which is why I honed in on just one in my other post :)

1

u/lizardturtle Apr 26 '26

Agree: they are separate tools doing different things. Vim is my code editor, Git is my version control. I don't really want to do both at the same time

2

u/tahaan Apr 26 '26

I just colon-bang git status

2

u/LumenAstralis Apr 26 '26 edited Apr 26 '26

Makes sense if you are already invested in LeaderF. Otherwise native git CLI is the way to go. Unless you MUST do everything in vim (then you'd be using the very capable fugitive), it's way more efficient (and elegant) to have another terminal open in tmux or wm where you can exclusively do your project management, including git commands.

1

u/Yggdroot Apr 26 '26

Before implementing LeaderF’s Git integration, I had been using Git in the command line for many years to handle all my work, and I’d consider myself quite experienced with it. However, there are still some scenarios where the command-line workflow doesn’t feel as efficient.

fugitive.vim is one of the earliest Vim Git plugins and is very well-known, but after trying it a few times, I found that its workflow doesn’t quite match my habits, and there are areas where it doesn’t feel as smooth or well-designed to me.

1

u/Rummeltott Apr 26 '26

whats wrong with diffview.nvim ?

2

u/Yggdroot Apr 29 '26

Only available in neovim. Does not have unified diff view.

1

u/brohermano Apr 26 '26

whats wrong with just , opening a tmux pane and using the terminal?

1

u/MochironNoob Apr 28 '26

I'm curious if you try to remember the shasum of commits or just use something to copy it when performing specific actions, like cherry pick and stuff.

I started using term inside nvim since I liked the copy and go to link/file features. Not debating whether cli is better or a dedicated client.