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 中高效使用终端。
扩展阅读
- gitsigns.nvim 文档
- Neogit 文档
- diffview.nvim 文档
:h diff— 内置差异功能