chrisgrieser / nvim-tinygit

A lightweight bundle of commands focussed on swift and streamlined git operations.
MIT License
170 stars 5 forks source link
commit-message conventional-commits git-client nvim-plugin

nvim-tinygit

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

Showcase interactive staging Showcase smart commit Showcase git history

Feature Overview

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, Fixup, and Squash Commits

Amending

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

Fixup or Squash Commits

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

Undo Last Commit/Amend

require("tinygit").undoLastCommitOrAmend()

GitHub Interaction

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 Opens the current file at GitHub in the browser and copy the URL to the system clipboard.

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

Push & PR

-- 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.

Keymaps in the diff popup

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

Stash

Simple wrappers around git stash push and git stash pop.

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

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.

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.

-- default config
require("tinygit").setup {
    staging = { -- requires telescope
        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,
    },
    commitMsg = {
        commitPreview = true, -- requires `nvim-notify` or `snacks.nvim`
        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 = {
            -- 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, 
    },
    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. To change for example the width of the preview, use:

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

<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' />