With vim-fugitive you can perform
almost any Git command from within Vim with :Git. (realizing full-well that you can shell
out to Git with :!git and :read !git) The Fugitive is nicer, and turns commits
into hyperlinks (it's more intuitive to browse interactively).
GitGutter is a Vim plugin that
provides markers in the sign column that marks modified lines. It also provides hunk
text objects ic and ac for operating on hunks.
Use ]c and [c for jumping between hunks, or use
:GitGutterQuickFix for loading all hunks into the quickfix list. Hunks can be previewed,
staged, or undone with <leader>hp, <leader>hs, or
<leader>hu respectively.
You can also use :Git add --patch from Fugitive to stage hunks interactively from within
Vim.
You can use :Git commit from within Vim, which will open a new window. I don't normally do
this, because I usually keep one or more terminal panes set aside for Git.
I think everyone should set the
commit.verbose
config option, which adds the staged diff to the commit editor. This can really slow down vim for large
commits (but you shouldn't have large commits in the first place!) If you really need to
disable showing this diff in the commit editor, you can commit with
git -c commit.verbose=false commit.
I highly recommend making commits that touch submodules do nothing but touch the submodule. In the case of adding a new submodule, it should be
git submodule add $REMOTE_URL
git commit
Updating a submodule to a new hash should also be done in its own commit. I do make the concession, however, that this is a questionable practice if you value independently buildable commits (as in, each commit builds and passes the pipeline). Use your best judgment, based on your team's Git values (hopefully they do have values).
# Update the submodule locally
cd $SUBMODULE_PATH
git switch $GIT_BRANCH
git pull
cd -
# Commit the submodule update by itself
git add $SUBMODULE_PATH
git commit
When committing a submodule update like this (as opposed to rewording a commit that updates a submodule as would be common in an interactive rebase) I believe you should always add the submodule changes to the commit for traceability. This can be done from within Vim by
:read !git diff --submodule --staged $SUBMODULE_PATH
Technically, you can leave off the $SUBMODULE_PATH if you followed my advice that changes
to submodule should be committed by themselves.
:read !git when squashing two
submodule update commits during an interactive rebase.
You can use gq to reflow the text in a commit message. Use visual-line mode to select
text to reflow or gqip to reflow the current paragraph.
Fugitive provides :Git log (which can accept any of the usual commandline arguments).
Pressing <CR> on any of the commit hashes will open that commit in a new buffer (a
fancier git-show).
fzf.vim provides :Commits and :BCommits that opens an interactive commit
browser that you can search. Again, pressing <CR> on a selected commit (or multiple
commits, selected with TAB in their own buffers.
git-gl
because then I can trigger special sauce on keybinds. See
https://github.com/Notgnoshi/dotfiles/issues/13.
:BCommits is similar to running :Git log %. Additionally, you can make a
visual selection. Then, running :BCommits shows commits that touched that range of lines.
This is an easier-to-browse :Git blame.
Fugitive provides :Git blame which nicely wraps git-blame in a
scroll-synchronized window opened to the side of the current buffer. Pressing <CR> on
the selected commit will open that commit in a new buffer. Pressing - will reblame at the
selected commit.
When you open a commit with :Git blame or similar, you'll see something like
tree d80fb1c28a89bcdf6798dd26f986e1745e207525
parent 4e4ea6709c08807b1d769e89a582720d4e11ebfb
author Austin Gill <Notgnoshi@gmail.com> Sun Jul 25 13:46:12 2021 -0500
committer Austin Gill <Notgnoshi@gmail.com> Mon Aug 30 14:50:15 2021 -0500
which, notably, doesn't include the hash of the displayed commit. To get the hash, do
y<C-G> to yank the hash. Or, possibly more helpful, as long as you have
system clipboard support, you can do "+y<C-G>.
Use :Gedit master:% to open the current file as of the master revision in a
new buffer. You can do the same with :Git diff master:% % to the current file against
master.
TODO: This is something I still have to learn. I typically do
git status followed by git diff $FILE_WITH_CONFLICTS in one terminal pane,
and resolve the conflicts manually with Vim in another pane. This isn't a terrible experience, but I
bet it could be better.