A lightweight bundle of commands focussed on swift and streamlined git operations.
git add -A
). Optionally trigger
a git push
afterward.git blame
and branch state.Commit Message Input | Commit Notification |
---|---|
Select From Commit History ("git pickaxe") | File History Diff Popup |
---|---|
Install the Treesitter parser for git filetypes: TSInstall gitcommit git_rebase
-- lazy.nvim
{
"chrisgrieser/nvim-tinygit",
ft = { "git_rebase", "gitcommit" }, -- so ftplugins are loaded
dependencies = {
"stevearc/dressing.nvim",
"nvim-telescope/telescope.nvim", -- either telescope or fzf-lua
-- "ibhagwan/fzf-lua",
"rcarriga/nvim-notify", -- optional, but will lack some features without it
},
},
-- packer
use {
"chrisgrieser/nvim-tinygit",
requires = {
"stevearc/dressing.nvim",
"nvim-telescope/telescope.nvim", -- either telescope or fzf-lua
-- "ibhagwan/fzf-lua",
"rcarriga/nvim-notify", -- optional, but will lack some features without it
},
}
git add --all
) before the
commit.git push
if the repo is clean after committing.git push
is triggered afterward, so there are no surprises.require("tinygit").smartCommit { pushIfClean = false } -- options default to `false`
Example Workflow Assuming these keybindings:
vim.keymap.set("n", "ga", "<cmd>Gitsigns add_hunk<CR>") -- gitsigns.nvim
vim.keymap.set("n", "gc", function() require("tinygit").smartCommit() end)
vim.keymap.set("n", "gp", function() require("tinygit").push() end)
ga
.gc
to enter a commit message.gp
to push the commits.Using pushIfClean = true
allows you to combine staging, committing, and
pushing into a single step, when it is the last commit you intend to make.
amendOnlyMsg
just opens the commit popup to change the last commit message,
and does not stage any changes.amendNoEdit
keeps the last commit message; if there are no staged changes,
stages all changes (git add --all
), like smartCommit
.git push --force-with-lease
afterward, if the branch has
diverged (that is, the amended commit was already pushed).-- options default to `false`
require("tinygit").amendOnlyMsg { forcePushIfDiverged = false }
require("tinygit").amendNoEdit { forcePushIfDiverged = false }
fixupCommit
lets you select a commit from the last X commits and runs git commit --fixup
on the selected commit.git add --all
), like
smartCommit
.squashInstead = true
to squash instead of fixup (git commit --squash
).autoRebase = true
automatically runs rebase with --autosquash
and
--autostash
afterward, confirming all fixups and squashes without opening a
rebase view. (Note that this can potentially result in conflicts.)-- options show default values
require("tinygit").fixupCommit {
selectFromLastXCommits = 15,
squashInstead = false,
autoRebase = false,
}
undoLastCommit
removes the most recent commit (in a non-destructive way)require("tinygit").undoLastCommit()
git reset --mixed HEAD~
which removes the last commit.curl
.)-- state: all|closed|open (default: all)
-- type: all|issue|pr (default: all)
require("tinygit").issuesAndPrs { type = "all", state = "all" }
-- alternative: if the word under the cursor is of the form `#123`,
-- just open that issue/PR
require("tinygit").openIssueUnderCursor()
-- file|repo (default: file)
require("tinygit").githubUrl("file")
push
can be combined with other actions, depending on the options.createGitHubPr
opens a PR from the current branch browser.gh
cli, as it uses a GitHub web feature.-- options default to `false`
require("tinygit").push {
pullBefore = false,
forceWithLease = false,
createGitHubPr = false,
}
require("tinygit").createGitHubPr()
Search the git history. Select from the matching commits to open a popup with a diff of the changes.
git log -G
).git log -L
).git
uses heuristics to determine the enclosing function of a
change, so this is not
100% perfect and has varying reliability across languages.Keymaps in the diff popup
<Tab>
/<S-Tab>
: cycle through the commits.yh
: yank the commit hash to the system clipboard.n
/N
(file history): go to the next/previous occurrence of the query.require("tinygit").searchFileHistory()
require("tinygit").functionHistory()
require("tinygit").stashPush()
require("tinygit").stashPop()
Shows the message and date (git blame
) of the last commit that changed the
current file (not line).
require("tinygit.statusline").blame()
[!TIP] Some status line plugins also allow you to put components into the tabline or winbar. If your status line is too crowded, you can add the blame-component to the one of those bars instead.
The component can be configured with the statusline.blame
options in the plugin
configuration.
Shows whether the local branch is ahead or behind of its remote counterpart.
(Note that this component does not run git fetch
for performance reasons, so
the information may not be up-to-date with remote changes.)
require("tinygit.statusline").branchState()
tinygit
also comes with some highlighting improvements for interactive
rebasing (git rebase -i
).
[!NOTE] This requires
nvim
as your git editor (or sequence editor). You can do so by runninggit config --global core.editor "nvim"
.
If you want to disable the modifications by tinygit
, add this to your config:
vim.g.tinygit_no_rebase_ftplugin = true
The setup
call is optional. These are the default settings:
local defaultConfig = {
commitMsg = {
-- Shows diffstats of the changes that are going to be committed.
-- (requires nvim-notify)
commitPreview = true,
conventionalCommits = {
enforce = false, -- disallow commit messages without a keyword
-- stylua: ignore
keywords = {
"fix", "feat", "chore", "docs", "refactor", "build", "test",
"perf", "style", "revert", "ci", "break", "improv",
},
},
-- enable vim's builtin spellcheck for the commit message input field.
-- (configured to ignore capitalization and correctly consider camelCase)
spellcheck = false,
-- if commit message references issue/PR, open it in the browser
openReferencedIssue = false,
-- how long to remember the state of the message input field when aborting
keepAbortedMsgSecs = 300,
},
push = {
preventPushingFixupOrSquashCommits = true,
confirmationSound = true, -- currently macOS only, PRs welcome
},
issueIcons = {
openIssue = "🟢",
closedIssue = "🟣",
openPR = "🟩",
mergedPR = "🟪",
closedPR = "🟥",
},
historySearch = {
diffPopup = {
width = 0.8, -- float, 0 to 1
height = 0.8,
border = "single",
},
-- if trying to call `git log` on a shallow repository, automatically
-- unshallow the repo by running `git fetch --unshallow`
autoUnshallowIfNeeded = false,
},
statusline = {
blame = {
-- Any of these authors and the component is not shown (useful for bots)
ignoreAuthors = {},
-- show component, but leave out names (useful for your own name)
hideAuthorNames = {},
maxMsgLen = 35,
icon = "ï°– ",
},
branchState = {
icons = {
ahead = "󰶣",
behind = "󰶡",
diverge = "󰃻",
},
},
},
}
The appearance of the commit message input field and of the selectors is configured via dressing.nvim. To enable normal mode in the input field, use:
require("dressing").setup {
input = { insert_only = false },
}
The appearance of the commit preview is determined by nvim-notify. To change for example the width of the preview, use:
require("notify").setup {
max_width = 60,
}
gitsigns.nvim
: No feature overlap. tinygit
rather complements gitsigns
as the latter is used to stage changes (:GitSigns stage_hunk
) quickly, and
the former allows you to commit (and push) those changes quickly.Neogit
/ Fugitive
: These two probably cover every feature tinygit
has,
but with much more configuration options. The benefit of tinygit
is that it
is more lightweight and aims to streamline common actions by smartly combining
operations. For instance, the smart-commit command combines staging,
committing, and pushing.diffview.nvim
: No overlap, except for the command to search the file history.
tinygit
's version of file history search should be easier to use and has a few
more quality-of-life features, such as automatically jumping to occurrences of
the search term. As opposed to diffview
, the diff is not presented in a
side-by-side-diff, but in a unified view.In my day job, I am a sociologist studying the social mechanisms underlying the digital economy. For my PhD project, I investigate the governance of the app economy and how software ecosystems manage the tension between innovation and compatibility. If you are interested in this subject, feel free to get in touch.
I also occasionally blog about vim: Nano Tips for Vim