强曰为道

与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

16 - Git 集成

“Version control is not a separate workflow — it’s part of editing.”

16.1 Vim 内置 Git 支持

16.1.1 基本命令

:!git status        " 查看状态
:!git diff          " 查看差异
:!git add %         " 暂存当前文件
:!git commit -m "msg"  " 提交
:!git log --oneline    " 查看日志

16.2 gitsigns.nvim

16.2.1 功能概述

gitsigns 在编辑器的标记列(sign column)显示 Git 变更状态,提供行级差异操作。

  │ + │   新增行(绿色)
  │ ~ │   修改行(蓝色)
  │ - │   删除行(红色)
  │ _ │   未跟踪

16.2.2 安装与配置

{ "lewis6991/gitsigns.nvim",
    event = { "BufReadPre", "BufNewFile" },
    opts = {
        signs = {
            add          = { text = "│" },
            change       = { text = "│" },
            delete       = { text = "_" },
            topdelete    = { text = "‾" },
            changedelete = { text = "~" },
            untracked    = { text = "┆" },
        },
        signcolumn = true,
        numhl      = false,
        linehl     = false,
        word_diff  = false,
        watch_gitdir = { follow_files = true },
        attach_to_untracked = true,
        current_line_blame = false,
        current_line_blame_opts = {
            virt_text = true,
            virt_text_pos = "eol",
            delay = 1000,
        },
        on_attach = function(bufnr)
            local gs = package.loaded.gitsigns
            local map = function(mode, l, r, desc)
                vim.keymap.set(mode, l, r, { buffer = bufnr, desc = desc })
            end

            -- 导航
            map("n", "]h", gs.next_hunk, "下一个 hunk")
            map("n", "[h", gs.prev_hunk, "上一个 hunk")

            -- 操作
            map("n", "<leader>hs", gs.stage_hunk, "暂存 hunk")
            map("n", "<leader>hr", gs.reset_hunk, "重置 hunk")
            map("v", "<leader>hs", function() gs.stage_hunk({vim.fn.line("."), vim.fn.line("v")}) end, "暂存选中")
            map("v", "<leader>hr", function() gs.reset_hunk({vim.fn.line("."), vim.fn.line("v")}) end, "重置选中")
            map("n", "<leader>hS", gs.stage_buffer, "暂存缓冲区")
            map("n", "<leader>hu", gs.undo_stage_hunk, "撤销暂存")
            map("n", "<leader>hR", gs.reset_buffer, "重置缓冲区")
            map("n", "<leader>hp", gs.preview_hunk, "预览 hunk")
            map("n", "<leader>hb", function() gs.blame_line({full=true}) end, "行级 blame")
            map("n", "<leader>hd", gs.diffthis, "差异比较")
            map("n", "<leader>hD", function() gs.diffthis("~") end, "差异比较(HEAD)")
        end,
    },
}

16.2.3 gitsigns 命令

命令功能
Gitsigns stage_hunk暂存当前 hunk
Gitsigns reset_hunk重置当前 hunk
Gitsigns stage_buffer暂存整个文件
Gitsigns preview_hunk浮动窗口预览变更
Gitsigns blame_line当前行 blame
Gitsigns diffthis打开差异视图
Gitsigns toggle_signs切换标记显示
Gitsigns toggle_linehl切换行高亮
Gitsigns toggle_word_diff切换单词差异

16.3 Neogit

16.3.1 概述

Neogit 是一个类似 Magit(Emacs)的 Git 界面,提供交互式的 Git 操作。

16.3.2 安装

{ "NeogitOrg/neogit",
    cmd = "Neogit",
    keys = {
        { "<leader>gg", "<cmd>Neogit<cr>", desc = "Neogit" },
    },
    dependencies = {
        "nvim-lua/plenary.nvim",
        "sindrets/diffview.nvim",
    },
    opts = {
        integrations = {
            diffview = true,
        },
        signs = {
            section = { "▸", "▾" },
            item = { "▸", "▾" },
            hunk = { "", "" },
        },
    },
}

16.3.3 Neogit 界面操作

Neogit 状态缓冲区:
┌──────────────────────────────────┐
│ Unstaged changes                 │
│   modified: src/main.lua         │
│   modified: src/utils.lua        │
│                                  │
│ Staged changes                   │
│   new file: src/config.lua       │
│                                  │
│ Recent commits                   │
│   abc1234 fix: typo              │
│   def5678 feat: add config       │
└──────────────────────────────────┘

操作:
s       Stage (暂存)
u       Unstage (取消暂存)
c       Commit menu (提交菜单)
P       Push menu (推送菜单)
F       Pull menu (拉取菜单)
b       Branch menu (分支菜单)
d       Diff
L       Log

16.4 diffview.nvim

16.4.1 差异视图

{ "sindrets/diffview.nvim",
    cmd = { "DiffviewOpen", "DiffviewFileHistory" },
    keys = {
        { "<leader>gd", "<cmd>DiffviewOpen<cr>", desc = "Diff View" },
        { "<leader>gh", "<cmd>DiffviewFileHistory<cr>", desc = "File History" },
        { "<leader>gf", "<cmd>DiffviewFileHistory %<cr>", desc = "Current File History" },
    },
    opts = {
        enhanced_diff_hl = true,
        view = {
            merge_tool = {
                layout = "diff3_mixed",
            },
        },
    },
}

16.4.2 diffview 命令

:DiffviewOpen               " 打开当前分支的差异
:DiffviewOpen HEAD~2        " 与 2 个提交前对比
:DiffviewOpen main          " 与 main 分支对比
:DiffviewFileHistory        " 所有文件历史
:DiffviewFileHistory %      " 当前文件历史
:DiffviewClose              " 关闭差异视图

16.5 内置差异比较

" vimdiff 模式
vimdiff file1 file2         " 终端中打开
:vert diffsplit file2       " 在 Vim 中打开差异

" 差异操作
]c          " 下一个差异
[c          " 上一个差异
do          " 获取差异(diff obtain)
dp          " 推送差异(diff put)
:diffupdate " 刷新差异
:diffthis    " 将当前窗口加入差异

16.6 冲突解决

16.6.1 Git 冲突标记

<<<<<<< HEAD
当前分支的内容
=======
要合并的分支内容
>>>>>>> feature

16.6.2 冲突解决插件

{ "akinsho/git-conflict.nvim",
    version = "*",
    config = true,
    keys = {
        { "<leader>gco", "<cmd>GitConflictChooseOurs<cr>", desc = "选择我们的" },
        { "<leader>gct", "<cmd>GitConflictChooseTheirs<cr>", desc = "选择他们的" },
        { "<leader>gcb", "<cmd>GitConflictChooseBoth<cr>", desc = "选择两者" },
        { "<leader>gcn", "<cmd>GitConflictNone<cr>", desc = "都不选" },
        { "]x", "<cmd>GitConflictNextConflict<cr>", desc = "下一个冲突" },
        { "[x", "<cmd>GitConflictPrevConflict<cr>", desc = "上一个冲突" },
    },
}

16.7 业务场景

场景工具
查看当前文件变更gitsigns (]h, [h)
暂存部分行gitsigns (Visual + <leader>hs)
提交代码Neogit (c)
对比分支diffview (DiffviewOpen main)
查看文件历史diffview (DiffviewFileHistory %)
解决冲突git-conflict
Git 操作全览Neogit (<leader>gg)

16.8 总结

插件用途
gitsigns.nvim行级差异标记、hunk 操作
neogit交互式 Git 界面
diffview.nvim差异比较、文件历史
git-conflict.nvim冲突解决

下一步第 17 章 - 终端集成 → 在 Neovim 中高效使用终端。


扩展阅读