Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/chrisgrieser/nvim-tinygit

Lightweight and nimble git client for nvim.
https://github.com/chrisgrieser/nvim-tinygit

commit-message conventional-commits git-client nvim-plugin

Last synced: 8 days ago
JSON representation

Lightweight and nimble git client for nvim.

Awesome Lists containing this project

README

        

# nvim-tinygit


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

Showcase interactive staging
Showcase smart commit
Showcase git history

## Feature Overview
- **Interactive Staging** of hunks (parts of a file). Displays hunk diffs with
proper syntax highlighting, and allows resetting or navigating to the hunk.
- **Smart-Commit**: Open a popup to enter a commit message with syntax highlighting,
commit preview, automatic issue number insertion, and overlength indicators.
If there are no staged changes, stages all changes before doing so (`git add
-A`). Optionally trigger a `git push` afterward.
- Quick commands for amend, stash, fixup, or undoing commits.
- Search **issues & PRs**. Open the selected issue or PR in the browser.
- Open the **GitHub URL** of the current line or selection.
- **Explore the git history**: Search the file for a string ("git pickaxe"), or
examine a function's or line's history. Displays the results in a diff view
with syntax highlighting, correctly following file renamings.
- **Statusline components:** `git blame` of a file and branch state.
- **Streamlined workflow:** operations are smartly combined to minimize
friction. For instance, the smart-commit command combines staging, committing,
and pushing, and searching the file history combines unshallowing, searching,
and navigating diffs.

- [Installation](#installation)
- [Commands](#commands)
* [Interactive Staging](#interactive-staging)
* [Smart-Commit](#smart-commit)
* [Amend, Fixup, and Squash Commits](#amend-fixup-and-squash-commits)
* [Undo Last Commit/Amend](#undo-last-commitamend)
* [GitHub Interaction](#github-interaction)
* [Push & PR](#push--pr)
* [Explore the History of a File, Function, or Line ("git pickaxe")](#explore-the-history-of-a-file-function-or-line-git-pickaxe)
* [Stash](#stash)
- [Statusline Components](#statusline-components)
* [Git Blame](#git-blame)
* [Branch State](#branch-state)
- [Configuration](#configuration)
- [About me](#about-me)

## Installation
**Hard Requirements**
- nvim 0.10 or higher
- `dressing.nvim`

**Optional/Recommended Requirements**
- Treesitter parser for syntax highlighting: `TSInstall gitcommit`
- `nvim-notify` for the commit preview, issue number insertion, and various
notifications
- [telescope.nvim](https://github.com/nvim-telescope/telescope.nvim) or
[fzf-lua](https://github.com/ibhagwan/fzf-lua) for better UI when selecting
commits or issues/PRs.
- `telescope` is required for interactive staging.

```lua
-- lazy.nvim
{
"chrisgrieser/nvim-tinygit",
dependencies = {
"stevearc/dressing.nvim",
"nvim-telescope/telescope.nvim", -- optional, but recommended
"rcarriga/nvim-notify", -- optional, but recommended
},
},

-- packer
use {
"chrisgrieser/nvim-tinygit",
requires = {
"stevearc/dressing.nvim",
"nvim-telescope/telescope.nvim", -- optional, but recommended
"rcarriga/nvim-notify", -- optional, but recommended
},
}
```

## Commands

### Interactive Staging
- This feature requires
[telescope.nvim](https://github.com/nvim-telescope/telescope.nvim).
- This command stages hunks, that is, *parts* of a file instead of the
full file. It is roughly comparable to `git add -p`.
- Use `` to (un)stage the hunk, `` to go to the hunk, or `` cycles through the
issues (currently opt-in, see plugin configuration).
- Only supports the commit subject line (no commit body).

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

**Example Workflow**
Assuming these keybindings:

```lua
vim.keymap.set("n", "ga", "Gitsigns add_hunk") -- 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, Fixup, and Squash Commits
**Amending**
- `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`.
- Optionally runs `git push --force-with-lease` afterward, if the branch has
diverged (that is, the amended commit was already pushed).

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

**Fixup or Squash Commits**
- `fixupCommit` lets you select a commit from the last X commits and runs `git
commit --fixup` on the selected commit.
- If there are no staged changes, stages all changes (`git add --all`), like
`smartCommit`.
- Use `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.)

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

### Undo Last Commit/Amend

```lua
require("tinygit").undoLastCommitOrAmend()
```

- Changes in the working directory are kept, but unstaged. (In the background,
this uses `git reset --mixed`.)
- If there was a `push` operation done as a followup (such as `.smartCommit {
pushIfClean = false }`), the last commit is not undone.

### GitHub Interaction
**Search issues & PRs**
- Requires `curl`.

```lua
-- 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**
Opens the current file at GitHub in the browser and copy the URL to the system
clipboard.
- Normal mode: open the current file or repo.
- Visual mode: open selected lines.

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

### Push & PR
- `push` can be combined with other actions, depending on the options.
- `createGitHubPr` opens a PR from the current branch browser.
* This requires the repo to be a fork with sufficient information on the remote.
* This does not require the `gh` cli, as it uses a GitHub web feature.

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

### Explore the History of a File, Function, or Line ("git pickaxe")
Search the git history. Select from the matching commits to open a popup with a
diffview of the changes.

- Search the git **history of the current file** (`git log -G`).
* The search is case-insensitive and supports regex.
* Correctly follows file renamings, and displays past file names in the commit
selection.
* Leave the input field empty to display *all* commits that changed the
current file.
- Explore the **history of a function in the current file** (`git log -L`).
* The search is literal.
* If the current buffer has an LSP with support for document symbols
attached, you can select a function. (Otherwise, you are prompted to
enter a function name.)
* Note that [`git` uses heuristics to determine the enclosing function of a
change](https://news.ycombinator.com/item?id=38153309), so this is not
100% perfect and has varying reliability across languages.
- Go through the **history of the current line (range)** (`git log -L`).
* In normal mode, searches the history of the line under the cursor.
* When called in visual mode, searches the history of the selected line
range.

**Keymaps in the diff popup**
- ``: show older commit
- ``: show newer commit
- `yh`: yank the commit hash to the system clipboard
- `R`: restore file to state at commit
- `n`/`N`: go to the next/previous occurrence of the query (only file history)

```lua
require("tinygit").searchFileHistory()
require("tinygit").functionHistory()
require("tinygit").lineHistory()
```

### Stash
Simple wrappers around `git stash push` and `git stash pop`.

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

## Statusline Components

### Git Blame
Shows the message and date (`git blame`) of the last commit that changed the
current *file* (not line).

```lua
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
> one of those bars instead.

The component can be configured with the `statusline.blame` options in the [plugin
configuration](#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.)

```lua
require("tinygit.statusline").branchState()
```

## Configuration
The `setup` call is optional.

```lua
-- default config
require("tinygit").setup {
staging = { -- requires telescope
contextSize = 1, -- larger values "merge" hunks. 0 is not supported.
stagedIndicator = "✜ ",
keymaps = { -- insert & normal mode
stagingToggle = "", -- stage/unstage hunk
gotoHunk = "",
resetHunk = "",
},
moveToNextHunkOnStagingToggle = false,
},
commitMsg = {
commitPreview = true, -- requires nvim-notify
spellcheck = false,
keepAbortedMsgSecs = 300,
inputFieldWidth = 72, -- `false` to use dressing.nvim config
conventionalCommits = {
enforce = false,
-- stylua: ignore
keywords = {
"fix", "feat", "chore", "docs", "refactor", "build", "test",
"perf", "style", "revert", "ci", "break", "improv",
},
},
insertIssuesOnHash = {
-- Experimental. Typing `#` will insert the most recent open issue.
-- Requires nvim-notify.
enabled = false,
next = "", -- insert & normal mode
prev = "",
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,
},
historySearch = {
diffPopup = {
width = 0.8, -- float, 0 to 1
height = 0.8,
border = "single",
},
autoUnshallowIfNeeded = false,
},
issueIcons = {
openIssue = "🟢",
closedIssue = "🟣",
notPlannedIssue = "⚪",
openPR = "🟩",
mergedPR = "🟪",
draftPR = "⬜",
closedPR = "🟥",
},
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 = "󰃻",
},
},
},
backdrop = {
enabled = true,
blend = 50, -- 0-100
},
}
```

The appearance of the commit preview and notifications is determined by
[nvim-notify](https://github.com/rcarriga/nvim-notify). To change for example
the width of the preview, use:

```lua
require("notify").setup {
max_width = 60,
}
```

## 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](https://nanotipsforvim.prose.sh)

- [Academic Website](https://chris-grieser.de/)
- [Mastodon](https://pkm.social/@pseudometa)
- [ResearchGate](https://www.researchgate.net/profile/Christopher-Grieser)
- [LinkedIn](https://www.linkedin.com/in/christopher-grieser-ba693b17a/)


Buy Me a Coffee at ko-fi.com