Home

Awesome

<!-- LTeX: enabled=false -->

nvim-tinygit

<!-- LTeX: enabled=true --> <a href="https://dotfyle.com/plugins/chrisgrieser/nvim-tinygit"> <img src="https://dotfyle.com/plugins/chrisgrieser/nvim-tinygit/shield?style=flat" /> </a>

A lightweight bundle of commands focused on swift and streamlined git operations.

<img alt="Showcase interactive staging" width=70% src="https://github.com/chrisgrieser/nvim-tinygit/assets/73286100/3c055861-6b93-4065-8601-f79568d8ac28"> <img alt="Showcase smart commit" width=70% src="https://github.com/chrisgrieser/nvim-tinygit/assets/73286100/7000ca1e-199b-4632-802b-fe630589f8f5"> <img alt="Showcase git history" width=70% src="https://github.com/chrisgrieser/nvim-tinygit/assets/73286100/b4cb918e-ff95-40ac-a09f-feb767ba2b94">

Feature overview

<!-- toc --> <!-- tocstop -->

Installation

Hard requirements

Optional/recommended requirements

-- lazy.nvim
{
	"chrisgrieser/nvim-tinygit",
	dependencies = "stevearc/dressing.nvim",
},

-- packer
use {
	"chrisgrieser/nvim-tinygit",
	requires = "stevearc/dressing.nvim",
}

Commands

Interactive staging

require("tinygit").interactiveStaging()

Smart-commit

-- values shown are the defaults
require("tinygit").smartCommit { pushIfClean = false, pullBeforePush = true }

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)
  1. Stage some hunks (changes) via ga.
  2. Use gc to enter a commit message.
  3. Repeat 1 and 2.
  4. When done, 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.

Amend and fixup commits

Amending

-- options default to `false`
require("tinygit").amendOnlyMsg { forcePushIfDiverged = false }
require("tinygit").amendNoEdit { forcePushIfDiverged = false, stageAllIfNothingStaged = true }

Fixup commits

-- options show default values
require("tinygit").fixupCommit {
	selectFromLastXCommits = 15,
	autoRebase = false,
}

Undo last commit/amend

require("tinygit").undoLastCommitOrAmend()
<!-- LTeX: enabled=false -->

GitHub interaction

<!-- LTeX: enabled=true -->

Search issues & PRs

-- 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`,
-- open that issue/PR
require("tinygit").openIssueUnderCursor()

GitHub URL Creates a permalink to the current file/lines at GitHub. The link is opened in the browser and copied to the system clipboard. In normal mode, uses the current file, in visual mode, uses the selected lines.

-- file|repo|blame (default: file)
require("tinygit").githubUrl()

Push & PRs

-- options default to `false`
require("tinygit").push {
	pullBefore = false,
	forceWithLease = false,
	createGitHubPr = false,
}
require("tinygit").createGitHubPr()

Search file history

Search the git history of the current file. Select from the matching commits to open a popup with a diffview of the changes.

If the config history.autoUnshallowIfNeeded is set to true, will also automatically un-shallow the repo if needed.

require("tinygit").fileHistory()

The type of history search depends on the mode .searchHistory is called from:

Keymaps in the diff popup

Stash

Simple wrappers around git stash push and git stash pop.

require("tinygit").stashPush()
require("tinygit").stashPop()

Status line components

<!-- LTeX: enabled=false -->

git blame

<!-- LTeX: enabled=true -->

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 tab line or win bar. If your status line is too crowded, you can add the blame-component to one of those bars instead.

The component can be configured with the statusline.blame options in the plugin configuration.

Branch state

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()

Configuration

The setup call is optional.

[!NOTE] Recently (2024-11-23), the config structure has been overhauled:

-- default config
require("tinygit").setup {
	stage = { -- requires `telescope.nvim`
		contextSize = 1, -- larger values "merge" hunks. 0 is not supported.
		stagedIndicator = "󰐖",
		keymaps = { -- insert & normal mode
			stagingToggle = "<Space>", -- stage/unstage hunk
			gotoHunk = "<CR>",
			resetHunk = "<C-r>",
		},
		moveToNextHunkOnStagingToggle = false,

		-- accepts the common telescope picker config
		telescopeOpts = { 
			layout_strategy = "horizontal",
			layout_config = {
				horizontal = {
					preview_width = 0.65,
					height = { 0.7, min = 20 },
				},
			},
		},
	},
	commit = {
		preview = true, -- requires `nvim-notify` or `snacks.nvim`
		spellcheck = false,
		keepAbortedMsgSecs = 300,
		inputFieldWidth = 72,
		conventionalCommits = {
			enforce = false,
			-- stylua: ignore
			keywords = {
				"fix", "feat", "chore", "docs", "refactor", "build", "test",
				"perf", "style", "revert", "ci", "break", "improv",
			},
		},
		insertIssuesOnHashSign = {
			-- Typing `#` will insert the most recent open issue.
			-- Requires `nvim-notify` or `snacks.nvim`.
			enabled = false,
			next = "<Tab>", -- insert & normal mode
			prev = "<S-Tab>",
			issuesToFetch = 20,
		},
	},
	push = {
		preventPushingFixupOrSquashCommits = true,
		confirmationSound = true, -- currently macOS only, PRs welcome

		-- Pushed commits contain references to issues, open those issues.
		-- Not used when using force-push.
		openReferencedIssues = false,
	},
	github = {
		icons = {
			openIssue = "🟢",
			closedIssue = "🟣",
			notPlannedIssue = "⚪",
			openPR = "🟩",
			mergedPR = "🟪",
			draftPR = "⬜",
			closedPR = "🟥",
		},
	},
	history = {
		diffPopup = {
			width = 0.8, -- between 0-1
			height = 0.8,
			border = "single",
		},
		autoUnshallowIfNeeded = false,
	},
	appearance = {
		mainIcon = "󰊢",
		backdrop = {
			enabled = true,
			blend = 50, -- 0-100
		},
	},
	statusline = {
		blame = {
			ignoreAuthors = {}, -- hide component if these authors (useful for bots)
			hideAuthorNames = {}, -- show component, but hide names (useful for your own name)
			maxMsgLen = 40,
			icon = "ﰖ",
		},
		branchState = {
			icons = {
				ahead = "󰶣",
				behind = "󰶡",
				diverge = "󰃻",
			},
		},
	},
}

The appearance of the commit preview and notifications is determined by nvim-notify or snacks.nvim respectively.

Credits

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

<a href='https://ko-fi.com/Y8Y86SQ91' target='_blank'> <img height='36' style='border:0px;height:36px;' src='https://cdn.ko-fi.com/cdn/kofi1.png?v=3' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>