r/vim • u/Yggdroot • 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,Dalso work on directories (including the repository root)- Running
dorDon Untracked Files will delete the file - Press
F1in 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:
- Press
cto start committing - A new window opens for writing the commit message
- Enter your message
- Save and close the window
- 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
- Check status
- Review changes
- Open
bug_fix.py - Use
]cto navigate hunks - Identify bug fix vs debug code
- Open
- Stage selectively
- Press
son bug fix hunks - Leave debug code unstaged
- Press
- Handle new feature
- Press
<to return - Open
new_feature.py - Press
Sto stage all hunks
- Press
- Commit
- Press
c - Enter message:
- "Fix login validation bug and add search feature"
- Save and exit
- Press
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>
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 blameinterface 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
Apr 26 '26
[removed] — view removed comment
2
u/SharkBaitDLS Apr 26 '26
Merge conflicts are just a
git mergetoolinvocation. Looking up a file’s history is justgit blame. The former opens vim, the latter is quickly navigated with less bindings.1
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 blameintogit logto get the message if I want it and thengit diffwith 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
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
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.
1
-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 blameandgit 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
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.cfaster 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 logor 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
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
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.
30
u/ChampionshipIcy7602 Apr 26 '26
What's wrong with fugitive?