Magit 用户手册
Table of Contents
- 1. 1 简介
- 2. 2 安装
- 3. 3 快速入门
- 4. 4 界面概念 (Interface Concepts)
- 4.1. 4.1 模式和缓冲区 (Modes and Buffers)
- 4.1.1. 4.1.1 切换缓冲区 (Switching Buffers)
- 4.1.2. 4.1.2 命名缓冲区 (Naming Buffers)
- 4.1.3. 4.1.3 退出窗口 (Quitting Windows)
- 4.1.4. 4.1.4 Magit 缓冲区的自动刷新 (Automatic Refreshing of Magit Buffers)
- 4.1.5. 4.1.5 访问文件的缓冲区的自动保存 (Automatic Saving of File-Visiting Buffers)
- 4.1.6. 4.1.6 访问文件的缓冲区的自动 Reverting (Automatic Reverting of File-Visiting Buffers)
- 4.2. 4.2 Sections (部分)
- 4.3. 4.3 Transient 命令
- 4.4. 4.4 Transient 参数和缓冲区变量 (Transient Arguments and Buffer Variables)
- 4.5. 4.5 补全, 确认和选择 (Completion, Confirmation and the Selection)
- 4.6. 4.6 鼠标支持 (Mouse Support)
- 4.7. 4.7 运行 Git (Running Git)
- 4.1. 4.1 模式和缓冲区 (Modes and Buffers)
- 5. 5 检查 (Inspecting)
- 6. 6 操作 (Manipulating)
- 6.1. 6.1 创建仓库 (Creating Repository)
- 6.2. 6.2 克隆仓库 (Cloning Repository)
- 6.3. 6.3 Staging 和 Unstaging
- 6.4. 6.4 应用 (Applying)
- 6.5. 6.5 提交 (Committing)
- 6.6. 6.6 分支 (Branching)
- 6.7. 6.7 合并 (Merging)
- 6.8. 6.8 解决冲突 (Resolving Conflicts)
- 6.9. 6.9 变基 (Rebasing)
- 6.10. 6.10 拣选 (Cherry Picking)
- 6.11. 6.11 重置 (Resetting)
- 6.12. 6.12 Stashing
- 7. 7 传输 (Transferring)
- 8. 8 杂项 (Miscellaneous)
- 8.1. 8.1 标签 (Tagging)
- 8.2. 8.2 注释 (Notes)
- 8.3. 8.3 子模块 (Submodules)
- 8.4. 8.4 子树 (Subtree)
- 8.5. 8.5 工作树 (Worktree)
- 8.6. 8.6 稀疏检出 (Sparse checkouts)
- 8.7. 8.7 捆绑 (Bundle)
- 8.8. 8.8 常用命令 (Common Commands)
- 8.9. 8.9 Wip 模式 (Wip Modes)
- 8.10. 8.10 用于访问文件的缓冲区的命令 (Commands for Buffers Visiting Files)
- 8.11. 8.11 访问 Blobs 的缓冲区的 Minor Mode (Minor Mode for Buffers Visiting Blobs)
- 9. 9 自定义 (Customizing)
- 10. 10 管道 (Plumbing)
- 11. 附录 A 常见问题 (FAQ)
- 11.1. A.1 FAQ - 如何…? (How to …?)
- 11.1.1. A.1.1 Magit 怎么发音? (How to pronounce Magit?)
- 11.1.2. A.1.2 如何显示 git 的输出? (How to show git's output?)
- 11.1.3. A.1.3 如何安装 gitman info 手册? (How to install the gitman info manual?)
- 11.1.4. A.1.4 如何显示 gpg 加密文件的 diffs? (How to show diffs for gpg-encrypted files?)
- 11.1.5. A.1.5 分支和推送如何工作? (How does branching and pushing work?)
- 11.1.6. A.1.6 我应该禁用 VC 吗? (Should I disable VC?)
- 11.2. A.2 FAQ - 问题和错误 (Issues and Errors)
- 11.2.1. A.2.1 Magit 很慢 (Magit is slow)
- 11.2.2. A.2.2 我一次更改了几千个文件, 现在 Magit 无法使用了 (I changed several thousand files at once and now Magit is unusable)
- 11.2.3. A.2.3 我在提交时遇到问题 (I am having problems committing)
- 11.2.4. A.2.4 我正在使用 MS Windows 并且无法用 Magit 推送 (I am using MS Windows and cannot push with Magit)
- 11.2.5. A.2.5 我正在使用 macOS, 某功能在 shell 中工作但在 Magit 中不行 (I am using macOS and SOMETHING works in shell, but not in Magit)
- 11.2.6. A.2.6 展开文件以显示 diff 导致它消失 (Expanding a file to show the diff causes it to disappear)
- 11.2.7. A.2.7 COMMITEDITMSG 缓冲区中的 Point 是错误的 (Point is wrong in the COMMITEDITMSG buffer)
- 11.2.8. A.2.8 Mode-line 信息并不总是最新的 (The mode-line information isn't always up-to-date)
- 11.2.9. A.2.9 分支和标签共享相同名称破坏了某些东西 (A branch and tag sharing the same name breaks SOMETHING)
- 11.2.10. A.2.10 我的 Git hooks 在命令行上工作但在 Magit 中不行 (My Git hooks work on the command-line but not inside Magit)
- 11.2.11. A.2.11 从命令行提交时未使用 git-commit-mode (git-commit-mode isn't used when committing from the command-line)
- 11.2.12. A.2.12 跳转到访问文件的缓冲区时 Point 最终位于不可见文本内 (Point ends up inside invisible text when jumping to a file-visiting buffer)
- 11.2.13. A.2.13 我不再能够保存弹出窗口默认值 (I am no longer able to save popup defaults)
- 11.1. A.1 FAQ - 如何…? (How to …?)
- 12. 11 调试工具 (Debugging Tools)
- 13. 附录 B 按键索引 (Keystroke Index)
- 14. 附录 C 函数和命令索引 (Function and Command Index)
- 15. 附录 D 变量索引 (Variable Index)
1. 1 简介
Magit 是版本控制系统 Git 的一个接口, 作为一个 Emacs 软件包实现. Magit 立志成为一个完整的 Git porcelain. 虽然我们还不能 (尚未) 声称 Magit 封装并改进了每一个 Git 命令, 但它已经足够完整, 即使是经验丰富的 Git 用户也可以直接在 Emacs 中执行几乎所有的日常版本控制任务. 虽然存在许多优秀的 Git 客户端, 但只有 Magit 和 Git 本身配得上 "porcelains" (瓷件) 的称号.
Staging (暂存) 和以其他方式应用更改是 Git porcelain 中最重要的功能之一, 在这方面 Magit 优于其他任何工具, 包括 Git 本身. Git 自身的 staging 接口 (git add --patch) 非常繁琐, 以至于许多用户只在特殊情况下使用它. 在 Magit 中, stage 一个 hunk (补丁块) 甚至只是 hunk 的一部分, 就像 stage 文件的所有更改一样简单.
Magit 界面中最可见的部分是 status buffer (状态缓冲区), 它显示有关当前仓库的信息. 其内容是通过运行几个 Git 命令并使其输出可操作而创建的. 除其他外, 它显示有关当前分支的信息, 列出未 pull 和未 push 的更改, 并包含显示 staged 和 unstaged 更改的 sections (部分). 这听起来可能很嘈杂, 但由于 sections 是可折叠的, 所以并非如此.
要 stage 或 unstage 一个更改, 可以将光标放在更改上, 然后输入 s 或 u. 更改可以是一个文件或一个 hunk, 或者当 region (区域) 处于活动状态时 (即, 有选中内容时), 可以是多个文件或 hunks, 甚至只是 hunk 的一部分. 这些命令 (以及许多其他命令) 将作用于的更改会高亮显示.
除了 staging 和 unstaging 之外, Magit 还实现了其他几种 "apply variants" (应用变体). 人们可以 discard (丢弃) 或 reverse (反转) 更改, 或将其 apply (应用) 到工作树. Git 自己的 porcelain 仅支持 staging 和 unstaging, 你必须在命令行上执行类似 git diff ... | ??? | git apply ... 的操作来 discard, revert, 或 apply 单个 hunk. 事实上, 这正是 Magit 在内部所做的 (这也是 "apply variants" 一词的由来).
Magit 不仅仅是为 Git 专家准备的, 但它确实假设用户对 Git 和 Emacs 有一定的经验. 话虽如此, 许多用户报告说, 使用 Magit 最终教会了他们 Git 的功能以及如何充分利用它. 其他用户则希望他们能更早地切换到 Emacs, 这样就能更早地使用 Magit.
虽然必须了解 Emacs 的基本功能才能充分利用 Magit, 但掌握足够的 Emacs 技能并不需要很长时间, 即使对于喜欢其他编辑器的用户来说也是值得的. 建议 Vim 用户尝试 Evil (https://github.com/emacs-evil/evil), 即 "Emacs 的可扩展 VI 层", 以及 Spacemacs (https://github.com/syl20bnr/spacemacs), 一个 "专注于 Evil 的 Emacs 启动套件".
Magit 提供了一个一致且高效的 Git porcelain. 经过短暂的学习后, 你将能够比在命令行上更快地执行大部分日常版本控制任务. 你可能还会开始使用那些过去看起来太令人生畏的功能.
Magit 完全拥抱 Git. 它通过一个简单但灵活的接口暴露了许多高级功能, 而不是像许多 GUI 客户端那样只封装琐碎的功能. 当然 Magit 支持 logging, cloning, pushing 和其他通常不会以壮观方式失败的命令; 但它也支持那些通常无法在单一步骤中完成的任务. Magit 完全支持 merging, rebasing, cherry-picking, reverting 和 blaming 等任务, 不仅提供启动这些任务的命令, 还在过程中显示上下文相关信息, 并提供用于解决冲突和在解决冲突后恢复序列的命令.
Magit 封装并在许多情况下改进了至少以下 Git porcelain 命令: add, am, bisect, blame, branch, checkout, cherry, cherry-pick, clean, clone, commit, config, describe, diff, fetch, format-patch, init, log, merge, merge-tree, mv, notes, pull, rebase, reflog, remote, request-pull, reset, revert, rm, show, stash, submodule, subtree, tag, 和 worktree. 更多的 Magit porcelain 命令是在 Git plumbing 命令之上实现的.
2. 2 安装
Magit 可以使用 Emacs 的包管理器安装, 也可以从其开发仓库手动安装.
2.1. 2.1 从 Melpa 安装
Magit 可从 Melpa 和 Melpa-Stable 获取. 如果你以前没有使用过 Emacs 的包管理器, 那么现在是时候通过阅读 Emacs 手册中的文档来熟悉它了, 参见 emacs 中的 "Packages" 一节. 然后将其中一个档案添加到 package-archives:
使用 Melpa:
(require 'package) (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
使用 Melpa-Stable:
(require 'package) (add-to-list 'package-archives '("melpa-stable" . "https://stable.melpa.org/packages/") t)
添加首选档案后, 你需要使用以下命令更新本地包列表:
M-x package-refresh-contents RET
完成后, 你可以使用以下命令安装 Magit 及其依赖项:
M-x package-install RET magit RET
现在请参阅第 4 页的 2.3 节 [Post-Installation Tasks].
2.2. 2.2 从 Git 仓库安装
Magit 依赖于 compat, cond-let, llama, seq (使用 Emacs >= 29.1 时内置版本即可), transient 和 with-editor 库, 这些库可从 Melpa 和 Melpa-Stable 获取. 使用 M-x package-install RET <package> RET 安装它们. 当然你也可以从它们的仓库手动安装.
然后克隆 Magit 仓库:
$ git clone https://github.com/magit/magit.git ~/.emacs.d/site-lisp/magit $ cd ~/.emacs.d/site-lisp/magit
然后编译库并生成 info 手册:
$ make
如果你没有从 Melpa 安装 compat, cond-let, llama, seq (仅针对 Emacs 28), transient 和 with-editor, 或者没有安装在 /path/to/magit/../<package>, 那么你必须告诉 make 在哪里找到它们. 为此, 在运行 make 之前创建文件 /path/to/magit/config.mk, 内容如下:
LOAD_PATH = -L ~/.emacs.d/site-lisp/magit/lisp LOAD_PATH += -L ~/.emacs.d/site-lisp/compat LOAD_PATH += -L ~/.emacs.d/site-lisp/cond-let LOAD_PATH += -L ~/.emacs.d/site-lisp/llama LOAD_PATH += -L ~/.emacs.d/site-lisp/seq LOAD_PATH += -L ~/.emacs.d/site-lisp/transient/lisp LOAD_PATH += -L ~/.emacs.d/site-lisp/with-editor/lisp
最后将此添加到你的 init 文件中:
(add-to-list 'load-path "~/.emacs.d/site-lisp/magit/lisp") (require 'magit) (with-eval-after-load 'info (info-initialize) (add-to-list 'Info-directory-list "~/.emacs.d/site-lisp/magit/docs/"))
当然, 如果你也手动安装了依赖项, 那么你也必须告诉 Emacs 它们的位置, 方法是在上面添加:
(add-to-list 'load-path "~/.emacs.d/site-lisp/compat") (add-to-list 'load-path "~/.emacs.d/site-lisp/cond-let") (add-to-list 'load-path "~/.emacs.d/site-lisp/llama") (add-to-list 'load-path "~/.emacs.d/site-lisp/seq") (add-to-list 'load-path "~/.emacs.d/site-lisp/transient/lisp") (add-to-list 'load-path "~/.emacs.d/site-lisp/with-editor")
注意, 你必须将 lisp 子目录添加到 load-path, 而不是仓库的顶层, 并且 load-path 的元素不应以斜杠结尾, 而 Info-directory-list 的元素应该以斜杠结尾.
你可以加载文件 magit-autoloads.el 来仅加载 autoload 定义, 而不是 require 功能 magit.
(load "/path/to/magit/lisp/magit-autoloads")
如果你不想通过添加到 load-path 直接从仓库运行 Magit, 你可能想使用 sudo make install 将其安装在其他目录中, 并相应地设置 load-path.
要更新 Magit, 请使用:
$ git pull $ make
有时可能需要运行 make clean all.
要查看所有可用目标, 请使用 make help.
现在请参阅第 4 页的 2.3 节 [Post-Installation Tasks].
2.3. 2.3 安装后任务
安装 Magit 后, 你应该验证你确实在使用你认为的 Magit, Git 和 Emacs 版本. 最好在执行此操作之前重新启动 Emacs, 以确保你没有使用过时的 load-path 值.
M-x magit-version RET
应该显示类似以下内容:
Magit 2.8.0, Git 2.10.2, Emacs 25.1.1, gnu/linux
然后你可能还想阅读许多用户可能希望自定义的选项. 参见第 126 页的 9.2 节 [Essential Settings].
为了能够跟踪本手册中发现的 Git manpages 的交叉引用, 你可能还需要手动安装 gitman info 手册, 或 advice Info-follow-nearest-node 以打开实际的 manpage. 参见第 143 页的 [How to install the gitman info manual?].
如果你是 Magit 的全新手, 请参阅第 6 页的第 3 章 [Getting Started].
如果你遇到问题, 请参阅第 143 页的附录 A [FAQ]. 另请参阅第 148 页的第 11 章 [Debugging Tools].
最后但同样重要的是, 请考虑捐款, 以确保我可以继续开发 Magit. 有关各种捐赠选项, 请参阅 https://magit.vc/donate.
3. 3 快速入门
这个简短的教程描述了许多 Magitians 每天使用的最基本功能. 它只是冰山一角, 但应该足以让你入门.
重要提示: 为了本教程, 克隆一些仓库是最安全的. 或者你可以使用现有的本地仓库, 但如果你这样做, 那么在继续之前你应该提交所有未提交的更改.
输入 C-x g 在一个专用缓冲区中显示有关当前 Git 仓库的信息, 该缓冲区称为 status buffer (状态缓冲区).
大多数 Magit 命令通常从 status buffer 调用. 它可以被视为使用 Magit 与 Git 交互的主要接口. 许多其他 Magit buffers 可能在给定时间存在, 但它们通常是从这个 buffer 创建的.
根据你的仓库处于什么状态, 此 buffer 可能包含标题为 "Staged changes", "Unstaged changes", "Unmerged into origin/master", "Unpushed to origin/master" 等许多部分 (sections).
由于我们从安全状态开始, 你可以轻松返回 (通过执行 git reset --hard PRE-MAGIT-STATE), 目前没有 staged 或 unstaged 的更改. 编辑一些文件并保存更改. 然后回到 status buffer, 同时通过输入 C-x g 刷新它. (当 status buffer 或任何 Magit buffer 是当前 buffer 时, 你也可以只使用 g 来刷新它).
使用 p 和 n 在 sections 之间移动. 注意某些 sections 的主体是隐藏的. 输入 TAB 展开或折叠光标处的 section. 你也可以使用 C-tab 循环显示当前 section 及其子 section 的可见性. 移动到名为 "Unstaged changes" 的 section 内的文件 section, 然后输入 s 以 stage 对该文件所做的更改. 该文件现在出现在 "Staged changes" 下.
Magit 可以 stage 和 unstage 单个 hunks, 而不仅仅是整个文件. 移动到你刚刚 stage 的文件, 使用 TAB 展开它, 使用 n 移动到其中一个 hunks, 并通过输入 u 仅 unstage 那个 hunk. 注意 staging (s) 和 unstaging (u) 命令如何作用于光标处的更改. 许多其他命令也以同样的方式运行.
你也可以 un-/stage 仅仅 hunk 的一部分. 在 hunk section 的主体内 (使用 C-n 移动到那里), 使用 C-SPC 设置标记并向下移动, 直到一些添加和/或删除的行落在 region 内, 但不是全部. 再次输入 s 进行 stage.
也可以一次 un-/stage 多个文件. 移动到文件 section, 输入 C-SPC, 使用 n 移动到下一个文件, 然后 s 以 stage 两个文件. 注意标记和光标都必须在同级 sections 的标题上才能起作用. 如果 region 看起来像在其他 buffers 中那样, 那么它就没有选中可以作为一个单元操作的 Magit sections.
然后当然你想提交你的更改. 输入 c. 这会在 frame 底部的 buffer 中显示可用的 commit 命令和参数. 每个命令和参数都以调用/设置它的键为前缀. 现在不用担心这个. 我们想要创建一个 "normal" commit, 这通过再次输入 c 来完成.
现在出现了两个新 buffers. 一个用于编写提交信息, 另一个显示带有你即将提交的更改的 diff. 写一条信息, 然后输入 C-c C-c 以实际创建提交.
你可能不想 push 你刚刚创建的提交, 因为你只是提交了一些随机更改, 但如果不是这种情况, 你可以通过输入 P 显示所有可用的 push 命令和参数, 然后输入 p 将名为 local branch 的分支推送到配置为 push-remote 的远程仓库上的同名分支. (如果尚未配置 push-remote, 那么首先会提示你选择要 push 到的 remote.)
到目前为止, 我们已经提到了 commit 和 push 菜单命令. 这些可能是你使用最多的菜单, 但还有许多其他菜单. 要显示列出所有其他菜单 (以及各种 apply 命令和其他一些基本命令) 的菜单, 请输入 h. 尝试几个. (这种菜单也称为 "transient prefix commands" 或简称为 "transients".)
该菜单中的按键绑定对应于 Magit buffers 中的绑定, 包括但不限于 status buffer. 所以你可以输入 h d 来调出 diff 菜单, 但一旦你记住 "d" 代表 "diff", 你通常只需输入 d 即可.
这个 "前缀的前缀" 即使在你记住了所有绑定后也很有用, 因为它可以从非 Magit buffers 轻松访问 Magit 命令. 因此, 默认情况下, 它全局绑定到 C-x M-g.
类似的菜单主要针对当前 buffer 中访问的文件执行命令, 全局绑定到 C-c M-g. 该绑定也可用于不访问文件的 buffers, 但那样只有部分命令可用.
前两段中提到的全局按键绑定非常不方便. 我们建议改用 C-c g 和 C-c f, 但默认情况下不能使用这些键序列, 因为它们严格保留给用户添加的绑定. 如果你想明确选择推荐的按键绑定, 请参阅第 129 页的 [Global Bindings].
Magit 还提供上下文菜单和其他鼠标命令, 参见第 29 页的 4.6 节 [Mouse Support].
虽然现在不是必须这样做, 但如果你坚持使用 Magit, 强烈建议你也阅读下一节.
4. 4 界面概念 (Interface Concepts)
4.1. 4.1 模式和缓冲区 (Modes and Buffers)
Magit 提供了几种 major-modes (主模式). 对于这些模式中的每一种, 每个仓库通常只存在一个 buffer. Commits, diffs, logs 和其他一些东西都有单独的模式和 buffers.
除了这些专用 buffers 之外, 还有一个概览 buffer, 称为 status buffer (状态缓冲区). 用户通常从这个 buffer 调用 Git 命令, 或者创建或访问其他 buffers.
在本手册中, 我们经常谈论 "Magit buffers". 我们的意思是那些 major-modes 派生自 magit-mode 的 buffers.
M-x magit-toggle-buffer-lock
这个命令将当前 buffer 锁定到其值, 或者如果 buffer 已经锁定, 则解锁它.
锁定 buffer 到其值可以防止它被重用于显示另一个值. 锁定 buffer 的名称包含其值, 这允许将其与其他锁定的 buffers 和未锁定的 buffer 区分开来.
并非所有的 Magit buffers 都可以锁定到其值; 例如, 锁定 status buffer 没有意义.
每个仓库只能有一个使用特定 major-mode 的未锁定 buffer. 因此, 当一个 buffer 被解锁并且该模式和仓库的另一个未锁定 buffer 已经存在时, 前者会被删除, 而后者会显示在其位置.
4.1.1. 4.1.1 切换缓冲区 (Switching Buffers)
magit-display-buffer buffer &optional display-function[Function] 此函数是display-buffer的包装器, 用于显示任何 Magit buffer. 它在某个窗口中显示 BUFFER, 并且与display-buffer不同, 只要magit-display-buffer-noselect为nil, 它还会选中该窗口. 它还运行下面提到的 hooks. 如果可选的 DISPLAY-FUNCTION 为非nil, 则使用它来显示 buffer. 通常它是nil, 并使用magit-display-buffer-function指定的函数.magit-display-buffer-noselect[Variable] 当此变量为非nil时,magit-display-buffer仅显示 buffer 但放弃选中窗口. 此变量不应全局设置, 它仅旨在由自动更新 "另一个窗口" 的代码进行 let-bound. 例如, 当你在 log buffer 中移动时更新 revision buffer 时会用到它.magit-display-buffer-function[User Option] 此处指定的函数由magit-display-buffer调用, 带有一个参数 (一个 buffer), 以实际显示该 buffer. 此函数应调用display-buffer, 将该 buffer 作为第一个参数, 并将显示操作列表作为第二个参数.
Magit 提供了下面列出的几个函数, 它们是此选项的合适值. 如果你想使用不同的规则, 那么一个好的方法是从复制其中一个函数开始, 然后根据你的需要进行调整.
不使用 display-buffer 的包装器, 也可以直接使用该函数本身, 在这种情况下, 必须通过将显示操作添加到 display-buffer-alist 来指定它们.
要了解显示操作, 请参阅 elisp 中的 "Choosing Window" 一节.
magit-display-buffer-traditional buffer[Function] 此函数是选项magit-display-buffer-function的当前默认值. 在添加该选项和此函数之前, 行为被硬编码在代码库的许多地方, 但现在所有规则都包含在这个函数中 (除了上面提到的 "noselect" 特殊情况).magit-display-buffer-same-window-except-diff-v1[Function] 此函数在当前选定的窗口中显示大多数 buffers. 如果 buffer 的模式派生自magit-diff-mode或magit-process-mode, 则在另一个窗口中显示.magit-display-buffer-fullframe-status-v1[Function] 此函数在显示 status buffer 时填充整个 frame. 否则, 它的行为类似于magit-display-buffer-traditional.magit-display-buffer-fullframe-status-topleft-v1[Function] 此函数在显示 status buffer 时填充整个 frame. 它的行为类似于magit-display-buffer-fullframe-status-v1, 除了它将派生自magit-diff-mode或magit-process-mode的 buffers 显示在当前 buffer 的上方或左侧, 而不是下方或右侧. 结果是, Magit buffers 倾向于在与使用magit-display-buffer-traditional时相同的一侧弹出.magit-display-buffer-fullcolumn-most-v1[Function] 此函数显示大多数 buffers 以填充 frame 的整个高度. 但是, 如果 (1) buffer 的模式派生自magit-process-mode, 或 (2) buffer 的模式派生自magit-diff-mode, 前提是当前 buffer 的模式派生自magit-log-mode或magit-cherry-mode, 则 buffer 显示在另一个窗口中.magit-pre-display-buffer-hook[User Option] 此 hook 由magit-display-buffer在显示 buffer 之前运行.magit-save-window-configuration[Function] 此函数保存当前窗口配置. 稍后当 buffer 被 bury 时, 可以通过magit-restore-window-configuration恢复它.magit-post-display-buffer-hook[User Option] 此 hook 由magit-display-buffer在显示 buffer 后运行.magit-maybe-set-dedicated[Function] 此函数记住是否必须创建一个新窗口来显示 buffer, 或者是否重用了现有窗口. 此信息稍后由magit-mode-quit-window使用, 以确定在其最后一个 Magit buffer 被 bury 时是否应删除该窗口.
4.1.2. 4.1.2 命名缓冲区 (Naming Buffers)
magit-generate-buffer-name-function[User Option] 用于生成 Magit buffers 名称的函数. 这样的函数应该考虑选项magit-uniquify-buffer-names以及magit-buffer-name-format. 如果不这样做, 则应在 doc-string 中明确说明. 如果它支持除magit-buffer-name-format选项文档中提到的那些之外的 %-sequences, 则其自己的 doc-string 应该描述添加的内容.magit-generate-buffer-name-default-function mode[Function] 此函数返回适用于 major-mode 为 MODE 的 buffer 的名称, 该 buffer 显示有关default-directory所在仓库的信息. 此函数使用magit-buffer-name-format并支持该选项文档中提到的所有 %-sequences. 它也尊重选项magit-uniquify-buffer-names.magit-buffer-name-format[User Option] 用于命名 Magit buffers 的格式字符串. 至少支持以下 %-sequences:%m: major-mode 的名称, 但删除了-mode后缀.%M: 类似%m, 但将magit-status-mode缩写为magit.%v: buffer 被锁定到的值, 在括号中; 如果 buffer 未锁定到值, 则为空字符串.%V: 类似%v, 但字符串以空格为前缀, 除非它是空字符串.%t: 仓库工作树的顶层目录, 或者如果magit-uniquify-buffer-names为非nil, 则为其缩写.%x: 如果magit-uniquify-buffer-names为nil则为*, 否则为空字符串. 由于uniquify包的限制, buffer 名称必须以路径结尾.
该值应始终包含
%m或%M,%v或%V, 以及%t. 如果magit-uniquify-buffer-names为非nil, 则该值必须以%t或%t%x结尾. 参见 issue #2841.magit-uniquify-buffer-names[User Option] 此选项控制 Magit buffers 的名称是否唯一化. 如果名称没有被唯一化, 那么它们包含相应仓库工作树顶层的完整路径. 如果它们被唯一化, 那么它们以顶层的 basename 结尾, 或者如果那会与其他 buffers 使用的名称冲突, 那么所有这些 buffers 的名称都会被调整直到不再冲突. 这是使用uniquify包完成的; 自定义其选项以控制 buffer 名称如何唯一化.
4.1.3. 4.1.3 退出窗口 (Quitting Windows)
q(magit-mode-bury-buffer) 此命令 bury (掩埋) 或 kill (杀死) 当前 Magit buffer. 由选项magit-bury-buffer-function指定的函数用于在不带前缀参数调用时 bury buffer, 或在带单个前缀参数调用时 kill 它. 当使用两个或更多前缀参数调用时, 它总是 kill 与当前项目关联的所有 Magit buffers, 包括当前 buffer.magit-bury-buffer-function[User Option] 用于实际 bury 或 kill 当前 buffer 的函数.magit-mode-bury-buffer带一个参数调用此函数. 如果参数为非nil, 则该函数必须 kill 当前 buffer. 否则它必须 bury 它. 当前默认值是magit-mode-quit-window.magit-restore-window-configuration kill-buffer[Function] 使用quit-windowbury 或 kill 当前 buffer, 该函数调用时将KILL-BUFFER作为第一个参数, 将选定窗口作为第二个参数. 然后恢复当前 buffer 在选定 frame 中显示之前存在的窗口配置. 不幸的是, 这也意味着 point 在选定 frame 中显示的所有 buffers 中都会被调整.magit-mode-quit-window kill-buffer[Function] 使用quit-windowbury 或 kill 当前 buffer, 该函数调用时将KILL-BUFFER作为第一个参数, 将选定窗口作为第二个参数. 然后, 如果该窗口最初是为了显示 Magit buffer 而创建的, 并且被 bury 的 buffer 是该窗口中显示过的最后一个剩余 Magit buffer, 也就是该窗口被删除.
4.1.4. 4.1.4 Magit 缓冲区的自动刷新 (Automatic Refreshing of Magit Buffers)
运行可能改变当前仓库状态的命令后, 当前 Magit buffer 和相应的 status buffer 会被刷新. 只要 buffer 保存到相应仓库内的文件, status buffer 就可以自动刷新, 方法是添加一个 hook, 如下所示:
(with-eval-after-load 'magit-mode (add-hook 'after-save-hook 'magit-after-save-refresh-status t))
自动刷新 Magit buffers 确保显示的信息大部分时间是最新的, 但在大型仓库中可能会导致明显的延迟. 为了将延迟降至最低, 并且因为这样做有时可能是不希望的, 不会刷新其他 Magit buffers.
Buffers 也可以显式刷新, 这对于上次刷新期间不是当前 buffer 的 buffers 以及在 Magit 外部对仓库进行更改后非常有用.
g(magit-refresh) 如果当前 buffer 的主模式派生自magit-mode, 则刷新当前 buffer 以及相应的 status buffer. 如果选项magit-revert-buffers要求这样做, 那么它还会 revert 所有访问当前仓库中被跟踪文件的未修改 buffers.G(magit-refresh-all) 此命令刷新属于当前仓库的所有 Magit buffers, 并 revert 所有访问当前仓库中被跟踪文件的未修改 buffers. 即使magit-revert-buffers为nil, 访问文件的 buffers 也总是被 reverted.magit-refresh-buffer-hook[User Option] 此 hook 在本次刷新期间刷新的每个 Magit buffer 中运行 - 通常是当前 buffer 和 status buffer.magit-refresh-status-buffer[User Option] 当此选项为非nil时, 除了总是自动刷新的当前 Magit buffer 之外, 在运行 git 产生副作用后, status buffer 也会自动刷新. 只有在用尽所有其他选项以提高性能后, 才将其设置为nil.magit-after-save-refresh-status[Function] 此函数旨在添加到after-save-hook. 这样做之后, 每当 buffer 保存到仓库内的文件时, 相应的 status buffer 就会被刷新. 请注意, 刷新 Magit buffer 是通过从头开始重新创建其内容来完成的, 这在大型仓库中可能会很慢. 如果你不满意 Magit 的性能, 那么你显然不应该将此函数添加到该 hook.
4.1.5. 4.1.5 访问文件的缓冲区的自动保存 (Automatic Saving of File-Visiting Buffers)
默认情况下, 访问文件的 buffers 会在特定时间点保存. 这并不能保证 Magit buffers 始终是最新的, 但是, 只要只在 Emacs 中编辑文件并仅使用 Magit 与 Git 交互, 就可以相当自信. 有疑问时或发生外部更改后, 输入 g (magit-refresh) 显式保存并刷新.
magit-save-repository-buffers[User Option] 此选项控制在特定事件之前是否保存访问文件的 buffers. 如果此值为非nil, 那么属于当前仓库的所有已修改的访问文件的 buffers 可能会在运行命令之前, 创建新 Magit buffers 之前以及显式刷新此类 buffers 之前被保存. 如果此值为dontask, 则无需用户干预即可完成此操作. 如果为t, 则用户必须确认每次保存.
4.1.6. 4.1.6 访问文件的缓冲区的自动 Reverting (Automatic Reverting of File-Visiting Buffers)
默认情况下, Magit 会自动 revert 访问 Git 仓库中被跟踪文件的 buffers, 在它们在磁盘上发生更改后. 使用 Magit 时, 经常通过运行 Git (即 "在 Emacs 外部") 更改磁盘上的文件, 这使得这成为一个相当重要的功能. 例如, 如果你在 status buffer 中 discard 一个更改, 那么这是通过运行 git apply --reverse ... 完成的, Emacs 认为文件 "在磁盘上已更改". 如果 Magit 没有自动 revert buffer, 那么你必须在访问 buffer 中输入 M-x revert-buffer RET RET 才能继续进行更改.
magit-auto-revert-mode[User Option] 启用此模式后, 访问被跟踪文件的 buffers 会在访问的文件在磁盘上更改后自动 reverted.global-auto-revert-mode[User Option] 启用此模式后, 任何访问文件的 buffer 都会在访问的文件在磁盘上更改后自动 reverted. 如果你喜欢访问被跟踪文件的 buffers 自动 reverted, 那么你可能也喜欢任何 buffer 被 reverted, 而不仅仅是那些访问被跟踪文件的 buffers. 如果是这种情况, 请启用此模式而不是magit-auto-revert-mode.magit-auto-revert-immediately[User Option] 此选项控制 Magit 是否立即 reverts buffers. 如果此值为非nil并且启用了global-auto-revert-mode或magit-auto-revert-mode, 那么 Magit 会在运行 Git 产生副作用后通过显式调用auto-revert-buffers立即 reverts buffers. 如果auto-revert-use-notify为非nil(并且实际上支持文件通知), 那么magit-auto-revert-immediately不必为非nil, 因为 reverts 无论如何都会立即发生. 如果magit-auto-revert-immediately和auto-revert-use-notify均为nil, 那么 reverts 会在auto-revert-interval秒的用户不活动后发生. 这是不可取的.auto-revert-use-notify[User Option] 此选项控制是否应使用文件通知功能. 请注意, 即使在无法使用文件通知的系统上, 此变量不幸地默认为t.magit-auto-revert-tracked-only[User Option] 此选项控制magit-auto-revert-mode是仅 reverts 被跟踪的文件, 还是位于 Git 仓库内的所有文件, 包括未跟踪的文件和位于 Git 控制目录内的文件.auto-revert-mode[User Option] 全局模式magit-auto-revert-mode通过在适当的 buffers 中打开此局部模式来工作 (但global-auto-revert-mode的实现方式不同). 你也可以手动打开或关闭它, 如果 Magit 没有注意到以前未跟踪的文件现在被跟踪了, 或者反之, 这可能是必要的.auto-revert-stop-on-user-input[User Option] 此选项控制用户输入的到达是否会暂停自动 revertsauto-revert-interval秒.auto-revert-interval[User Option] 此选项控制 Emacs 在恢复暂停的 reverts 之前等待多少秒.auto-revert-buffer-list-filter[User Option] 此选项指定auto-revert-buffers使用的附加过滤器, 以确定是否应 revert buffer. 此选项由 Magit 提供, Magit 也会 adviseauto-revert-buffers遵守它. 不自己打开局部模式auto-revert-mode的 Magit 用户最好将该值设置为magit-auto-revert-repository-buffer-p. 但是默认值为nil, 以免打扰直接使用局部模式的用户. 如果你在运行 Magit 命令时遇到延迟, 那么你应该考虑使用 Magit 提供的谓词之一 - 特别是如果你也使用 Tramp. 在 Magit 没有为他们做的 buffers 中打开auto-revert-mode的用户, 可能不应该使用任何过滤器. 打开global-auto-revert-mode的用户不必担心此选项, 因为如果启用了全局模式, 它将被忽略.auto-revert-verbose[User Option] 此选项控制 Emacs 是否报告 buffer 何时被 reverted.
带有 auto-revert- 前缀的选项位于名为 auto-revert 的 Custom 组中. 其他特定于 Magit 的选项位于 magit 组中.
- 自动 Reverting 的风险 (Risk of Reverting Automatically)
对于绝大多数用户来说, 在磁盘上更改文件后自动 revert 访问文件的 buffers 是无害的.
如果 buffer 已修改 (即, 它包含尚未保存的更改), 那么 Emacs 将拒绝自动 revert 它. 如果你保存先前修改的 buffer, 那么会导致被 Git 视为未提交的更改. Git 将拒绝执行任何会导致这些更改丢失的命令. 换句话说, 如果有任何东西可能丢失, 那么 Git 或 Emacs 将拒绝丢弃更改.
但是, 如果你将访问文件的 buffers 用作一种临时的 "staging area", 那么自动 reverts 可能会导致数据丢失. 到目前为止, 我只听说过一个用户使用这种工作流程.
一个例子: 你在一个 buffer 中访问某个文件, 编辑它, 并保存更改. 然后, 在 Emacs 外部 (或者至少不是使用 Magit 或保存 buffer) 你再次更改磁盘上的文件. 此时 buffer 是唯一存在中间版本的地方. 你已经将更改保存到磁盘, 但那之后已被覆盖. 同时 Emacs 认为 buffer 未修改 (因为自上次保存到访问的文件以来你没有对其进行任何更改), 因此不反对将其自动 revert. 此时 Auto-Revert 模式将启动. 它会检查 buffer 是否已修改, 既然不是这种情况, 它将 revert 它. 中间版本将会丢失. (实际上你仍然可以使用
undo命令找回它.)如果你的工作流程依赖于 Emacs 在 buffer 中保留中间版本, 那么你必须禁用所有 Auto-Revert 模式. 但请考虑, 即使不使用 Auto-Revert 模式, 这样的工作流程也是危险的, 因此应避免. 如果 Emacs 崩溃或者你错误地退出了 Emacs, 那么你也会丢失 buffer 内容. 将没有包含中间版本的自动保存文件 (因为当你保存 buffer 时它被删除了), 并且不会询问你是否要保存 buffer (因为它未修改).
4.2. 4.2 Sections (部分)
Magit buffers 被组织成嵌套的 sections, 类似于 Org 模式中 sections 的处理方式. sections 可以折叠和展开. 每个 section 也有一个类型, 某些 sections 也有一个值. 对于每种 section 类型, 也可以有一个局部 keymap, 由该类型的所有 sections 共享.
利用 section 的值和类型, 许多命令对当前 section 进行操作, 或者当 region 处于活动状态并选择相同类型的 sections 时, 对所有选定的 sections 进行操作. 仅对特定 section 类型有意义的命令 (相对于仅仅根据类型表现不同) 通常绑定在 section 类型 keymaps 中.
4.2.1. 4.2.1 Section 移动 (Section Movement)
要在 section 内移动, 请使用常规键 (C-p, C-n, C-b, C-f 等), 其全局绑定未被遮蔽. 要移动到另一个 section, 请使用以下命令.
这里描述的 section 移动命令运行 hook magit-section-movement-hook. 请注意, 它们显式运行该 hook, 而 Emacs 和其他包定义的任意其他移动不运行该 hook. 该 hook, 以及可以添加到其中或作为其默认值一部分的 hook 函数, 如下所述.
p(magit-section-backward) 如果不在 section 的开头, 则移动到当前 section 的开头. 如果在 section 的开头, 则移动到上一个可见 section 的开头.n(magit-section-forward) 移动到下一个可见 section 的开头.M-p(magit-section-backward-siblings) 移动到上一个同级 section 的开头. 如果没有上一个同级 section, 则移动到父 section.M-n(magit-section-forward-siblings) 移动到下一个同级 section 的开头. 如果没有下一个同级 section, 则移动到父 section.^(magit-section-up) 移动到当前 section 的父 section 的开头.
上述命令都调用 hook magit-section-movement-hook. 下面列出的任何函数都可以用作此 hook 的成员.
你可能想删除 Magit 使用 add-hook 添加的一些函数. 在这样做时, 你必须确保你不尝试删除尚未添加的函数, 例如:
(with-eval-after-load 'magit-diff (remove-hook 'magit-section-movement-hook 'magit-hunk-set-window-start))
magit-section-movement-hook[Variable] 此 hook 由所有上述 section 移动命令在到达目的地后运行. 它不由 Emacs 或第三方包提供的任意其他移动命令 (如next-line) 运行.magit-hunk-set-window-start[Function] 此 hook 函数确保当前 section 的开头是可见的, 前提它是 hunk section. 否则, 它什么也不做. 加载magit-diff将此函数添加到 hook.magit-section-set-window-start[Function] 此 hook 函数确保当前 section 的开头是可见的, 无论 section 的类型如何. 如果你将此添加到magit-section-movement-hook, 那么你必须依次删除 hunk-only 变体.magit-log-maybe-show-more-commits[Function] 此 hook 函数仅在 log buffers 中有效, 并且 point 在 "show more" section 上. 如果是这种情况, 那么它会将显示的提交数量加倍. 加载magit-log将此函数添加到 hook.magit-log-maybe-update-revision-buffer[Function] 在 log buffer 内移动时, 此函数会更新 revision buffer, 前提是它已在同一 frame 的另一个窗口中显示. 加载magit-log将此函数添加到 hook.magit-log-maybe-update-blob-buffer[Function] 在 log buffer 内移动且同一 frame 的另一个窗口显示 blob buffer 时, 此函数会在该窗口中显示 point 处 commit 的 blob buffer.magit-status-maybe-update-revision-buffer[Function] 在 status buffer 内移动时, 此函数会更新 revision buffer, 前提是它已在同一 frame 的另一个窗口中显示.magit-status-maybe-update-stash-buffer[Function] 在 status buffer 内移动时, 此函数会更新 stash buffer, 前提是它已在同一 frame 的另一个窗口中显示.magit-status-maybe-update-blob-buffer[Function] 在 status buffer 内移动且同一 frame 的另一个窗口显示 blob buffer 时, 此函数会在该窗口中显示 point 处 commit 的 blob buffer.magit-stashes-maybe-update-stash-buffer[Function] 在列出 stashes 的 buffer 内移动时, 此函数会更新 stash buffer, 前提是它已在同一 frame 的另一个窗口中显示.magit-update-other-window-delay[User Option] 自动更新另一个窗口之前的延迟. 使用 Magit 自己的 section 移动命令 (但不是其他移动命令) 在某些 buffers 中移动时, 可以选择性地更新在另一个窗口中显示的某些其他 buffers, 以显示有关 point 处 section 的信息. 当按住键移动超过一个 section 时, 这将为途中的每个 section 更新该 buffer. 为了防止这种情况, 更新 revision buffer 会延迟, 此选项控制延迟多长时间. 为了获得最佳体验, 你可能需要调整此延迟和/或图形环境或操作系统的键盘重复率和延迟.
4.2.2. 4.2.2 Section 可见性 (Section Visibility)
Magit 提供了许多用于更改 sections 可见性的命令, 但你只需要接下来的两个即可开始使用.
TAB(magit-section-toggle) 切换当前 section 主体的可见性.C-c TAB(magit-section-cycle)C-<tab>(magit-section-cycle) 循环当前 section 及其子项的可见性. 如果使用C-<tab>调用此命令, 并且该键全局绑定到tab-next, 那么此命令将转向表现得像那个命令, 你必须改为使用C-c TAB来循环 section 可见性. 如果你想继续使用C-<tab>循环 section 可见性, 但也想使用tab-bar-mode, 那么你必须阻止该模式使用此键, 并将另一个键绑定到tab-next. 因为tab-bar-mode不使用模式映射而是操纵全局映射, 这涉及 advisingtab-bar--define-keys.M-<tab>(magit-section-cycle-diffs) 循环当前 buffer 中 diff 相关 sections 的可见性.S-<tab>(magit-section-cycle-global) 循环当前 buffer 中所有 sections 的可见性.1(magit-section-show-level-1)2(magit-section-show-level-2)3(magit-section-show-level-3)4(magit-section-show-level-4) 显示当前 section 周围直到 N 级的 sections.M-1(magit-section-show-level-1-all)M-2(magit-section-show-level-2-all)M-3(magit-section-show-level-3-all)M-4(magit-section-show-level-4-all) 显示所有 sections 直到 N 级.
一些用于实现上述命令的函数也作为命令本身公开. 默认情况下, 没有键绑定到这些命令, 因为它们通常被认为不太有用. 但你的情况可能有所不同.
magit-section-show[Command] 显示当前 section 的主体.magit-section-hide[Command] 隐藏当前 section 的主体.magit-section-show-headings[Command] 递归显示当前 section 子项的标题. 仅显示标题. 以前显示的纯文本主体将被隐藏.magit-section-show-children[Command] 递归显示当前 section 子项的主体. 带有前缀参数时, 显示子项直到当前 section 的层级, 并隐藏更深的子项.magit-section-hide-children[Command] 递归隐藏当前 section 子项的主体.magit-section-toggle-children[Command] 切换当前 section 子项主体的可见性.
当 buffer 首次创建时, 一些 sections 显示为展开, 而其他则不显示. 这是硬编码的. 当 buffer 刷新时, 保留先前的可见性. 某些 sections 的初始可见性也可以使用 hook magit-section-set-visibility-hook 覆盖.
magit-section-initial-visibility-alist[User Option] 此选项可用于覆盖 sections 的初始可见性. 将来它也将用于定义默认值, 但目前 section 的默认值仍是硬编码的. 值为一个 alist. 每个元素将 section 类型或谱系映射到此类 sections 的初始可见性状态. 状态必须是show或hide之一, 或返回这些符号之一的函数. 函数将 section 作为唯一参数调用. 使用命令magit-describe-section-briefly确定 section 的谱系或类型. 输出中的向量是 section 谱系, 类型是该向量的第一个元素. 可以使用通配符, 参见magit-section-match.magit-section-cache-visibility[User Option] 此选项控制如果 section 消失并在稍后再次出现, 是否应恢复其先前的可见性状态. 值为布尔值或 section 类型的列表. 如果为t, 则缓存所有 sections 的可见性. 否则仅针对类型与列出的类型之一匹配的 sections 执行此操作. 这要求函数magit-section-cached-visibility是magit-section-set-visibility-hook的成员.magit-section-set-visibility-hook[Variable] 此 hook 在首次创建 buffer 时以及刷新现有 buffer 时运行, 用于确定当前插入的 section 的可见性. 每个函数都带有一个参数 (正在插入的 section) 调用. 它应该返回hide或show, 或者nil以保持可见性未定义. 如果没有函数决定可见性并且 buffer 正在刷新, 则保留可见性; 或者如果正在创建 buffer, 则使用硬编码的默认值. 通常这应该仅用于设置初始可见性, 而不在刷新期间使用. 如果magit-insert-section--oldroot为非nil, 则 buffer 正在刷新, 这些函数应立即返回nil.magit-section-visibility-indicators[User Option] 此选项控制是否以及如何指示 section 可以展开/折叠. 如果为nil, 则不显示任何指示器. 否则值必须是一个包含两个元素的列表. 第一个控制图形 frames 中使用的指示器, 第二个控制终端 frames 中的指示器. 对于图形 frames, 以下所有形式均有效, 而终端 frames 没有 fringes, 因此不支持第一种形式.(EXPANDABLE-BITMAP . COLLAPSIBLE-BITMAP)这两个值必须是值为 fringe bitmaps 的变量. 在这种情况下, 每个可以展开或折叠的 section 在左 fringe 中都有一个指示器. 要在指示器周围提供额外的填充, 请在magit-mode-hook中设置left-fringe-width, 例如:(add-hook 'magit-mode-hook (lambda () (setq left-fringe-width 20)))
(EXPANDABLE-CHAR . COLLAPSIBLE-CHAR)在这种情况下, 每个可以展开或折叠的 section 在左 margin 中都有一个指示器.(STRING . BOOLEAN)在这种情况下, STRING (通常是省略号) 显示在每个折叠 section 的标题末尾. 展开的 sections 没有指示器. cdr 控制省略号的外观是否考虑 section 高亮. 这样做可能会对性能产生影响, 而不这样做有点丑陋.
4.2.3. 4.2.3 Section Hooks
哪些 sections 被插入到某些 buffers 中是由 hooks 控制的. 这包括 status 和 refs buffers. 对于其他 buffers, 例如 log 和 diff buffers, 这是不可能的. 命令 magit-describe-section 可用于查看哪个 hook (如果有) 负责在 point 处插入 section.
对于其 sections 可以由用户自定义的 buffers, 存在一个名为 magit-TYPE-sections-hook 的 hook 变量. 应使用 magit-add-section-hook 更改此 hook. 避免使用 add-hooks 或 Custom 接口.
各种可用的 section hook 变量将在本手册后面与相应的 "section 插入函数" 一起描述.
magit-add-section-hook hook function &optional at append local[Function] 将函数 FUNCTION 添加到 section hook HOOK 的值中. 除非可选的 APPEND 为非nil, 否则在 hook 列表的开头添加 FUNCTION, 在这种情况下, FUNCTION 添加在末尾. 如果 FUNCTION 已经是成员, 则将其移动到新位置. 如果可选的 AT 为非nil且是 hook 列表的成员, 则改为在其旁边添加 FUNCTION. 根据 APPEND 在 AT 之前或之后添加, 或者如果 APPEND 是符号replace, 则用 FUNCTION 替换 AT. 对于任何其他非nil值, 将 FUNCTION 放在 AT 之后. 如果为nil, 则将 FUNCTION 放在 AT 之前. 如果 FUNCTION 已经是列表的成员但 AT 不是, 则将 FUNCTION 留在原地. 如果可选的 LOCAL 为非nil, 则修改 hook 的 buffer-local 值而不是其全局值. 这通过复制默认值使 hook 变为 local. 然后修改该副本. HOOK 应该是一个符号. 如果 HOOK 为 void, 则首先将其设置为nil. HOOK 的值不能是单个 hook 函数. FUNCTION 应该是一个不带参数并在 point 处插入一个或多个 sections 并向前移动 point 的函数. 当插入 section 没有意义时, FUNCTION 可以选择不插入它的 section(s). 它不应该被滥用于其他副作用.
要从 section hook 中删除函数, 请使用 remove-hook.
4.2.4. 4.2.4 Section 类型和值 (Section Types and Values)
每个 section 都有一个类型, 例如 hunk, file 和 commit. 某些 section 类型的实例也有一个值. 例如, file 类型 section 的值是一个文件名.
用户通常不必担心 section 的类型和值, 但有时了解它们会很方便.
H(magit-describe-section) 此命令在一个单独的 buffer 中显示有关 point 处 section 的信息.magit-describe-section-briefly[Command] 此命令在 echo area 中显示有关 point 处 section 的信息, 格式为#<magit-section VALUE [TYPE PARENT-TYPE...] BEGINNING-END>.
许多命令根据 point 处 section 的类型表现不同和/或以某种方式使用该 section 的值. 但这只是同一按键根据当前 section 执行不同操作的原因之一.
此外, 可能会为每种 section 类型定义一个 keymap, 命名为 magit-TYPE-section-map. 该 keymap 用作属于相应类型任何 section 的所有文本的文本属性 keymap. 如果某种类型不存在这样的 map, 那么你可以自己定义它, 它会被自动使用.
4.2.5. 4.2.5 Section 选项 (Section Options)
本节描述了对不仅仅某种类型 sections 有影响的选项. 正如你所见, 这样的选项并不多.
magit-section-show-child-count[User Option] 是否将子项数量附加到 section 标题. 这仅影响可以从这些信息中受益的 sections.
4.3. 4.3 Transient 命令
许多 Magit 命令实现为 transient 命令. 首先用户调用一个 prefix (前缀) 命令, 这会导致其 infix (中缀) 参数和 suffix (后缀) 命令显示在 echo area 中. 然后用户可选地设置一些 infix 参数, 最后调用其中一个 suffix 命令.
这是在库 transient 中实现的. 早期的 Magit 版本使用包 magit-popup, 更早的版本使用库 magit-key-mode.
Transient 在 transient 中有文档记录.
C-x M-g(magit-dispatch)C-c g(magit-dispatch) 此 transient prefix 命令将 Magit 的大多数其他 prefix 命令绑定为 suffix 命令, 并在临时 buffer 中显示它们, 直到调用其中一个. 调用这样的子前缀会导致显示该命令的 suffixes, 而不是magit-dispatch的 suffixes. 此命令在 Magit buffers 外部也很有用 (或者特别有用), 因此 Magit 默认将其绑定到全局 keymap 中的C-c M-g.C-c g将是一个更好的绑定, 但我们默认不能使用它, 因为该键序列保留给用户. 参见第 129 页的 [Global Bindings], 了解更多默认和推荐的按键绑定.
4.4. 4.4 Transient 参数和缓冲区变量 (Transient Arguments and Buffer Variables)
一旦使用这些参数调用的 git 命令返回, 许多 Magit transient prefix 命令的 infix 参数就不再有效. 创建 commit 的命令就是一个很好的例子. 如果用户更改了参数, 那么这只会影响下一次 suffix 命令的调用. 如果稍后再次调用相同的 transient prefix 命令, 则参数最初会重置为默认值. 此默认值可以为当前 Emacs 会话设置或永久保存, 参见 transient 中的 "Saving Values" 一节. 也可以使用 C-M-p 和 C-M-n 在以前使用的参数集之间循环, 参见 transient 中的 "Using History" 一节.
但是, 即使在使用这些参数调用的 git 命令返回后, 许多其他 transient 命令的 infix 参数也会继续有效. 最重要的此类命令是那些在专用 buffer 中显示 diff 或 log 的命令. 只要相应的 diff 或 log 正在显示, 它们的参数显然会继续有效. 此外, 使用的参数存储在 buffer-local 变量中以供将来参考.
对于第二组命令, 再次调用 transient prefix 命令时将参数重置为全局值并不总是可取的.
如上所述, 可以在 transient 弹出窗口可见时循环显示以前使用的参数集. 这意味着我们可以始终将 infix 参数重置为默认值, 因为现有 buffer 中处于活动状态的参数集只需按几次 C-M-p 即可. Magit 可以配置为这种行为, 但因为我预计大多数用户不会觉得这很方便, 所以这不是默认设置.
另请注意, 可以使用 D 和 L 上各自的 "refresh" transient prefix 命令更改当前 buffer 中使用的 diff 和 log 参数 (包括包含 diff 和 log sections 的 status buffer). (另一方面, d 和 l 旨在更改显示 什么 diff 或 log. 也可以同时更改 diff 或 log 的显示 方式, 但如果你只想做后者, 那么你应该使用 refresh 变体.) 因为这些二级 diff 和 log transient prefixes 是关于更改当前 buffer 中使用的参数, 所以它们总是以该 buffer 中当前有效的参数集开始.
有些命令通常直接调用, 即使它们也可以作为 transient prefix 命令的 suffix 调用. 最突出的是 magit-show-commit, 通常在 point 位于 log 中的 commit 上时通过输入 RET 调用, 但也可以从 magit-diff transient prefix 调用.
当直接调用此类命令时, 重用相应 buffer-local 值指定的参数非常重要, 而不是使用默认参数. 想象一下你在 log 中按 RET 在不同的 buffer 中显示 point 处的 commit, 然后使用 D 更改该 buffer 中 diff 的显示方式. 然后你在另一个 commit 上按 RET 来显示它, 此时 diff 参数被重置为默认值. 这不酷; 所以 Magit 默认不这样做.
magit-prefix-use-buffer-arguments[User Option] 此选项控制某些 transient prefix 命令中最初显示的 infix 参数是否基于其 suffixes 更新的 buffer 中当前有效的参数.magit-diff和magit-logtransient prefix 命令受此选项影响.magit-direct-use-buffer-arguments[User Option] 此选项控制某些命令在直接调用时 (即, 不作为 transient prefix 命令的 suffix), 是否使用它们即将更新的 buffer 中当前活动的参数. 替代方法是使用这些参数的默认值, 这可能会更改 buffer 中使用的参数.
上述两个选项的有效值为:
always: 始终使用相应 buffer 中当前活动的参数集, 当然前提是该 buffer 存在.selected或t: 使用相应 buffer 的参数集, 但仅当它显示在当前 frame 的窗口中时. 这是两个变量的默认值.current: 使用相应 buffer 的参数集, 但仅当它是当前 buffer 时.never: 从不使用相应 buffer 的参数集.
恐怕这还会变得更复杂:
- 全局 diff 和 log 参数是为每种支持的模式单独设置的. 例如 diff 参数在
magit-diff-mode,magit-revision-mode,magit-merge-preview-mode和magit-status-modebuffers 中具有不同的值. 设置或保存一种模式的值不会更改其他模式的值. 但是历史记录是共享的. - 当从 log buffer 直接调用
magit-show-commit时, 文件过滤器是从该 buffer 获取的, 而不是从 revision buffer 或模式的全局 diff 参数获取的. - 即使它们是 diff 前缀的 suffixes,
magit-show-commit和magit-stash-show也不使用 diff 命令使用的 diff buffer, 而是使用专用的 revision 和 stash buffers. 当你调用 diff 前缀时, Magit 不知道你将调用哪个 suffix 命令. 虽然不确定, 但用户通常会调用使用 diff buffer 的命令之一, 因此初始 infix 参数是该 buffer 中使用的参数. 但是如果你直接调用其中一个命令, 那么 Magit 知道它应该使用来自 revision 或 stash buffer 的参数. - Log 前缀还具有 reflog 命令, 但这些命令不使用 log 参数.
- 如果从
magit-refs-modebuffer 调用magit-show-refs, 那么它充当 refresh 前缀, 因此无条件使用 buffer 的参数作为初始参数. 如果它在其他地方带前缀参数调用, 那么它充当常规前缀, 因此尊重magit-prefix-use-buffer-arguments. 如果它在其他地方不带前缀参数调用, 那么它充当直接命令, 因此尊重magit-direct-use-buffer-arguments.
4.5. 4.5 补全, 确认和选择 (Completion, Confirmation and the Selection)
4.5.1. 4.5.1 动作确认 (Action Confirmation)
默认情况下, 许多可能导致数据丢失的操作都必须得到确认. 这包括许多非常常见的操作, 因此这可能很快变得烦人. 许多这些操作可以撤消, 如果你考虑过如何撤消某些错误, 那么禁用相应操作的确认应该是安全的.
选项 magit-no-confirm 可用于告诉 Magit 执行某些操作而无需用户确认. 请注意, 虽然此选项仅用于禁用特定操作集的确认, 但下一节将解释另一种告诉 Magit 少问问题的方法.
magit-no-confirm[User Option] 此选项的值是一个符号列表, 代表在执行之前无需用户确认的操作. 默认情况下, 许多潜在危险的命令会要求用户确认. 下面的每个符号都代表一个操作, 当无意中调用或未完全意识到后果时, 可能会导致流泪. 在许多情况下, 有几个命令执行某个操作的变体, 因此我们不使用命令名称, 而是使用更通用的符号.- 应用更改:
discard: 丢弃一个或多个更改 (即 hunks 或文件的完整 diff) 会丢失该更改, 很明显.reverse: Reverting 一个或多个更改通常可以通过 reverting reversion 来撤消.stage-all-changes,unstage-all-changes: 当同时存在 staged 和 unstaged 更改时, un-/staging 所有内容会破坏这种区别. 当然这也适用于 un-/staging 单个更改时, 但那时损失较小, 并且人们经常这样做, 每次都必须确认是不可接受的.
- 文件:
delete: 当删除 Git 尚未跟踪的文件时, 它将完全丢失, 而不仅仅是最后的更改. 非常危险.trash: 也可以将其移动到系统垃圾箱, 而不是删除文件. 显然比删除它危险性小得多. 另请参见选项magit-delete-by-moving-to-trash.resurrect: 删除的文件可以通过 "删除" 删除来轻松恢复, 这使用与最初用于删除该文件的相同命令来完成.untrack: Untracking 一个文件可以通过再次 tracking 它来撤消.rename: 重命名文件很容易撤消.
- 序列:
reset-bisect: 中止 (Git 称为 "resetting") bisect 操作会丢失迄今为止收集的所有信息.abort-cherry-pick: 中止 cherry-pick 会丢弃用户已经执行的所有冲突解决.abort-revert: 中止 revert 会丢弃用户已经执行的所有冲突解决.abort-rebase: 中止 rebase 会丢弃所有已修改的 commits, 但可以从 reflog 恢复这些 commits.abort-merge: 中止 merge 会丢弃用户已经执行的所有冲突解决.merge-dirty: 使用 dirty worktree 进行合并可能很难回到合并启动前的状态.
- 引用:
delete-unmerged-branch: 一旦删除了分支, 只能使用 Git 提供的低级恢复工具来恢复. 甚至 reflog 也消失了. 用户总是必须通过接受默认选择 (或选择另一个分支) 来确认删除分支, 但当分支尚未合并时, 还要确保用户意识到这一点.delete-pr-remote: 当删除从 pull-request 创建的分支时, 如果该 remote 上没有其他分支仍然存在, 那么magit-branch-delete提议也删除该 remote. 这应该是安全的, 因为它仅在 remotes 命名空间中不存在其他 refs 时发生, 并且如果需要, 你可以重新创建 remote.drop-stashes: Dropping stash 是危险的, 因为 Git 将 stashes 存储在 reflog 中. 一旦删除了 stash, 不使用 Git 提供的低级恢复工具就无法恢复. 当 drop 单个 stash 时, 用户总是必须通过接受默认值 (或选择另一个) 来确认. 此操作仅涉及一次删除多个 stashes.
- Publishing:
set-and-push: 当 push 到 upstream 或 push-remote 且实际上尚未配置时, 用户可以先设置目标. 如果他/她过快确认默认值, 那么他/她最终可能会 push 到错误的分支, 如果远程仓库配置为不允许修复此类错误, 那么这可能会非常尴尬和恼人.
编辑已发布历史: 如果不在此处添加这些符号, 在编辑已推送到
magit-published-branches中列出的分支之一的 commits 之前, 你将收到警告.amend-published: 影响大多数 amend 到 "HEAD" 的命令.rebase-published: 影响执行交互式 rebases 的命令. 这包括来自 commit transient 的修改 "HEAD" 以外 commit 的命令, 即各种 fixup 和 squash 变体.edit-published: 影响命令magit-edit-line-commit和magit-diff-edit-hunk-commit. 这两个命令使得很容易意外编辑已发布的 commit, 所以在配置它们不要求确认之前你应该三思.
要完全禁用确认, 请在此处添加所有三个符号或将
magit-published-branches设置为nil.- 各种:
stash-apply-3way: 当不能使用git stash apply应用 stash 时, Magit 改用git apply, 可能使用--3way参数, 这并不总是完全安全的. 另请参见magit-stash-apply.kill-process: 很少有理由 kill 一个进程.
- 全局设置:
你可以将其设置为原子
t, 而不是将所有上述符号添加到此选项的值中, 这具有与添加所有上述符号相同的效果. 这样做肯定是一个坏主意, 特别是因为将来可能会添加其他符号. 所以即使你不想被要求确认任何这些操作, 你最好还是单独添加所有相应的符号.
当启用
magit-wip-before-change-mode时, 以下操作可以相当容易地撤消:discard,reverse,stage-all-changes和unstage-all-changes. 当且仅当启用了此模式时,safe-with-wip具有与单独添加所有这些符号相同的效果.- 应用更改:
4.5.2. 4.5.2 补全和确认 (Completion and Confirmation)
许多 Magit 命令要求用户从可能的操作对象列表中进行选择, 同时提供最可能的选择作为默认值. 对于许多这些命令, 默认值是 point 处的对象, 前提是它实际上是一个有效的操作对象. 对于许多作用于分支的命令, 如果 point 处没有分支, 则当前分支用作默认值.
这些命令将询问确认和询问操作目标结合到一个动作中. 用户可以使用 RET 确认默认目标或使用 C-g 中止. 这类似于 y-or-n-p 提示, 但确认或中止的键不同.
同时, 用户也有机会选择另一个目标, 这很有用, 因为对于某些命令和/或在某些情况下, 你可能想在通过移动到目标选择它之前先选择动作.
但是你可能会发现, 对于某些命令, 你总是想使用默认目标 (如果有), 或者甚至你希望命令对默认值进行操作而无需任何确认. 选项 magit-dwim-selection 可用于配置某些命令以实现该效果.
注意, 当 region 处于活动状态时, 许多命令作用于使用基于 region 的机制选定的对象, 在许多情况下会询问确认. 这种基于 region 的机制称为 "selection" (选择), 下一节将详细描述. 当存在对调用的命令有效的 selection 时, 该命令从不提议对其他东西进行操作, 并且它是否要求确认不受此选项控制.
另请注意, Magit 会要求确认某些不与补全 (或 selection) 耦合的操作. 此类对话框也不受此选项影响, 并在上一节中进行了描述.
magit-dwim-selection[User Option] 此选项可用于告诉某些命令使用 point 处的对象, 而不是要求用户选择要操作的候选对象, 无论是否确认. 值的形式为((COMMAND nil|PROMPT DEFAULT)...).COMMAND是不应提示选择的命令. 要产生效果, 该命令必须使用函数magit-completing-read或使用该函数的实用程序函数.- 如果命令多次使用
magit-completing-read, 那么PROMPT可用于仅影响其中一种使用.PROMPT如果为非nil, 是一个正则表达式, 用于匹配传递给magit-completing-read的PROMPT参数. DEFAULT指定如何使用默认值. 如果为t, 则无需确认即可使用传递给magit-completing-read的DEFAULT参数. 如果为ask, 则给用户中止的机会.DEFAULT也可以为nil, 在这种情况下条目无效.
4.5.3. 4.5.3 选择 (The Selection)
如果 region 处于活动状态, 那么许多 Magit 命令将作用于使用基于 region 的机制选定的对象, 而不是单个对象. 当 region 不处于活动状态时, 这些命令作用于 point 处的对象或读取单个操作对象. 这在上一节中已有描述–本节仅涵盖如何选择多个对象, 如何将其可视化, 以及在这种情况下某些命令的行为方式.
Magit 的多对象选择机制 (或者更确切地说是代表这些对象的 sections) 基于 Emacs region, 但 Magit 认为选定的区域通常比 region 更大, 并且适用额外的限制.
Magit 区分有资格形成有效 Magit selection 的 region 和没有资格的 region. 如果 region 不符合资格, 则按其在其他 Emacs buffers 中的方式显示. 如果 region 确实符合 Magit selection 的资格, 则 selection 始终可视化, 而 region 本身仅在开始和结束于同一行时才可视化.
为了使 region 有资格作为 Magit selection, 它必须从一个 section 的标题开始, 并在同级 section 的标题结束. 注意, 如果 region 的结束处于 section 标题的最开始 (即, 在一行的最开始), 那么该 section 被认为在 selection 内.
这与 Emacs 中通常处理 region 的方式不一致–如果 region 在一行的开头结束, 那么该行在 region 之外. 由于 Magit 如何可视化 selection, 这种差异应该是显而易见的.
并非每个命令都对每个有效的 selection 起作用. 有些命令甚至不考虑 point 的位置, 其他命令可能作用于 point 处的 section 但不支持作用于 selection, 即使支持 selection 的命令当然也只有在它选择了它们可以操作的对象时才这样做.
这是 selection 必须包含 point 处 section 的主要原因. 即使存在 selection, 调用的命令也可能会忽略它, 在这种情况下它可能只作用于当前 section. 仅对当前 section 进行操作而不对其他选定的 sections 进行操作, 比对当前 section 进行操作而不是选定的 sections 进行操作要安全得多. 后者会非常令人惊讶, 如果当前 section 始终是 selection 的一部分, 那么这种情况就不会发生.
magit-keep-region-overlay[Variable] 此变量控制即使存在有效的 Magit selection 或 hunk-internal region, region 是否也照常可视化. 有关更多信息, 请参阅 doc-string.
4.5.4. 4.5.4 块内区域 (The hunk-internal region)
与上一节描述的 Magit selection 有些相关的是 hunk-internal region (块内区域).
像 selection 一样, hunk-internal region 基于 Emacs region, 但会导致该 region 不像在其他 Emacs buffers 中那样可视化, 并且即使它在行的最开始结束, 也包括 region 结束的那一行.
与基于必须从一个 section 的标题开始并在同级 section 的 section 结束的 region 的 selection 不同, hunk-internal region 必须从 hunk section 的主体 内 开始, 并在 同一 section 的主体中结束.
"Apply" 命令遵循 hunk-internal region, 这些命令除其他目标外还可以作用于 hunk. 如果 hunk-internal region 处于活动状态, 那么此类命令仅作用于 hunk 的标记部分, 而不是完整的 hunk.
4.5.5. 4.5.5 对补全框架的支持 (Support for Completion Frameworks)
内置选项 completing-read-function 指定 completing-read 用于要求用户从选项列表中进行选择的低级函数. 其默认值为 completing-read-default. 替代补全框架通常通过替换其自己的实现来激活自身.
主要是出于历史原因, Magit 提供了一个类似的名为 magit-completing-read-function 的选项, 它仅控制 magit-completing-read 使用的低级函数. 此选项还可以为 Magit 使用与 Emacs 其余部分不同的补全机制, 但不建议这样做.
你很可能不必自定义 Magit 特定选项来使用替代补全框架. 例如, 如果你启用了 ivy-mode, 那么 Magit 将尊重它, 如果你启用了 helm-mode, 那么你也完成了.
magit-completing-read-function[User Option] 此变量的值是由使用magit-completing-read(相对于内置completing-read) 的代码用于执行补全的低级函数. 默认值magit-builtin-completing-read至少适用于标准补全机制,ivy-mode和helm-mode. 内置completing-read和completing-read-default不适合在此处使用.magit-builtin-completing-read执行一些额外的工作, 任何用来代替它的函数也必须做同样的事情.magit-builtin-completing-read prompt choices &optional predicate require-match initial-input hist def[Function] 此函数使用内置completing-read执行补全, 并做一些额外的 Magit 特定工作.magit-completing-read prompt choices &optional predicate require-match initial-input hist def fallback[Function] 这是 Magit 命令在需要用户选择单个操作对象时使用的函数. 参数含义与completing-read相同, 除了FALLBACK, 它是此函数独有的, 如下所述. 此函数可能不要求用户从可能的候选列表中进行选择, 而是仅返回DEF指定的默认值, 无论是否需要用户确认. 是否如此取决于PROMPT,this-command和magit-dwim-selection. 有关更多信息, 请参阅后者的文档.如果在 minibuffer 中读取值, 则此函数的行为类似于
completing-read, 除了以下几点:COLLECTION必须是选项列表. 不支持函数.- 如果
REQUIRE-MATCH为nil且用户未选择退出, 则返回nil而不是空字符串. - 如果
REQUIRE-MATCH为any, 则不需要匹配但需要非空输入 (或非nilDEFAULT, 因为它被替换为空输入). - 如果
REQUIRE-MATCH为非nil且用户未选择退出, 则引发用户错误. FALLBACK指定仅在主要默认值DEF为nil时使用的辅助默认值. 辅助默认值不受magit-dwim-selection的影响–如果DEF为nil但FALLBACK不为nil, 那么此函数总是要求用户选择一个候选者, 就像两个默认值都为nil一样.- 在
PROMPT和DEF(如果DEF为nil则为FALLBACK) 上调用format-prompt. 这会将 ": " 附加到提示, 并且还可能将默认值添加到提示, 使用minibuffer-default-prompt-format指定的格式并取决于magit-completing-read-default-prompt-predicate.
4.5.6. 4.5.6 附加补全选项 (Additional Completion Options)
magit-list-refs-sortby[User Option] 对于许多从用户读取 ref 或 refs 的命令, 此选项的值可用于控制 refs 的顺序. 有效值包括git for-each-ref的--sort标志接受的任何键. 默认情况下, refs 按其全名按字母顺序排序 (例如, "refs/heads/master").
4.6. 4.6 鼠标支持 (Mouse Support)
双击 section 标题可切换其主体的可见性 (如果有). 同样, 单击左 fringe 可切换相应 section 的可见性.
提供了一个上下文菜单, 但必须显式启用. 在 Emacs 28 及更高版本中, 启用全局模式 context-menu-mode. 如果你使用较旧的 Emacs 版本, 设置 magit-section-show-context-menu-for-emacs<28.
4.7. 4.7 运行 Git (Running Git)
4.7.1. 4.7.1 查看 Git 输出 (Viewing Git Output)
Magit 运行 Git 要么是为了副作用 (例如, 推动时), 要么是为了获取一些值 (例如, 当前分支的名称).
当运行 Git 产生副作用时, 进程输出会记录在每个仓库的 log buffer 中, 当事情没有按预期进行时, 可以使用 magit-process-buffer 命令查阅.
保留多达 magit-process-log-max 个 Git 命令的输出/错误.
$(magit-process-buffer) 此命令显示当前仓库的 process buffer.
在该 buffer 内, 用于导航和显示 sections 的常用键绑定可用. 还有一个额外的命令.
k(magit-process-kill) 此命令 kill (杀死) point 处 section 代表的进程.M-x magit-toggle-git-debug此命令切换是否报告额外的 git 错误. Magit 基本上出于两个原因之一调用 git: 为了副作用或对其标准输出做某事. 当运行 git 产生副作用时, 其输出 (包括错误消息) 进入 process buffer, 使用$时会显示该 buffer. 当 git 的输出以某种方式被消耗时, 将其也插入此 buffer 会太昂贵, 但是使用此命令可以暂时启用. 在这种情况下, 如果 git 以非零退出状态返回, 那么至少将其标准错误插入此 buffer. 还要注意, 仅仅因为 git 以非零状态退出并打印错误消息, 通常并不意味着就 Magit 而言这是一个错误, 这也是我们通常隐藏这些错误消息的另一个原因. 某些错误消息是否与某些意外行为相关, 必须根据具体情况进行判断.
4.7.2. 4.7.2 Git 进程状态 (Git Process Status)
当 Git 进程为副作用运行时, Magit 在 mode line 中使用 magit-mode-line-process face 显示一个指示器.
如果 Git 进程成功退出, 进程指示器将立即从 mode line 中移除.
在 Git 错误的情况下, 进程指示器不会被移除, 而是用 magit-mode-line-process-error face 高亮显示, 并且来自 process buffer 的错误详情作为工具提示提供给鼠标用户. 此错误指示器保留在 mode line 中, 直到下一次 magit buffer 刷新.
如果你不希望在 mode line 中指示进程错误, 请将 magit-process-display-mode-line-error 设置为 nil.
进程错误显示在 status buffer 的顶部和 echo area 中. 在这两个地方都附加了一个提示, 通知用户他们可以在 process buffer 中看到完整的输出以及如何显示该 buffer. 但是, 一旦你意识到了这一点, 你可能想将 magit-show-process-buffer-hint 设置为 nil.
4.7.3. 4.7.3 手动运行 Git (Running Git Manually)
虽然 Magit 提供了许多 Emacs 命令与 Git 交互, 但它并没有涵盖所有内容. 在这些情况下, 你现有的 Git 知识将派上用场. Magit 提供了一些命令, 通过在 minibuffer 中输入任意 Git 命令来运行它们, 而不必切换到 shell.
!(magit-run) 此 transient prefix 命令绑定以下 suffix 命令, 并在临时 buffer 中显示它们, 直到调用 suffix.! !(magit-git-command-topdir) 此命令从用户读取命令并在当前工作树的顶层目录中执行它. 字符串 "git " 用作提示用户输入命令时的初始输入. 可以将其删除以运行其他命令.:(magit-git-command)! p此命令从用户读取命令并在default-directory中执行它. 带有前缀参数时, 命令改为在当前工作树的顶层目录中执行. 字符串 "git " 用作提示用户输入命令时的初始输入. 可以将其删除以运行其他命令.! s(magit-shell-command-topdir) 此命令从用户读取命令并在当前工作树的顶层目录中执行它.! S(magit-shell-command) 此命令从用户读取命令并在default-directory中执行它. 带有前缀参数时, 命令改为在当前工作树的顶层目录中执行.magit-shell-command-verbose-prompt[User Option] 上述命令在读取 shell 命令时使用的提示是否显示将在其中运行它的目录.
这些 suffix 命令启动外部 GUI 工具.
! k(magit-run-gitk) 此命令在当前仓库中运行gitk.! a(magit-run-gitk-all) 此命令在当前仓库中运行gitk --all.! b(magit-run-gitk-branches) 此命令在当前仓库中运行gitk --branches.! g(magit-run-git-gui) 此命令在当前仓库中运行git gui.! m(magit-git-mergetool) 此命令在当前仓库中运行git mergetool --gui. 带有前缀参数时, 这充当 transient prefix 命令, 允许用户选择 mergetool 并更改一些设置.
4.7.4. 4.7.4 Git 可执行文件 (Git Executable)
当 Magit 调用 Git 时, 它可以使用 git 可执行文件的绝对路径, 或者仅使用其名称.
当在本地运行 git 且 system-type 为 windows-nt (任何 Windows 版本) 或 darwin (macOS) 时, 加载 Magit 时 magit-git-executable 设置为绝对路径.
在 Windows 上, 必须使用绝对路径, 因为 Git 附带了几个用于实际 git 二进制文件的 wrapper 脚本, 这些脚本也放置在 $PATH 上, 使用这些 wrappers 之一而不是二进制文件会严重降低性能. 对于某些 macOS 用户, 仅使用可执行文件的名称同样性能极差, 因此我们也避免在该平台上这样做. 在其他平台上, 仅使用名称似乎工作正常.
在通过 Tramp 在远程机器上运行 git 时使用绝对路径, 使用适合本地机器的绝对路径会有问题, 因此使用单独的选项来控制在远程机器上使用的名称或路径.
magit-git-executable[User Option] Magit 在本地主机上使用的 git 可执行文件. 这应该是可执行文件的绝对路径, 或者是字符串 "git" 以让 Emacs 自己找到可执行文件, 使用做这类事情的标准机制.magit-remote-git-executable[User Option] Magit 在通过 Tramp 的远程机器上使用的 git 可执行文件. 通常这应该只是字符串 "git". 考虑自定义tramp-remote-path而不是此选项.
如果 Emacs 无法找到正确的可执行文件, 那么你可以通过显式设置这两个选项之一的值来解决此问题. 这样做应该被视为一种权宜之计; 最好确保 exec-path 或 tramp-remote-path 中的顺序正确.
注意 exec-path 是基于 Emacs 启动时有效的 PATH 环境变量的值设置的. 如果你在 shell 的 init 文件中设置 PATH, 那么只有当你从该 shell 启动 Emacs 时才会对 Emacs 产生影响 (因为进程的环境只传递给其子进程, 而不传递给任意其他进程). 如果这不是你启动 Emacs 的方式, 那么 exec-path-from-shell 包可能会有所帮助; 虽然老实说我也认为这是一种权宜之计.
命令 magit-debug-git-executable 可用于找出 Emacs 在哪里搜索 git.
M-x magit-debug-git-executable此命令显示一个 buffer, 其中包含有关magit-git-executable和magit-remote-git-executable的信息.M-x magit-version此命令在 echo area 中显示当前使用的 Magit, Git 和 Emacs 版本. 非交互式地这只返回 Magit 版本.
4.7.5. 4.7.5 全局 Git 参数 (Global Git Arguments)
magit-git-global-arguments[User Option] 此处设置的参数在每次git可执行文件作为子进程运行时使用. 它们放置在可执行文件本身之后和 git 命令之前 - 如git HERE... COMMAND REST. 有关有效参数, 请参阅 git(1) manpage. 小心你在这里添加的内容, 特别是如果你使用 Tramp 连接到具有古老 Git 版本的服务器. 除非你真的知道你在做什么, 否则永远不要删除默认值的一部分. 并且在添加任何内容之前要非常仔细地考虑; 每次 Magit 出于任何目的运行 Git 时都会使用它.
5. 5 检查 (Inspecting)
Magit 提供的功能大致可以分为三类: 检查现有数据, 操作现有数据或添加新数据, 以及传输数据. 当然, 这是一个相当粗略的区别, 经常不够准确, 但它比没有区别更有用. 本节关注检查数据, 接下来的两节关注操作和传输数据. 然后是关于杂项功能的一节, 这些功能很难归入此分类.
当然, 其他区别也是有意义的, 例如 Git 的 porcelain (瓷件) 和 plumbing (管道) 命令之间的区别, 这在很大程度上相当于 Emacs 的交互式命令和非交互式函数之间的区别. 前面提到的所有章节主要关注 porcelain – Magit 的 plumbing 层将在后面描述.
5.1. 5.1 状态缓冲区 (Status Buffer)
虽然其他 Magit buffers 包含例如一个特定的 diff 或一个特定的 log, 但 status buffer 包含 staged 和 unstaged 更改的 diffs, unpushed 和 unpulled 提交的 logs, stashes 和 untracked 文件的列表, 以及与当前分支相关的信息.
在某些未完成的操作期间–例如当合并导致冲突时–会显示有助于继续或中止操作的附加信息.
命令 magit-status 在另一个窗口中显示属于当前仓库的 status buffer. 这个命令使用频率非常高, 因此应该全局绑定. 我们建议使用 C-x g:
(global-set-key (kbd "C-x g") 'magit-status)
C-x g(magit-status) 当从现有的 Git 仓库中调用时, 此命令在一个 buffer 中显示该仓库的状态. 如果当前目录不位于 Git 仓库内, 则此命令会提示输入现有仓库或任意目录, 具体取决于选项magit-repository-directories, 并显示所选仓库的状态.- 如果该选项指定了任何现有仓库, 则要求用户选择其中一个.
- 否则, 要求用户使用常规文件名补全选择任意目录. 如果所选目录是现有工作树的顶层目录, 则显示其 status buffer.
- 否则, 提议用户将所选目录初始化为新仓库. 创建仓库后显示其 status buffer.
也可以使用一个或多个前缀参数强制执行这些回退行为:
- 使用两个前缀参数 (或更确切地说, 数值前缀值为 16 或更大) 读取任意目录, 然后如上所述对其进行操作. 使用命令
magit-init可以完成同样的事情. - 使用单个前缀参数从用户读取现有仓库, 或者如果根据
magit-repository-directories的值找不到仓库, 则行为与使用两个前缀参数相同.
magit-repository-directories[User Option] Git 仓库或包含 Git 仓库的目录列表. 每个元素的形式为(DIRECTORY . DEPTH).DIRECTORY必须是一个目录或目录文件名 (字符串).DEPTH(整数) 指定查找 Git 仓库的最大深度. 如果为 0, 则仅添加DIRECTORY本身. 此选项控制magit-list-repositories列出哪些仓库. 它也以可能令人惊讶的方式影响magit-status(见上文).magit-status-quick[Command] 此命令是magit-status的替代方案, 通常避免刷新 status buffer. 如果当前 Git 仓库的 status buffer 存在但未在选定 frame 中显示, 则显示它而不刷新. 如果 status buffer 正在选定 frame 中显示, 则此命令刷新它. 前缀参数的含义与magit-status相同, 并另外导致 buffer 被刷新. 要使用此命令, 请将其添加到你的 init 文件:(global-set-key (kbd "C-x g") 'magit-status-quick)如果你这样做, 并且想要重新显示 buffer 并立即刷新它, 请输入C-x g后跟g. 可能的替代命令是magit-display-repository-buffer. 它支持显示属于当前仓库的任何现有 Magit buffer; 不仅仅是 status buffer.
5.1.1. 5.1.1 状态部分 (Status Sections)
Status buffers 的内容使用 hook magit-status-sections-hook 控制. 参见第 19 页的 [Section Hooks], 了解有关此类 hooks 以及如何自定义它们的信息.
magit-status-sections-hook[User Option] 此 hook 运行以将 sections 插入 status buffer. 本节中描述的函数, 以及后续章节中描述的函数magit-insert-status-headers和magit-insert-untracked-files, 都是此 hook 的成员. 可以添加到此 hook 的一些其他函数 (默认添加到其他 hooks) 列在第 57 页的 5.6 节 [References Buffer] 中.magit-insert-status-headers[Function] 插入适用于magit-status-modebuffers 的 header sections. 通过运行magit-status-headers-hookhook 上的函数来插入 sections. 参见第 37 页的 [Status Header Sections].magit-insert-merge-log[Function] 为正在进行的合并插入 section. 显示正在合并的 heads. 如果没有正在进行的合并, 则什么也不做.magit-insert-rebase-sequence[Function] 为正在进行的 rebase 序列插入 section. 如果没有此类序列正在进行, 则什么也不做.magit-insert-am-sequence[Function] 为正在进行的补丁应用序列插入 section. 如果没有此类序列正在进行, 则什么也不做.magit-insert-sequencer-sequence[Function] 为正在进行的 cherry-pick 或 revert 序列插入 section. 如果没有此类序列正在进行, 则什么也不做.magit-insert-bisect-output[Function] 在 bisecting 时, 插入包含git bisect输出的 section.magit-insert-bisect-rest[Function] 在 bisecting 时, 插入可视化 bisect 状态的 section.magit-insert-bisect-log[Function] 在 bisecting 时, 插入记录 bisect 进度的 section.magit-insert-unstaged-changes[Function] 插入显示 unstaged 更改的 section.magit-insert-staged-changes[Function] 插入显示 staged 更改的 section.magit-insert-stashes &optional ref heading[Function] 插入 stashes section, 显示 "refs/stash" 的 reflog. 如果可选的 REF 为非nil, 则显示该 ref 的 reflog. 如果可选的 HEADING 为非nil, 则使用它作为 section 标题, 而不是 "Stashes:".magit-insert-unpulled-from-upstream[Function] 插入显示尚未从 upstream 分支 pull 的提交的 section.magit-insert-unpulled-from-pushremote[Function] 插入显示尚未从 push-remote 分支 pull 的提交的 section.magit-insert-unpushed-to-upstream-or-recent[Function] 插入显示 unpushed 或其他最近提交的 section. 如果当前分支配置了 upstream 并且落后于当前分支, 则显示尚未 push 到 upstream 分支的提交. 如果未配置 upstream 或 upstream 不落后于当前分支, 则显示最后的magit-log-section-commit-count个提交.magit-insert-unpushed-to-upstream[Function] 插入显示尚未 push 到 upstream 的提交的 section.magit-insert-unpushed-to-pushremote[Function] 插入显示尚未 push 到 push-remote 的提交的 section.
5.1.2. 5.1.2 状态文件列表部分 (Status File List Sections)
这些函数遵循 buffer 的文件过滤器, 可以使用 D - - 设置.
magit-insert-untracked-files[Function] 此函数可能会插入未跟踪文件的列表. 是否实际这样做取决于下一个描述的选项.magit-status-show-untracked-files[User Option] 此选项控制上述函数是否在 status buffer 中插入未跟踪文件的列表.- 如果为
nil, 不列出任何未跟踪文件. - 如果为
t, 列出未跟踪文件, 但如果目录不包含任何被跟踪文件, 则仅列出该目录, 而不列出包含的未跟踪文件. - 如果为
all, 则列出每个单独的未跟踪文件. 这可能非常慢, 不建议使用.
Git 变量的对应值为 "no", "normal" 和 "all". 要在特定仓库中禁用列出未跟踪文件, 请将以下内容添加到
.dir-locals.el:((magit-status-mode (magit-status-show-untracked-files . "no")))
或者 (主要是出于历史原因), 可以使用
git config设置仓库本地值:git config set --local status.showUntrackedFiles no这不会覆盖此 Lisp 变量的 (如果有) 本地值, 但它确实会覆盖其全局值. 参见git-status(1)manpage 的最后一节, 以加快 Git 负责的工作部分. 将该列表转换为 sections 也不是免费的, 因此 Magit 仅列出magit-status-file-list-limit个文件.- 如果为
magit-status-file-list-limit[User Option] 此选项控制在 status buffer 中列出文件的每个 section 中最多列出多少个文件. 出于性能原因, 建议不要增加此限制.
虽然上述函数默认是 magit-status-section-hook 的成员, 但必须由用户显式添加以下函数. 因为这会对性能产生负面影响, 建议不要这样做.
magit-insert-tracked-files[Function] 插入被跟踪文件的列表.magit-insert-ignored-files[Function] 插入被忽略文件的列表.magit-insert-skip-worktree-files[Function] 插入 skip-worktree 文件的列表.magit-insert-assume-unchanged-files[Function] 插入假定未更改文件的列表.
5.1.3. 5.1.3 状态日志部分 (Status Log Sections)
magit-insert-unpulled-or-recent-commits[Function] 插入显示 unpulled 或最近提交的 section. 如果当前分支配置了 upstream 并且领先于当前分支, 则显示缺失的提交. 否则, 显示最后的magit-log-section-commit-count个提交.magit-insert-recent-commits[Function] 插入显示最后magit-log-section-commit-count个提交的 section.magit-log-section-commit-count[User Option]magit-insert-recent-commits和magit-insert-unpulled-or-recent-commits(如果没有 unpulled 提交) 显示多少个最近提交.magit-insert-unpulled-cherries[Function] 插入显示 unpulled 提交的 section. 类似于magit-insert-unpulled-commits, 但为每个尚未应用的提交 (即, 具有不与任何本地提交共享 patch-id 的提交) 加上 "+" 前缀, 所有其他的加上 "-" 前缀.magit-insert-unpushed-cherries[Function] 插入显示 unpushed 提交的 section. 类似于magit-insert-unpushed-commits, 但为每个尚未应用到 upstream 的提交 (即, 具有不与任何 upstream 提交共享 patch-id 的提交) 加上 "+" 前缀, 所有其他的加上 "-" 前缀.
5.1.4. 5.1.4 状态头部部分 (Status Header Sections)
Status buffers 的内容使用 hook magit-status-sections-hook 控制 (见第 34 页的 [Status Sections]).
默认情况下 magit-insert-status-headers 是该 hook 变量的第一个成员.
magit-insert-status-headers[Function] 插入适用于magit-status-modebuffers 的 headers sections. 通过运行magit-status-headers-hookhook 上的函数来插入 sections.magit-status-headers-hook[User Option] 运行此 hook 以将 headers sections 插入 status buffer. 此 hook 由magit-insert-status-headers运行, 而后者必须是magit-status-sections-hook的成员才能被使用.
默认情况下, 以下函数是上述 hook 的成员:
magit-insert-error-header[Function] 插入显示刚刚发生的 Git 错误消息的 header line. 此函数仅知道 Git 为副作用运行时发生的最后一个错误. 例如, 如果在生成 diff 时发生错误, 则不会插入该错误. 刷新 status buffer 会导致此 section 再次消失.magit-insert-diff-filter-header[Function] 插入显示有效 diff 过滤器的 header line.magit-insert-head-branch-header[Function] 插入关于当前分支或 detached HEAD 的 header line.magit-insert-upstream-branch-header[Function] 插入关于通常 pull 到当前分支的分支的 header line.magit-insert-push-branch-header[Function] 插入关于当前分支通常 push 到的分支的 header line.magit-insert-tags-header[Function] 插入关于当前和/或下一个 tag 的 header line, 以及 tag 和 HEAD 之间的提交数量.
也可以将以下函数添加到上述 hook 中:
magit-insert-repo-header[Function] 插入显示仓库顶层路径的 header line.magit-insert-remote-header[Function] 插入关于当前分支 remote 的 header line. 如果当前分支未配置 remote, 则回退显示 "origin" remote, 或者如果不存在则显示按字母顺序排列的第一个 remote.magit-insert-user-header[Function] 插入关于当前用户的 header line.
5.1.5. 5.1.5 状态模块部分 (Status Module Sections)
Status buffers 的内容使用 hook magit-status-sections-hook 控制 (见第 34 页的 [Status Sections]).
默认情况下 magit-insert-modules 不是该 hook 变量的成员.
magit-insert-modules[Function] 插入 submodule sections. Hookmagit-module-sections-hook控制插入哪些 module sections, 选项magit-module-sections-nested控制它们是否包裹在一个额外的 section 中.magit-module-sections-hook[User Option] 由magit-insert-modules运行的 Hook.magit-module-sections-nested[User Option] 此选项控制magit-insert-modules是否将插入的 sections 包裹在一个额外的 section 中. 如果为非nil, 则仅插入单个顶层 section. 如果为nil, 则magit-module-sections-hook中列出的所有 sections 都成为顶层 sections.magit-insert-modules-overview[Function] 为所有 submodules 插入 sections. 为每个 section 插入路径, 分支和git describe --tags的输出, 或者如果失败, 则为缩写的 HEAD commit hash. 在此类 submodule section 上按RET以显示其自己的 status buffer. 在 "Modules" section 上按RET以在单独的 buffer 中显示 submodules 列表. 这显示了超级仓库的 status buffer 中未显示的附加信息.magit-insert-modules-unpulled-from-upstream[Function] 为尚未从 upstream pull 的 modules 插入 sections. 这些 sections 可以展开以显示相应的提交.magit-insert-modules-unpulled-from-pushremote[Function] 为尚未从 push-remote pull 的 modules 插入 sections. 这些 sections 可以展开以显示相应的提交.magit-insert-modules-unpushed-to-upstream[Function] 为尚未 push 到 upstream 的 modules 插入 sections. 这些 sections 可以展开以显示相应的提交.magit-insert-modules-unpushed-to-pushremote[Function] 为尚未 push 到 push-remote 的 modules 插入 sections. 这些 sections 可以展开以显示相应的提交.
5.1.6. 5.1.6 状态选项 (Status Options)
magit-status-margin[User Option] 此选项指定 margin 是否最初显示在 Magit-Status 模式 buffers 中以及其格式. 该值的形式为(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH).- 如果
INIT为非nil, 则最初显示 margin. STYLE控制如何格式化作者或提交者日期. 它可以是age(显示提交的年龄),age-abbreviated(将时间单位缩写为一个字符), 或字符串 (适合format-time-string) 以显示实际日期. 选项magit-log-margin-show-committer-date控制显示哪个日期.WIDTH控制 margin 的宽度. 这是为了向前兼容而存在的, 目前不应更改该值.AUTHOR控制是否默认也显示作者姓名.AUTHOR-WIDTH必须是整数. 当显示作者姓名时, 这指定用于执行此操作的空间.
- 如果
另请参阅上一节中关于 status buffers 的更多选项.
5.2. 5.2 仓库列表 (Repository List)
magit-list-repositories[Command] 此命令在一个单独的 buffer 中显示仓库列表. 选项magit-repository-directories控制显示哪些仓库.magit-repolist-columns[User Option] 此选项控制命令magit-list-repositories显示哪些列以及如何显示它们. 每个元素的形式为(HEADER WIDTH FORMAT PROPS).HEADER是显示在 header 中的字符串.WIDTH是列的宽度.FORMAT是一个函数, 使用一个参数 (仓库标识, 通常是其 basename) 调用, 并且default-directory绑定到其工作树的顶层. 它必须返回要插入的字符串或nil.PROPS是一个支持键:right-align,:pad-right和:sort的 alist.:sort函数有一个奇怪的接口, 在tabulated-list--get-sort的 docstring 中有描述. 或者可以使用<和magit-repolist-version<, 因为这些函数会自动替换为满足接口的函数. 将:sort设置为nil以禁止排序; 如果未指定, 则列使用默认排序器排序. 你可能希望使用每列一个字符且列之间没有任何填充来显示一系列数字列, 在这种情况下, 你应该使用适当的HEADER, 将WIDTH设置为 1, 并将:pad-right设置为 9. 对于大于 9 的数字, 用+替换.
可以将以下函数添加到上述选项中:
magit-repolist-column-ident[Function] 此函数插入仓库的标识. 通常这只是其 basename.magit-repolist-column-path[Function] 此函数插入仓库的绝对路径.magit-repolist-column-version[Function] 此函数插入仓库HEAD修订版的描述.magit-repolist-column-branch[Function] 此函数插入当前分支的名称.magit-repolist-column-upstream[Function] 此函数插入当前分支的 upstream 分支的名称.magit-repolist-column-branches[Function] 此函数插入分支的数量.magit-repolist-column-stashes[Function] 此函数插入 stashes 的数量.magit-repolist-column-flag[Function] 此函数插入由magit-repolist-column-flag-alist指定的标志. 默认情况下, 这表示是否存在未提交的更改.N如果至少有一个未跟踪文件.U如果至少有一个 unstaged 文件.S如果至少有一个 staged 文件.
仅显示第一个适用的标志.
magit-repolist-column-flags[Function] 此函数插入由magit-repolist-column-flag-alist指定的所有标志. 这是函数magit-repolist-column-flag的替代方案, 后者仅列出找到的第一个.magit-repolist-column-unpulled-from-upstream[Function] 此函数插入不在当前分支中的 upstream 提交的数量.magit-repolist-column-unpulled-from-pushremote[Function] 此函数插入在 push 分支中但不在当前分支中的提交的数量.magit-repolist-column-unpushed-to-upstream[Function] 此函数插入在当前分支中但不在其 upstream 中的提交的数量.magit-repolist-column-unpushed-to-pushremote[Function] 此函数插入在当前分支中但不在其 push 分支中的提交的数量.
以下命令在 repolist buffers 中可用:
RET(magit-repolist-status) 此命令显示 point 处仓库的状态.m(magit-repolist-mark) 此命令标记 point 处的仓库.u(magit-repolist-unmark) 此命令取消标记 point 处的仓库.f(magit-repolist-fetch) 此命令 fetch 所有标记的仓库. 如果没有标记仓库, 则提议 fetch 所有显示的仓库.5(magit-repolist-find-file-other-frame) 此命令读取一个相对文件名 (不带补全), 并在新 frame 中打开每个标记仓库中的相应文件. 如果没有标记仓库, 则提议为所有显示的仓库执行此操作.
5.3. 5.3 日志 (Logging)
Status buffer 包含 unpushed 和 unpulled 提交的 logs, 但这显然是不够的. Transient 前缀命令 magit-log (在 l 上) 具有多个 suffix 命令, 这些命令在单独的 log buffer 中显示特定 log.
像其他 transient 前缀命令一样, magit-log 也具有多个 infix 参数, 可以在调用 suffix 命令之一之前更改这些参数. 但是, 在 log transient 的情况下, 这些参数可能取自当前仓库 log buffer 中当前使用的参数, 具体取决于 magit-prefix-use-buffer-arguments 的值 (参见第 21 页的 4.4 节 [Transient Arguments and Buffer Variables]).
有关各种参数的信息, 请参阅 git-log(1) manpage. 开关 ++order=VALUE 在传递给 git log 之前转换为 --author-date-order, --date-order 或 --topo-order 之一.
Log transient 还具有几个 reflog 命令. 参见第 47 页的 [Reflog].
l(magit-log) 此 transient 前缀命令绑定以下 suffix 命令以及适当的 infix 参数, 并在临时 buffer 中显示它们, 直到调用 suffix.l l(magit-log-current) 显示当前分支的 log. 当HEAD分离或带有前缀参数时, 显示从 minibuffer 读取的一个或多个 revisions 的 log.l h(magit-log-head) 显示HEAD的 log.l u(magit-log-related) 显示当前分支, 其 upstream 及其 push target 的 log. 当 upstream 是本地分支时, 也显示其自己的 upstream. 当HEAD分离时, 显示HEAD, 先前检出的分支及其 upstream 和 push-target 的 log.l o(magit-log-other) 显示从 minibuffer 读取的一个或多个 revs 的 log. 用户可以输入由空格分隔的任何 revision 或 revisions, 甚至 ranges, 但只有 branches, tags 和 point 处 commit 的表示形式可用作补全候选项.l L(magit-log-branches) 显示所有本地分支和HEAD的 log.l b(magit-log-all-branches) 显示所有本地和远程分支和HEAD的 log.l a(magit-log-all) 显示所有 references 和HEAD的 log.
存在两个额外的命令来显示当前 buffer 中访问的文件或 blob 的 log, 参见第 120 页的 8.10 节 [Commands for Buffers Visiting Files]. 命令 magit-cherry 也显示一个 log, 参见第 47 页的 [Cherries].
5.3.1. 5.3.1 刷新日志 (Refreshing Logs)
Transient 前缀命令 magit-log-refresh (在 L 上) 可用于更改当前 buffer 中使用的 log 参数, 而不更改显示的 log. 这在专用 log buffers 中有效, 在 status buffer 中也有效.
L(magit-log-refresh) 此 transient 前缀命令绑定以下 suffix 命令以及适当的 infix 参数, 并在临时 buffer 中显示它们, 直到调用 suffix.L g(magit-log-refresh) 此 suffix 命令设置当前 buffer 的本地 log 参数.L s(magit-log-set-default-arguments) 此 suffix 命令为与当前 buffer 类型相同的 buffers 设置默认 log 参数. 其他现有的相同类型的 buffers 不受影响, 因为它们的本地值已经初始化.L w(magit-log-save-default-arguments) 此 suffix 命令为与当前 buffer 类型相同的 buffers 设置默认 log 参数, 并保存该值以供将来会话使用. 其他现有的相同类型的 buffers 不受影响, 因为它们的本地值已经初始化.L L(magit-toggle-margin) 显示或隐藏 margin.
5.3.2. 5.3.2 日志缓冲区 (Log Buffer)
L(magit-log-refresh) 此 transient 前缀命令绑定以下 suffix 命令以及适当的 infix 参数, 并在临时 buffer 中显示它们, 直到调用 suffix. 参见第 42 页的 [Refreshing Logs].q(magit-log-bury-buffer) 在同一 frame 中 bury 当前 buffer 或 revision buffer. 类似于magit-mode-bury-buffer(见该条目), 但带有负前缀参数时, bury revision buffer (前提是它在当前 frame 中显示).C-c C-b(magit-go-backward) 在当前 buffer 的历史记录中向后移动.C-c C-f(magit-go-forward) 在当前 buffer 的历史记录中向前移动.C-c C-n(magit-log-move-to-parent) 移动到当前 commit 的父级. 默认情况下, 这是第一个父级, 但可以使用数字前缀指定另一个父级.j(magit-log-move-to-revision) 读取 revision 并在当前 log buffer 中移动到它. 如果选择的 reference 或 revision 未在当前 log buffer 中显示, 则通知用户并且不执行任何操作. 如果在任何 log buffer 之外调用, 则首先显示当前仓库的 log buffer; 必要时创建它.SPC(magit-diff-show-or-scroll-up) 更新 point 处对象的 commit 或 diff buffer. 要么在适当的 buffer 中显示 point 处的 commit 或 stash, 或者如果该 buffer 已经在当前 frame 中显示并且包含有关该 commit 或 stash 的信息, 则向上滚动 buffer. 如果 point 处没有 commit 或 stash, 则提示输入 commit.DEL(magit-diff-show-or-scroll-down) 更新 point 处对象的 commit 或 diff buffer. 要么在适当的 buffer 中显示 point 处的 commit 或 stash, 或者如果该 buffer 已经在当前 frame 中显示并且包含有关该 commit 或 stash 的信息, 则向下滚动 buffer. 如果 point 处没有 commit 或 stash, 则提示输入 commit.=(magit-log-toggle-commit-limit) 切换当前 log buffer 限制的提交数量. 如果提交数量当前受限, 则删除该限制. 否则将其设置为 256.+(magit-log-double-commit-limit) 将当前 log buffer 限制的提交数量加倍.-(magit-log-half-commit-limit) 将当前 log buffer 限制的提交数量减半.magit-log-auto-more[User Option] 当移动过最后一个条目时自动插入更多日志条目. 仅在使用magit-goto-*-section命令移动过最后一个条目时才考虑.magit-log-show-refname-after-summary[User Option] 是否在提交摘要后显示 refnames. 如果你使用非常长的分支名称, 这很有用.magit-log-show-color-graph-limit[User Option] 当显示超过此选项指定的提交时, 如果指定了--color参数, 则静默丢弃它. 这是必要的, 因为用于将控制序列转换为 faces 的ansi-color库太慢了.magit-log-show-signatures-limit[User Option] 当显示超过此选项指定的提交时, 如果指定了--show-signature参数, 则静默丢弃它. 这是必要的, 因为检查大量提交的签名太慢了.
Magit 在 logs 中显示 references 的方式与 Git 略有不同.
本地分支是蓝色的, 远程分支是绿色的. 当然这取决于使用的主题, 其他类型的 references 使用的颜色也是如此. 当前分支周围有一个框, 也是其各自 remote 的 HEAD 分支的远程分支.
如果本地分支及其 push-target 指向同一个 commit, 那么它们的名称会合并以节省空间并使这种关系可见. 例如:
origin/feature
[green][blue-]
代替
feature origin/feature
[blue-] [green-------]
另请注意, 虽然 transient 具有 --show-signature 参数, 但启用时实际上不会使用它, 因为 Magit 默认每个 commit 仅使用一行. 相反, commit 会被着色以指示签名 commit 对象的有效性, 使用名为 magit-signature-* 的 faces (见这些 faces).
有关 magit-log-margin 的描述, 请参阅第 45 页的 [Log Margin].
5.3.3. 5.3.3 日志边距 (Log Margin)
在显示一个或多个 logs 的 buffers 中, 可以在 margin (边距) 中显示有关每个 commit 的附加信息. 用于配置 margin 的选项名为 magit-INFIX-margin, 其中 INFIX 与相应 major-mode magit-INFIX-mode 中的相同. 在常规 log buffers 中, 那将是 magit-log-margin.
magit-log-margin[User Option] 此选项指定 margin 是否最初显示在 Magit-Log 模式 buffers 中以及其格式. 该值的形式为(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH).- 如果
INIT为非nil, 则最初显示 margin. STYLE控制如何格式化作者或提交者日期. 它可以是age(显示提交的年龄),age-abbreviated(将时间单位缩写为一个字符), 或字符串 (适合format-time-string) 以显示实际日期. 选项magit-log-margin-show-committer-date控制显示哪个日期.WIDTH控制 margin 的宽度. 这是为了向前兼容而存在的, 目前不应更改该值.AUTHOR控制是否默认也显示作者姓名.AUTHOR-WIDTH必须是整数. 当显示作者姓名时, 这指定用于执行此操作的空间.
- 如果
你可以通过在加载 magit 之前自定义 magit-log-margin 来将所有 magit-INFIX-margin 选项的 STYLE 和 AUTHOR-WIDTH 更改为相同的值. 如果你这样做, 那么其他选项的相应值将默认为你为该变量设置的值. 同样, 如果你将 magit-log-margin 中的 INIT 设置为 nil, 那么这将在所有其他选项的默认值中使用. 但是将其设置为 t, 即重新强制该选项的默认值, 不会传递给其他选项.
magit-log-margin-show-committer-date[User Option] 此选项指定是否在 margin 中显示提交者日期. 此选项仅控制是否显示提交者日期而不是作者日期. 是否在 margin 中显示某个日期以及是否显示 margin 完全由其他选项控制.L(magit-margin-settings) 此 transient 前缀命令绑定以下 suffix 命令, 每个命令都以某种方式更改 margin 的外观. 在一些支持 margin 的 buffers 中,L改为绑定到magit-log-refresh, 但该 transient 具有相同的命令, 以及一些其他不相关的命令.L L(magit-toggle-margin) 此命令显示或隐藏 margin.L l(magit-cycle-margin-style) 此命令循环 margin 使用的样式.L d(magit-toggle-margin-details) 此命令显示或隐藏 margin 中的详细信息.
5.3.4. 5.3.4 从日志中选择 (Select from Log)
当用户必须选择一个可从 HEAD 到达的最近 commit 时, 使用常规补全会很不方便 (因为大多数人无法记住 hashes 或 "HEAD~5", 至少在没有再次检查的情况下). 相反, 使用 log buffer 来选择 commit, 这具有按顺序显示 commits 并带有 commit 消息的优点.
此类选择 logs 用于选择 rebase 的开始以及选择要 squash 进入的 commit 时.
除了所有 log buffers 中可用的键绑定之外, 选择 log buffers 中还提供以下附加键绑定:
C-c C-c(magit-log-select-pick) 选择 point 处的 commit 并对其进行操作. 使用选定的 commit 作为参数调用magit-log-select-pick-function.C-c C-k(magit-log-select-quit) 中止选择 commit, 不对任何 commit 进行操作.magit-log-select-margin[User Option] 此选项指定 margin 是否最初显示在 Magit-Log-Select 模式 buffers 中以及其格式. 该值的形式为(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH).- 如果
INIT为非nil, 则最初显示 margin. STYLE控制如何格式化作者或提交者日期. 它可以是age(显示提交的年龄),age-abbreviated(将时间单位缩写为一个字符), 或字符串 (适合format-time-string) 以显示实际日期. 选项magit-log-margin-show-committer-date控制显示哪个日期.WIDTH控制 margin 的宽度. 这是为了向前兼容而存在的, 目前不应更改该值.AUTHOR控制是否默认也显示作者姓名.AUTHOR-WIDTH必须是整数. 当显示作者姓名时, 这指定用于执行此操作的空间.
- 如果
5.3.5. 5.3.5 Reflog (引用日志)
另请参阅 git-reflog(1) manpage.
这些 reflog 命令可从 log transient 获得. 参见第 42 页的 5.3 节 [Logging].
l r(magit-reflog-current) 显示当前分支的 reflog.l O(magit-reflog-other) 显示分支或另一个 ref 的 reflog.l H(magit-reflog-head) 显示HEADreflog.magit-reflog-margin[User Option] 此选项指定 margin 是否最初显示在 Magit-Reflog 模式 buffers 中以及其格式. 该值的形式为(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH).- 如果
INIT为非nil, 则最初显示 margin. STYLE控制如何格式化作者或提交者日期. 它可以是age(显示提交的年龄),age-abbreviated(将时间单位缩写为一个字符), 或字符串 (适合format-time-string) 以显示实际日期. 选项magit-log-margin-show-committer-date控制显示哪个日期.WIDTH控制 margin 的宽度. 这是为了向前兼容而存在的, 目前不应更改该值.AUTHOR控制是否默认也显示作者姓名.AUTHOR-WIDTH必须是整数. 当显示作者姓名时, 这指定用于执行此操作的空间.
- 如果
5.3.6. 5.3.6 Cherries
Cherries 是尚未应用到 upstream (还) 的 commits, 通常使用 log 可视化. 每个 commit 都以 - 前缀 (如果在 upstream 中有等效项) 和 + 前缀 (如果没有, 即它是一个 cherry).
命令 magit-cherry 显示单个分支的 cherries, 但 references buffer (参见第 57 页的 5.6 节 [References Buffer]) 可以一次显示多个 "upstreams" 的 cherries.
另请参阅 git-reflog(1) manpage.
Y(magit-cherry) 显示在某个分支中但尚未合并到 upstream 分支的 commits.magit-cherry-margin[User Option] 此选项指定 margin 是否最初显示在 Magit-Cherry 模式 buffers 中以及其格式. 该值的形式为(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH).- 如果
INIT为非nil, 则最初显示 margin. STYLE控制如何格式化作者或提交者日期. 它可以是age(显示提交的年龄),age-abbreviated(将时间单位缩写为一个字符), 或字符串 (适合format-time-string) 以显示实际日期. 选项magit-log-margin-show-committer-date控制显示哪个日期.WIDTH控制 margin 的宽度. 这是为了向前兼容而存在的, 目前不应更改该值.AUTHOR控制是否默认也显示作者姓名.AUTHOR-WIDTH必须是整数. 当显示作者姓名时, 这指定用于执行此操作的空间.
- 如果
5.4. 5.4 Diffing
Status buffer 包含 staged 和 unstaged 提交的 diffs, 但这显然是不够的. Transient 前缀命令 magit-diff (在 d 上) 具有多个 suffix 命令, 这些命令在单独的 diff buffer 中显示特定 diff.
像其他 transient 前缀命令一样, magit-diff 也具有多个 infix 参数, 可以在调用 suffix 命令之一之前更改这些参数. 但是, 在 diff transient 的情况下, 这些参数可能取自当前仓库 diff buffer 中当前使用的参数, 具体取决于 magit-prefix-use-buffer-arguments 的值 (参见第 21 页的 4.4 节 [Transient Arguments and Buffer Variables]).
另请参阅 git-diff(1) manpage.
d(magit-diff) 此 transient 前缀命令绑定以下 suffix 命令以及适当的 infix 参数, 并在临时 buffer 中显示它们, 直到调用 suffix.d d(magit-diff-dwim) 显示 point 处对象的更改. 例如, 如果 point 在 commit 上, 则显示该 commit 引入的更改. 同样, 如果 point 在标题为 "Unstaged changes" 的 section 上, 则在单独的 buffer 中显示这些更改. 一般来说, 将 point 处的对象与其可以比较的最合乎逻辑, 最琐碎且 (在任何情况下) 至少可能拥有的其他对象进行比较. 当 region 选择 commits 时, 比较两端的两个 commits. 在显示 diff 的 buffer 中, 你可以使用 "D r" 和 "D f" 控制比较的方式. 此函数并不总是显示你在任何给定情况下想要查看的更改. 你可以将显示的更改视为最小公分母. 这里不涉及 AI. 如果此命令从未执行你想要的操作, 请忽略它, 并改用允许你明确指定所需内容的命令.d r(magit-diff-range) 显示两个 commits 之间的差异. RANGE 应该是一个范围 (A..B 或 A…B) 但也可以是单个 commit. 如果省略范围的一侧, 则默认为HEAD. 如果只给出一个 commit, 则显示工作树相对于该 commit 的更改. 如果 region 处于活动状态, 则使用 region 第一行和最后一行的 revisions. 带有前缀参数时, 不是 diff revisions, 而是选择一个 revision 以沿其查看更改, 从两个 revisions 的共同祖先开始 (即, 使用 "…" 范围).d w(magit-diff-working-tree) 显示当前工作树与HEAD提交之间的更改. 带有前缀参数时, 显示工作树与从 minibuffer 读取的 commit 之间的更改.d s(magit-diff-staged) 显示 index 与HEAD提交之间的更改. 带有前缀参数时, 显示 index 与从 minibuffer 读取的 commit 之间的更改.d u(magit-diff-unstaged) 显示工作树与 index 之间的更改.d p(magit-diff-paths) 显示磁盘上任何两个文件之间的更改.
所有上述 suffix 命令都会更新仓库的 diff buffer. Diff transient 还具有两个在另一个 buffer 中显示差异的命令:
d c(magit-show-commit) 显示 point 处的 commit. 如果 point 处没有 commit 或带有前缀参数, 则提示输入 commit.d t(magit-stash-show) 在一个 buffer 中显示 stash 的所有 diffs.
存在两个额外的命令来显示当前 buffer 中访问的文件或 blob 的 diff, 参见第 120 页的 8.10 节 [Commands for Buffers Visiting Files].
5.4.1. 5.4.1 刷新 Diffs (Refreshing Diffs)
Transient 前缀命令 magit-diff-refresh (在 D 上) 可用于更改当前 buffer 中使用的 diff 参数, 而不更改显示的 diff. 这在专用 diff buffers 中有效, 在 status buffer 中也有效.
(有一个例外; diff 参数不能在由 magit-merge-preview 创建的 buffers 中更改, 因为底层 Git 命令不支持这些参数.)
D(magit-diff-refresh) 此 transient 前缀命令绑定以下 suffix 命令以及适当的 infix 参数, 并在临时 buffer 中显示它们, 直到调用 suffix.D g(magit-diff-refresh) 此 suffix 命令设置当前 buffer 的本地 diff 参数.D s(magit-diff-set-default-arguments) 此 suffix 命令为与当前 buffer 类型相同的 buffers 设置默认 diff 参数. 其他现有的相同类型的 buffers 不受影响, 因为它们的本地值已经初始化.D w(magit-diff-save-default-arguments) 此 suffix 命令为与当前 buffer 类型相同的 buffers 设置默认 diff 参数, 并保存该值以供将来会话使用. 其他现有的相同类型的 buffers 不受影响, 因为它们的本地值已经初始化.D t(magit-diff-toggle-refine-hunk) 此命令切换 hunk refinement (细化) 的开启或关闭.D r(magit-diff-switch-range-type) 此命令将 diff range 类型从 "revA..revB" 转换为 "revB…revA", 或反之亦然.D f(magit-diff-flip-revs) 此命令交换 diff range 中的 revisions, 从 "revA..revB" 到 "revB..revA", 或反之亦然.D F(magit-diff-toggle-file-filter) 此命令切换当前 buffer 中 diffs 的文件限制, 允许你在查看 commit 中的所有更改和受限子集之间快速切换. 作为特殊情况, 当从 log buffer 调用此命令时, 它会切换仓库 revision buffer 中的文件限制, 当你从限于一个或多个文件的 log buffer 中显示 revision 时, 这很有用.
除了上述允许更改任何支持参数的 transient 之外, 还有一些仅更改特定参数的命令.
-(magit-diff-less-context) 此命令将 diff hunks 的上下文减少 COUNT 行.+(magit-diff-more-context) 此命令将 diff hunks 的上下文增加 COUNT 行.0(magit-diff-default-context) 此命令将 diff hunks 的上下文重置为默认高度.
以下命令快速更改显示的 diff, 而无需使用 diff transient 之一.
C-c C-d(magit-diff-while-committing) 在提交时, 此命令显示即将提交的更改. 在 amending 时, 再次调用该命令可在仅显示新更改或显示将提交的所有更改之间切换. 此绑定在 diff buffer 以及 commit message buffer 中可用.C-c C-b(magit-go-backward) 此命令在当前 buffer 的历史记录中向后移动.C-c C-f(magit-go-forward) 此命令在当前 buffer 的历史记录中向前移动.
5.4.2. 5.4.2 Diffs 中可用的命令 (Commands Available in Diffs)
有些命令仅当 point 在 diff 内时才可用.
magit-diff-visit-file 和相关命令访问 point 处 diff 所关于的文件的适当版本. 同样 magit-diff-visit-worktree-file 和相关命令访问 point 处 diff 所关于的文件的 worktree 版本. 参见第 62 页的 [Visiting Files and Blobs from a Diff], 了解更多信息和键绑定.
C-c C-t(magit-diff-trace-definition) 此命令显示 point 处定义的 log.magit-log-trace-definition-function[User Option] 此选项指定的函数由magit-log-trace-definition使用, 以确定 point 处的函数. 对于有特殊需求的 major-modes, 你可以使用该模式的 hook 设置本地值.C-c C-e(magit-diff-edit-hunk-commit) 从 hunk 中, 此命令编辑相应的 commit 并访问文件. 首先它使用magit-diff-visit-file在正确位置访问被 hunk 修改的文件. 这实际上是访问一个 blob. 当 point 在 diff header 上, 而不在单个 hunk 内时, 这访问第一个 hunk 所关于的 blob. 然后它调用magit-edit-line-commit, 该命令使用交互式 rebase 使 commit 可编辑, 或者如果因为 commit 无法从HEAD到达而不可能, 则通过直接检出该 commit. 这也导致访问实际的 worktree 文件. 完成 rebase 后, 既不 kill blob 也不 kill 文件 buffer. 如果这是不希望的, 那么使用magit-rebase-edit-commit代替此命令可能更好.j(magit-jump-to-diffstat-or-diff) 此命令跳转到 diffstat 或 diff. 当 point 在 diffstat section 内的文件上时, 跳转到相应的 diff section. 否则, 跳转到 diffstat section 或其子项.
接下来的两个命令不是 Magit-Diff 模式 (或那件事的 Magit buffer) 特有的, 但这里也值得指出它们可用.
SPC(scroll-up) 此命令向上滚动文本.DEL(scroll-down) 此命令向下滚动文本.
5.4.3. 5.4.3 Diff 选项 (Diff Options)
magit-diff-refine-hunk[User Option] 是否在 diff hunks 中显示单词粒度的差异.nil: 从不显示精细差异.all: 为所有显示的 diff hunks 显示精细差异.t: 一旦 hunk 成为当前 section, 就对其进行 refine. 当选择另一个 section 时保持 refinement. 刷新 buffer 会删除所有 refinement. 此变体仅出于性能原因提供.
magit-diff-refine-ignore-whitespace[User Option] 是否在单词粒度差异中忽略空白更改.magit-diff-adjust-tab-width[User Option] 是否调整 diffs 中的 tabs 宽度. 确定正确的宽度可能很昂贵, 如果它需要打开大型和/或许多文件, 因此宽度缓存在变量magit-diff--tab-width-cache中. 将其设置为nil以使缓存无效.nil: 从不调整 tab 宽度. 改为使用 Magit buffer 本身的tab-width值.t: 如果相应的文件访问 buffer 存在, 则使用该 buffer 的tab-width值. 这样做很便宜, 因此即使存在相应的缓存条目也会使用此值.always: 如果没有这样的 buffer, 则临时访问文件以确定该值.NUMBER: 类似always, 但不访问大于NUMBER字节的文件.
magit-diff-paint-whitespace[User Option] 指定在哪里高亮显示空白错误. 参见magit-diff-highlight-trailing,magit-diff-highlight-indentation. 符号t表示在所有 diffs 中,status表示仅在 status buffer 中,nil表示不在任何地方.nil: 从不高亮显示空白错误.t: 到处高亮显示空白错误.uncommitted: 仅在显示未提交更改的 diffs 中高亮显示空白错误. 为了向后兼容,status被视为同义词.
magit-diff-paint-whitespace-lines[User Option] 指定在什么样的行中高亮显示空白错误.t: 仅在添加的行中高亮显示.both: 在添加和删除的行中高亮显示.all: 在添加, 删除和上下文行中高亮显示.
magit-diff-highlight-trailing[User Option] 是否在 diffs 中高亮显示行尾的空白. 仅当magit-diff-paint-whitespace为非nil时使用.magit-diff-highlight-indentation[User Option] 此选项控制如果使用了 "错误" 的缩进样式, 是否高亮显示缩进. 仅当magit-diff-paint-whitespace也为非nil时, 缩进才会被高亮显示. 该值是((REGEXP . INDENT)...)形式的 alist. 当前仓库的路径与每个元素逆序匹配. 因此, 如果REGEXP匹配, 则不尝试较早的元素. 如果使用的INDENT是tabs, 则使用 tabs 高亮显示缩进. 如果INDENT是整数, 则使用至少那么多空格高亮显示缩进. 否则, 都不高亮显示.magit-diff-hide-trailing-cr-characters[User Option] 是否在 diffs 中隐藏行尾的^M字符.magit-diff-highlight-hunk-region-functions[User Option] 此选项指定用于高亮显示 hunk-internal region 的函数.magit-diff-highlight-hunk-region-dim-outside用一个 face 覆盖 hunk 内部选择的外部, 使添加和删除的行具有与上下文行相同的背景颜色. 不应从此选项的值中删除此函数.magit-diff-highlight-hunk-region-using-overlays和magit-diff-highlight-hunk-region-using-underline通过在其前后放置定界水平线来强调 region. 由于 Emacs 显示引擎的限制, 这两个函数都有无法修复的故障. 有关更多信息, 请参阅 https://github.com/magit/magit/issues/2758 等. 除了或代替使用定界水平线来强调边界, 你可能希望强调文本本身, 使用magit-diff-highlight-hunk-region-using-face. 在终端 frames 中, 无法像 overlay 和 underline 变体通常那样绘制线条, 因此在那里它们回退到调用 face 函数.magit-diff-unmarked-lines-keep-foreground[User Option] 此选项控制 hunk-internal region 之外的添加和删除行是仅失去其独特的背景颜色还是也失去前景颜色. region 外部是否变暗完全取决于magit-diff-highlight-hunk-region-functions.magit-diff-extra-stat-arguments[User Option] 此选项指定与--stat一起使用的附加参数. 该值是零个或多个参数的列表, 或者是不带参数并返回此类列表的函数. 这里允许这些参数:--stat-width,--stat-name-width,--stat-graph-width和--compact-summary. 另请参阅git-diff(1)manpage.magit-format-file-function[User Option] 此函数用于格式化代表文件的行. 它用于 diffs 中的文件标题, diffstats 和文件列表 (例如未跟踪文件). 根据调用者, 它接收三个或五个参数; 签名必须是(kind file face &optional status orig).KIND是diff,module,stat和list之一.
5.4.4. 5.4.4 Revision Buffer
magit-revision-insert-related-refs[User Option] 是否在 revision buffers 中显示相关分支.nil: 不显示任何相关分支.t: 显示相关本地分支.all: 显示相关本地和远程分支.mixed: 显示所有包含分支和本地合并分支.
magit-revision-show-gravatars[User Option] 是否在 revision buffers 中显示 gravatar 图像. 如果为nil, 则不插入任何 gravatar 图像. 如果为t, 则插入两个图像. 如果为author或committer, 则仅插入相应的图像. 如果你自定义了选项magit-revision-headers-format并想插入图像, 那么你可能还需要指定在哪里这样做. 在这种情况下, 该值必须是两个正则表达式的 cons-cell. car 指定在哪里插入作者的图像. 图像的上半部分插入在匹配文本之后, 下半部分在下一行的同一列. cdr 指定在哪里插入提交者的图像, 依此类推. car 或 cdr 都可以为nil.magit-revision-use-hash-sections[User Option] 是否将 commit message 中的 hashes 转换为 sections. 如果为非nil, 那么 commit message 中的 hashes 将转换为 commit sections. 在性能和可靠性之间需要权衡:slow: 对每个单词调用 git 以绝对确定.quick: 跳过少于 7 个字符的单词.quicker: 另外跳过不包含数字的单词.quickest: 使用所有至少 7 个字符长且包含至少一个数字和一个字母的单词.
如果为
nil, 则没有 hashes 转换为 sections, 但你仍然可以使用 "RET" 访问 point 处的 commit.
Revision buffer 中显示的 diffs 可以自动限制为更改文件的子集. 如果 revision buffer 是从 log buffer 显示的, 则 revision buffer 将共享与该 log buffer 相同的文件限制 (另请参见命令 magit-diff-toggle-file-filter).
magit-revision-filter-files-on-follow[User Option] 当 log 参数包含--follow时, 从 log buffer 显示 commit 是否遵循 log 的文件过滤器. 当此选项为nil时, 如果 log 参数包含--follow, 则从 log 显示 commit 会忽略 log 的文件过滤器. 这样做可以避免在重命名事件之前的 commits 的 revision buffers 中显示空 diff. 在这种情况下, 可以使用 log transient 的--patch参数以内联方式显示文件限制的 diffs. 将此选项设置为非nil, 即使 log 参数中存在--follow, 也保持 log 的文件限制.
如果 revision buffer 不是从 log buffer 显示的, 则文件限制照常确定 (参见第 21 页的 4.4 节 [Transient Arguments and Buffer Variables]).
5.5. 5.5 Ediffing
本节描述如何从 Magit buffers 进入 Ediff. 有关如何使用 Ediff 本身的信息, 请参阅 ediff.
e(magit-ediff-dwim) 使用 Ediff 比较, stage, 或 resolve. 此命令尝试猜测用户想要使用 Ediff 比较, stage 或 resolve 什么文件, 以及什么 commit 或范围. 它可能只能猜测文件或范围/commit, 在这种情况下, 用户会被问及另一个. 它可能并不总是猜对, 在这种情况下必须显式使用适当的magit-ediff-*命令. 如果它根本无法读取用户的心思, 那么它会要求用户运行命令.E(magit-ediff) 此 transient 前缀命令绑定以下 suffix 命令, 并在临时 buffer 中显示它们, 直到调用 suffix.E r(magit-ediff-compare) 使用 Ediff 比较文件的两个 revisions. 如果 region 处于活动状态, 使用 region 第一行和最后一行的 revisions. 带有前缀参数时, 不是 diff revisions, 而是选择一个 revision 以沿其查看更改, 从两个 revisions 的共同祖先开始 (即, 使用 "…" 范围).E m(magit-ediff-resolve-rest) 此命令允许你使用 Ediff 解决 point 处文件中的未解决冲突. 如果 point 处没有文件或者它没有任何未合并的更改, 那么此命令会提示输入文件. 前提是merge.conflictstyle的值为diff3, 你可以在 Ediff 控制 buffer 中使用/查看文件的 merge-base revision.A,B和Ancestorbuffers 是从 worktree 文件中的冲突标记构建的. 因为你和/或 Git 可能已经解决了一些冲突, 这意味着这些 buffers 可能不包含来自相应 blobs 的实际版本.E M(magit-ediff-resolve-all) 此命令允许你使用 Ediff 解决 point 处文件中的所有冲突. 如果 point 处没有文件或者它没有任何未合并的更改, 那么此命令会提示输入文件. 前提是merge.conflictstyle的值为diff3, 你可以在 Ediff 控制 buffer 中使用/查看文件的 merge-base revision. 首先将 worktree 中的文件移到一边, 附加后缀.ORIG, 以便你以后可以返回该版本. 然后从冲突的双方和 merge-base (如果可用) 重建它. 如果只是按原样使用 worktree 文件就好了, 但 Ediff 不支持这一点. 这意味着 Git 已经解决的所有冲突都会恢复. 另一方面, Ediff 也会尝试解决冲突, 在许多情况下 Ediff 和 Git 应该产生类似的结果. 但是, 如果你已经手动解决了一些冲突, 那么这些更改将被丢弃 (尽管你可以从备份文件中恢复它们). 在这种情况下magit-ediff-resolve-rest可能更合适. 此命令相对于magit-ediff-resolve-rest的优势在于A,B和Ancestorbuffers 对应于相应 commits 的 blobs, 允许你在上下文中检查一方并使用这些 buffers 中的 Magit 命令来执行此操作. Blame 和 log 命令在这里特别有用.E t(magit-git-mergetool) 此命令实际上不使用 Ediff. 虽然它与magit-ediff-resolve-rest具有相同的目的, 但它使用git mergetool --gui来解决冲突. 带有前缀参数时, 这充当 transient 前缀命令, 允许用户选择 mergetool 并更改一些设置.E s(magit-ediff-stage) 使用 Ediff stage 和 unstage 文件的更改, 默认为 point 处的文件.E u(magit-ediff-show-unstaged) 使用 Ediff 显示文件的 unstaged 更改.E i(magit-ediff-show-staged) 使用 Ediff 显示文件的 staged 更改.E w(magit-ediff-show-working-tree) 使用 Ediff 显示文件在HEAD和 working tree 之间的更改.E c(magit-ediff-show-commit) 使用 Ediff 显示 commit 引入的文件的更改.E z(magit-ediff-show-stash) 使用 Ediff 显示 stash 引入的文件的更改.magit-ediff-dwim-resolve-function[User Option] 此选项控制magit-ediff-dwim使用哪个函数来解决冲突.magit-ediff-resolve-rest,magit-ediff-resolve-all或magit-git-mergetool之一; 它们都在上面进行了讨论.magit-ediff-dwim-show-on-hunks[User Option] 此选项控制当 point 位于未提交的 hunks 上时,magit-ediff-dwim调用什么命令. 当为nil时, 始终运行magit-ediff-stage. 否则, 使用magit-ediff-show-staged和magit-ediff-show-unstaged分别显示 staged 和 unstaged 更改.magit-ediff-show-stash-with-index[User Option] 此选项控制magit-ediff-show-stash是否包括一个 buffer, 其中包含 stash 创建时 index 中文件的状态. 这使得可以分辨 stash 中哪些更改是 staged 的.magit-ediff-quit-hook[User Option] 此 hook 在退出使用 Magit 命令创建的 Ediff 会话后运行. Hook 函数在 Ediff 控制 buffer 内运行, 不应更改当前 buffer. 这类似于ediff-quit-hook, 但考虑了 Magit 的需求. 使用 Magit 命令创建的 Ediff 会话会忽略常规的ediff-quit-hook.
5.6. 5.6 引用缓冲区 (References Buffer)
y(magit-show-refs) 此命令在专用 buffer 中列出分支和 tags. 但是, 如果再次从此 buffer 调用此命令, 或者如果带前缀参数调用它, 那么它充当 transient 前缀命令, 绑定以下 suffix 命令和一些 infix 参数.
所有以下 suffix 命令都列出完全相同的分支和 tags. 唯一的区别是可以通过更改 magit-refs-show-commit-count 的值来启用的可选功能 (见下文). 这些命令指定一个不同的分支或 commit, 所有其他 references 都与其进行比较.
y y(magit-show-refs-head) 此命令在专用 buffer 中列出分支和 tags. 每个 reference 都与HEAD进行比较.y c(magit-show-refs-current) 此命令在专用 buffer 中列出分支和 tags. 每个 reference 都与当前分支进行比较, 如果HEAD分离则与HEAD比较.y o(magit-show-refs-other) 此命令在专用 buffer 中列出分支和 tags. 每个 reference 都与从用户读取的分支进行比较.y r(magit-refs-set-show-commit-count) 此命令更改显示 commit 计数的 refs.magit-refs-show-commit-count[User Option] 是否在 Magit-Refs 模式 buffers 中显示提交计数.all: 显示分支和 tags 的计数.branch: 仅显示分支的计数.nil: 从不显示计数.
默认值为
nil, 因为其他任何值都可能非常昂贵.magit-refs-pad-commit-counts[User Option] 是否在 Magit-Refs 模式 buffers 中在所有侧面上填充所有提交计数. 如果为nil, 那么某些提交计数会直接显示在计数旁边的分支旁边, 中间没有任何空格. 如果分支名称 faces 看起来太像magit-dimmed, 这可能看起来很糟糕. 如果为非nil, 则在所有提交计数的两侧放置空格.magit-refs-show-remote-prefix[User Option] 是否在远程分支列表中显示 remote 前缀. 显示前缀是多余的, 因为 remote 的名称已经显示在分支列表之前的标题中.magit-refs-primary-column-width[User Option]magit-refs-modebuffers 中主列的宽度. 主列是包含当前行所关于的分支名称的列. 如果这是一个整数, 那么该列就有那么多列宽. 否则它必须是两个整数的 cons-cell. 第一个指定最小宽度, 第二个指定最大宽度. 在这种情况下, 实际宽度是使用显示的本地分支名称的长度确定的. (计算最佳宽度时不考虑远程分支和 tags.)magit-refs-focus-column-width[User Option]magit-refs-modebuffers 中焦点列的宽度. 焦点列是第一列, 它使用*或@标记一个分支 (通常是当前分支) 作为焦点分支. 对于每个其他 reference, 此列可选地显示它领先于焦点分支多少个 commits 和<, 或者如果它不领先则落后多少个 commits 和>, 或者如果它也不落后, 则显示=. 此列也可能仅显示焦点分支的*或@, 在这种情况下忽略此选项. 使用L v更改此列的详细程度.magit-refs-margin[User Option] 此选项指定 margin 是否最初显示在 Magit-Refs 模式 buffers 中以及其格式. 该值的形式为(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH).- 如果
INIT为非nil, 则最初显示 margin. STYLE控制如何格式化作者或提交者日期. 它可以是age(显示提交的年龄),age-abbreviated(将时间单位缩写为一个字符), 或字符串 (适合format-time-string) 以显示实际日期. 选项magit-log-margin-show-committer-date控制显示哪个日期.WIDTH控制 margin 的宽度. 这是为了向前兼容而存在的, 目前不应更改该值.AUTHOR控制是否默认也显示作者姓名.AUTHOR-WIDTH必须是整数. 当显示作者姓名时, 这指定用于执行此操作的空间.
- 如果
magit-refs-margin-for-tags[User Option] 此选项指定是否在 margin 中显示有关 tags 的信息. 默认情况下禁用此功能, 因为如果有许多 tags, 速度会很慢.
以下变量控制如何显示单个 refs. 如果你更改这些变量之一 (特别是 "%c" 部分), 那么你也应该更改其他变量以保持对齐. 支持以下 %-sequences:
%a: 此 ref 超过我们比较对象的提交数量.%b: 我们比较的对象超过此 ref 的提交数量.%c: 此 ref 超过我们比较对象的提交数量. 对于所有其他 refs与之比较的 ref, 如果它是当前分支, 则为 "@", 否则为 "#".%C: 对于所有其他 refs 与之比较的 ref, 如果它是当前分支, 则为 "@", 否则为 "#". 对于所有其他 refs 为 " ".%h: 此 ref 顶端的 Hash.%m: 此 ref 顶端的提交摘要.%n: 此 ref 的名称.%u: 此本地分支的 Upstream.%U: 此本地分支的 Upstream 以及额外的本地 vs. upstream 信息.magit-refs-filter-alist[User Option] 此选项的目的是放弃根据名称显示某些 refs. 如果你不想显示某种类型的任何 refs, 那么你应该从magit-refs-sections-hook中删除相应的函数. 此 alist 控制在magit-refs-modebuffers 中省略显示哪些 tags 和分支. 如果为nil, 则显示所有 refs (受magit-refs-sections-hook限制). 按顺序尝试所有键, 直到有一个匹配. 然后使用其值, 并忽略后续元素. 如果值为非nil, 则显示 reference, 否则不显示. 如果没有元素匹配, 则显示 reference. 键可以是 refname 必须匹配的正则表达式, 或者是将 refname 作为唯一参数并返回布尔值的函数. 诸如 "origin/master" 之类的远程分支仅显示为 "master", 但是对于此比较使用前者.RET(magit-visit-ref) 此命令在另一个 buffer 中访问 point 处的 reference 或 revision. 如果 point 处没有 revision 或带有前缀参数, 则提示输入 revision. 此命令的行为就像上面描述的magit-show-commit一样, 除非 point 在magit-refs-modebuffer 中的 reference 上, 在这种情况下行为可能不同, 但仅当你自定义了选项magit-visit-ref-behavior时.magit-visit-ref-behavior[User Option] 此选项控制magit-visit-ref在magit-refs-modebuffers 中的行为. 默认情况下magit-visit-ref在所有 buffers 中表现得像magit-show-commit, 包括magit-refs-modebuffers. 当 point 处 section 的类型是commit时, "RET" 绑定到magit-show-commit, 当类型是branch或tag时, 它绑定到magit-visit-ref. "RET" 是 Magit 最重要的键之一, 至少默认情况下它应该在所有 Magit 中表现一致, 特别是因为用户很快就知道它做了一些非常无害的事情; 它在另一个 buffer 中显示有关 point 处对象的更多信息. 然而 "RET" 过去在magit-refs-modebuffers 中表现不同, 做一些令人惊讶的事情, 其中一些不能真正描述为 "访问这个东西". 如果你已经习惯了这种行为, 你可以通过将下面符号中的一个或多个添加到此选项的值来恢复它. 但请记住, 这样做不仅会引入不一致,还会丢失一些功能, 可能不得不求助于M-x magit-show-commit来找回它.magit-visit-ref按此处描述的顺序查找这些符号. 如果符号的存在适用于当前情况, 则随后的符号不会影响结果.focus-on-ref: 带有前缀参数时, 更新 buffer 以显示相对于 point 处 reference 的提交计数和 cherry commits 列表, 而不是相对于当前 buffer 或HEAD. 考虑按 "C-u y o RET" 来代替添加此符号.create-branch: 如果 point 在远程分支上, 则创建一个同名的新本地分支, 使用远程分支作为其 upstream, 然后检出本地分支. 考虑按 "b c RET RET" 来代替添加此符号, 就像在其他 buffers 中那样.checkout-any: 检出 point 处的 reference. 如果该 reference 是 tag 或远程分支, 则这会导致 detached HEAD. 考虑按 "b b RET" 来代替添加此符号, 就像在其他 buffers 中那样.checkout-branch: 检出 point 处的本地分支. 考虑按 "b b RET" 来代替添加此符号, 就像在其他 buffers 中那样.
5.6.1. 5.6.1 引用部分 (References Sections)
References buffers 的内容使用 hook magit-refs-sections-hook 控制. 参见第 19 页的 [Section Hooks], 了解有关此类 hooks 以及如何自定义它们的信息. 以下所有函数都是默认值的成员. 请注意, 自定义此 hook 比自定义用于 status buffer 的相应 hook 意义要小得多.
magit-refs-sections-hook[User Option] 运行此 hook 以将 sections 插入 references buffer.magit-insert-local-branches[Function] 插入显示所有本地分支的 sections.magit-insert-remote-branches[Function] 插入显示所有远程跟踪分支的 sections.magit-insert-tags[Function] 插入显示所有 tags 的 sections.
5.7. 5.7 二分查找 (Bisecting)
另请参阅 git-bisect(1) manpage.
B(magit-bisect) 此 transient 前缀命令绑定以下 suffix 命令, 并在临时 buffer 中显示它们, 直到调用 suffix.
当 bisecting 未进行时, transient 具有以下 suffix 命令.
B B(magit-bisect-start) 开始 bisect 会话. Bisecting bug 意味着找到引入它的 commit. 此命令通过询问已知的 good commit 和已知的 bad commit 来启动此类 bisect 会话. 如果你正在 bisecting 一个不是 regression 的更改, 你可以选择概念上比 "bad" 和 "good" 更合适的替代术语, 但这样做的 infix 参数默认是禁用的.B s(magit-bisect-run) 通过在每一步之后运行命令来自动 Bisect.
当 bisecting 进行中时, transient 具有以下 suffix 命令.
B b(magit-bisect-bad) 将当前 commit 标记为 bad. 在你断言 commit 确实包含有问题的 bug 后使用此项.B g(magit-bisect-good) 将当前 commit 标记为 good. 在你断言 commit 不包含有问题的 bug 后使用此项.B m(magit-bisect-mark) 使用 bisect 术语之一标记当前 commit. 此命令提供了magit-bisect-bad和magit-bisect-good的替代方案, 在使用除 "bad" 和 "good" 之外的术语时很有用. 此 suffix 默认是禁用的.B k(magit-bisect-skip) 跳过当前 commit. 如果出于某种原因当前 commit 不是一个好的测试对象, 请使用此项. 此命令让 Git 选择一个不同的 commit.B r(magit-bisect-reset) Bisecting 后, 清理 bisection 状态并返回原始HEAD.
默认情况下, status buffer 显示有关正在进行的 bisect 会话的信息.
magit-bisect-show-graph[User Option] 此选项控制是否为仍需 bisected 的 commits 的 log 显示图形.
5.8. 5.8 访问文件和 Blobs (Visiting Files and Blobs)
Magit 提供了几个访问文件或 blob (存储在特定 commit 中的文件版本) 的命令. 实际上它提供了几组此类命令以及每组中的几个变体.
另请参阅第 120 页的 8.10 节 [Commands for Buffers Visiting Files].
5.8.1. 5.8.1 通用访问命令 (General-Purpose Visit Commands)
这些命令可用于在任何地方打开任何 blob. 默认情况下没有键绑定到这些命令, 但这可能会改变.
magit-find-file[Command] 此命令从用户读取文件名和 revision, 并在 buffer 中访问相应的 blob. buffer 显示在选定窗口中.magit-find-file-other-window[Command] 此命令从用户读取文件名和 revision, 并在 buffer 中访问相应的 blob. buffer 显示在另一个窗口中.magit-find-file-other-frame[Command] 此命令从用户读取文件名和 revision, 并在 buffer 中访问相应的 blob. buffer 显示在另一个 frame 中.
5.8.2. 5.8.2 从 Diff 访问文件和 Blobs (Visiting Files and Blobs from a Diff)
这些命令仅当 point 在 diff 内时才可以使用. 在其他地方使用 magit-find-file.
RET(magit-diff-visit-file) 此命令访问 point 处文件的适当版本. 在选定窗口中显示 buffer. 带有前缀参数OTHER-WINDOW, 改为在另一个窗口中显示 buffer. 在访问的文件或 blob 中, 转到与 diff 中位置对应的位置. 如果 point 在添加行或上下文行上, 访问对应于我方 (即, 新/右侧) 的 blob. 如果 point 在删除行上, 访问对应于彼方 (即, 旧/左侧) 的 blob. 这也适用于 staged 和 unstaged 更改的 diffs. 对于 staged 更改, 双方是来自 index 和HEADcommit 的 blobs. 对于 unstaged 更改, 双方是 worktree 中的实际文件和来自 index 的 blob. 要访问 worktree 中的文件, 无论当前 diff 是关于什么的, 请使用magit-diff-visit-worktree-file, 如下所述.C-<return>(magit-diff-visit-worktree-file) 此命令访问适当文件的 worktree 版本. diff 内 point 的位置决定了访问哪个文件. 与magit-diff-visit-file不同, 它总是访问 worktree 中的 "真实" 文件, 即文件的 "当前版本". 在文件访问 buffer 中, 此命令转到与 diff 中 point 所在行对应的行. 工作树, index 和其间其他 commits 中添加或删除的行会自动被考虑在内. buffer 显示在选定窗口中. 带有前缀参数时, buffer 显示在另一个窗口中.
存在上述两个命令的变体, 它们改为在另一个窗口或另一个 frame 中访问文件. 如果你更喜欢这种行为, 那么你可能想更改上面的键绑定, 但请注意, 上述命令在使用前缀参数调用时也使用另一个窗口.
magit-diff-visit-file-other-window[Command]magit-diff-visit-file-other-frame[Command]magit-diff-visit-worktree-file-other-window[Command]magit-diff-visit-worktree-file-other-frame[Command] 这些命令的行为类似于上述相应命令, 除了它们在另一个窗口或 frame 中显示 blob 或文件.magit-diff-visit-prefer-worktree[User Option] 此选项控制magit-diff-visit-file在从 staged 或 unstaged 更改的 hunk 中调用时, 是否总是访问 worktree 中的相应文件. 默认情况下magit-diff-visit-file不这样做. 相反, 它对 staged 和 unstaged 更改的行为就像对已提交更改一样, 通过访问旧/左侧或新/右侧的 blob, 具体取决于 point 是否在删除行上. 对于 staged 更改, 旧的一侧是来自 HEAD 的 blob, 右侧是来自 index 的 blob. 对于 unstaged 更改, 左侧是来自 index 的 blob (如果该文件在 index 中有任何更改, 否则是来自 HEAD 的 blob), 右侧是 worktree 中的文件. 能够从删除行跳转到 HEAD 或 index 非常有用, 因为它允许你例如使用 blame 来调查为什么添加了某行 (如果你已经删除了它). 但是如果你想对已经 staged 的更改进行进一步更改, 你当然需要转到 worktree 中的相应文件. 命令magit-diff-visit-worktree-file就是为此目的而创建的, 强烈建议你使用该命令, 即使你最初觉得必须记住使用C-<return>而不是RET这种情况下很不方便. 虽然不鼓励, 但你可以选择将此选项设置为t, 这会导致magit-diff-visit-file即使从 staged 更改的 hunk 中调用, 也会转到 worktree 中的文件. 如果你这样做, 你将失去立即转到已删除行的能力.magit-diff-visit-previous-blob[User Option] 此选项控制当 point 在删除行上调用时,magit-diff-visit-file是否访问前一个 blob. 当此值为t(默认值) 且 point 在删除行上时,magit-diff-visit-file访问来自旧/左侧 commit 的 blob (它仍然有那行), 而不是转到新/右侧 blob (它删除了那行). 将此设置为nil, 导致magit-diff-visit-file总是转到新/右侧 blob, 即使 point 在删除行上. 强烈不鼓励这样做. 相反, 如果你想访问新的一侧, 请将光标放在 hunk 内除了删除行之外的任何位置. 这样你就不会失去访问旧一侧的能力.
5.9. 5.9 追溯 (Blaming)
另请参阅 git-blame(1) manpage.
要开始 blaming, 调用 magit-file-dispatch transient 前缀命令. 当使用默认键绑定时, 可以通过按 C-c M-g 来完成. 当使用推荐绑定时, 此命令改为绑定到 C-c f. 另请参见第 129 页的 [Global Bindings].
Blaming suffix 命令可以直接从 file dispatch transient 调用. 但是如果你想设置一个 infix 参数, 那么你必须先进入 blaming 子前缀.
C-c f B(magit-blame)C-c f b(magit-blame-addition)C-c f B bC-c f r(magit-blame-removal)C-c f B rC-c f f(magit-blame-reverse)C-c f B fC-c f e(magit-blame-echo)C-c f B eC-c f q(magit-blame-quit)C-c f B q这些命令中的每一个都在下面单独记录, 连同它们的默认键绑定. 上面显示的绑定是推荐的绑定, 你可以按照第 129 页 [Global Bindings] 中的说明启用它们.C-c M-g B(magit-blame) 此 transient 前缀命令绑定以下 suffix 命令以及适当的 infix 参数, 并在临时 buffer 中显示它们, 直到调用 suffix.
请注意, 并非所有以下 suffixes 始终可用. 例如, 如果未启用 magit-blame-mode, 那么旨在关闭该模式的命令将没有任何用处, 因此不可用.
C-c M-g b(magit-blame-addition)C-c M-g B b此命令用有关最后触及这些行的 commits 的信息增强当前访问文件或访问 blob 的 buffer 中的每一行或每块行. 如果 buffer 访问该文件的 revision, 则考虑直到该 revision 的历史记录. 否则, 考虑文件的完整历史记录, 包括未提交的更改. 如果 Magit-Blame 模式已在当前 buffer 中打开, 那么 blaming 是递归完成的, 通过访问REVISION:FILE(使用magit-find-file), 其中REVISION是添加当前行或行块的 revision 的父级.C-c M-g r(magit-blame-removal)C-c M-g B r此命令用有关删除它的 revision 的信息增强当前访问 blob 的 buffer 中的每一行或每块行. 它不能用于访问文件的 buffers. 像magit-blame-addition一样, 此命令可以递归使用.C-c M-g f(magit-blame-reverse)C-c M-g B f此命令用有关行仍然存在的最后一个 revision 的信息增强当前访问文件或访问 blob 的 buffer 中的每一行或每块行. 像magit-blame-addition一样, 此命令可以递归使用.C-c M-g e(magit-blame-echo)C-c M-g B e此命令类似于magit-blame-addition, 除了它不打开read-only-mode并且它最初使用选项magit-blame-echo-style指定的可视化样式.
当启用 Magit-Blame 模式且未启用 Read-Only 模式时, 以下键绑定可用. 这些命令也可在其他 buffers 中使用; 这里仅描述在被 blamed 的文件访问 buffers 中相关的行为.
C-c M-g q(magit-blame-quit)C-c M-g B q此命令关闭 Magit-Blame 模式. 如果 buffer 是在递归 blame 期间创建的, 那么它也会 kill buffer.RET(magit-show-commit) 此命令显示最后触及 point 处行的 commit.SPC(magit-diff-show-or-scroll-up) 此命令更新 commit buffer. 这要么在适当的 buffer 中显示最后触及 point 处行的 commit, 或者如果该 buffer 已经在当前 frame 中显示并且如果该 buffer 包含有关该 commit 的信息, 那么向上滚动 buffer.DEL(magit-diff-show-or-scroll-down) 此命令更新 commit buffer. 这要么在适当的 buffer 中显示最后触及 point 处行的 commit, 或者如果该 buffer 已经在当前 frame 中显示并且如果该 buffer 包含有关该 commit 的信息, 那么向下滚动 buffer.
当同时启用 Magit-Blame 模式和 Read-Only 模式时, 以下键绑定可用.
b(magit-blame) 见上文.n(magit-blame-next-chunk) 此命令移动到下一个 chunk.N(magit-blame-next-chunk-same-commit) 此命令从同一个 commit 移动到下一个 chunk.p(magit-blame-previous-chunk) 此命令移动到上一个 chunk.P(magit-blame-previous-chunk-same-commit) 此命令从同一个 commit 移动到上一个 chunk.q(magit-blame-quit) 此命令关闭 Magit-Blame 模式. 如果 buffer 是在递归 blame 期间创建的, 那么它也会 kill buffer.M-w(magit-blame-copy-hash) 此命令将当前 chunk 的 commit hash 保存到 kill ring. 当 region 处于活动状态时, 该命令保存 region 的内容而不是 hash, 就像kill-ring-save一样.c(magit-blame-cycle-style) 此命令通过循环选项magit-blame-styles指定的样式来更改 blame 信息在当前 buffer 中的可视化方式.
Blaming 也使用以下选项控制.
magit-blame-styles[User Option] 此选项定义了用于可视化 blame 信息的样式列表. 目前请参阅其 doc-string 以了解更多信息.magit-blame-echo-style[User Option] 此选项指定命令magit-blame-echo使用的 blame 可视化样式. 这必须是一个符号, 用作magit-blame-styles中定义的一种样式的标识符.magit-blame-time-format[User Option] 此选项指定显示 blame 信息时用于显示时间的格式字符串.magit-blame-read-only[User Option] 此选项控制 blaming buffer 是否也使其暂时变为 read-only.magit-blame-disable-modes[User Option] 此选项列出了当 buffer 包含 blame 信息时应暂时禁用的不兼容 minor-modes. 当 buffer 不再显示 blame 信息时, 它们会再次启用.magit-blame-goto-chunk-hook[User Option] 此 hook 在 chunks 之间移动时运行.
6. 6 操作 (Manipulating)
6.1. 6.1 创建仓库 (Creating Repository)
I(magit-init) 此命令初始化一个仓库, 然后显示新仓库的 status buffer. 如果目录位于现有仓库下方, 则用户必须确认应在其中创建一个新仓库. 如果目录是现有仓库的根目录, 则用户必须确认应重新初始化它.
6.2. 6.2 克隆仓库 (Cloning Repository)
要克隆远程或本地仓库, 请使用 C, 它绑定到命令 magit-clone. 此命令既可以充当 transient 前缀命令 (绑定几个 infix 参数和 suffix 命令), 也可以直接调用 git clone, 具体取决于是否使用前缀参数以及 magit-clone-always-transient 的值.
magit-clone-always-transient[User Option] 此选项控制命令magit-clone是否始终充当 transient 前缀命令, 无论是否使用前缀参数. 如果为t, 那么该命令始终充当 transient 前缀. 如果为nil, 那么必须使用前缀参数才能使其充当 transient.C(magit-clone) 此命令要么如上所述充当 transient 前缀命令, 要么如下所述执行与transient-clone-regular相同的操作. 如果它充当 transient 前缀, 那么它绑定以下 suffix 命令和几个 infix 参数.C C(magit-clone-regular) 此命令创建现有仓库的常规克隆. 仓库和目标目录从用户读取.C s(magit-clone-shallow) 此命令创建现有仓库的浅克隆. 仓库和目标目录从用户读取. 默认情况下, 克隆历史的深度为单个 commit, 但带有前缀参数时深度从用户读取.C >(magit-clone-sparse) 此命令创建现有仓库的克隆并初始化稀疏检出, 避免检出完整的工作树. 要添加更多目录, 请使用magit-sparse-checkouttransient (参见第 115 页的 8.6 节 [Sparse checkouts]).C b(magit-clone-bare) 此命令创建现有仓库的裸克隆. 仓库和目标目录从用户读取.C m(magit-clone-mirror) 此命令创建现有仓库的镜像. 仓库和目标目录从用户读取.
以下 suffixes 默认是禁用的. 参见 transient 中的 "Enabling and Disabling Suffixes" 以了解如何启用它们.
C d(magit-clone-shallow-since) 此命令创建现有仓库的浅克隆. 仅克隆在日期之后提交的 commits, 日期从用户读取. 仓库和目标目录也从用户读取.C e(magit-clone-shallow-exclude) 此命令创建现有仓库的浅克隆. 这从用户读取一个分支或 tag. 从那里可到达的 commits 不会被克隆. 仓库和目标目录也从用户读取.magit-clone-set-remote-head[User Option] 此选项控制克隆是否导致在克隆中创建 referencerefs/remotes/<remote>/HEAD. 默认是在运行git clone后删除该 reference, 因为git clone坚持创建它. 这是因为已发现该 reference 不是特别有用, 因为当 remote 的HEAD更改时它不会自动更新. 将此选项设置为t保留 Git 创建 reference 的默认行为.magit-clone-set-remote.pushDefault[User Option] 此选项控制克隆后是否设置 Git 变量remote.pushDefault的值.- 如果为
t, 则始终设置且不询问. - 如果为
ask, 则每次克隆仓库时询问用户. - 如果为
nil, 则从不设置.
- 如果为
magit-clone-default-directory[User Option] 此选项控制读取克隆操作的目标时使用的默认目录名称.- 如果为
nil(默认值), 则使用default-directory的值. - 如果为目录, 则使用该目录.
- 如果为函数, 则使用 remote url 作为唯一参数调用它, 并使用返回值.
- 如果为
magit-clone-name-alist[User Option] 此选项将匹配仓库名称的正则表达式映射到仓库 urls, 使得用户在克隆仓库时可以输入短名称而不是 urls. 每个元素的形式为(REGEXP HOSTNAME USER). 当用户在克隆命令询问名称或 url 时输入名称时, 会在此列表中查找. 使用第一个REGEXP匹配的元素. 选项magit-clone-url-format指定的格式用于将名称转换为 url, 使用HOSTNAME和仓库名称. 如果提供的名称包含斜杠, 则使用它. 否则如果名称省略了仓库所有者, 则使用匹配条目中指定的默认用户. 如果USER包含点, 则将其视为 Git 变量, 并使用其值作为用户名. 否则按原样用作用户名.magit-clone-url-format[User Option] 此选项指定的格式用于将仓库名称转换为 urls.%h是主机名,%n是仓库名称 (包括所有者名称). 该值可以是字符串 (代表单个静态格式) 或带有元素(HOSTNAME . FORMAT)的 alist, 将主机名映射到格式. 当使用 alist 时,t键代表默认格式. 单个格式字符串的示例:(setq magit-clone-url-format "git@%h:%n.git")
按主机名格式字符串的示例:
(setq magit-clone-url-format '(("git.example.com" . "git@%h:~%n") (nil . "git@%h:%n.git")))
magit-post-clone-hook[User Option] 在 Git 进程成功完成克隆仓库后运行的 hook. 当调用 hook 时,default-directory被 let-bound 到仓库被克隆到的目录.
6.3. 6.3 Staging 和 Unstaging
像 Git 一样, Magit 当然可以 stage 和 unstage 完整的文件. 与 Git 不同, 它还允许用户优雅地 un-/stage 单个 hunks 甚至只是 hunk 的一部分. 要使用 Git 直接 stage 单个 hunks 和部分 hunks, 必须使用非常模态且相当笨拙的 git add --interactive 会话接口.
另一方面, 使用 Magit, 只需将 point 移动到 status buffer 或单独 diff buffer 中显示的 diff 内的相应 section, 然后键入 s 或 u, 即可 un-/stage 单个 hunks. 要仅对 hunk 的部分进行操作, 请使用 region 标记应 un-/staged 的更改, 然后按用于 un-/stage 的相同键. 要一次 stage 多个文件或 hunks, 请使用从这种 section 的标题开始并在同类型同级 section 的标题结束的 region.
除了 staging 和 unstaging 之外, Magit 还提供了其他几种 "apply variants", 它们也可以对文件, 一次多个文件, hunk, 一次多个 hunks 以及 hunk 的部分进行操作. 这些 apply variants 将在下一节中描述.
你还可以使用 Ediff 进行 stage 和 unstage. 参见第 55 页的 5.5 节 [Ediffing].
s(magit-stage) 将 point 处的更改添加到 staging area. 带有前缀参数和 point 处的未跟踪文件 (或多个文件), stage 文件但不 stage 其内容. 这使得可以只 stage 新文件更改的子集.S(magit-stage-modified) Stage worktree 中修改文件的所有更改. Stage 被跟踪文件所有新内容, 并从 index 中删除不再存在于 worktree 中的被跟踪文件. 带有前缀参数也 stage 以前未跟踪 (但未忽略) 的文件.u(magit-unstage) 从 staging area 移除 point 处的更改. 只有 staged 更改可以被 unstaged. 但默认情况下, 当在已提交更改上调用此命令时, 它会执行类似于 unstaging 的操作: 它反转 index 中的更改, 但不反转 worktree 中的更改.U(magit-unstage-all) 从 staging area 移除所有更改.magit-unstage-committed[User Option] 此选项控制magit-unstage是否通过在 index 中反转已提交更改 (但不在 worktree 中) 来 "unstages" 它们. 替代方法是引发错误.M-x magit-reverse-in-index此命令在 index 中反转 point 处的已提交更改, 但不在 worktree 中反转. 默认情况下没有键直接绑定到此命令, 但当在已提交更改上按u(magit-unstage) 时会间接调用它. 这允许从HEAD中提取更改, 同时将其保留在 worktree 中, 以便稍后可以使用单独的 commit 提交它. 典型的工作流程如下:- 可选地确保没有未提交的更改.
- 访问
HEAD提交并导航到不应包含在该提交中的更改. - 输入
u(magit-unstage) 以在 index 中反转它. 这假设magit-unstage-committed为非nil. - 输入
c e以使用 staged 更改 extendHEAD, 包括那些之前已经 staged 的更改. - 可选地使用
s或Sstage 剩余的更改, 然后输入c c创建新提交.
M-x magit-reset-index将 index 重置为某个 commit. commit 从用户读取, 默认为 point 处的 commit. 如果 point 处没有 commit, 则默认为HEAD.
6.3.1. 6.3.1 从访问文件的缓冲区 Staging (Staging from File-Visiting Buffers)
细粒度的 un-/staging 必须在 status 或 diff buffer 中完成, 但也可以直接在当前 buffer 中 un-/stage 对该 buffer 访问文件所做的所有更改.
M-x magit-stage-file当在访问文件的 buffer 内调用时, stage 对该文件的所有更改. 在 Magit buffer 中, stage point 处的文件 (如果有). 否则提示要 stage 的文件. 带有前缀参数时, 即使在访问文件的 buffer 中或 point 处有文件 section, 也总是提示用户输入文件.M-x magit-unstage-file当在访问文件的 buffer 内调用时, unstage 对该文件的所有更改. 在 Magit buffer 中, unstage point 处的文件 (如果有). 否则提示要 unstage 的文件. 带有前缀参数时, 即使在访问文件的 buffer 中或 point 处有文件 section, 也总是提示用户输入文件.
6.4. 6.4 应用 (Applying)
Magit 提供了几种 "apply variants": stage, unstage, discard, reverse, 和 "regular apply". 至少当在 hunk 上操作时, 它们都是使用 git apply 实现的, 这就是为什么它们被称为 "apply variants".
- Stage: 将更改从 worktree 应用到 index. 更改也保留在 worktree 中.
- Unstage: 从 index 中移除更改. 更改保留在 worktree 中.
- Discard: 对 staged 更改, 从 worktree 和 index 中移除它. 对 unstaged 更改, 仅从 worktree 中移除它.
- Reverse: 在 worktree 中反转更改. 已提交和 staged 更改都可以被反转. Unstaged 更改不能被反转. 而是丢弃它们.
- Apply: 将更改应用到 worktree. 已提交和 staged 更改都可以被应用. Unstaged 更改不能被应用 - 因为它们已经被应用了.
上一节描述了 staging 和 unstaging 命令. 下面是实现其余 apply variants 的命令.
a(magit-apply) 将 point 处的更改应用到 worktree. 带有前缀参数回退到 3-way merge. 这样做也会导致更改被应用到 index.k(magit-discard) 从 worktree 中移除 point 处的更改. 在具有未解决冲突的 hunk 或文件上, 提示保留哪一方 (同时丢弃另一方). 如果 point 在一方的文本内, 则不提示直接保留该方.v(magit-reverse) 在 worktree 中反转 point 处的更改. 带有前缀参数回退到 3-way merge. 这样做也会导致更改被应用到 index.
带有前缀参数时, 所有 apply variants 在适当的时候尝试 3-way merge (即, 当内部使用 git apply 时).
6.5. 6.5 提交 (Committing)
当用户发起提交时, Magit 调用不带 --message 参数的 git commit, 因此 Git 必须从用户获取消息. 为此, 它创建一个文件 (如 .git/COMMIT_EDITMSG), 然后在 $EDITOR (或 $GIT_EDITOR) 指定的编辑器中打开该文件.
Magit 安排该编辑器为 Emacsclient. 一旦用户完成编辑会话, Emacsclient 退出, Git 创建提交, 使用文件内容作为提交消息.
6.5.1. 6.5.1 发起提交 (Initiating a Commit)
另请参阅 git-commit(1) manpage.
c(magit-commit) 此 transient 前缀命令绑定以下 suffix 命令以及适当的 infix 参数, 并在临时 buffer 中显示它们, 直到调用 suffix.
- 创建新提交
c c(magit-commit-create) 创建一个新提交.
- 编辑最后一次提交
这些命令修改最后一次 (即 "HEAD") 提交. 提交立即被修改 (即替换). 存在用于修改其他 (非 HEAD) 提交的类似命令. 些命令将在接下来的两节中描述. 对于本节中的每个命令, 我们都会提到相应的非 HEAD 命令, 以明确关系.
下面的命令描述提到了它们调用
git commit时使用的特定参数. 菜单中指定的参数会追加到这些参数后面.c e(magit-commit-extend) 此命令将 staged 更改 amend 到最后一次提交, 而不编辑其提交消息. 此命令调用git commit --amend --no-edit. 带有前缀参数时, 不更新提交者日期; 不带参数时, 更新它. 选项magit-commit-extend-override-date可用于反转前缀参数的含义. 非交互式地, 可选的OVERRIDE-DATE参数控制此行为, 并且该选项无关紧要.c a(magit-commit-amend) 此命令将 staged 更改 amend 到最后一次提交, 并弹出一个 buffer 让用户编辑其提交消息. 此命令调用git commit --amend --edit.c w(magit-commit-reword) 此命令弹出一个 buffer 让用户编辑最后一次提交的消息. 提交树保持不变, staged 更改保持 staged. 此命令调用git commit --amend --only --edit. 带有前缀参数时, 不更新提交者日期; 不带参数时, 更新它. 选项magit-commit-reword-override-date可用于反转前缀参数的含义. 非交互式地, 可选的OVERRIDE-DATE参数控制此行为, 并且该选项无关紧要.
- 编辑任何可到达的提交
这些命令从 staged 更改和/或使用新提交消息创建一个新提交, 该提交以现有提交为目标. 任何从 HEAD 可到达的提交 (包括 HEAD 本身) 都可以是目标.
新提交旨在最终被 squash 进目标提交, 但这不是立即完成的. Squashing 在稍后时间完成, 当你显式调用
magit-rebase-autosquash, 或在另一个 rebase 命令中使用--autosquash时.一些命令要求你立即编写新的提交消息, 或立即编辑现有消息.
新提交被称为 "squash" 和 "fixup" 提交. 区别在于当 "squash" 提交被 squash 进其目标提交时, 用户有机会修改用于最终提交的消息; 而对于 "fixup" 提交, 目标提交的现有消息按原样使用, "fixup" 提交的消息被丢弃.
如果 point 在可到达的提交上, 那么所有这些命令都以该提交为目标, 无需确认. 如果 point 在某个可到达的提交上, 但你想以另一个提交为目标, 使用前缀参数, 在专门用于该任务的 log buffer 中选择一个提交. 前缀参数的含义可以通过自定义
magit-commit-squash-confirm来反转.下面的命令描述提到了它们调用
git commit时使用的特定参数. 菜单中指定的参数会追加到这些参数后面.接下来的两个命令也存在 "instant" 变体, 将在下一节中描述. 那些变体与这里描述的变体行为相同, 除了它们立即启动
--autosquashrebase.c f(magit-commit-fixup) 此命令从 staged 更改创建一个新的 fixup 提交, 目标是 point 处的可到达提交 (如果有). 否则提示用户输入提交. 如果你想更正目标提交中的一些小缺陷, 且不需要更改目标提交的现有消息, 请使用此变体. 此命令调用git commit --fixup=COMMIT --no-edit.c s(magit-commit-squash) 此命令从 staged 更改创建一个新的 squash 提交, 目标是 point 处的可到达提交 (如果有). 否则提示用户输入提交. 如果你想有机会更改最终提交消息, 但直到两个提交被 squash 成最终组合提交时才进行, 请使用此变体. 此命令调用git commit --squash=COMMIT --no-edit.c A(magit-commit-alter) 此命令从 staged 更改创建一个新的 fixup 提交, 目标是 point 处的可到达提交 (如果有). 否则提示用户输入提交. 如果你想现在编写最终提交消息, 但 (像本节中的所有变体一样) 不想立即将 fixup 和目标提交 squash 成最终组合提交, 请使用此变体. 此命令调用git commit --fixup=amend:COMMIT --edit.c n(magit-commit-augment) 此命令从 staged 更改创建一个新的 squash 提交, 目标是 point 处的可到达提交 (如果有). 否则提示用户输入提交. 如果你想现在描述新更改, 但想延迟编写描述组合提交中更改的最终消息, 直到你实际将 squash 和目标提交组合成最终提交时, 请使用此变体. 你可以将你在这里写的新消息视为 "笔记", 一旦你编写最终提交消息就会被整合. 此命令调用git commit --squash=COMMIT --edit.c W(magit-commit-revise) 此命令弹出一个包含 point 处可到达提交 (如果有) 的提交消息的 buffer. 否则提示用户输入要目标的提交. 如果你想更正目标提交的消息, 但想延迟执行实际更改该提交的--autosquashrebase, 请使用此变体. 此命令调用git commit --fixup=reword:COMMIT --edit.
- 编辑任何可到达的提交并立即变基
这些命令从 staged 更改创建一个新提交, 该提交以现有提交为目标. 任何从 HEAD 可到达的提交 (包括 HEAD 本身) 都可以是目标.
新提交立即被 squash 进其目标提交, 使用
--autosquashrebase.下面的命令描述提到了它们调用
git commit时使用的特定参数. 在调用git commit时, 菜单中指定的参数会追加到这些参数后面.c F(magit-commit-instant-fixup) 此命令创建一个 fixup 提交, 目标是 point 处的可到达提交 (如果有). 否则提示用户输入提交. 然后它立即执行 rebase, 将新提交 squash 进目标提交. 目标提交的原始提交消息保持不变. 此命令调用git commit --fixup=COMMIT --no-edit然后git rebase --autosquash MERGE-BASE.c S(magit-commit-instant-squash) 此命令创建一个 squash 提交, 目标是 point 处的可到达提交 (如果有). 否则提示用户输入提交. 然后它立即执行 rebase, 将新提交 squash 进目标提交. 在 rebase 阶段, 要求用户根据目标提交的原始消息编写最终提交消息. 此命令调用git commit --squash=COMMIT --no-edit然后git rebase --autosquash MERGE-BASE.
- 提交命令使用的选项
- 所有或大多数提交命令使用
magit-commit-show-diff[User Option] 是否在提交时自动显示相关的 diff.magit-commit-ask-to-stage[User Option] 当提交且没有 staged 内容时, 是否询问 stage 所有 unstaged 更改.magit-post-commit-hook[User Option] 在用户未编辑消息的情况下创建提交后运行的 hook. 如果this-command是magit-post-commit-hook-commands的成员, 则此 hook 由magit-refresh运行. 这仅包括名为magit-commit-*且不需要用户在 buffer 中编辑提交消息的命令. 另请参见git-commit-post-finish-hook.magit-commit-diff-inhibit-same-window[User Option] 在提交时显示 diff 时是否禁止使用同一窗口. 当编写提交时, 会自动显示要提交的更改的 diff. 这个想法是 diff 显示在同一 frame 的不同窗口中, 对于大多数用户来说这很有效. 换句话说, 大多数用户可以完全忽略此选项, 因为它的值对他们没有影响. 但是, 对于配置了 Emacs 即使包显式尝试创建新窗口也从不创建新窗口的用户, 显示两个新 buffers 必然意味着第一个立即被第二个替换. 在我们的例子中, 消息 buffer 立即被 diff buffer 替换, 这当然是非常不可取的. 一种解决方法是在这种特定情况下抑制此用户配置. 用户必须通过切换此选项来显式选择加入. 我们不能无条件启用此解决方法, 因为这再次导致其他用户的问题: 如果 frame 太小或相关设置太激进, 那么 diff buffer 最终会显示在新 frame 中. 另请参见 https://github.com/magit/magit/issues/4132.- 所有 squash 和 fixup 命令使用
magit-commit-squash-confirm[User Option] 被 squash 和 fixup 目标的提交是否必须确认. 当为非nil时, point 处的提交 (如果有) 用作默认选择. 否则必须确认. 此选项仅影响magit-commit-squash和magit-commit-fixup. "Instant" 变体总是需要确认, 因为在使用这些变体时出错更难恢复.- 特定提交命令使用
magit-commit-extend-override-date[User Option] 使用magit-commit-extend是否更改提交者日期.magit-commit-reword-override-date[User Option] 使用magit-commit-reword是否更改提交者日期.
6.5.2. 6.5.2 编辑提交消息 (Editing Commit Messages)
在如上一节所述发起提交后, 出现两个新 buffers. 一个显示即将提交的更改, 另一个用于编写消息.
提交消息在编辑会话中编辑–在后台 git 等待编辑器 (在我们的例子中是 emacsclient) 将提交消息保存到文件 (在大多数情况下为 .git/COMMIT_EDITMSG) 然后返回. 如果编辑器以非零退出状态返回, 那么 git 不会创建提交. 所以最重要的命令是那些用于完成和中止提交的命令.
C-c C-c(with-editor-finish) 通过以退出代码 0 返回来完成当前编辑会话. Git 然后使用它在文件中找到的消息创建提交.C-c C-k(with-editor-cancel) 通过以退出代码 1 返回来取消当前编辑会话. Git 然后取消提交, 但保持文件不变.
除了被 git commit 使用之外, 消息还可以存储在环中, 该环持续到 Emacs 关闭. 默认情况下, 消息在编辑会话的开始和结束时存储 (无论会话是成功完成还是被取消). 有时从该环中取回消息很有用.
C-c M-s(git-commit-save-message) 将当前 buffer 内容保存到提交消息环.M-p(git-commit-prev-message) 在将当前消息保存到环后, 向后循环提交消息环. 带有数字前缀 ARG, 后退 ARG 条评论.M-n(git-commit-next-message) 在将当前消息保存到环后, 向前循环提交消息环. 带有数字前缀 ARG, 后退 ARG 条评论.
默认情况下, 调用提交时会自动显示即将提交的更改的 diff. 要防止这种情况, 从 server-switch-hook 中移除 magit-commit-diff.
(remove-hook 'with-editor-filter-visit-hook 'magit-commit-diff)
然后你可以输入 C-c C-d 来显示 diff, 当你实际上想看到它时, 但仅限于此. 或者你可以保留 hook, 只在生成 diff 需要太长时间的情况下输入 C-g. 如果你这样做, 那么你最终会得到一个损坏的 diff buffer, 但这样做的好处是你通常可以看到 diff, 这很有用, 因为它增加了你发现潜在问题的几率.
当 amend 现有提交时, 显示即将添加到该提交的更改或将这些更改与已经提交的更改一起显示可能会很有用.
C-c C-d(magit-diff-while-committing) 提交时, 显示即将提交的更改. Amend 时, 再次调用该命令可在仅显示新更改或显示将提交的所有更改之间切换.
- 使用 Revision Stack
C-c C-w(magit-pop-revision-stack) 此命令将 revision 的表示形式插入当前 buffer. 它可以在用于编写提交消息的 buffers 中使用, 也可以在其他 buffers 中使用, 例如用于编辑电子邮件或 ChangeLog 文件的 buffers. 默认情况下, 此命令弹出最后添加到magit-revision-stack的 revision, 并根据magit-pop-revision-stack-format将其插入当前 buffer. Revisions 可以使用magit-copy-section-value和magit-copy-buffer-revision放入堆栈. 如果堆栈为空或带有前缀参数, 它改为在 minibuffer 中读取 revision. 通过使用 minibuffer 历史记录, 这允许选择较早弹出的项目或插入任意 reference 或 revision, 而无需先将其推入堆栈. 从 minibuffer 读取 revision 时, 可能无法猜测正确的仓库. 当在仓库内 (例如, 在撰写提交消息时) 调用此命令时, 使用该仓库. 否则 (例如, 在撰写电子邮件时) 使用为堆栈顶层元素记录的仓库 (即使我们插入另一个 revision). 如果未在仓库内调用且堆栈为空, 或带有两个前缀参数, 也在 minibuffer 中读取仓库.magit-pop-revision-stack-format[User Option] 此选项控制命令magit-pop-revision-stack如何将 revision 插入当前 buffer. 堆栈上的条目格式为(HASH TOPLEVEL), 此选项的格式为(POINT-FORMAT EOB-FORMAT INDEX-REGEXP), 所有这些都可以是nil或字符串 (尽管EOB-FORMAT或POINT-FORMAT中的任何一个都应该是字符串, 并且如果INDEX-REGEXP为非nil, 那么这两种格式也应该是非nil). 首先使用INDEX-REGEXP查找先前插入的条目, 通过从 point 向后搜索. 第一个子匹配必须匹配索引号. 该数字加一, 并成为要插入条目的索引号. 如果不想对插入的 revisions 编号, 请将INDEX-REGEXP设置为nil. 如果INDEX-REGEXP为非nil, 那么POINT-FORMAT和EOB-FORMAT都应包含"%N", 它将被上一步确定的数字替换. 这两种格式, 如果为非nil且在删除%N后, 随后使用git show --format=FORMAT ...在TOPLEVEL内展开.POINT-FORMAT的展开插入到 point 处,EOB-FORMAT的展开插入到 buffer 末尾 (如果 buffer 以注释结尾, 则插入在注释之前).
- Commit Pseudo Headers (提交伪标题)
一些项目在提交消息中使用伪标题. Magit 对此类标题进行着色, 并提供一些命令来插入此类标题.
git-commit-known-pseudo-headers[User Option] 要高亮显示的 Git 伪标题列表.C-c C-i(git-commit-insert-pseudo-header) 插入提交消息伪标题.C-c C-a(git-commit-ack) 插入一个标题, 确认你已查看该提交.C-c C-r(git-commit-review) 插入一个标题, 确认你已审查该提交.C-c C-s(git-commit-signoff) 插入一个标题以签署提交.C-c C-t(git-commit-test) 插入一个标题, 确认你已测试该提交.C-c C-o(git-commit-cc) 插入一个标题, 提及可能感兴趣的人.C-c C-p(git-commit-reported) 插入一个标题, 提及报告该提交修复的问题的人.C-c M-i(git-commit-suggested) 插入一个标题, 提及建议更改的人.
- Commit 模式和 Hooks (Commit Mode and Hooks)
git-commit-mode是一个 minor mode, 仅用于建立某些键绑定. 这使得可以在用于编辑提交消息的 buffers 中使用任意 major mode. 甚至可以在不同的仓库中使用不同的 major modes, 这在不同项目强加不同提交消息约定时很有用.git-commit-major-mode[User Option] 此选项的值是用于编辑 Git 提交消息的 major mode.
因为
git-commit-mode是 minor mode, 我们不使用其 mode hook 来设置 buffer, 除了键绑定. 所有其他设置发生在函数git-commit-setup中, 该函数除其他外运行 hookgit-commit-setup-hook.git-commit-setup-hook[User Option] 在git-commit-setup结束时运行的 Hook.
以下函数适用于此 hook:
git-commit-save-message[Function] 将当前 buffer 内容保存到提交消息环.git-commit-setup-changelog-support[Function] 调用此函数后, ChangeLog 条目被视为段落.git-commit-turn-on-auto-fill[Function] 打开auto-fill-mode.git-commit-turn-on-flyspell[Function] 打开 Flyspell 模式. 还防止检查注释, 最后检查当前非注释文本.git-commit-propertize-diff[Function] Propertize 提交消息 buffer 中显示的 diff. 当使用--verbose参数时, Git 将此类 diffs 插入到提交消息模板中.magit-commit默认不提供该参数, 因为在单独的 buffer 中显示的 diff 更有用. 但一些用户不同意, 这就是此函数存在的原因.bug-reference-mode[Function] 在 buffer 中超链接 bug 引用.with-editor-usage-message[Function] 在 echo area 中显示使用信息.git-commit-post-finish-hook[User Option] 在用户完成编写提交消息后运行的 Hook. 此 hook 仅在用于编辑提交消息的 buffer 中按C-c C-c后运行. 如果在用户未在 buffer 中输入消息的情况下创建提交, 则不运行此 hook. 直到新提交创建后才运行此 hook. 如果这样做让 Git 花费超过一秒钟, 那么根本不运行此 hook. 对于某些命令, 如magit-rebase-continue, 此 hook 从不运行, 因为这样做会导致竞争条件. 此 hook 仅在magit可用时运行. 另请参见magit-post-commit-hook.
- 提交消息约定 (Commit Message Conventions)
Git-Commit 高亮显示违反普遍接受的提交消息约定的情况. 某些违规甚至会导致 Git-Commit 要求你确认你真的想这样做. 这种唠叨当然可以关闭, 但这样做的结果通常是, 现在是由审查你提交的人类而不是代码来浪费时间告诉你修复你的提交.
git-commit-summary-max-length[User Option] 提交消息摘要行的预期最大长度. 超过此列的字符会被着色以指示违反了此偏好.git-commit-finish-query-functions[User Option] 执行提交前调用的查询函数列表. 调用函数时提交消息 buffer 为当前 buffer. 如果其中任何一个返回nil, 则不执行提交且不 kill buffer. 用户应修复问题并重试. 函数带有一个参数调用. 如果为非nil, 则表示用户使用前缀参数强制完成会话, 尽管存在问题. 函数通常应尊重此意愿并返回非nil. 默认情况下, 唯一成员是git-commit-check-style-conventions.git-commit-check-style-conventions[Function] 此函数检查违反某些基本样式约定的情况. 对于每个违规, 它都会询问用户是否仍要继续.git-commit-style-convention-checks[User Option] 此选项控制同名函数尝试强制执行哪些约定. 值为标识某些约定的不言自明的符号列表;non-empty-second-line和overlong-summary-line.
6.6. 6.6 分支 (Branching)
6.6.1. 6.6.1 两个远程 (The Two Remotes)
某个本地分支的 upstream branch (上游分支) 是该本地分支上的提交最终应合并到的分支, 通常类似于 origin/master. 对于 master 分支本身, upstream 分支和它被 push 到的分支通常是同一个远程分支. 但对于功能分支, upstream 分支和它被 push 到的分支应该不同.
功能分支上的提交最终也应该进入远程分支, 如 origin/master 或 origin/maint. 因此, 此类分支应用作 upstream. 但功能分支不应直接 push 到此类分支. 相反, 功能分支 my-feature 通常被 push 到 my-fork/my-feature 或如果你是贡献者 origin/my-feature. 在新功能经过审查后, 维护者将该功能合并到 master 中. 最后 master (而不是 my-feature 本身) 被 push 到 origin/master.
但新功能很少在第一次尝试时就完美无缺, 因此功能分支通常必须经过多次审查, 改进和重新 push. 因此, Pushing 应该很容易做到, 出于这个原因, 许多 Git 用户得出结论, 最好使用本地功能分支被 push 到的远程分支作为其 upstream.
但幸运的是, Git 早就获得了对 push-remote 的支持, 可以使用变量 branch.<name>.pushRemote 和 remote.pushDefault 与 upstream 分支分开配置. 所以我们不再需要选择两个 remotes 中的哪一个用作 "the remote".
每个 fetching, pulling 和 pushing transient 命令都具有三个 suffix 命令, 它们作用于当前分支和某个其他分支. 其中, p 绑定到作用于 push-remote 的命令, u 绑定到作用于 upstream 的命令, e 绑定到作用于任何其他分支的命令. Status buffer 显示 push-remote 和 upstream 的 unpushed 和 unpulled 提交.
配置这两个 remotes 相当简单. 与 fetching, pulling 和 pushing 相关的所有变量 (以及一些其他分支相关变量) 的值都可以使用命令 magit-branch-configure 进行检查和更改, 该命令可从处理分支的许多 transient 前缀命令获得. 也可以在 pushing 时设置 push-remote 或 upstream (参见第 107 页的 7.4 节 [Pushing]).
6.6.2. 6.6.2 分支命令 (Branch Commands)
Transient 前缀命令 magit-branch 用于创建和检出分支, 以及更改现有分支. 它不用于 fetch, pull, merge, rebase 或 push 分支, 即此命令处理分支本身, 而不是从它们可到达的 commits. 这些功能可从单独的 transient 命令获得.
b(magit-branch) 此 transient 前缀命令绑定以下 suffix 命令, 并在临时 buffer 中显示它们, 直到调用 suffix. 默认情况下, 它还绑定并显示一些分支相关 Git 变量的值, 并允许更改其值.magit-branch-direct-configure[User Option] 此选项控制 transient 命令magit-branch是否可用于直接更改 Git 变量的值. 这默认为t(以避免更改键绑定). 当设置为nil时, 该 transient 命令不显示任何变量, 必须改用其 suffix 命令magit-branch-configure来查看和更改分支相关变量.b C(magit-branch-configure)f CF CP C此 transient 前缀命令绑定设置分支相关变量值的命令, 并在临时 buffer 中显示它们, 直到退出 transient. 带有前缀参数时, 此命令总是提示输入分支. 不带前缀参数时, 这取决于它是否作为magit-branch的 suffix 调用以及magit-branch-direct-configure选项. 如果magit-branch已经显示当前分支的变量, 那么调用另一个显示同一分支变量的 transient 是没有用的. 在这种情况下, 此命令提示输入分支. 变量在 [Branch Git Variables], 第 86 页中描述.b b(magit-checkout) 检出在 minibuffer 中读取的 revision, 默认为 point 处的分支或任意 revision. 如果 revision 是本地分支, 那么它成为当前分支. 如果它是其他东西, 那么HEAD变为 detached. 如果 worktree 或 staging area 包含更改, 则检出失败.b n(magit-branch-create) 创建一个新分支. 要求用户输入一个分支或任意 revision 用作新分支的起点. 当提供分支名称时, 它成为新分支的 upstream 分支. 新分支的名称也在 minibuffer 中读取. 另请参见选项magit-branch-prefer-remote-upstream.b c(magit-branch-and-checkout) 此命令像magit-branch-create一样创建新分支, 但随后也会检出它. 另请参见选项magit-branch-prefer-remote-upstream.b l(magit-branch-checkout) 此命令检出已有的或新的本地分支. 它从用户读取分支名称, 提供所有本地分支和一部分远程分支作为候选项. 存在同名本地分支的远程分支从候选项列表中省略. 用户还可以输入全新的分支名称.- 如果用户选择现有的本地分支, 则检出该分支.
- 如果用户选择远程分支, 则它创建并检出同名的新本地分支, 并将所选远程分支配置为 push target.
- 如果用户输入新分支名称, 则在从用户读取起点后, 创建并检出该分支.
在后两种情况下, upstream 也会被设置. 是否将其设置为所选起点或其他内容取决于
magit-branch-adjust-remote-upstream-alist的值.b s(magit-branch-spinoff) 此命令创建并检出一个新分支, 从当前分支开始并跟踪当前分支. 该分支反过来重置为它与其 upstream 共享的最后一次提交. 如果当前分支没有 upstream 或没有 unpushed 提交, 则无论如何都会创建新分支, 并且以前的当前分支不受影响. 这对于在旧分支 (可能但不一定是 "master") 上开始工作后创建功能分支很有用. 如果当前分支是选项magit-branch-prefer-remote-upstream(见下文) 值的成员, 那么当前分支将照常作为起点, 但起点的 upstream 可能用作新分支的 upstream, 而不是起点本身. 如果可选的FROM为非nil, 那么源分支重置为FROM~, 而不是它与其 upstream 共享的最后一次提交. 交互式地, 仅当 region 选择了一些 commits 时,FROM才为非nil, 并且在这些 commits 中,FROM是领先源分支最少 commits 的 commit. selection 另一端的 commit 实际上并不重要,FROM和HEAD之间的所有 commits 都移动到新分支. 如果FROM不能从HEAD到达或可以从源分支的 upstream 到达, 则引发错误.b S(magit-branch-spinout) 此命令的行为类似于magit-branch-spinoff, 除了它不更改当前分支. 如果有任何未提交的更改, 那么它的行为与magit-branch-spinoff完全相同.b x(magit-branch-reset) 此命令重置分支, 默认为 point 处的分支, 到另一个分支的顶端或任何其他 commit. 当重置的分支是当前分支时, 执行 hard reset. 如果有任何未提交的更改, 那么用户必须确认重置, 因为这些更改将会丢失. 当你开始在一个功能分支上工作但意识到这全是垃圾并想重新开始时, 这很有用. 当重置为另一个分支并使用前缀参数时, 目标分支设置为正在重置的分支的 upstream.b k(magit-branch-delete) 删除一个或多个分支. 如果 region 标记了多个分支, 则提议删除这些分支. 否则, 提示删除单个分支, 默认为 point 处的分支. 当以某种方式删除分支很危险时要求确认. 选项magit-no-confirm可以自定义为在某些情况下不需要确认. 请参阅其 docstring 以了解为什么默认情况下在某些情况下需要确认或如果提示令人困惑.b m(magit-branch-rename) 重命名分支. 分支和新名称在 minibuffer 中读取. 带有前缀参数时, 即使该名称与现有分支冲突, 也重命名分支.magit-branch-read-upstream-first[User Option] 创建分支时, 是否在要创建的分支名称之前读取 upstream 分支. 默认为t, 我建议你保持原样.magit-branch-prefer-remote-upstream[User Option] 此选项指定创建新分支时是否优先选择远程 upstreams 而不是本地 upstreams. 当创建新分支时, point 处的分支, 提交或 stash 被建议作为新分支的起点, 或者如果 point 处没有此类 revision, 则建议当前分支. 在任何一种情况下, 用户都可以选择另一个起点. 如果所选起点是分支, 那么也可以根据 Git 变量branch.autoSetupMerge的值将其设置为新分支的 upstream. 默认情况下, 对远程分支执行此操作, 但不对本地分支执行. 你可能更喜欢始终使用某个远程分支作为 upstream. 如果所选起点是 (1) 本地分支, (2) 其名称与此选项值的成员匹配, (3) 该本地分支的 upstream 是同名的远程分支, 并且 (4) 该远程分支可以 fast-forwarded 到本地分支, 那么所选分支用作起点, 但其自己的 upstream 用作新分支的 upstream. 此选项值的成员被视为分支名称, 必须完全匹配, 除非它们包含使它们作为分支名称无效的字符. 建议使用触发解释为 regexp 的字符是*和^. 一些你可能认为无效的其他字符实际上并非如此, 例如+$都是完全有效的. 更确切地说, 如果git check-ref-format --branch STRING以非零状态退出, 则将STRING视为 regexp. 假设所选分支符合这些条件, 你最终会得到例如:feature --upstream--> origin/master代替feature --upstream--> master --upstream--> origin/master你更喜欢哪种是个人偏好问题. 如果你确实更喜欢前者, 那么你应该将诸如master,next和maint之类的分支添加到此选项的值中.magit-branch-adjust-remote-upstream-alist[User Option] 此选项的值是分支远程分支时用作 upstream 的分支的 alist. 当从位于 remote 上的临时分支 (例如功能或热修复分支) 创建本地分支时, 该远程分支通常不应用作 upstream 分支, 因为 push-remote 已经允许访问它, 并且让 upstream 和 push-remote 都引用同一个相关分支是浪费的. 相反, 应该使用像 "maint" 或 "master" 这样的分支作为 upstream. 此选项允许指定在分支某些远程分支时应用作 upstream 的分支. 值的形式为((UPSTREAM . RULE)...). 使用第一个匹配元素, 忽略后续元素.UPSTREAM是要用作RULE指定的分支的 upstream 的分支. 它可以是本地或远程分支.RULE可以是正则表达式, 匹配其 upstream 应为UPSTREAM指定的分支. 或者它可以是 不应 使用UPSTREAM的 唯一 分支的列表; 所有其他分支都会使用. 匹配是在剥离被分支的分支名称的 remote 部分后完成的. 如果你在所有仓库中使用一组有限的非临时分支, 那么你可以使用类似:(("origin/master" . ("master" "next" "maint")))或者如果所有临时分支的名称都包含斜杠 (至少在某些仓库中), 那么一个好的值可能是:(("origin/master" . "/"))当然你也可以微调:(("origin/maint" . "\\~hotfix/") ("origin/master" . "\\~feature/"))
UPSTREAM可以是本地分支:(("master" . ("master" "next" "maint")))因为主分支不再几乎总是命名为 "master", 你也应该考虑其他常用名称:(("main" . ("main" "master" "next" "maint")) ("master" . ("main" "master" "next" "maint")))
magit-branch-orphan[Command] 此命令创建并检出一个新的孤儿分支, 内容来自给定的 revision.magit-branch-or-checkout[Command] 此命令是magit-checkout和magit-branch-and-checkout之间的混合体, 旨在作为magit-branch中前者的替代品. 它首先询问用户现有的分支或 revision. 如果用户输入实际上可以解析为分支或 revision, 那么它检出它, 就像magit-checkout一样. 否则它使用输入作为其名称创建并检出一个新分支. 在这样做之前, 它读取新分支的起点. 这类似于magit-branch-and-checkout所做的. 要使用此命令代替magit-checkout, 将此添加到你的 init 文件:(transient-replace-suffix 'magit-branch 'magit-checkout '("b" "dwim" magit-branch-or-checkout))
6.6.3. 6.6.3 分支 Git 变量 (Branch Git Variables)
这些变量可以从 transient 前缀命令 magit-branch-configure 设置. 默认情况下它们也可以从 magit-branch 设置. 参见第 82 页的 [Branch Commands].
branch.NAME.merge[Variable] 与branch.NAME.remote一起, 此变量定义本地分支NAME的 upstream 分支. 此变量的值是 upstream 分支的完整引用.branch.NAME.remote[Variable] 与branch.NAME.merge一起, 此变量定义本地分支NAME的 upstream 分支. 此变量的值是 upstream remote 的名称.branch.NAME.rebase[Variable] 此变量控制 pull 到分支NAME是通过 rebasing 还是通过 merging fetched 分支来完成.- 当
true时, pulling 通过 rebasing 完成. - 当
false时, pulling 通过 merging 完成. - 当
undefined时, 使用pull.rebase的值. 该变量的默认值为false.
- 当
branch.NAME.pushRemote[Variable] 此变量指定名为NAME的分支通常被 push 到的 remote. 值必须是现有 remote 的名称. 不可能指定要将本地分支 push 到的分支名称. 远程分支的名称总是与本地分支的名称相同. 如果此变量未定义但定义了remote.pushDefault, 则使用后者的值. 默认情况下remote.pushDefault未定义.branch.NAME.description[Variable] 此变量可用于描述名为NAME的分支. 该描述用于例如将分支转换为一系列补丁时.
以下变量指定如果未设置上述分支特定变量时使用的默认值.
pull.rebase[Variable] 此变量指定 pulling 是通过 rebasing 还是通过 merging 完成. 它可以使用branch.NAME.rebase覆盖.- 当
true时, pulling 通过 rebasing 完成. - 当
false(默认) 时, pulling 通过 merging 完成.
由于将 upstream 分支合并到功能或热修复分支从来都不是一个好主意, 并且大多数分支都是这样的分支, 你应该考虑将此设置为
true, 并将branch.master.rebase设置为false.- 当
remote.pushDefault[Variable] 此变量指定本地分支通常被 push 到哪个 remote. 这可以使用branch.NAME.pushRemote对每个分支进行覆盖.
以下变量在创建分支期间使用, 并控制是否在此时自动设置各种分支特定变量.
branch.autoSetupMerge[Variable] 此变量指定在什么情况下创建分支NAME应该导致变量branch.NAME.merge和branch.NAME.remote根据用于创建分支的起点进行设置. 如果起点不是分支, 则从不设置这些变量.- 当
always时, 无论起点是本地还是远程分支, 都设置变量. - 当
true(默认) 时, 当起点是远程分支时设置变量, 但当它是本地分支时不设置. - 当
false时, 从不设置变量.
- 当
branch.autoSetupRebase[Variable] 此变量指定创建分支NAME是否应导致变量branch.NAME.rebase设置为true.- 当
always时, 无论起点是本地还是远程分支, 都设置变量. - 当
local时, 当起点是本地分支时设置变量, 但当它是远程分支时不设置. - 当
remote时, 当起点是远程分支时设置变量, 但当它是本地分支时不设置. - 当
never(默认) 时, 从不设置变量.
- 当
注意相应的命令总是更改仓库本地值. 如果你想更改全局值 (当本地值未定义时使用), 那么你必须在命令行上执行此操作, 例如:
git config --global remote.autoSetupMerge always
有关这些变量的更多信息, 你还应该参阅 git-config(1) manpage. 另请参阅 git-branch(1) manpage, git-checkout(1) manpage 和第 107 页的 7.4 节 [Pushing].
magit-prefer-remote-upstream[User Option] 此选项控制读取分支名称并将其设置为 upstream 分支的命令, 在有选择时是否提供本地或远程分支作为默认补全候选项. 这影响所有使用magit-read-upstream-branch或magit-read-starting-point的命令, 包括所有更改 upstream 的命令和许多创建新分支的命令.
6.6.4. 6.6.4 辅助分支命令 (Auxiliary Branch Commands)
这些命令默认情况下无法从 transient magit-branch 获得.
magit-branch-shelve[Command] 此命令 shelve (搁置) 分支. 这是通过删除分支, 并创建一个指向分支指向的同一 commit 的新 reference "refs/shelved/BRANCH-NAME" 来完成的. 如果删除的分支有 reflog, 那么它被保留为新 reference 的 reflog. 如果你想将分支移出视线, 但还没准备好完全丢弃它, 这很有用.magit-branch-unshelve[Command] 此命令 unshelves 之前使用magit-branch-shelveshelved 的分支. 这是通过删除 reference "refs/shelved/BRANCH-NAME" 并创建一个指向被删除 reference 指向的同一 commit 的分支 "BRANCH-NAME" 来完成的. 如果删除的 reference 有 reflog, 那么它被恢复为分支的 reflog.
6.7. 6.7 合并 (Merging)
另请参阅 git-merge(1) manpage. 有关如何解决合并冲突的信息, 请参阅下一节.
m(magit-merge) 此 transient 前缀命令绑定以下 suffix 命令以及适当的 infix 参数, 并在临时 buffer 中显示它们, 直到调用 suffix.
当没有合并正在进行时, transient 具有以下 suffix 命令.
m m(magit-merge-plain) 此命令将另一个分支或任意 revision 合并到当前分支. 要合并的分支或 revision 在 minibuffer 中读取, 默认为 point 处的分支. 除非有冲突或使用前缀参数, 否则结果合并提交使用通用提交消息, 用户没有机会在创建提交之前检查或更改它. 带有前缀参数时, 这实际上并不创建合并提交, 这使得可以检查冲突是如何解决的并调整提交消息.m e(magit-merge-editmsg) 此命令将另一个分支或任意 revision 合并到当前分支, 并打开提交消息 buffer, 以便用户可以进行调整. 直到用户使用C-c C-c完成之前, 实际上不会创建提交.m n(magit-merge-nocommit) 此命令将另一个分支或任意 revision 合并到当前分支, 但实际上不创建合并提交. 用户可以进一步调整合并, 即使自动冲突解决成功, 也可以调整提交消息.m a(magit-merge-absorb) 此命令将另一个本地分支合并到当前分支, 然后删除前者. 在合并源分支之前, 首先将其 force push 到其 push-remote, 前提是相应的远程分支已经存在. 这确保相应的 pull-request (如果有) 不会卡在正在合并的 commits 的某些过时版本上. 最后, 如果使用magit-branch-pull-request创建了合并的分支, 那么相应的远程分支也会被删除.m d(magit-merge-dissolve) 此命令将当前分支合并到另一个本地分支, 然后删除前者. 后者成为新的当前分支. 在合并源分支之前, 首先将其 force push 到其 push-remote, 前提是相应的远程分支已经存在. 这确保相应的 pull-request (如果有) 不会卡在正在合并的 commits 的某些过时版本上. 最后, 如果使用magit-branch-pull-request创建了合并的分支, 那么相应的远程分支也会被删除.m s(magit-merge-squash) 此命令将另一个分支或任意 revision 引入的更改 squash 到当前分支. 这仅应用 squashed commits 所做的更改. 不保留任何允许创建实际合并提交的信息. 你可能应该使用 apply transient 中的命令代替此命令.m p(magit-merge-preview) 此命令显示将另一个分支或任意 revision 合并到当前分支的预览. 注意, 通常更改 diff 显示方式的命令在此命令创建的 buffers 中不起作用, 因为底层 Git 命令不支持 diff 参数.
当合并正在进行时, transient 改为具有以下 suffix 命令.
m m(magit-merge) 在用户解决冲突后, 此命令继续合并. 如果某些冲突未解决, 则此命令失败.m a(magit-merge-abort) 此命令中止当前合并操作.
6.8. 6.8 解决冲突 (Resolving Conflicts)
当合并分支 (或以其他方式组合或更改历史) 时, 可能会发生冲突. 如果你在两个分支中编辑了同一文件的两个完全不同的部分, 然后将其中一个分支合并到另一个分支中, 那么 Git 可以自行解决此问题, 但如果你编辑了文件的同一区域, 那么需要人工决定如何将两个版本或 "冲突的各方" 组合成一个.
这里我们只能提供该主题的简要介绍, 并指引你使用一些可以提供帮助的工具. 如果你是新手, 请同时查阅 Git 自己的文档以及其他资源.
如果文件有冲突且 Git 无法自行解决, 那么它会将两个版本以及特殊标记放入受影响的文件中, 目的是表示文件未解决部分以及不同版本之间的边界. 这些边界行以包含七次相同字符的字符串开始, <, |, = 和 > 之一, 后面是有关各个版本来源的信息, 例如:
~
<<<<<<< HEAD
Take the blue pill.
=====
Take the red pill.
>>>>>>> feature
~
在这种情况下, 你在一个分支上选择服用蓝色药丸, 而在另一个分支上你选择了红色药丸. 现在你要合并这两个分歧的分支, Git 不可能知道你想服用哪种药丸.
为了解决该冲突, 你必须通过仅保留其中一方来创建受影响区域的版本, 可能通过编辑它以引入来自另一方的更改, 删除其他版本以及标记, 然后 stage 结果. 可能的解决方案可能是:
~
Take both pills.
~
通常, 不仅要看到冲突的双方, 还要看到文件同一区域在不同分支上被修改两次之前的 "原始" 版本, 这很有用. 通过运行一次此命令指示 Git 也插入该版本:
git config --global merge.conflictStyle diff3
上面的冲突可能看起来像这样:
~
<<<<<<< HEAD
Take the blue pill.
| merged common ancestors |
Take either the blue or the red pill, but not both.
=====
Take the red pill.
>>>>>>> feature
~
如果是这种情况, 那么上面的冲突解决将是不正确的, 这证明了为什么在冲突版本旁边看到原始版本是有用的.
你可以完全手动执行冲突解决, 但 Emacs 也提供了一些帮助该过程的包: Smerge, Ediff (ediff) 和 Emerge (emacs 中的 "Emerge" 节). Magit 不提供自己的冲突解决工具, 但它确实使使用 Smerge 和 Ediff 更方便. (Ediff 取代了 Emerge, 所以你可能不想使用后者.)
在 Magit status buffer 中, 具有未解决冲突的文件列在 "Unstaged changes" 和/或 "Staged changes" sections 中. 它们以单词 "unmerged" 为前缀, 在此上下文中本质上是 "unresolved" 的同义词.
当 point 在此类文件 section 上按 RET 会显示访问该文件的 buffer, 在该 buffer 中打开 smerge-mode, 并将 point 放在第一个有冲突的区域内. 然后你应该使用常规编辑命令和/或 Smerge 命令解决该冲突.
不幸的是 Smerge 没有手册, 但你可以通过绑定 C-c ^ C-h 获取命令列表, 并在 point 位于命令名称上时按 RET 阅读其文档.
通常你会编辑一个版本, 然后告诉 Smerge 仅保留该版本. 使用 C-c ^ m (smerge-keep-mine) 保留 HEAD 版本或 C-c ^ o (smerge-keep-other) 保留 ||||||| 之后的版本. 然后使用 C-c ^ n 移动到同一文件中的下一个冲突区域. 一旦你解决了冲突, 返回 Magit status buffer. 文件现在应该显示为 "modified", 不再是 "unmerged", 因为 Smerge 在你解决完最后一个冲突后保存 buffer 时会自动 stage 文件.
Magit 现在封装了提到的 Smerge 命令, 允许你使用这些键绑定而无需转到文件访问 buffer. 此外, 在具有未解决冲突的 hunk 上 k (magit-discard) 会询问保留哪一方, 或者如果 point 在一方上, 则不提示直接保留它. 同样, 在未解决的文件上 k 询问保留哪一方.
或者你可以使用 Ediff, 它为文件的不同版本使用单独的 buffers. 要使用 Ediff 解决文件中的冲突, 在 status buffer 中 point 位于此类文件上时按 e.
Ediff 也可用于其他目的. 有关如何从 Magit 进入 Ediff 的更多信息, 请参阅第 55 页的 5.5 节 [Ediffing]. 解释如何使用 Ediff 超出了本手册的范围, 请参阅 ediff.
如果你不确定应该使用 Smerge 还是 Ediff, 请使用前者. 它更容易理解和使用, 除了真正复杂的冲突, 后者通常是大材小用.
6.9. 6.9 变基 (Rebasing)
另请参阅 git-rebase(1) manpage. 有关如何解决 rebase 期间发生的冲突的信息, 请参阅上一节.
r(magit-rebase) 此 transient 前缀命令绑定以下 suffix 命令以及适当的 infix 参数, 并在临时 buffer 中显示它们, 直到调用 suffix.
当没有 rebase 正在进行时, transient 具有以下 suffix 命令.
使用这些命令之一启动 rebase 序列. Git 可能会在中途停止, 要么是因为你告诉它这样做, 要么是因为应用 commit 由于冲突而失败. 当这种情况发生时, status buffer 会在一个类似于 log section 的 section 中显示有关正在进行的 rebase 序列的信息. 参见第 96 页的 [Information About In-Progress Rebase].
有关 upstream 和 push-remote 的信息, 请参阅第 81 页的 [The Two Remotes].
r p(magit-rebase-onto-pushremote) 此命令将当前分支 rebase 到其 push-remote. 带有前缀参数或当 push-remote 未配置或不可用时, 让用户首先配置 push-remote.r u(magit-rebase-onto-upstream) 此命令将当前分支 rebase 到其 upstream 分支. 带有前缀参数或当 upstream 未配置或不可用时, 让用户首先配置 upstream.r e(magit-rebase-branch) 此命令将当前分支 rebase 到 minibuffer 中读取的分支. 所有从 head 可到达但从所选分支TARGET不可到达的 commits 都将被 rebased.r s(magit-rebase-subset) 此命令启动非交互式 rebase 序列, 将 commits 从START到HEAD转移到NEWBASE.START必须从最近 commits 列表中选择.
默认情况下, Magit 使用 --autostash 参数, 这会导致未提交的更改在 rebase 开始前存储在 stash 中. 这些更改在 rebase 完成后恢复, 如果可能, stash 被移除. 如果 stash 无法干净地应用, 则不移除 stash. 如果在解决冲突时出现问题, 这允许你重新开始.
即使其中一个动作专用于交互式 rebases, transient 也具有 infix 参数 --interactive. 这可用于将其他非交互式 rebase 变体之一转换为交互式 rebase.
例如, 如果你想清理功能分支并同时将其 rebase 到 master, 那么你可以使用 r-i u. 但我们建议你分两步进行. 首先使用 r i 清理功能分支, 然后在第二步中使用 r u 将其 rebase 到 master. 这样, 如果事情变得比你想象的更复杂和/或你犯了错误并不得不重新开始, 那么你只需要重做一半的工作.
显式启用 --interactive 对以下命令没有影响, 因为它们总是使用该参数, 即使在 transient 中未启用它.
r i(magit-rebase-interactive) 此命令启动交互式 rebase 序列.r f(magit-rebase-autosquash) 此命令将 squash 和 fixup commits 与其预期目标组合. 默认情况下, 只有从 upstream 分支不可到达的 commits 才可能被 squashed into. 如果未配置 upstream 或带有前缀参数, 则提示用户输入第一个可能被 squashed into 的 commit.r m(magit-rebase-edit-commit) 此命令启动交互式 rebase 序列, 让用户编辑单个较旧的 commit.r w(magit-rebase-reword-commit) 此命令启动交互式 rebase 序列, 让用户重写单个较旧 commit 的消息.r k(magit-rebase-remove-commit) 此命令使用 rebase 删除单个较旧的 commit.
当 rebase 正在进行时, transient 改为具有以下 suffix 命令.
r r(magit-rebase-continue) 此命令重新启动当前的 rebasing 操作. 在某些情况下, 这会弹出一个提交消息 buffer 供你编辑. 带有前缀参数时, 按原样重用旧消息.r s(magit-rebase-skip) 此命令跳过当前 commit 并重新启动当前的 rebase 操作.r e(magit-rebase-edit) 此命令让用户编辑当前 rebase 操作的 todo 列表.r a(magit-rebase-abort) 此命令中止当前 rebase 操作, 恢复原始分支.
6.9.1. 6.9.1 编辑 Rebase 序列 (Editing Rebase Sequences)
C-c C-c(with-editor-finish) 通过以退出代码 0 返回来完成当前编辑会话. Git 然后使用它在文件中找到的 rebase 指令.C-c C-k(with-editor-cancel) 通过以退出代码 1 返回来取消当前编辑会话. Git 然后放弃启动 rebase 序列.RET(git-rebase-show-commit) 在另一个 buffer 中显示当前行上的 commit 并选择该 buffer.SPC(git-rebase-show-or-scroll-up) 在另一个 buffer 中显示当前行上的 commit 而不选择该 buffer. 如果 revision buffer 已在当前 frame 的另一个窗口中可见, 则向上滚动该窗口.DEL(git-rebase-show-or-scroll-down) 在另一个 buffer 中显示当前行上的 commit 而不选择该 buffer. 如果 revision buffer 已在当前 frame 的另一个窗口中可见, 则向下滚动该窗口.p(git-rebase-backward-line) 移动到上一行.n(forward-line) 移动到下一行.M-p(git-rebase-move-line-up) 向上移动当前 commit (或命令).M-n(git-rebase-move-line-down) 向下移动当前 commit (或命令).r(git-rebase-reword) 编辑当前行上 commit 的消息.e(git-rebase-edit) 在当前行上的 commit 处停止.s(git-rebase-squash) 此命令将当前行上的 commit 折叠到上一个 commit 中, 给用户机会手动合并这两条消息.S(git-rebase-squish) 此命令将当前行上的 commit 折叠到上一个 commit 中, 丢弃上一个 commit 的消息, 但给用户机会编辑最终消息 (基于当前 commit 的消息). 此动作在 commits 列表中显示的指示器是fixup -c(带有小写 c).f(git-rebase-fixup) 此命令将当前行上的 commit 折叠到上一个 commit 中, 仅按原样使用上一个 commit 的消息并丢弃当前 commit 的消息.F(git-rebase-alter) 此命令将当前行上的 commit 折叠到上一个 commit 中, 丢弃上一个 commit 的消息并改用当前 commit 的消息. 这就像git-rebase-alter, 除了它使用另一个消息. 这也像git-rebase-squish, 除了它让用户编辑消息. 此动作在 commits 列表中显示的指示器是fixup -C(带有大写 C).k(git-rebase-kill-line) 注释掉当前动作行, 或者如果已经注释, 则取消注释.c(git-rebase-pick) 使用当前行上的 commit.x(git-rebase-exec) 插入要在处理 commit 后运行的 shell 命令. 如果当前行上已经有这样的命令, 则编辑它. 带有前缀参数时, 即使当前行上已经有一个命令, 也会插入一个新命令. 输入为空时, 删除当前行上的命令 (如果有).b(git-rebase-break) 在当前行之前插入一个 break 动作, 指示 Git 将控制权交还给用户.y(git-rebase-insert) 读取任意 commit 并将其插入当前行下方.C-x u(git-rebase-undo) 撤消一些先前的更改. 像undo但在 read-only buffers 中工作.git-rebase-auto-advance[User Option] 更改一行后是否移动到下一行.git-rebase-show-instructions[User Option] 是否在 rebase buffer 内显示使用说明.git-rebase-confirm-cancel[User Option] 取消是否需要确认.
当使用 --rebase-merges 选项执行 rebase 时, 序列将包括几种其他类型的动作, 以下命令变得相关.
l(git-rebase-label) 此命令插入 label 动作或编辑 point 处的一个.t(git-rebase-reset) 此命令插入 reset 动作或编辑 point 处的一个. 提示将提供当前 buffer 中存在的 labels.MM(git-rebase-merge) 此命令插入 merge 动作或编辑 point 处的一个. 提示将提供当前 buffer 中存在的 labels. 不支持通过-c或-C重用消息; merge 总是会调用编辑器.Mt(git-rebase-merge-toggle-editmsg) 此命令切换 point 处 merge 动作的-C和-c选项. 这些选项都指定应重用其消息的 commit. 小写变体指示 Git 在创建 merge 时调用编辑器, 允许用户编辑消息.
6.9.2. 6.9.2 关于进行中 Rebase 的信息 (Information About In-Progress Rebase)
当 rebase 序列正在进行时, status buffer 具有一个 section, 列出已经应用的 commits 以及仍需应用的 commits.
Commits 分为两半. 当 rebase 在 commit 处停止时 (因为用户必须处理冲突或者因为他/她明确请求 rebase 在该 commit 处停止), point 位于分隔这两组的 commit 上, 即 HEAD. 它上面的 commits 尚未应用, 而 HEAD 和它下面的 commits 已经应用. 在这两组已应用和尚未应用的 commits 之间, 有时会有一个被丢弃的 commit.
每个 commit 都以一个单词为前缀, 并且这些单词还会以不同的颜色显示, 以指示 commits 的状态.
使用以下颜色:
- 使用与
defaultface 相同前景色显示的 Commits 尚未应用. - 黄色 commits 与 rebase 停止处的 commit 有特殊关系. 这用于单词 "join", "goal", "same" 和 "work" (见下文).
- 灰色 commits 已经应用.
- 蓝色 commit 是
HEADcommit. - 绿色 commit 是 rebase 序列停止处的 commit. 如果这与
HEAD是同一个 commit (例如, 因为在 rebase 停止在该 commit 后你还没有做任何事情, 那么此 commit 显示为蓝色, 而不是绿色). 只有当你在 rebase 停止在某个 commit 后创建一个或多个新 commits 时, 才能同时存在绿色和蓝色 commit. - 红色 commits 已被丢弃. 它们仅供参考, 例如以便更容易进行 diff.
当然这些颜色受使用的 color-theme 影响.
使用以下单词:
- 前缀为
pick,reword,edit,squash和fixup的 Commits 尚未应用. 这些单词在这里的含义与在用于编辑 rebase 序列的 buffer 中的含义相同. 参见第 93 页的 [Editing Rebase Sequences]. 当指定了--rebase-merges选项时, 可能还会出现reset,label和merge行. - 前缀为
done和onto的 Commits 已经应用. 这样的 commit 可能是HEAD, 在这种情况下它是蓝色的. 否则它是灰色的. - 前缀为
onto的 commit 是所有其他 commits 正在被 re-applied 之上的 commit. 此 commit 本身不需要被 re-applied, 它是 rebase 在开始 re-apply 其他 commits 之前回退到的 commit. - 前缀为
done的 Commits 已经 re-applied. 这包括已被 re-applied 的 commits, 但也包括你在 rebase 期间创建的新 commits. - 所有其他 commits, 那些没有前缀以上任何单词的 commits, 以某种方式与 rebase 停止处的 commit 相关.
为了确定 commit 是否与停止处的 commit 相关, 比较它们的 hashes, trees 和 patch-ids1. 为此目的不使用提交消息.
一般来说, 与停止处 commit 相关的 commits 可以具有任何使用的颜色, 尽管并非所有颜色/单词组合都是可能的.
用于停止处 commits 的单词是:
- 当 commit 前缀为
void时, 表示 Magit 确信该 commit 中的所有更改均已使用几个新 commits 应用. 此 commit 从HEAD不再可达, 并且也不是恢复会话时将被应用的 commits 之一. - 当 commit 前缀为
join时, 表示 rebase 序列在该 commit 处停止是因为冲突 - 你现在必须将更改与已经应用的内容 join (merge). 从某种意义上说, 这是 rebase 停止处的 commit, 但虽然其效果已经在 index 和 worktree 中 (带有冲突标记), 但 commit 本身尚未实际应用 (它不是HEAD). 所以它显示为黄色, 就像其他仍需应用的 commits 一样. - 当 commit 前缀为
stop或蓝色或绿色same时, 表示 rebase 在此 commit 处停止, 它仍然应用或已被再次应用, 并且至少其 patch-id 未更改.- 当 commit 前缀为
stop时, 表示 rebase 在该 commit 处停止, 因为你之前请求那样做, 并且其 patch-id 未更改. 它甚至可能仍然是完全相同的 commit. - 当 commit 前缀为蓝色或绿色
same时, 表示虽然其 tree 或 hash 发生了变化, 但其 patch-id 没有. 如果是蓝色, 那么它是HEADcommit (像往常一样蓝色). 当它是绿色时, 那么它不再是HEAD, 因为已经创建了其他 commit (但在继续 rebase 之前).
- 当 commit 前缀为
- 当 commit 前缀为
goal, 黄色same或work时, 表示 rebase 应用了该 commit, 但你随后将HEAD重置为较早的 commit (可能是为了将其拆分为多个 commits), 并且有一些未提交的更改剩余, 这些更改可能 (但不一定) 源自该 commit.- 当 commit 前缀为
goal时, 表示仍然可以在不手动编辑任何文件的情况下, 通过提交 index 或通过 stage 所有更改然后提交来创建一个具有完全相同 tree ( "goal") 的新 commit. 当原始 tree 仍然以未污染的形式存在于 index 或 worktree 中时, 就是这种情况. - 当 commit 前缀为黄色
same时, 表示不再可能创建一个具有完全相同 tree 的 commit, 但仍然可能创建一个具有相同 patch-id 的 commit. 如果你创建了一个带有其他更改的新 commit, 但原始 commit 的更改仍然以未污染的形式存在于 index 或 worktree 中, 就会出现这种情况. - 当 commit 前缀为
work时, 表示你将HEAD重置为较早的 commit, 并且有一些 staged 和/或 unstaged 更改 (可能, 但不一定) 源自该 commit. 但是不再可能创建一个具有相同 tree 或至少相同 patch-id 的新 commit, 因为你已经做了其他更改.
- 当 commit 前缀为
- 当 commit 前缀为
poof或gone时, 表示 rebase 应用了该 commit, 但你随后将HEAD重置为较早的 commit (可能是为了将其拆分为多个 commits), 并且没有未提交的更改.- 当 commit 前缀为
poof时, 表示它不再从HEAD可达, 但已被一个或多个 commits 替换, 这些 commits 共同具有完全相同的效果. - 当 commit 前缀为
gone时, 表示它不再从HEAD可达, 并且我们也无法确定其更改是否仍然在一个或多个新 commits 中生效. 它们可能是, 但如果是这样, 那么肯定还有其他更改, 使得无法确定.
- 当 commit 前缀为
如果你不完全理解上面的内容, 请不要担心. 没关系, 你会通过练习获得足够好的理解.
对于其他序列操作, 如 cherry-picking, 会显示类似的 section, 但由于用于实现它们的 git 命令的限制, 它们缺少上述一些功能. 最重要的是, 这些序列仅支持 "picking" 一个 commit, 而不支持其他动作如 "rewording", 并且它们不跟踪已经应用的 commits.
6.10. 6.10 拣选 (Cherry Picking)
另请参阅 git-cherry-pick(1) manpage.
A(magit-cherry-pick) 此 transient 前缀命令绑定以下 suffix 命令以及适当的 infix 参数, 并在临时 buffer 中显示它们, 直到调用 suffix.
当没有 cherry-pick 或 revert 正在进行时, transient 具有以下 suffix 命令.
A A(magit-cherry-copy) 此命令将COMMITS从另一个分支复制到当前分支. 如果 region 选择了多个 commits, 则复制这些 commits, 不提示. 否则提示用户输入 commit 或范围, 默认为 point 处的 commit.A a(magit-cherry-apply) 此命令将COMMITS从另一个分支的更改应用到当前分支. 如果 region 选择了多个 commits, 则使用这些 commits, 不提示. 否则提示用户输入 commit 或范围, 默认为 point 处的 commit. 此命令还有一个顶级绑定, 可以通过在顶层键入a来调用而不使用 transient.
以下命令不仅将一些 commits 应用于某个分支, 还从另一个分支中删除它们. 删除是使用 git-update-ref 或必要时使用 git-rebase 执行的. 应用 commits 以及使用 git-rebase 删除它们都可能导致冲突. 如果发生这种情况, 那么这些命令会中止, 你不仅必须解决冲突, 还要像这些命令根本不存在一样手动完成该过程.
A h(magit-cherry-harvest) 此命令将必须位于另一个BRANCH上的选定COMMITS移动到当前分支, 并从前者中删除它们. 当此命令成功时, 当前分支与之前相同. 在当前分支上应用 commits 或从其他分支删除它们可能会导致冲突. 当发生这种情况时, 此命令停止, 你必须解决冲突然后手动完成该过程.A d(magit-cherry-donate) 此命令将选定COMMITS从当前分支移动到另一个现有BRANCH, 并从前者中删除它们. 当此命令成功时, 当前分支与之前相同.HEAD最初允许是 detached. 在其他分支上应用 commits 或从当前分支删除它们可能会导致冲突. 当发生这种情况时, 此命令停止, 你必须解决冲突然后手动完成该过程.A n(magit-cherry-spinout) 此命令将选定COMMITS从当前分支移动到新分支BRANCH, 并从前者中删除它们. 当此命令成功时, 当前分支与之前相同. 在其他分支上应用 commits 或从当前分支删除它们可能会导致冲突. 当发生这种情况时, 此命令停止, 你必须解决冲突然后手动完成该过程.A s(magit-cherry-spinoff) 此命令将选定COMMITS从当前分支移动到新分支BRANCH, 并从前者中删除它们. 当此命令成功时, 检出新分支. 在其他分支上应用 commits 或从当前分支删除它们可能会导致冲突. 当发生这种情况时, 此命令停止, 你必须解决冲突然后手动完成该过程.
当 cherry-pick 或 revert 正在进行时, transient 改为具有以下 suffix 命令.
A A(magit-sequence-continue) 恢复当前的 cherry-pick 或 revert 序列.A s(magit-sequence-skip) 在 cherry-pick 或 revert 序列期间跳过停止处的 commit.A a(magit-sequence-abort) 中止当前的 cherry-pick 或 revert 序列. 这会丢弃自序列开始以来所做的所有更改.
6.10.1. 6.10.1 撤销 (Reverting)
V(magit-revert) 此 transient 前缀命令绑定以下 suffix 命令以及适当的 infix 参数, 并在临时 buffer 中显示它们, 直到调用 suffix.
当没有 cherry-pick 或 revert 正在进行时, transient 具有以下 suffix 命令.
V V(magit-revert-and-commit) 通过创建新 commit 来 revert commit. 提示输入 commit, 默认为 point 处的 commit. 如果 region 选择多个 commits, 则 revert 它们所有, 不提示.V v(magit-revert-no-commit) 通过在 worktree 中反向应用它来 revert commit. 提示输入 commit, 默认为 point 处的 commit. 如果 region 选择多个 commits, 则 revert 它们所有, 不提示.
当 cherry-pick 或 revert 正在进行时, transient 改为具有以下 suffix 命令.
V V(magit-sequence-continue) 恢复当前的 cherry-pick 或 revert 序列.V s(magit-sequence-skip) 在 cherry-pick 或 revert 序列期间跳过停止处的 commit.V a(magit-sequence-abort) 中止当前的 cherry-pick 或 revert 序列. 这会丢弃自序列开始以来所做的所有更改.
6.11. 6.11 重置 (Resetting)
另请参阅 git-reset(1) manpage.
x(magit-reset-quickly) 将HEAD和 index 重置为从用户读取的某个 commit (默认为 point 处的 commit), 并可能也重置 worktree. 带有前缀参数重置 worktree, 否则不重置.X m(magit-reset-mixed) 将HEAD和 index 重置为从用户读取的某个 commit (默认为 point 处的 commit). Worktree 保持不变.X s(magit-reset-soft) 将HEAD重置为从用户读取的某个 commit (默认为 point 处的 commit). Index 和 worktree 保持不变.X h(magit-reset-hard) 将HEAD, index 和 worktree 重置为从用户读取的某个 commit (默认为 point 处的 commit).X k(magit-reset-keep) 将HEAD, index 和 worktree 重置为从用户读取的某个 commit (默认为 point 处的 commit). 未提交的更改保持不变.X i(magit-reset-index) 将 index 重置为从用户读取的某个 commit (默认为 point 处的 commit). 保持HEAD和 worktree 不变, 因此如果 commit 引用HEAD, 那么这有效地 unstages 所有更改.X w(magit-reset-worktree) 将 worktree 重置为从用户读取的某个 commit (默认为 point 处的 commit). 保持HEAD和 index 不变.X f(magit-file-checkout) 将 worktree 和 index 中的文件更新为 revision 中的内容. revision 和文件均从用户读取.
6.12. 6.12 Stashing
另请参阅 git-stash(1) manpage.
z(magit-stash) 此 transient 前缀命令绑定以下 suffix 命令以及适当的 infix 参数, 并在临时 buffer 中显示它们, 直到调用 suffix.z z(magit-stash-both) 创建 index 和 worktree 的 stash. 根据 infix 参数包括未跟踪文件. 一个前缀参数等同于--include-untracked, 而两个前缀参数等同于--all.z i(magit-stash-index) 仅创建 index 的 stash. Unstaged 和未跟踪更改不被 stashed.z w(magit-stash-worktree) 创建 worktree 中 unstaged 更改的 stash. 根据 infix 参数包括未跟踪文件. 一个前缀参数等同于--include-untracked, 而两个前缀参数等同于--all.z x(magit-stash-keep-index) 创建 index 和 worktree 的 stash, 保持 index 完整. 根据 infix 参数包括未跟踪文件. 一个前缀参数等同于--include-untracked, 而两个前缀参数等同于--all.z Z(magit-snapshot-both) 创建 index 和 worktree 的快照. 根据 infix 参数包括未跟踪文件. 一个前缀参数等同于--include-untracked, 而两个前缀参数等同于--all.z I(magit-snapshot-index) 仅创建 index 的快照. Unstaged 和未跟踪更改不被 stashed.z W(magit-snapshot-worktree) 创建 worktree 中 unstaged 更改的快照. 根据 infix 参数包括未跟踪文件. 一个前缀参数等同于--include-untracked, 而两个前缀参数等同于--all.z a(magit-stash-apply) 将 stash 应用于 worktree. 当使用 v2.38.0 之前的 Git 版本时, 简单地运行git stash apply或带有前缀参数运行git stash apply --index. 当使用 Git v2.38.0 或更高版本时, 表现得更智能: 首先尝试git stash apply --index, 它尝试保留存储在 stash 中的 index (如果有). 这可能会失败, 因为应用 stash 可能会导致冲突, 而这些冲突必须存储在 index 中, 使得无法同时也存储 stash 的 index. 如果git stash失败, 那么可能会回退到使用git apply. 如果 stash 不触及任何 unstaged 文件, 那么将--3way传递给该命令. 否则询问用户是否使用该参数或--reject. 自定义magit-no-confirm如果你想在不被提示的情况下回退到使用--3way.z p(magit-stash-pop) 将 stash 应用于 worktree. 成功完成后 (如果 stash 可以在没有任何冲突的情况下应用, 同时保留 stash 的 index), 则从 stash 列表中删除 stash. 当使用 v2.38.0 之前的 Git 版本时, 简单地运行git stash pop或带有前缀参数运行git stash pop --index. 当使用 Git v2.38.0 或更高版本时, 表现得更智能: 首先尝试git stash pop --index, 它尝试保留存储在 stash 中的 index (如果有). 这可能会失败, 因为应用 stash 可能会导致冲突, 而这些冲突必须存储在 index 中, 使得无法同时也存储 stash 的 index. 如果git stash失败, 那么可能会回退到使用git apply. 如果 stash 不触及任何 unstaged 文件, 那么将--3way传递给该命令. 否则询问用户是否使用该参数或--reject. 自定义magit-no-confirm如果你想在不被提示的情况下回退到使用--3way.z k(magit-stash-drop) 从 stash 列表中移除 stash. 当 region 处于活动状态时, 提议 drop 所有包含的 stashes.z v(magit-stash-show) 在 buffer 中显示 stash 的所有 diffs.z b(magit-stash-branch) 从现有 stash 创建并检出一个新分支. 新分支从创建 stash 时的 commit 开始.z B(magit-stash-branch-here) 从现有 stash 创建并检出一个新分支. 使用当前分支或HEAD作为新分支的起点. 然后应用 stash, 如果应用干净则 dropping 它.z f(magit-stash-format-patch) 从STASH创建补丁.k(magit-stash-clear) 通过删除REF移除REF的 reflog 中保存的所有 stashes.z l(magit-stash-list) 在 buffer 中列出所有 stashes.magit-stashes-margin[User Option] 此选项指定 margin 是否最初显示在 stashes buffers 中以及其格式. 该值的形式为(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH).- 如果
INIT为非nil, 则最初显示 margin. STYLE控制如何格式化作者或提交者日期. 它可以是age(显示提交的年龄),age-abbreviated(将时间单位缩写为一个字符), 或字符串 (适合format-time-string) 以显示实际日期. 选项magit-log-margin-show-committer-date控制显示哪个日期.WIDTH控制 margin 的宽度. 这是为了向前兼容而存在的, 目前不应更改该值.AUTHOR控制是否默认也显示作者姓名.AUTHOR-WIDTH必须是整数. 当显示作者姓名时, 这指定用于执行此操作的空间.
- 如果
7. 7 传输 (Transferring)
7.1. 7.1 Remotes
7.1.1. 7.1.1 Remote 命令 (Remote Commands)
Transient 前缀命令 magit-remote 用于添加 remotes 和更改现有 remotes. 此命令仅处理 remotes 本身, 不处理分支或 commits 的传输. 这些功能可从单独的 transient 命令获得.
另请参阅 git-remote(1) manpage.
M(magit-remote) 此 transient 前缀命令绑定以下 suffix 命令, 并在临时 buffer 中显示它们, 直到调用 suffix. 默认情况下, 它还绑定并显示一些 remote 相关 Git 变量的值, 并允许更改其值.magit-remote-direct-configure[User Option] 此选项控制 remote 相关 Git 变量是否可以直接从 transientmagit-remote访问. 如果为t(默认) 且检出了本地分支, 则magit-remote具有该分支 upstream remote 的变量, 或者如果HEAD分离, 则为origin(如果存在). 如果为nil, 则必须使用magit-remote-configure来执行此操作.M C(magit-remote-configure) 此 transient 前缀命令绑定设置 remote 相关变量值的命令, 并在临时 buffer 中显示它们, 直到退出 transient. 带有前缀参数时, 此命令总是提示输入 remote. 不带前缀参数时, 这取决于它是否作为magit-remote的 suffix 调用以及magit-remote-direct-configure选项. 如果magit-remote已经显示 upstream 的变量, 那么调用另一个显示同一 remote 变量的 transient 是没有意义的. 在这种情况下, 此命令提示输入 remote. 变量在 [Remote Git Variables], 第 105 页中描述.M a(magit-remote-add) 此命令添加一个 remote 并 fetch 它. Remote 名称和 url 在 minibuffer 中读取.M r(magit-remote-rename) 此命令重命名 remote. 旧名称和新名称都在 minibuffer 中读取.M u(magit-remote-set-url) 此命令更改 remote 的 url. Remote 和新 url 都在 minibuffer 中读取.M k(magit-remote-remove) 此命令删除一个 remote, 在 minibuffer 中读取.M p(magit-remote-prune) 此命令为在 minibuffer 中读取的 remote 删除陈旧的远程跟踪分支.M P(magit-remote-prune-refspecs) 此命令为在 minibuffer 中读取的 remote 删除陈旧的 refspecs. 如果 remote 上不再存在至少一个将由于该 refspec 而被 fetched 的分支, 则 refspec 是陈旧的. 陈旧的 refspec 是有问题的, 因为它的存在导致 Git 拒绝根据剩余的非陈旧 refspecs 进行 fetch. 如果只剩下陈旧的 refspecs, 那么此命令提议删除 remote 或用默认 refspec ("+refs/heads/*:refs/remotes/REMOTE/*") 替换陈旧的 refspecs. 此命令还删除由于现在陈旧的 refspecs 而创建的远程跟踪分支. 其他陈旧的分支不被移除.magit-remote-add-set-remote.pushDefault[User Option] 此选项控制在添加 remote 后是否询问用户是否要设置remote.pushDefault. 如果为ask, 则总是询问用户. 如果为ask-if-unset, 则仅当变量尚未设置时询问用户. 如果为nil, 则不询问用户且不设置变量. 如果值为字符串, 则在添加的 remote 名称等于该字符串且变量尚未设置时, 无需询问用户即可设置变量.
7.1.2. 7.1.2 Remote Git 变量 (Remote Git Variables)
这些变量可以从 transient 前缀命令 magit-remote-configure 设置. 默认情况下它们也可以从 magit-remote 设置. 参见第 104 页的 [Remote Commands].
remote.NAME.url[Variable] 此变量指定名为NAME的 remote 的 url. 它可以有多个值.remote.NAME.fetch[Variable] 从名为NAME的 remote fetch 时使用的 refspec. 它可以有多个值.remote.NAME.pushurl[Variable] 此变量指定用于 push 到名为NAME的 remote 的 url. 如果未指定, 则使用remote.NAME.url. 它可以有多个值.remote.NAME.push[Variable] push 到名为NAME的 remote 时使用的 refspec. 它可以有多个值.remote.NAME.tagOpts[Variable] 此变量指定默认 fetch 哪些 tags. 如果值为--no-tags, 则不 fetch tags. 如果值为--tags, 则 fetch 所有 tags. 如果此变量没有值, 则仅 fetch 可从 fetched 分支到达的 tags.
7.2. 7.2 Fetching
另请参阅 git-fetch(1) manpage. 有关 upstream 和 push-remote 的信息, 请参阅第 81 页的 [The Two Remotes].
f(magit-fetch) 此 transient 前缀命令绑定以下 suffix 命令以及适当的 infix 参数, 并在临时 buffer 中显示它们, 直到调用 suffix.f p(magit-fetch-from-pushremote) 此命令从当前 push-remote fetch. 带有前缀参数或当 push-remote 未配置或不可用时, 让用户首先配置 push-remote.f u(magit-fetch-from-upstream) 此命令从当前分支的 upstream fetch. 如果当前分支配置了 upstream 并且命名了一个现有 remote, 则使用它. 否则尝试使用另一个 remote: 如果仅配置了一个 remote, 则使用它. 否则如果存在名为 "origin" 的 remote, 则使用它. 如果无法确定 remote, 则此命令在magit-fetchtransient 前缀中不可用, 直接调用它会导致错误.f e(magit-fetch-other) 此命令从 minibuffer 中读取的仓库 fetch.f o(magit-fetch-branch) 此命令从 remote fetch 分支, 两者都在 minibuffer 中读取.f r(magit-fetch-refspec) 此命令使用显式 refspec 从 remote fetch, 两者都在 minibuffer 中读取.f a(magit-fetch-all) 此命令从所有 remotes fetch.f m(magit-fetch-modules) 此命令 fetch 所有 submodules. 带有前缀参数时, 它充当 transient 前缀命令, 允许调用者设置选项.magit-pull-or-fetch[User Option] 默认情况下 fetch 和 pull 命令可从单独的 transient 前缀命令获得. 将其设置为t会将上述一些 (但不是全部) suffix 命令添加到magit-pulltransient. 如果你这样做, 那么你可能还想更改这些前缀命令的键绑定, 例如:(setq magit-pull-or-fetch t) (define-key magit-mode-map "f" 'magit-pull) ; was magit-fetch (define-key magit-mode-map "F" nil) ; was magit-pull
7.3. 7.3 Pulling
另请参阅 git-pull(1) manpage. 有关 upstream 和 push-remote 的信息, 请参阅第 81 页的 [The Two Remotes].
F(magit-pull) 此 transient 前缀命令绑定以下 suffix 命令, 并在临时 buffer 中显示它们, 直到调用 suffix.F p(magit-pull-from-pushremote) 此命令从当前分支的 push-remote pull. 带有前缀参数或当 push-remote 未配置或不可用时, 让用户首先配置 push-remote.F u(magit-pull-from-upstream) 此命令从当前分支的 upstream pull. 带有前缀参数或当 upstream 未配置或不可用时, 让用户首先配置 upstream.F e(magit-pull-branch) 此命令从 minibuffer 中读取的分支 pull.
7.4. 7.4 Pushing
另请参阅 git-push(1) manpage. 有关 upstream 和 push-remote 的信息, 请参阅第 81 页的 [The Two Remotes].
P(magit-push) 此 transient 前缀命令绑定以下 suffix 命令以及适当的 infix 参数, 并在临时 buffer 中显示它们, 直到调用 suffix.P p(magit-push-current-to-pushremote) 此命令将当前分支 push 到其 push-remote. 带有前缀参数或当 push-remote 未配置或不可用时, 让用户首先配置 push-remote.P u(magit-push-current-to-upstream) 此命令将当前分支 push 到其 upstream 分支. 带有前缀参数或当 upstream 未配置或不可用时, 让用户首先配置 upstream.P e(magit-push-current) 此命令将当前分支 push 到 minibuffer 中读取的分支.P o(magit-push-other) 此命令将任意分支或 commit push 到某处. 源和目标都在 minibuffer 中读取.P r(magit-push-refspecs) 此命令将一个或多个 refspecs push 到 remote, 两者都在 minibuffer 中读取. 要使用多个 refspecs, 请用逗号分隔. 补全仅适用于冒号前的部分, 或者当没有使用冒号时.P m(magit-push-matching) 此命令将所有匹配的分支 push 到另一个仓库. 如果仅存在一个 remote, 则 push 到该 remote. 否则提示 remote, 提供为当前分支配置的 remote 作为默认值.P t(magit-push-tags) 此命令将所有 tags push 到另一个仓库. 如果仅存在一个 remote, 则 push 到该 remote. 否则提示 remote, 提供为当前分支配置的 remote 作为默认值.P T(magit-push-tag) 此命令将一个 tag push 到另一个仓库.
Infix 参数之一 --force-with-lease 值得警告. 它在没有值的情况下传递, 这意味着 "只要远程跟踪分支与其远程端的对应部分匹配, 就允许 force push". 如果你设置了工具进行自动 fetches (Magit 本身不提供此类功能), 使用 --force-with-lease 可能是危险的, 因为你并不真正控制或知道远程跟踪 refs 的状态. 在这种情况下, 你应该考虑将 push.useForceIfIncludes 设置为 true (自 Git 2.30 起可用).
还有两个 push 命令, 默认情况下无法从 push transient 获得. 请参阅其 doc-strings 以获取有关如何将它们添加到 transient 的说明.
magit-push-implicitly args[Command] 此命令在不使用显式 refspec 的情况下 push 到某处. 此命令仅运行git push -v [ARGS].ARGS是 infix 参数. 不使用显式 refspec 参数. 相反, 行为至少取决于这些 Git 变量:push.default,remote.pushDefault,branch.<branch>.pushRemote,branch.<branch>.remote,branch.<branch>.merge, 和remote.<remote>.push. 如果你将此 suffix 添加到 transient 前缀而不明确指定描述, 那么将尝试预测此命令将做什么. 例如:(transient-insert-suffix 'magit-push "p" '("i" magit-push-implicitly))
magit-push-to-remote remote args[Command] 此命令在不使用显式 refspec 的情况下 push 到远程REMOTE. Remote 在 minibuffer 中读取. 此命令仅运行git push -v [ARGS] REMOTE.ARGS是 infix 参数. 不使用 refspec 参数. 相反, 行为至少取决于这些 Git 变量:push.default,remote.pushDefault,branch.<branch>.pushRemote,branch.<branch>.remote,branch.<branch>.merge, 和remote.<remote>.push.
7.5. 7.5 普通补丁 (Plain Patches)
W(magit-patch) 此 transient 前缀命令绑定以下 suffix 命令以及适当的 infix 参数, 并在临时 buffer 中显示它们, 直到调用 suffix.W c(magit-patch-create) 此命令为一组 commits 创建补丁. 如果 region 标记了几个 commits, 则为所有这些 commits 创建补丁. 否则它充当 transient 前缀命令, 具有几个 infix 参数并绑定自身作为 suffix 命令. 当此命令作为自身的 suffix 调用时, 它使用指定的 infix 参数创建补丁.w a(magit-patch-apply) 此命令应用补丁. 这是一个 transient 前缀命令, 具有几个 infix 参数并绑定自身作为 suffix 命令. 当此命令作为自身的 suffix 调用时, 它使用指定的 infix 参数应用补丁.W s(magit-patch-save) 此命令从当前 diff 创建补丁. 在magit-diff-mode或magit-revision-modebuffers 中,C-x C-w也绑定到此命令.
也可以通过在 magit-diff-mode 或 magit-revision-mode buffer 中使用 C-x C-w 来保存普通补丁文件.
7.6. 7.6 Maildir 补丁 (Maildir Patches)
另请参阅 git-am(1) manpage 和 git-apply(1) manpage.
w(magit-am) 此 transient 前缀命令绑定以下 suffix 命令以及适当的 infix 参数, 并在临时 buffer 中显示它们, 直到调用 suffix.w w(magit-am-apply-patches) 此命令应用一个或多个补丁. 如果 region 标记了文件, 则将这些文件作为补丁应用. 否则此命令在 minibuffer 中读取文件名, 默认为 point 处的文件.w m(magit-am-apply-maildir) 此命令应用来自 maildir 的补丁.w a(magit-patch-apply) 此命令应用普通补丁. 有关更详细的描述, 请参见第 109 页的 7.5 节 [Plain Patches]. 此命令仅出于历史原因从magit-amtransient 获得.
当 "am" 操作正在进行时, transient 改为具有以下 suffix 命令.
w w(magit-am-continue) 此命令恢复当前的补丁应用序列.w s(magit-am-skip) 此命令在补丁应用序列期间跳过停止处的补丁.w a(magit-am-abort) 此命令中止当前的补丁应用序列. 这会丢弃自序列开始以来所做的所有更改.
8. 8 杂项 (Miscellaneous)
8.1. 8.1 标签 (Tagging)
另请参阅 git-tag(1) manpage.
t(magit-tag) 此 transient 前缀命令绑定以下 suffix 命令以及适当的 infix 参数, 并在临时 buffer 中显示它们, 直到调用 suffix.t t(magit-tag-create) 此命令在REV处创建带有给定NAME的新 tag. 带有前缀参数时, 它创建一个 annotated tag.t r(magit-tag-release) 此命令创建一个发布 tag. 它假设发布 tags 匹配magit-release-tag-regexp. 首先它提示新 tag 的名称, 使用现有的最高 tag 作为初始输入, 并留给用户增加版本字符串的所需部分. 如果你使用非常规的发布 tags 或版本号 (例如v1.2.3-custom.1), 你可以设置magit-release-tag-regexp和magit-tag-version-regexp-alist变量. 如果启用了--annotate, 则提示新 tag 的消息. 提议的 tag 消息基于最高 tag 的消息, 前提是它包含相应的版本字符串并将新版本字符串替换为该版本字符串. 否则它提议类似 "Foo-Bar 1.2.3" 的内容, 给定例如TAG"v1.2.3" 和位于类似 "/path/to/foo-bar" 的仓库.t k(magit-tag-delete) 此命令删除一个或多个 tags. 如果 region 标记了多个 tags (且没有其他内容), 则提议删除这些 tags. 否则, 它提示删除单个 tag, 默认为 point 处的 tag.t p(magit-tag-prune) 此命令提议从REMOTE删除本地缺失的 tags, 反之亦然.
8.2. 8.2 注释 (Notes)
另请参阅 git-notes(1) manpage.
T(magit-notes) 此 transient 前缀命令绑定以下 suffix 命令以及适当的 infix 参数, 并在临时 buffer 中显示它们, 直到调用 suffix.T T(magit-notes-edit) 编辑附加到 commit 的 note, 默认为 point 处的 commit. 默认情况下使用 Git 变量core.notesRef的值或 "refs/notes/commits" (如果未定义).T r(magit-notes-remove) 移除附加到 commit 的 note, 默认为 point 处的 commit. 默认情况下使用 Git 变量core.notesRef的值或 "refs/notes/commits" (如果未定义).T p(magit-notes-prune) 移除有关不可达 commits 的 notes.
可以将一个 note ref 合并到另一个中. 这可能会导致冲突, 必须在临时 worktree ".git/NOTESMERGEWORKTREE" 中解决.
T m(magit-notes-merge) 将从用户读取的 ref 的 notes 合并到当前 notes ref 中. 当前 notes ref 是 Git 变量core.notesRef的值或 "refs/notes/commits" (如果未定义).
当 notes 合并正在进行时, transient 具有以下 suffix 命令, 而不是上面列出的那些.
T c(magit-notes-merge-commit) 在手动解决冲突后提交当前 notes ref 合并.T a(magit-notes-merge-abort) 中止当前 notes ref 合并.
以下变量控制 magit-notes-*, git notes 和 git show 对哪些 notes reference 进行操作和显示. 本地和全局值都会显示并可以修改.
core.notesRef[Variable] 此变量指定默认显示的 notes ref, 以及命令默认操作的 notes ref.notes.displayRef[Variable] 此变量指定除core.notesRef指定的 ref 之外还要显示的其他 notes ref. 它可以有多个值, 并可能以*结尾以显示refs/notes/命名空间中的所有 refs (或**如果某些名称包含斜杠).
8.3. 8.3 子模块 (Submodules)
另请参阅 git-submodule(1) manpage.
8.3.1. 8.3.1 列出子模块 (Listing Submodules)
命令 magit-list-submodules 在单独的 buffer 中显示当前仓库的 submodules 列表. 也可以直接在超级仓库的 status buffer 中显示有关 submodules 的信息, 方法是将 magit-insert-modules 添加到 hook magit-status-sections-hook, 如第 38 页的 [Status Module Sections] 所述.
magit-list-submodules[Command] 此命令在单独的 buffer 中显示当前仓库的已填充 submodules 列表. 可以通过在标题为 "Modules" 的 section 上按RET来调用它.magit-submodule-list-columns[User Option] 此选项控制命令magit-list-submodules显示哪些列以及如何显示它们. 每个元素的形式为(HEADER WIDTH FORMAT PROPS).HEADER是显示在 header 中的字符串.WIDTH是列的宽度.FORMAT是一个函数, 使用一个参数 (仓库标识, 通常是其 basename) 调用, 并且default-directory绑定到其工作树的顶层. 它必须返回要插入的字符串或nil.PROPS是一个支持键:right-align,:pad-right和:sort的 alist.:sort函数有一个奇怪的接口, 在tabulated-list--get-sort的 docstring 中有描述. 或者可以使用<和magit-repolist-version<, 因为这些函数会自动替换为满足接口的函数. 将:sort设置为nil以禁止排序; 如果未指定, 则列使用默认排序器排序. 你可能希望使用每列一个字符且列之间没有任何填充来显示一系列数字列, 在这种情况下, 你应该使用适当的HEADER, 将WIDTH设置为 1, 并将:pad-right设置为 9. 对于大于 9 的数字, 用+替换.
8.3.2. 8.3.2 子模块 Transient (Submodule Transient)
o(magit-submodule) 此 transient 前缀命令绑定以下 suffix 命令以及适当的 infix 参数, 并在临时 buffer 中显示它们, 直到调用 suffix.
下面的一些命令默认对使用 region 选择的 modules 进行操作. 为简便起见, 它们的描述谈论 "选定的 modules", 但如果未选择 modules, 则它们作用于当前 module, 或者如果 point 不在 module 上, 则读取单个 module 进行操作. 带有前缀参数时, 这些命令忽略 selection 和当前 module, 而是作用于所有合适的 modules.
o a(magit-submodule-add) 此命令将位于URL的仓库添加为 module. 可选的PATH是相对于超级项目根目录的 module 路径. 如果为nil, 则基于URL确定路径.o r(magit-submodule-register) 此命令通过将选定 modules 的 urls 从 ".gitmodules" 复制到 "$GITDIR/config" 来注册它们. 这些值可以在运行magit-submodule-populate之前进行编辑. 如果你不需要编辑任何 urls, 则直接使用后者.o p(magit-submodule-populate) 此命令创建选定 modules 的工作目录, 检出记录的 commits.o u(magit-submodule-update) 此命令更新选定 modules, 检出记录的 commits.o s(magit-submodule-synchronize) 此命令同步选定 modules 的 urls, 将值从 ".gitmodules" 复制到超级项目的 ".git/config" 以及 modules 的配置中.o d(magit-submodule-unpopulate) 此命令移除选定 modules 的工作目录.o l(magit-list-submodules) 此命令显示当前仓库 modules 的列表.o f(magit-fetch-modules) 此命令 fetch 所有已填充 modules. 带有前缀参数时, 它充当 transient 前缀命令, 允许调用者设置选项. 也 fetch 超级仓库, 因为git fetch不支持不这样做.
8.4. 8.4 子树 (Subtree)
另请参阅 git-subtree(1) manpage.
O(magit-subtree) 此 transient 前缀命令绑定两个 sub-transients; 一个用于导入 subtree, 一个用于导出 subtree.O i(magit-subtree-import) 此 transient 前缀命令绑定以下 suffix 命令以及适当的 infix 参数, 并在临时 buffer 中显示它们, 直到调用 suffix. 此命令的 suffixes 导入 subtrees. 如果设置了--prefix参数, 则 suffix 命令使用该 prefix 而不提示用户. 如果未设置, 则它们在 minibuffer 中读取 prefix.O i a(magit-subtree-add) 此命令在PREFIX处添加来自REPOSITORY的COMMIT作为新 subtree.O i c(magit-subtree-add-commit) 此命令在PREFIX处添加COMMIT作为新 subtree.O i m(magit-subtree-merge) 此命令将COMMIT合并到PREFIXsubtree.O i f(magit-subtree-pull) 此命令将COMMIT从REPOSITORYpull 到PREFIXsubtree.O e(magit-subtree-export) 此 transient 前缀命令绑定以下 suffix 命令以及适当的 infix 参数, 并在临时 buffer 中显示它们, 直到调用 suffix. 此命令的 suffixes 导出 subtrees. 如果设置了--prefix参数, 则 suffix 命令使用该 prefix 而不提示用户. 如果未设置, 则它们在 minibuffer 中读取 prefix.O e p(magit-subtree-push) 此命令提取PREFIXsubtree 的历史记录并将其 push 到REPOSITORY上的REF.O e s(magit-subtree-split) 此命令提取PREFIXsubtree 的历史记录.
8.5. 8.5 工作树 (Worktree)
另请参阅 git-worktree(1) manpage.
Z(magit-worktree) 此 transient 前缀命令绑定以下 suffix 命令, 并在临时 buffer 中显示它们, 直到调用 suffix.Z b(magit-worktree-checkout) 在PATH处的新 worktree 中检出BRANCH.Z c(magit-worktree-branch) 创建一个新BRANCH并在PATH处的新 worktree 中检出它.Z m(magit-worktree-move) 将现有 worktree 移动到新PATH.Z k(magit-worktree-delete) 删除 worktree, 默认为 point 处的 worktree. 主 worktree 不能被删除.Z g(magit-worktree-status) 显示 point 处 worktree 的状态. 如果 point 处没有 worktree, 则在 minibuffer 中读取一个. 如果 point 处的 worktree 是其状态已在当前 buffer 中显示的 worktree, 则改为在 Dired 中显示它.
8.6. 8.6 稀疏检出 (Sparse checkouts)
稀疏检出提供了一种将 worktree 限制为目录子集的方法. 参见 git-sparse-checkout(1) manpage.
警告: Git 在 2.25 版本中引入了 git sparse-checkout 命令, 并且仍然将其宣传为实验性的且可能会更改. Magit 的接口应被视为相同. 特别是, 如果 Git 引入了向后不兼容的更改, Magit 的稀疏检出功能可能会以需要更新 Git 版本的方式进行更新.
>(magit-sparse-checkout) 此 transient 前缀命令绑定以下 suffix 命令, 并在临时 buffer 中显示它们, 直到调用 suffix.> e(magit-sparse-checkout-enable) 此命令初始化仅包含顶层目录中文件的稀疏检出. 注意magit-sparse-checkout-set和magit-sparse-checkout-add会在必要时自动初始化稀疏检出. 但是, 你可能希望在调用magit-sparse-checkout-disable后显式调用magit-sparse-checkout-enable以重新初始化稀疏检出, 传递额外参数给git sparse-checkout init, 或异步执行初始化.> s(magit-sparse-checkout-set) 此命令接受目录列表并将稀疏检出配置为仅包含这些子目录中的文件. 任何先前包含的目录都会被排除, 除非它们在提供的目录列表中.> a(magit-sparse-checkout-add) 此命令类似于magit-sparse-checkout-set, 但它是将指定的目录列表添加到已包含在稀疏检出中的目录集中.> r(magit-sparse-checkout-reapply) 此命令将当前配置的稀疏检出模式应用于 worktree. 如果在诸如 merging 或 rebasing 等操作之后检出了排除的文件, 这很有用.> d(magit-sparse-checkout-disable) 此命令恢复完整检出. 要返回之前的稀疏检出, 调用magit-sparse-checkout-enable.
在克隆仓库时, 也可以通过使用 magit-clone transient 中的 magit-clone-sparse 命令来启动稀疏检出 (参见第 68 页的 6.2 节 [Cloning Repository]).
如果你希望 status buffer 指示何时启用了稀疏检出, 请将函数 magit-sparse-checkout-insert-header 添加到 magit-status-headers-hook.
8.7. 8.7 捆绑 (Bundle)
另请参阅 git-bundle(1) manpage.
magit-bundle[Command] 此 transient 前缀命令绑定几个用于运行git bundle子命令的 suffix 命令, 并在临时 buffer 中显示它们, 直到调用 suffix.
8.8. 8.8 常用命令 (Common Commands)
magit-switch-to-repository-buffer[Command]magit-switch-to-repository-buffer-other-window[Command]magit-switch-to-repository-buffer-other-frame[Command]magit-display-repository-buffer[Command] 这些命令从用户读取属于当前仓库的任何现有 Magit buffer, 然后切换到选定的 buffer (不刷新它). 最后一个变体使用magit-display-buffer来执行此操作, 因此尊重magit-display-buffer-function.
这些是可以在其 major-modes 派生自 magit-mode 的所有 buffers 中使用的一些命令. 除了下面的命令外, 还有其他常用命令, 但它们不适合放在其他任何地方.
C-w(magit-copy-section-value) 此命令将当前 section 的值保存到kill-ring, 并且, 如果当前 section 是 commit, branch 或 tag section, 它还会将 (引用的) revision 推送到magit-revision-stack. 当当前 section 是分支或 tag, 且使用前缀参数时, 它将顶端的 revision 保存到kill-ring而不是 reference 名称. 当 region 处于活动状态时, 此命令将其保存到kill-ring, 就像kill-ring-save一样, 而不是如上所述. 如果使用前缀参数且 region 在 hunk 内, 则它剥离 diff 标记列并根据前缀参数的符号仅保留添加或删除的行.M-w(magit-copy-buffer-revision) 此命令将当前 buffer 中显示的 revision 保存到kill-ring, 并将其推送到magit-revision-stack. 它主要用于magit-revision-modebuffers, 这是唯一始终明确应该保存哪个 revision 的 buffers. 大多数其他 Magit buffers 通常以某种方式显示多个 revision, 因此此命令必须选择其中一个, 而该选择可能并不总是你认为的最佳选择.
在 Magit 之外 M-w 和 C-w 通常绑定到 kill-ring-save 和 kill-region, 这些命令在 Magit buffers 中也很有用. 因此当 region 处于活动状态时, 这两个命令都表现得像 kill-ring-save 而不是如上所述.
8.9. 8.9 Wip 模式 (Wip Modes)
Git 将已提交的更改保留足够长的时间, 以便用户恢复意外删除的更改. 它通过在一段时间内 (默认 30 天) 不垃圾回收任何已提交但不再被引用的对象来做到这一点.
但 Git 不跟踪 worktree 中的未提交更改, 甚至不跟踪 index (staging area). 因为 Magit 使修改未提交更改变得如此方便, 所以在这个过程中也很容易搬起石头砸自己的脚.
出于这个原因, Magit 提供了一个全局模式, 在某些操作之后或之前将 被跟踪 文件保存到 work-in-progress references. (目前未跟踪文件从未保存, 由于技术原因, 在创建第一个 commit 之前也没有保存任何内容).
使用两个单独的 work-in-progress references 来跟踪 index 和 worktree 的状态: refs/wip/index/<branchref> 和 refs/wip/wtree/<branchref>, 其中 <branchref> 是当前分支的完整 ref, 例如 refs/heads/master. 当 HEAD 分离时, HEAD 用于代替 <branchref>.
检出另一个分支 (或分离 HEAD) 会导致对后续更改使用不同的 wip refs.
magit-wip-mode[User Option] 启用此模式后, 未提交的更改会在适当的时候 (即, 否则可能会丢失数据时) 提交到专用的 work-in-progress refs. 直接设置此变量不会生效; 请使用 Custom 接口或调用相应的 mode 函数.
要查看分支及其 wip refs 的 log, 请使用命令 magit-wip-log 和 magit-wip-log-current. 使用这些命令时应使用 --graph.
magit-wip-log[Command] 此命令显示分支及其 wip refs 的 log. 带有负前缀参数时, 仅显示 worktree wip ref. 前缀参数的绝对数值控制显示每个 wip ref 的多少个 "分支". 仅当magit-wip-merge-branch的值为nil时这才是相关的.magit-wip-log-current[Command] 此命令显示当前分支及其 wip refs 的 log. 带有负前缀参数时, 仅显示 worktree wip ref. 前缀参数的绝对数值控制显示每个 wip ref 的多少个 "分支". 仅当magit-wip-merge-branch的值为nil时这才是相关的.X w(magit-reset-worktree) 此命令将 worktree 重置为从用户读取的某个 commit (默认为 point 处的 commit), 同时保持HEAD和 index 不变. 这可用于将文件恢复到提交给 wip ref 的状态. 注意这将丢弃在此命令调用之前可能存在的任何 unstaged 更改 (但当然只有在将该更改提交到 worktree wip ref 之后).
请注意, 即使你启用了 magit-wip-mode, 这也不会提供完美的保护. 尽管使用了 magit-wip-mode, 丢失更改的最可能场景是在 Emacs 外部进行更改, 然后也在 Emacs 外部销毁它. 在这种情况下, Magit 作为一个 Emacs 包, 没有机会阻止你搬起石头砸自己的脚.
当你不仅定 Magit 是否确实将更改提交到 wip refs 时, 你可以显式请求提交对所有被跟踪文件的所有更改.
M-x magit-wip-commit此命令将对所有被跟踪文件的所有更改提交到 index 和 worktree work-in-progress refs. 像上面描述的模式一样, 它不提交未跟踪文件, 但它确实检查所有被跟踪文件的更改. 当你怀疑模式可能忽略了在 Emacs/Magit 外部所做的更改时, 使用此命令.magit-wip-namespace[User Option] 用于 work-in-progress refs 的命名空间. 必须以斜杠结尾. wip refs 命名为<namespace>index/<branchref>和<namespace>wtree/<branchref>. 当在HEAD分离时创建快照,HEAD用于代替<branchref>.magit-wip-mode-lighter[User Option]magit-wip-mode的 Mode-line lighter.
8.9.1. 8.9.1 Wip 图 (Wip Graph)
magit-wip-merge-branch[User Option] 此选项控制在分支上创建新 commit 后, 当前分支是否合并到 wip refs 中. 如果为非nil且当前分支有新 commits, 则在创建新 wip commit 之前将其合并到 wip ref 中. 这使得更容易检查 wip 历史记录, 并且 wip commits 永远不会被垃圾回收. 如果为nil且当前分支有新 commits, 则在创建新 wip commit 之前将 wip ref 重置为分支的顶端. 使用此设置, wip commits 最终会被垃圾回收. 如果为immediately, 则使用git-commit-post-finish-hook创建合并提交. 这不鼓励, 因为它可能导致竞争条件, 例如在 rebases 期间.
当 magit-wip-merge-branch 为 t 时, 历史记录如下所示:
~
---------- refs/wip/index/refs/heads/master
/ / /
A–—B–—C refs/heads/master
~
当 magit-wip-merge-branch 为 nil 时, 在真实分支上创建 commit 然后进行更改会导致 wip refs 被重新创建以从新 commit 分叉. 但 wip refs 上的旧 commits 不会丢失. 它们仍然可以从 reflog 中获得. 为了更容易看到 wip ref 的分叉点何时更改, 会在其上创建一个带有消息 "restart autosaving" 的附加 commit (下面的 xx0 commits 是此类边界 commits).
从以下开始:
~
BI0—BI1 refs/wip/index/refs/heads/master
/
A—B refs/heads/master
\
BW0—BW1 refs/wip/wtree/refs/heads/master
~
提交 staged 更改并编辑保存文件将导致:
~
BI0—BI1 refs/wip/index/refs/heads/master
/
A—B—C refs/heads/master
\ \
\ CW0—CW1 refs/wip/wtree/refs/heads/master
\
BW0—BW1 refs/wip/wtree/refs/heads/master@{2}
~
直到 staged 某些更改之前, index wip ref 的分叉点不会改变. 同样, 仅仅检出分支或创建 commit 不会改变 worktree wip ref 的分叉点. 直到实际上有应该提交到相应 wip ref 的更改时, 分叉点才会被调整.
8.10. 8.10 用于访问文件的缓冲区的命令 (Commands for Buffers Visiting Files)
默认情况下, Magit 定义了一些全局按键绑定. 这些绑定是在根本不提供绑定和提供我希望使用的更好绑定之间的妥协. Magit 默认无法提供推荐的绑定集, 因为这些键序列严格保留给用户添加的绑定. 另请参阅第 129 页的 [Global Bindings], 和 elisp 中的 "Key Binding Conventions" 一节.
要使用推荐的绑定, 请将此添加到你的 init 文件并重新启动 Emacs.
(setq magit-define-global-key-bindings 'recommended)
如果你不想 Magit 向全局 keymap 添加任何绑定, 请将此添加到你的 init 文件并重新启动 Emacs.
(setq magit-define-global-key-bindings nil)
C-c f(magit-file-dispatch)C-c f s(magit-stage-file)C-c f s(magit-stage-buffer-file)C-c f u(magit-unstage-file)C-c f u(magit-unstage-buffer-file)C-c f , x(magit-file-untrack)C-c f , r(magit-file-rename)C-c f , k(magit-file-delete)C-c f , c(magit-file-checkout)C-c f D(magit-diff)C-c f d(magit-diff-buffer-file)C-c f L(magit-log)C-c f l(magit-log-buffer-file)C-c f t(magit-log-trace-definition)C-c f M(magit-log-merged)C-c f B(magit-blame)C-c f b(magit-blame-additions)C-c f r(magit-blame-removal)C-c f f(magit-blame-reverse)C-c f m(magit-blame-echo)C-c f q(magit-blame-quit)C-c f p(magit-blob-previous)C-c f n(magit-blob-next)C-c f v(magit-find-file)C-c f V(magit-blob-visit-file)C-c f g(magit-status-here)C-c f G(magit-display-repository-buffer)C-c f c(magit-commit)C-c f e(magit-edit-line-commit)
这些命令中的每一个都在下面单独记录, 连同它们的默认键绑定. 上面显示的绑定是推荐的绑定, 你可以通过遵循上面的说明来启用它们.
C-c M-g(magit-file-dispatch) 此 transient 前缀命令绑定以下 suffix 命令, 并在临时 buffer 中显示它们, 直到调用 suffix.C-c M-g s(magit-stage-file)C-c M-g s(magit-stage-buffer-file) Stage 当前 buffer 中访问的文件的所有更改. 当未访问文件时, 使用第一个命令, 该命令提示输入文件.C-c M-g u(magit-unstage-file)C-c M-g u(magit-unstage-buffer-file) Unstage 当前 buffer 中访问的文件的所有更改. 当未访问文件时, 使用第一个命令, 该命令提示输入文件.C-c M-g , x(magit-file-untrack) 此命令 untracks 从用户读取的文件, 默认为访问的文件.C-c M-g , r(magit-file-rename) 此命令重命名从用户读取的文件, 默认为访问的文件.C-c M-g , k(magit-file-delete) 此命令删除从用户读取的文件, 默认为访问的文件.C-c M-g , c(magit-file-checkout) 此命令将 worktree 和 index 中的文件更新为 revision 中的内容. revision 和文件均从用户读取.C-c M-g D(magit-diff) 此 transient 前缀命令绑定几个 diff suffix 命令和 infix 参数, 并在临时 buffer 中显示它们, 直到调用 suffix. 参见第 48 页的 5.4 节 [Diffing]. 这是d在 Magit buffers 中绑定的相同命令. 如果从访问文件的 buffer 调用此命令, 则限制 diff 为特定文件的选项 (--) 的初始值设置为访问的文件.C-c M-g d(magit-diff-buffer-file) 此命令显示当前 buffer 访问的文件或 blob 的 diff.magit-diff-buffer-file-locked[User Option] 此选项控制magit-diff-buffer-file是否使用专用 buffer. 参见第 8 页的 4.1 节 [Modes and Buffers].C-c M-g L(magit-log) 此 transient 前缀命令绑定几个 log suffix 命令和 infix 参数, 并在临时 buffer 中显示它们, 直到调用 suffix. 参见第 42 页的 5.3 节 [Logging]. 这是l在 Magit buffers 中绑定的相同命令. 如果从访问文件的 buffer 调用此命令, 则限制 log 为特定文件的选项 (--) 的初始值设置为访问的文件.C-c M-g l(magit-log-buffer-file) 此命令显示当前 buffer 访问的文件或 blob 的 log. 当使用前缀参数或当--follow是活动 log 参数时, 会跟随重命名. 当 region 处于活动状态时, log 限制为选定的行范围.magit-log-buffer-file-locked[User Option] 此选项控制magit-log-buffer-file是否使用专用 buffer. 参见第 8 页的 4.1 节 [Modes and Buffers].C-c M-g t(magit-log-trace-definition) 此命令显示 point 处定义的 log.C-c M-g M(magit-log-merged) 此命令读取一个 commit 和一个分支, 并显示关于前者合并到后者的 log. 即使在 fast-forward 合并的情况下, 这也会显示多个 commits.C-c M-g B(magit-blame) 此 transient 前缀命令绑定所有 blaming suffix 命令以及适当的 infix 参数, 并在临时 buffer 中显示它们, 直到调用 suffix. 有关此命令及以下命令的更多信息, 另请参见第 64 页的 5.9 节 [Blaming]. 除了magit-blamesub-transient 之外, dispatch transient 还直接绑定了几个 blaming suffix 命令. 有关这些命令和绑定的信息, 请参见第 64 页的 5.9 节 [Blaming].C-c M-g p(magit-blob-previous) 此命令访问修改当前文件的上一个 blob.C-c M-g n(magit-blob-next) 此命令访问修改当前文件的下一个 blob.C-c M-g v(magit-find-file) 此命令读取 revision 和文件并访问相应的 blob.C-c M-g V(magit-blob-visit-file) 此命令访问 worktree 中对应于当前 blob 的文件. 当访问 blob 或来自 index 的版本时, 它会转到 worktree 中相应文件的相同位置.C-c M-g g(magit-status-here) 此命令在 buffer 中显示当前仓库的状态, 就像magit-status一样. 此外, 它尝试转到该 buffer 中与当前访问文件 buffer (如果有) 中位置对应的位置. 在这样做之前, 保存所有属于当前仓库的访问文件的 buffers, 不提示.C-c M-g G(magit-display-repository-buffer) 此命令读取并显示属于当前仓库的 Magit buffer, 不刷新它.C-c M-g c(magit-commit) 此 transient 前缀命令绑定以下 suffix 命令以及适当的 infix 参数, 并在临时 buffer 中显示它们, 直到调用 suffix. 参见第 73 页的 [Initiating a Commit].C-c M-g e(magit-edit-line-commit) 此命令使添加当前行的 commit 可编辑. 带有前缀参数时, 它使删除该行的 commit 可编辑 (如果有). 提交使用git blame确定, 并使用git rebase --interactive(如果可以从HEAD到达) 或通过检出该 commit (或指向它的分支) (否则) 来使其可编辑.
8.11. 8.11 访问 Blobs 的缓冲区的 Minor Mode (Minor Mode for Buffers Visiting Blobs)
magit-blob-mode 在访问 blob 的 buffers 中启用某些 Magit 功能. 此类 buffers 可以使用 magit-find-file 和下面提到的一些命令创建, 这些命令也负责打开此 minor mode. 目前此模式仅建立几个键绑定, 但可能会扩展.
p(magit-blob-previous) 此命令访问修改当前文件的上一个 blob.n(magit-blob-next) 此命令访问修改当前文件的下一个 blob.q(magit-bury-or-kill-buffer) 此命令 bury 当前 buffer, 如果它在多个窗口中显示和/或使用了前缀参数. 如果都不是, 它改为 kill 当前 buffer.
你可能想将 u 绑定到另一个命令. 合适的命令包括 bury-buffer, magit-bury-buffer 和 magit-kill-this-buffer.
9. 9 自定义 (Customizing)
Git 和 Emacs 都是高度可定制的. Magit 既是 Git porcelain 也是 Emacs 包, 因此使用 Git 变量和 Emacs 选项来定制它是有意义的. 然而这种灵活性并非没有问题, 包括但不限于以下几点.
- 一些 Git 变量在 Magit 中自动生效, 无需任何显式支持. 有时这是可取的 - 在其他情况下, 它会破坏 Magit.
当某个 Git 设置破坏 Magit 但你想在命令行上继续使用该设置时, 可以通过向
magit-git-global-arguments追加类似("-c" "some.variable=compatible-value")的内容来仅为 Magit 覆盖该值. - 某些设置如
fetch.prune=true被 Magit 命令尊重 (因为它们只是调用相应的 Git 命令), 但它们的值并未反映在相应的 transient buffers 中. 在这种情况下,magit-fetch中的--prune参数可能处于活动或非活动状态, 但这并不妨碍 Git 变量被 suffix 命令尊重. 所以即使--prune参数显示的似乎表明不会发生 pruning, pruning 可能仍然会发生.
我打算在未来的版本中解决这些和类似的问题.
9.1. 9.1 每个仓库的配置 (Per-Repository Configuration)
Magit 可以使用 Git 变量和 Emacs 选项在每个仓库级别进行配置.
要仅为一个仓库设置 Git 变量, 只需在 /path/to/repo/.git/config 中设置它, 而不是 $HOME/.gitconfig 或 /etc/gitconfig. 参见 git-config(1) manpage.
同样, 可以通过编辑 /path/to/repo/.dir-locals.el 来仅为一个仓库设置 Emacs 选项. 参见 emacs 中的 "Directory Variables". 例如, 要在仅一个大型仓库中禁用访问文件的 buffers 的自动刷新, 请使用:
/path/to/huge/repo/.dir-locals.el((nil . ((magit-refresh-buffers . nil))))
可能只是对于非常大的仓库将某些信息插入 Magit buffers 成本很高, 在这种情况下, 你可以仅为该仓库禁用相应的 section 插入器:
/path/to/tag/invested/repo/.dir-locals.el((magit-status-mode . ((eval . (magit-disable-section-inserter 'magit-insert-tags-header)))))
magit-disable-section-inserter fn[Function] 此函数在当前仓库中禁用 section 插入器FN. 它仅用于.dir-locals.el和.dir-locals-2.el.
如果你想将相同的设置应用于多个 (但不是全部) 仓库, 那么保持仓库本地配置文件同步很快就会变得烦人. 为了避免这种情况, 你可以为某些类别的仓库 (例如 "huge repositories") 创建配置文件, 然后在每个仓库的配置文件中包含这些文件. 例如:
/path/to/huge/repo/.git/config[include] path = /path/to/huge-gitconfig/path/to/huge-gitconfig[status] showUntrackedFiles = no$HOME/.emacs.d/init.el(dir-locals-set-class-variables 'huge-git-repository '((nil . ((magit-refresh-buffers . nil))))) (dir-locals-set-directory-class "/path/to/huge/repo/" 'huge-git-repository)
9.2. 9.2 基本设置 (Essential Settings)
接下来的三节列出并讨论了许多用户出于安全和/或性能原因可能想要自定义的几个变量.
9.2.1. 9.2.1 安全 (Safety)
本节讨论了你可能出于安全原因想要更改 (或不更改) 的各种变量.
Git 将已提交的更改保留足够长的时间, 以便用户恢复意外删除的更改. 它不对 worktree 中的未提交更改, 甚至 index (staging area) 执行此操作. 因为 Magit 使修改未提交的更改变得如此容易, 所以在此过程中也很容易搬起石头砸自己的脚. 出于这个原因, Magit 提供了三个全局模式, 在某些操作之后或之前将 被跟踪 文件保存到 work-in-progress references. 参见第 117 页的 8.9 节 [Wip Modes].
出于性能考虑, 默认情况下不启用这些模式. 相反, 许多潜在的破坏性命令每次使用时都需要确认. 在许多情况下, 可以通过将符号添加到 magit-no-confirm (参见第 26 页的 [Completion and Confirmation]) 来禁用此功能. 如果你启用各种 wip 模式, 那么你应该将 safe-with-wip 添加到此列表中.
同样, 在将文件移动到系统垃圾箱之前不需要确认 - 如果你错误地删除了文件, 你可以从那里恢复它. 选项 magit-delete-by-moving-to-trash 控制是否使用系统垃圾箱, 默认情况下是这样. 尽管如此, trash 不是 magit-no-confirm 的成员 - 你可能想更改它.
默认情况下, 当访问的文件在磁盘上发生更改时, 访问文件的 buffers 会自动 reverted. 这并不像看起来那么危险, 但要做出明智的决定, 你应该参阅第 14 页的 [Risk of Reverting Automatically].
9.2.2. 9.2.2 性能 (Performance)
在 Magit 运行 git 产生副作用后, 它还会刷新当前 Magit buffer 和相应的 status buffer. 这是必要的, 因为否则可能会显示过时的信息而用户没有注意到. Magit buffers 通过从头开始重新创建其内容来更新, 这使得更新更简单且不易出错, 但也更昂贵. 保持简单并仅从头开始重新创建所有内容是一个旧的设计决策, 偏离它将需要重大的重构.
同时你可以告诉 Magit 仅自动刷新当前 Magit buffer, 而不刷新 status buffer. 如果你这样做, 那么 status buffer 仅在它是当前 buffer 时才自动刷新.
(setq magit-refresh-status-buffer nil)
你还应该检查是否有任何第三方包向 magit-refresh-buffer-hook, magit-pre-refresh-hook 和 magit-post-refresh-hook 添加了任何内容. 如果有, 则检查这些添加是否显著影响性能.
可以使用 M-x magit-toggle-verbose-refresh 告诉 Magit 详细刷新 buffers. 启用此功能有助于找出哪些 sections 是瓶颈. 打印到 *Messages* buffer 的每一行都包含 section 名称, 显示此 section 所花费的秒数, 以及 0 到 2 个感叹号: 感叹号越多, section 越慢.
当访问的文件在磁盘上更改时, Magit 也会 revert 位于当前仓库内的访问文件的 buffers. 这是在内置库 autorevert 的 auto-revert-mode 之上实现的. 要确定这是否影响性能, 请检查当存在许多 buffers 和/或当某些 buffers 使用 TRAMP 访问文件时, 性能是否明显变差. 如果是这样, 那么这应该会有所帮助.
(setq auto-revert-buffer-list-filter 'magit-auto-revert-repository-buffer-p)
有关替代方法, 请参阅第 12 页的 [Automatic Reverting of File-Visiting Buffers].
如果你启用了任何默认禁用的功能, 那么你应该检查它们是否显著影响性能. 它们很可能因为已知会降低性能 (至少在大型仓库中) 而未默认启用.
如果性能仅在某些异常大的仓库中较慢, 那么你可能只想在每个仓库或每个仓库类的基础上禁用某些功能. 参见第 125 页的 9.1 节 [Per-Repository Configuration]. 例如, 在具有异常数量 tags 的仓库中确定下一个和当前 tag 需要很长时间. 因此, 最好禁用 magit-insert-tags-headers, 如上述节点中所释.
- Log 性能 (Log Performance)
在显示 logs 时, Magit 限制最初显示的提交数量, 希望这可以避免不必要的工作. 当使用
--graph时, 遗憾的是对于大型历史记录这并没有达到预期的效果. Junio, Git 的维护者, 在 Git 邮件列表 (https://www.spinics.net/lists/git/msg232230.html) 上说: "–graph 想要计算整个历史记录, 而 max-count 仅在 –graph 完成其计算后的输出阶段产生影响".换句话说, 并不是 Git 输出差异很慢, 或者 Magit 解析输出很慢 - 问题在于 Git 首先出去抽了根烟.
我们实际上通过不仅使用
-<N>而且还使用范围来限制提交数量来解决此问题. 但不幸的是, 这并不总是可能的.当显示超过几千个提交时, 使用
--graph可能会减慢速度.使用
--color --graph甚至更慢. Magit 使用 Emacs 的一部分代码将控制字符转换为 faces. 该代码非常慢, 当显示具有许多分支和合并的 log 时, 这一点非常明显. 出于这个原因, 默认情况下不再启用--color. 考虑保持这种状态. - Diff 性能 (Diff Performance)
如果 diffs 很慢, 那么考虑通过将以下全部或部分变量设置为
nil来关闭一些可选的 diff 功能:magit-diff-highlight-indentation,magit-diff-highlight-trailing,magit-diff-paint-whitespace,magit-diff-highlight-hunk-body, 和magit-diff-refine-hunk.当显示 commit 而不是任意 diff 时, 会显示一些附加信息. 在某些情况下计算此信息可能非常昂贵. 如果使用
magit-revision-mode查看 commit 比在magit-diff-mode中查看同一 commit 花费的时间多得多, 那么考虑将magit-revision-insert-related-refs设置为nil.当你经常遇到包含删除文件的 diffs 时, 你可能想启用
--irreversible-delete参数. 如果你这样做, 那么 diffs 仍然显示文件已被删除, 但不显示文件的完整已删除内容. 此参数默认不可用, 参见transient中的 "Enabling and Disabling Suffixes". 完成后, 你应该启用它并保存该设置, 参见transient中的 "Saving Values". 你应该在 diff (d) 和 diff refresh (D) transient popups 中都这样做. - Refs Buffer 性能 (Refs Buffer Performance)
当刷新 "references buffer" 很慢时, 通常是因为显示了几百个 refs. 解决此问题的最佳方法显然是显示更少的 refs.
如果你对查看 tags 列表不感兴趣或仅略感兴趣, 那么首先不显示它们:
(remove-hook 'magit-refs-sections-hook 'magit-insert-tags)
然后你还应该确保列出的远程分支实际上都存在. 你可以使用
f-pa修剪不再存在的分支. - 提交性能 (Committing Performance)
当你发起提交时, Magit 默认会自动显示你即将提交的更改的 diff. 对于大型提交, 这可能需要很长时间, 当你提交大量生成的数据而实际上并不打算在提交之前检查时, 这尤其令人分心. 可以使用以下命令关闭此行为:
(remove-hook 'server-switch-hook 'magit-commit-diff)
(remove-hook 'with-editor-filter-visit-hook 'magit-commit-diff)
然后你可以输入
C-c C-d来显示 diff, 当你实际上想看到它时, 但仅限于此. 或者你可以保留 hook, 只在生成 diff 需要太长时间的情况下输入C-g. 如果你这样做, 那么你最终会得到一个损坏的 diff buffer, 但这样做的好处是你通常可以看到 diff, 这很有用, 因为它增加了你发现潜在问题的几率. - Microsoft Windows 性能 (Microsoft Windows Performance)
为了更新 status buffer, 必须运行 git 数十次. 这在 Microsoft Windows 上是有问题的, 因为该操作系统启动进程的速度非常慢. 遗憾的是, 这是一个只能由微软自己解决的问题, 而他们似乎对此并不特别感兴趣.
除了子进程问题外, 还有其他 Windows 特定的性能问题. 其中一些有变通方法. "Git for Windows" 的维护者试图提高 Windows 上的性能. 始终使用最新版本以受益于最新的性能调整. Magit 也试图解决一些 Windows 特定的问题.
据一些消息来源称, 设置以下 Git 变量也有帮助.
~~ini git config --global core.preloadindex true # default since v2.1 git config --global core.fscache true # default since v2.8 git config --global gc.auto 256 ~~你还应该检查防病毒程序是否影响性能.
- MacOS 性能 (MacOS Performance)
在 Emacs 26.1 之前, 在 macOS 上使用
fork创建子进程. 这不必要地复制了 GUI 资源, 这是昂贵的. 结果是, 在 Darwin 上分叉所需的时间比在 Linux 上长约 30 倍, 并且因为 Magit 启动许多 git 进程, 所以这产生了很大的不同.所以确保你使用的是至少 Emacs 26.1, 在这种情况下将使用更快的
vfork. (在 Darwin 上创建子进程仍比 Linux 慢两倍左右.) 参见 https://lists.gnu.org/archive/html/bug-gnu-emacs/2017-04/msg00201.html 获取更多信息.此外, 从像 brew 或 nix 这样的包管理器安装的 git 似乎比本机可执行文件慢. 对你正在运行的 git 可执行文件与
/usr/bin/git进行性能分析, 如果你发现显着差异, 请尝试使用后者作为magit-git-executable.
9.2.3. 9.2.3 全局绑定 (Global Bindings)
magit-define-global-key-bindings[User Option] 此选项控制可以将哪组 Magit 键绑定 (如果有) 添加到全局 keymap, 即使在当前 Emacs 会话中首次使用 Magit 之前.- 如果值为
nil, 则不添加绑定. 如果为
default, 可能添加:C-x g magit-status C-x M-g magit-dispatch C-c M-g magit-file-dispatch
如果为
recommended, 可能添加:C-x g magit-status C-c g magit-dispatch C-c f magit-file-dispatch
这些绑定是强烈推荐的, 但我们不能默认使用它们, 因为
C-c <LETTER>命名空间严格保留给用户添加的绑定 (参见elisp中的 "Key Binding Conventions").
所选集合中的绑定可能会在运行
after-init-hook时添加. 仅当那时没有其他键绑定到同一命令, 并且没有其他命令绑定到同一键时, 才会添加每个绑定. 换句话说, 我们尽量避免添加不必要的绑定, 以及与其他绑定冲突的绑定. 添加这些绑定延迟到运行after-init-hook之后, 允许用户在其 init 文件的任何位置设置变量 (而不必确保在加载或自动加载 magit 之前这样做), 并增加所有潜在冲突的用户绑定已经添加的可能性. 要设置此变量, 请使用setq或 Custom 接口. 不要使用函数customize-set-variable, 因为这样做会导致在评估该形式时立即加载 Magit (这与custom-set-variables不同, 后者不加载定义自定义变量的库). 如果after-init-hook已经运行, 设置此变量没有效果.- 如果值为
10. 10 管道 (Plumbing)
以下各节描述如何使用 Magit 的几个核心抽象来扩展 Magit 本身或实现单独的扩展.
Magit 使用的一些低级功能已被分解为单独的库/包, 以便它们可以被其他包使用, 而无需依赖 Magit. 有关 with-editor 的信息, 请参阅 with-editor. transient 还没有手册.
如果你试图找到一个未使用的键, 可以绑定到你自己的 Magit 扩展提供的命令, 那么请查看 https://github.com/magit/magit/wiki/Plugin-Dispatch-Key-Registry.
10.1. 10.1 调用 Git (Calling Git)
Magit 提供了许多用于调用 Git 的专用函数. 所有这些函数都在 magit-git.el 或 magit-process.el 中定义, 并具有前缀 magit-run-, magit-call-, magit-start- 或 magit-git- (也用于其他事物) 之一.
所有这些函数都接受不定数量的参数, 这些参数是指定 Git (或在某些情况下是任意可执行文件) 命令行参数的字符串. 这些参数在传递给可执行文件之前被扁平化; 所以除了字符串, 它们也可以是字符串列表, 并且为 nil 的参数会被静默丢弃. 其中一些函数在这些命令行参数之前还需要一个强制性参数.
粗略地说, 这些函数运行 Git 要么是为了获取一些值, 要么是为了副作用. 返回值的函数用于收集填充 Magit buffer 所需的信息, 而其他函数用于实现 Magit 命令.
仅值组中的函数始终同步运行, 并且它们从不触发刷新. 副作用组中的函数可以根据它们是同步还是异步运行 Git, 以及它们在可执行文件完成后是否触发刷新, 进一步划分为子组.
10.1.1. 10.1.1 从 Git 获取值 (Getting a Value from Git)
这些函数运行 Git 以获取值, 退出状态或输出. 当然你也可以使用它们来运行具有副作用的 Git 命令, 但应避免这样做.
magit-git-exit-code &rest args[Function] 使用ARGS执行 git 并返回其退出代码.magit-git-success &rest args[Function] 使用ARGS执行 git, 如果退出代码为 0 则返回t, 否则返回nil.magit-git-failure &rest args[Function] 使用ARGS执行 git, 如果退出代码为 1 则返回t, 否则返回nil.magit-git-true &rest args[Function] 使用ARGS执行 git, 如果 git 打印的第一行是字符串 "true", 则返回t, 否则返回nil.magit-git-false &rest args[Function] 使用ARGS执行 git, 如果 git 打印的第一行是字符串 "false", 则返回t, 否则返回nil.magit-git-insert &rest args[Function] 使用ARGS执行 git 并在 point 处插入其输出.magit-git-string &rest args[Function] 使用ARGS执行 git 并返回其输出的第一行. 如果没有输出或以换行符开头, 则返回nil.magit-git-lines &rest args[Function] 使用ARGS执行 git 并将其输出作为行列表返回. 输出中任何位置的空行都被省略.magit-git-items &rest args[Function] 使用ARGS执行 git 并将其 null 分隔的输出作为列表返回. 输出中任何位置的空项都被省略.
如果选项 magit-git-debug 的值为非 nil 并且 git 以非零退出状态退出, 那么在 echo area 中警告并在当前仓库的 process buffer 中添加包含 git 标准错误的 section.
magit-process-git destination &rest args[Function] 在单独的进程中同步调用 Git, 返回其退出代码.DESTINATION指定如何处理输出, 类似于call-process, 除了支持文件处理程序. 在调用期间启用 Cygwin 的 "noglob" 选项并确保 unix eol 转换.magit-process-file process &optional infile buffer display &rest args[Function] 在单独的进程中同步处理文件. 与process-file相同, 但在调用期间临时启用 Cygwin 的 "noglob" 选项并确保 unix eol 转换.
如果在使用上述函数之一时发生错误, 那么通常是因为 bug, 即使用了实际上不支持的参数. 此类错误通常不报告, 但当它们发生时我们需要能够调试它们.
magit-git-debug[User Option] 是否报告在使用magit-git-insert,magit-git-string,magit-git-lines或magit-git-items时发生的错误. 这实际上并不引发错误. 相反, 在 echo area 中显示一条消息, 并将 git 的标准错误插入当前仓库 process buffer 的新 section 中.magit-git-str &rest args[Function] 这是magit-git-string的一个变体, 它忽略选项magit-git-debug. 它主要旨在用于处理确实尊重该选项的函数中的错误时. 在处理错误时使用此类函数可能会导致另一个错误, 从而导致无限递归. 你可能永远不需要使用此函数.
10.1.2. 10.1.2 调用 Git 产生效果 (Calling Git for Effect)
这些函数用于运行 git 以产生某种效果. 大多数实际运行 git 的 Magit 命令都是通过使用此类函数来完成的.
因为我们在使用这些函数时不需要消耗 git 的输出, 所以它们的输出被记录到每个仓库的 buffer 中, 可以使用 Magit buffer 中的 $ 或其他地方的 M-x magit-process 显示.
这些函数可以通过两种不同的方式产生效果. 首先, 运行 git 可能会更改某些内容, 即创建或 push 新 commit. 其次, 该更改可能需要刷新 Magit buffers 以反映仓库的更改状态. 但刷新并不总是可取的, 因此只有其中一些函数在 git 返回后执行此类刷新.
有时异步运行 git 很有用. 例如, 当用户刚刚发起 push 时, 没有理由让她等待直到完成. 在其他情况下, 等待 git 完成后再让用户做其他事情是有意义的. 例如, 在 stage 更改后, 等待刷新完成很有用, 因为这也自动移动到下一个更改.
同步函数返回退出代码, 而异步函数返回进程对象.
magit-call-git &rest args[Function] 使用ARGS同步调用 git.magit-call-process program &rest args[Function] 使用ARGS同步调用PROGRAM.magit-run-git &rest args[Function] 使用ARGS同步调用 git 然后刷新.magit-run-git-with-input &rest args[Function] 使用ARGS同步调用 git 并将当前 buffer 的内容作为标准输入发送给它. 如果当前 buffer 的default-directory在远程文件系统上, 此函数实际上异步运行 git. 但随后它等待进程返回, 因此函数本身是同步的.magit-git &rest args[Function] 使用ARGS同步调用 git, 仅用于副作用. 此函数不刷新 buffer.magit-git-wash washer &rest args[Function] 使用ARGS执行 Git, 在 point 处插入 washed 输出. 实际上首先在 point 处插入原始输出. 如果没有输出调用magit-cancel-section. 否则暂时将 buffer 缩小到插入的文本, 移动到其开头, 然后调用函数WASHER并将ARGS作为其唯一参数.
现在是异步变体.
magit-run-git-async &rest args[Function] 启动 Git, 准备刷新, 并返回进程对象.ARGS被扁平化然后用作 Git 的参数. 在 echo area 中显示命令行参数. Git 返回后, 一些 buffers 被刷新: 调用此函数时当前的 buffer (如果是 Magit buffer 且仍然存在), 以及相应的 Magit status buffer. 如果magit-revert-buffers为非nil, 则访问当前仓库中被跟踪文件的未修改 buffers 被 reverted.magit-run-git-with-editor &rest args[Function] 导出GIT_EDITOR并启动 Git. 同时也准备刷新并返回进程对象.ARGS被扁平化然后用作 Git 的参数. 在 echo area 中显示命令行参数. Git 返回后, 一些 buffers 被刷新: 调用此函数时当前的 buffer (如果是 Magit buffer 且仍然存在), 以及相应的 Magit status buffer.magit-start-git input &rest args[Function] 启动 Git, 准备刷新, 并返回进程对象. 如果INPUT为非nil, 它必须是 buffer 或现有 buffer 的名称. buffer 内容成为进程的标准输入. 选项magit-git-executable指定 Git 可执行文件, 选项magit-git-global-arguments指定常量参数. 其余参数ARGS指定 Git 的参数. 它们在使用前被扁平化. Git 返回后, 一些 buffers 被刷新: 调用此函数时当前的 buffer (如果是 Magit buffer 且仍然存在), 以及相应的 Magit status buffer. 如果magit-revert-buffers为非nil, 则访问当前仓库中被跟踪文件的未修改 buffers 被 reverted.magit-start-process &rest args[Function] 启动PROGRAM, 准备刷新, 并返回进程对象. 如果可选参数INPUT为非nil, 它必须是 buffer 或现有 buffer 的名称. buffer 内容成为进程的标准输入. 使用start-file-process启动进程, 然后设置使用 sentinelmagit-process-sentinel和过滤器magit-process-filter. 这些函数所需的信息存储在进程对象中. 当此函数返回时, 进程尚未开始运行, 因此可以覆盖 sentinel 和过滤器. 进程返回后,magit-process-sentinel刷新在调用magit-start-process时当前的 buffer (如果是 Magit buffer 且仍然存在), 以及相应的 Magit status buffer. 如果magit-revert-buffers为非nil, 则访问当前仓库中被跟踪文件的未修改 buffers 被 reverted.magit-this-process[Variable] 即将启动的子进程. 这可以用来改变过滤器和 sentinel.magit-process-raise-error[Variable] 当此值为非nil时, 如果 git 以非零退出状态退出,magit-process-sentinel将引发错误. 用于调试目的.
10.2. 10.2 Section 管道 (Section Plumbing)
10.2.1. 10.2.1 创建 Sections (Creating Sections)
magit-insert-section &rest args[Macro] 在 point 处插入一个 section.TYPE是 section 类型, 一个符号. 许多作用于当前 section 的命令根据该类型表现不同. 此外, 如果存在变量magit-TYPE-section-map, 则使用该 map 作为属于 section 的所有文本的文本属性 keymap (但这可能会在子 sections 中被覆盖).TYPE也可以具有形式(eval FORM), 在这种情况下FORM在运行时求值. 可选的VALUE是 section 的值, 通常是作用于 section 时所需的字符串. 当可选的HIDE为非nil时, 默认折叠 section 主体, 即首次创建 section 时, 但不是在刷新 buffer 时. 否则, 默认展开它. 这可以使用magit-section-set-visibility-hook覆盖. 当在刷新期间重新创建 section 时, 继承前任的可见性并忽略HIDE(但仍然尊重 hook).BODY是任意数量的实际插入 section 标题和主体的形式. 可选的NAME, 如果指定, 必须是符号, 然后绑定到正在插入的 section 的结构体. 在评估BODY之前, section 对象的开始设置为point的值, 在评估BODY之后, 其结束设置为point的新值;BODY负责向前移动point. 如果在BODY内部发现 section 为空, 那么可以使用magit-cancel-section中止并删除部分插入的 section 的所有痕迹. 这可能发生在通过 washing Git 的输出创建 section 时, 而 Git 这次实际上没有输出任何内容.magit-insert-heading &rest args[Function] 插入当前正在插入的 section 的标题. 此函数只能在magit-insert-section内部使用. 当不带任何参数调用时, 仅将表示正在插入的 section 的对象的content槽设置为 point 处的标记. 像这样使用此函数时, section 应仅包含一行. 当带有参数ARGS(必须是字符串) 调用时, 在 point 处插入这些字符串. 在这发生之前 section 不应包含任何文本, 之后它也应只包含一行. 如果这些字符串中的任何一个内部设置了face属性, 则按原样插入所有字符串. 否则对所有插入的文本使用magit-section-headingface. section 结构的content属性是标题的结尾 (从start到content) 和主体的开头 (从content到end). 如果content的值为nil, 则 section 没有标题并且其主体不能折叠. 如果 section 确实有标题, 那么其高度必须恰好是一行, 包括尾随换行符. 这不是强制执行的; 你负责正确处理. 唯一的例外是此函数会在必要时插入换行符.magit-cancel-section[Function] 取消当前正在插入的 section. 这将退出magit-insert-section的最内层调用, 并删除该调用内部已发生的所有痕迹.magit-define-section-jumper sym title &optional value[Function] 定义一个交互式函数以转到 sectionSYM.TITLE是 section 的显示标题.
10.2.2. 10.2.2 Section 选择 (Section Selection)
magit-current-section[Function] 返回 point 处的 section.magit-region-sections &optional condition multiple[Function] 返回选定 sections 的列表. 当 region 处于活动状态并构成有效的 section selection 时, 返回所有选定 sections 的列表. 当 region 从一个 section 的标题开始并在同一 section 的标题或同级 section 的标题结束时, 就是这种情况. 如果可选的MULTIPLE为非nil, 那么 region 不能在同一 section 中开始和结束. 当 selection 无效时, 返回nil. 在这种情况下, 大多数可以作用于选定 sections 的命令将改为作用于 point 处的 section. 当 region 看起来像在任何其他 buffer 中那样时, selection 无效. 当 selection 有效时, region 使用magit-section-highlightface. 这不适用于 diffs, 那里的情况稍微复杂一些, 但即使在这里, 如果 region 看起来像通常那样, 那么就此函数而言, 这不是一个有效的 selection. 如果可选的CONDITION为非nil, 那么 selection 不仅必须有效; 所有选定的 sections 还必须匹配CONDITION, 否则返回nil. 参见magit-section-match了解CONDITION可以采取的形式.magit-region-values &optional condition multiple[Function] 返回选定 sections 的值的列表. 返回magit-region-sections(见该条目) 本身会返回的值.
10.2.3. 10.2.3 匹配 Sections (Matching Sections)
M-x magit-describe-section-briefly显示有关 point 处 section 的信息. 此命令用于调试目的.magit-section-ident section[Function] 返回SECTION的唯一标识符. 返回值的形式为((TYPE . VALUE)...).magit-get-section ident &optional root[Function] 返回由IDENT标识的 section.IDENT必须是magit-section-ident返回的列表.magit-section-match condition &optional section[Function] 如果SECTION匹配CONDITION, 则返回t.SECTION默认为 point 处的 section. 如果未指定SECTION且 point 处也没有 section, 则返回nil.CONDITION可以采取以下形式:(CONDITION...): 如果任何CONDITION匹配, 则匹配.[CLASS...]: 如果 section 的类与第一个CLASS相同或者是其子类; section 的父类匹配第二个CLASS; 依此类推, 则匹配.[* CLASS...]: 匹配匹配[CLASS...]的 sections 以及递归匹配其所有子 sections.CLASS: 如果 section 的类与CLASS相同或者是其子类, 则匹配; 无论父 sections 的类如何.
每个
CLASS应该是一个类符号, 标识派生自magit-section的类. 为了向后兼容,CLASS也可以是一个 "类型符号". 如果其type槽的值是eq, 则 section 匹配这样的符号. 如果类型符号在magit--section-type-alist中有条目, 那么如果其类是对应于该类型 (根据该 alist) 的类的子类, 则 section 也匹配该类型. 注意不需要指定magit-describe-section-briefly打印的完整 section 谱系, 除非你当然想要那么精确.magit-section-value-if condition &optional section[Function] 如果 point 处的 section 匹配CONDITION, 则返回其值. 如果可选的SECTION为非nil, 则测试它是否匹配. 如果 point 处没有 section 且SECTION为nil, 则返回nil. 如果 section 不匹配, 则返回nil. 参见magit-section-match了解CONDITION可以采取的形式.magit-section-case &rest clauses[Function] 在 point 处 section 的类型上选择子句. 每个子句看起来像(CONDITION BODY...). 将 section 的类型与每个CONDITION进行比较; 顺序评估第一个匹配项的BODY形式, 并返回最后一个形式的值. 在BODY内部, 符号it绑定到 point 处的 section. 如果没有子句成功或 point 处没有 section, 返回nil. 参见magit-section-match了解CONDITION可以采取的形式. 此外, 允许在最后一个子句中使用CONDITIONt, 如果没有其他CONDITION匹配, 则匹配, 即使 point 处没有 section.magit-root-section[Variable] 当前 buffer 中的根 section. 所有其他 sections 都是此 section 的后代. 此变量的值由magit-insert-section设置, 你永远不应该修改它.
对于 diff 相关 sections, 存在一些额外的工具.
magit-diff-type &optional section[Function] 返回SECTION的 diff 类型. 返回的类型是符号staged,unstaged,committed或undefined之一. 此类型与所有 sections 通用的通用类型 (存储在相应magit-section结构体的type槽中) 具有类似的目的, 但考虑了额外的信息. 当SECTION与 diffs 无关且包含它的 buffer 也不是仅 diff buffer 时, 返回nil. 目前类型也可以是tracked和untracked之一, 但这些值并未在每个应该处理的地方显式处理. 可能的修复方法是在这里直接返回nil. Section 必须是diff或hunksection, 或子项为diff类型的 section. 如果可选的SECTION为nil, 返回当前 section 的 diff 类型. 在其主模式为magit-diff-mode的 buffers 中,SECTION被忽略, 类型使用其他方式确定. 在magit-revision-modebuffers 中, 类型始终为committed.magit-diff-scope &optional section strict[Function] 返回SECTION或选定 section(s) 的 diff 范围. Diff 的 "scope" 描述选择了 diff 的哪一部分, 它是一个符号,region,hunk,hunks,file,files或list之一. 不要将其与magit-diff-type返回的 diff "type" 混淆. 如果可选的SECTION为非nil, 则返回它的范围, 忽略 region 选择的 sections. 否则返回当前 section 的范围, 或者如果 region 处于活动状态并选择了一组有效的 diff 相关 sections, 则返回这些 sections 的类型, 即hunks或files. 如果SECTION(或如果nil为当前 section) 是hunksection 并且 region 在该 section 的主体内开始和结束, 则类型为region. 如果可选的STRICT为非nil, 那么如果 point 处的 section 的 diff 类型为untracked或 point 处的 section 实际上不是diff而是diffstatsection, 则返回nil.
10.3. 10.3 刷新缓冲区 (Refreshing Buffers)
所有创建新 Magit buffer 或更改现有 buffer 中显示内容的命令都通过调用 magit-mode-setup 来完成. 除其他外, 该函数设置 default-directory (到仓库的顶层), magit-refresh-function 和 magit-refresh-args 的 buffer local 值.
通过调用作为 magit-refresh-function 的本地值的函数 (一个名为 magit-*-refresh-buffer 的函数, 其中 * 可能是像 diff 这样的东西) 并使用 magit-refresh-args 的值作为参数作为参数.
magit-mode-setup buffer switch-func mode refresh-func &optional refresh-args[Macro] 此函数显示并选中BUFFER, 打开MODE, 并进行第一次刷新. 此函数通过调用magit-mode-display-buffer(使用BUFFER,MODE和SWITCH-FUNC作为参数) 来显示并可选地选中BUFFER. 然后它将magit-refresh-function的本地值设置为REFRESH-FUNC, 将magit-refresh-args的本地值设置为REFRESH-ARGS. 最后它通过调用REFRESH-FUNC(使用REFRESH-ARGS作为参数) 来创建 buffer 内容. 在切换到BUFFER之前, 所有参数都会被求值.magit-mode-display-buffer buffer mode &optional switch-function[Function] 此函数在某个窗口中显示BUFFER并选中它.BUFFER可以是 buffer 或字符串 (buffer 的名称). 返回该 buffer. 除非BUFFER已经在选定 frame 中显示, 否则将先前的窗口配置存储为 buffer 本地值, 以便稍后可以通过magit-mode-bury-buffer恢复它. 使用SWITCH-FUNCTION显示和选中 buffer. 如果该值为nil, 且当前 buffer 的 major mode 派生自magit-mode, 则使用pop-to-buffer. 否则使用switch-to-buffer.magit-refresh-function[Variable] 此 buffer-local 变量的值是用于刷新当前 buffer 的函数. 它使用magit-refresh-args作为参数调用.magit-refresh-args[Variable]magit-refresh-function用于刷新当前 buffer 的参数列表.magit-refresh-function使用这些参数调用. 该值通常使用magit-mode-setup设置, 但在某些情况下, 提供可以更改该值的命令也很有用. 例如,magit-diff-refreshtransient 可用于更改用于显示 diff 的任何参数, 而无需再次指定应显示哪些差异, 但magit-diff-more-context,magit-diff-less-context和magit-diff-default-context仅更改-U<N>参数. 在这两种情况下, 这都是通过更改此变量的值然后调用magit-refresh-function来完成的.
10.4. 10.4 约定 (Conventions)
另请参阅第 26 页的 [Completion and Confirmation].
10.4.1. 10.4.1 主题化 Faces (Theming Faces)
默认主题使用蓝色表示本地分支, 绿色表示远程分支, 金麒麟色 (棕黄色) 表示 tags. 创建新主题时, 你可能应该遵循该示例. 如果你的主题已经使用其他颜色, 则坚持使用这些颜色.
在旧版本中, 这些 reference faces 曾经有背景颜色和周围的框. 基本默认 faces 不再这样做, 以使 Magit buffers 不那么嘈杂, 你应该至少在框方面遵循该示例. (过去使用框是为了解决高亮覆盖层和文本属性背景之间的冲突. 这不再是必要的, 因为高亮不再导致其他背景颜色消失.) 或者你可以保留背景颜色和/或框, 但随后必须特别注意相应地调整 magit-branch-current. 默认情况下, 它看起来主要像 magit-branch-local, 但带有一个框 (默认情况下, 前者是唯一使用框的 face, 正是为了让它突出). 如果前者也使用框, 那么你必须确保它在其他方面与后者不同.
最难主题化的 faces 是那些与 diffs, 标题, 高亮和 region 相关的 faces. 有些 faces 属于所有这四组 - 预计要花一些时间才能弄好.
默认主题中的 region face, 无论是浅色还是深色变体, 以及随 Emacs 分发或由第三方分发的许多其他主题中, 都非常丑陋. 通常使用非常突出的背景颜色, 这很丑陋, 但如果这是唯一的问题, 那是可以接受的. 不幸的是, 许多主题还设置了前景色, 这确保了 region 内的所有文本都是可读的. 如果不这样做, 可能会出现某些前景色太接近 region 背景色而无法阅读的情况. 但这也意味着 region 内的文本会丢失所有语法高亮.
我认为在使 region face 正确方面所做的工作是衡量主题一般质量的一个很好的指标. 我对 region face 的建议是: 使用与 default face 的背景颜色略有不同的背景颜色, 并且根本不设置前景色. 因此, 对于浅色主题, 你可以使用浅灰色 (可能有色调) 作为 default 的背景颜色, 并使用稍深的灰色作为 region 的背景. 这通常应该足以不与任何其他 face 的前景色冲突. 但是, 如果其他一些 faces 也设置了浅灰色作为背景颜色, 那么你也应该确保它不与那些冲突 (尽管在某些情况下可能是可以接受的).
Magit 仅在 region 根据其自身定义 "无效" 时才使用 region face. 在 Magit buffer 中, region 用于选择多个同级 sections, 以便支持它的命令作用于所有这些 sections 而不仅仅是当前 section, 或者用于在单个 hunk section 内选择行. 在所有其他情况下, section 被认为是无效的, Magit 不会对其采取行动. 但这种无效 sections 会发生, 要么是因为用户尚未将 point 移动到足够远以使其有效, 要么是因为她想使用非 magit 命令来作用于 region, 例如 kill-region.
因此, 对无效 sections 使用常规 region face 是一个特性. 它告诉用户 Magit 将无法对其采取行动. 如果那个 face 看起来有点奇怪, 甚至 (如果不那么严重) 如果它与 section 标题和其他具有背景颜色的东西的背景颜色冲突, 也是可以接受的.
Magit 高亮显示当前 section. 如果一个 section 有子 sections, 那么所有子 sections 都会被高亮显示. 这是使用名称中带有 "highlight" 的 faces 完成的. 对于大多数 sections, magit-section-highlight 用于主体和标题. 像 region face 一样, 它应该只将背景颜色设置为类似于 default 的颜色. highlight 背景颜色必须与 region 背景颜色和 default 背景颜色都不同.
对于 diff 相关 sections, Magit 使用各种 faces 来高亮显示所选 section(s) 的不同部分. 请注意, 与所有其他 section 标题不同, hunk 标题默认具有背景颜色, 因为拥有非常明显的 hunks 分隔符很有用. face magit-diff-hunk-heading 应该不同于 magit-diff-hunk-heading-highlight 和 magit-section-highlight, 以及 magit-diff-context 和 magit-diff-context-highlight. 默认情况下, 我们通过更改前景色来做到这一点. 更改背景颜色会导致并发症, 并且我们已经有足够多无法绕过的问题了. (还要注意, 让 section 标题始终为粗体通常是个好主意, 但仅限于有子 sections 的 sections).
当存在有效的 region 选择 diff 相关同级 sections (即多个文件或 hunks) 时, 所有这些 sections 的主体都使用相应的 highlight faces, 但除此之外, 标题改用 magit-diff-file-heading-selection 或 magit-diff-hunk-heading-selection faces 之一. 这些 faces 必须与常规 highlight 变体不同, 以提供 region 处于活动状态的明确视觉指示.
在主题化 diff 相关 faces 时, 首先将选项 magit-diff-refine-hunk 设置为 all. 你个人可能更喜欢只 refine 当前 hunk 或根本不使用 hunk refinement, 但你的主题的一些用户希望所有 hunks 都被 refined, 所以你必须迎合这一点.
(还要打开 magit-diff-highlight-indentation, magit-diff-highlight-trailing, 和 magit-diff-paint-whitespace; 并在你用于测试的代码中插入一些空白错误.)
对于添加的行, 你必须调整三个 faces: magit-diff-added, magit-diff-added-highlight, 和 diff-refined-added. 确保后者与前两者以及 smerge-other 和 diff-added 配合良好. 然后对删除的行, 上下文行, 我们添加的行和他们添加的行做同样的事情. 还要确保相应的 added, removed 和 context faces 对于 highlighted 和 unhighlighted 变体使用大致相同的饱和度. 还要确保文件和 diff 标题与 context lines 配合良好 (例如, 使它们看起来不同). Line faces 应该同时设置前景和背景颜色. 例如, 对于添加的行, 使用两种不同的绿色.
如果 highlighted 和 unhighlighted 变体的前景色相同是最好的, 所以你需要找到一种在 highlight 和 unhighlighted 背景, refine 背景以及 highlight context 背景上都表现良好的颜色. 当存在 hunk 内部 region 时, added- 和 removed-lines 背景颜色仅在该 region 内使用. region 外部使用 highlighted context 背景颜色. 这使得更容易看到什么正在被 staged. 带有 hunk 内部 region 时, hunk 标题使用 magit-diff-hunk-heading-selection 显示, 并且在落在 region 内的行周围添加细线. 它的背景颜色必须与涉及的各种其他背景颜色有明显的区别.
没人说这会很容易. 如果你的主题限制自己使用一组特定的颜色, 那么你应该在这里破例. 否则不可能让 diffs 在每一个变体中都看起来很好. 实际上你可能只想坚持这些 faces 的默认定义. 你已经被警告过了. 另外请注意, 如果你没弄好, 在某些情况下这看起来就像 Magit 中的 bug - 所以请做好它, 或者根本别做.
11. 附录 A 常见问题 (FAQ)
接下来的两个节点列出了常见问题. 有关常见和最近提出的问题的列表 (即尚未进入手册的问题), 请参阅 https://github.com/magit/magit/wiki/FAQ.
请同时参阅第 148 页的第 11 章 [Debugging Tools].
11.1. A.1 FAQ - 如何…? (How to …?)
11.1.1. A.1.1 Magit 怎么发音? (How to pronounce Magit?)
mu[m's] git 或 magi{c => t} 都可以.
口号是 "It's Magit! The magical Git client" (是 Magit! 神奇的 Git 客户端), 所以像 magic 一样发音 Magit 是有道理的, 同时考虑到 C 和 T 的发音不同.
德语 "Magie" 的发音与英语 "magic" 不同, 所以如果你说德语, 那么你可以使用上述理由来证明使用前一种发音是正当的; Mag{ie => it}.
你也可以仅仅因为你更喜欢它而选择前一种发音.
另请参见 https://magit.vc/assets/videos/magic.mp4. 另请参见 https://emacs.stackexchange.com/questions/13696.
11.1.2. A.1.2 如何显示 git 的输出? (How to show git's output?)
要显示最近运行的 git 命令的输出, 按 $ (或者, 如果不可用, 使用 M-x magit-process-buffer). 这显示一个包含每个 git 调用 section 的 buffer; 像往常一样按 TAB 展开或折叠它们.
默认情况下, 只有当 git 为副作用运行时, 其输出才会插入 process buffer. 当输出以某种方式被消耗时, 将其也插入 process buffer 会太昂贵. 出于调试目的, 可以使用 M-x magit-toggle-git-debug 强制这样做.
11.1.3. A.1.3 如何安装 gitman info 手册? (How to install the gitman info manual?)
Git 的 manpages 可以导出为名为 gitman 的 info 手册. Magit 自己的 info 手册链接到该手册中的节点而不是实际的 manpages, 仅仅因为 Info 不支持链接到 manpages.
不幸的是, 一些发行版默认不安装 gitman 手册, 你必须安装单独的文档包才能获得它.
Magit 修补了 info, 增加了访问指向 gitman info 手册链接的能力, 改为查看相应的 manpage. 如果你更喜欢那种方法, 那么将 magit-view-git-manual-method 的值设置为受支持的 Emacs 包 man 或 woman 之一, 例如:
(setq magit-view-git-manual-method 'man)
11.1.4. A.1.4 如何显示 gpg 加密文件的 diffs? (How to show diffs for gpg-encrypted files?)
Git 支持显示加密文件的 diffs, 但必须被告知这样做. 由于 Magit 只是使用 Git 来获取 diffs, 配置 Git 也会影响 Magit 内部显示的 diffs.
git config --global diff.gpg.textconv "gpg --no-tty --decrypt" echo "*.gpg filter=gpg diff=gpg" > .gitattributes
11.1.5. A.1.5 分支和推送如何工作? (How does branching and pushing work?)
请参阅第 81 页的 6.6 节 [Branching], 以及 https://emacsair.me/2016/01/18/magit-2.4
11.1.6. A.1.6 我应该禁用 VC 吗? (Should I disable VC?)
如果你不使用 VC (内置版本控制接口), 那么你可能会想禁用它, 尤其是因为我们曾经建议你这样做.
我们不再建议你禁用 VC. 这样做会破坏依赖于 VC 启用的有用的第三方包 (如 diff-hl).
如果你无论如何都选择禁用 VC, 那么你可以通过更改 vc-handled-backends 的值来做到这一点.
11.2. A.2 FAQ - 问题和错误 (Issues and Errors)
11.2.1. A.2.1 Magit 很慢 (Magit is slow)
参见第 126 页的 [Performance], 以及第 144 页的 [I changed several thousand files at once and now Magit is unusable].
11.2.2. A.2.2 我一次更改了几千个文件, 现在 Magit 无法使用了 (I changed several thousand files at once and now Magit is unusable)
Magit 目前不期望在这种条件下工作良好. 如果能这就太好了. 在这种条件下达到令人满意的性能将需要进行大量的重构. 这不是一个小任务, 但我希望能最终找到时间来实现它.
但目前我们建议你使用命令行来完成这一个提交.
另请参见第 126 页的 [Performance].
11.2.3. A.2.3 我在提交时遇到问题 (I am having problems committing)
这很可能意味着 Magit 在寻找合适的 emacsclient 可执行文件时遇到问题. 参见 with-editor 中的 "Configuring With-Editor" 一节和 with-editor 中的 "Debugging" 一节.
11.2.4. A.2.4 我正在使用 MS Windows 并且无法用 Magit 推送 (I am using MS Windows and cannot push with Magit)
几乎可以肯定 Magit 只是这个问题附带的. 这更有可能是一个配置问题, 即使你可以在命令行上推送.
详细的设置说明可以在 https://github.com/magit/magit/wiki/Pushing-with-Magit-from-Windows 找到.
11.2.5. A.2.5 我正在使用 macOS, 某功能在 shell 中工作但在 Magit 中不行 (I am using macOS and SOMETHING works in shell, but not in Magit)
这通常发生是因为 Emacs 没有与你的 shell 相同的环境变量. 尝试安装并配置 https://github.com/purcell/exec-path-from-shell. 默认情况下它同步 $PATH, 这有助于 Magit 找到你在 shell 上使用的同一个 git.
如果 SOMETHING 是 "使用 gpg-agent 进行提交和/或 tag 签名的密码缓存", 那么你还需要同步 $GPG_AGENT_INFO.
11.2.6. A.2.6 展开文件以显示 diff 导致它消失 (Expanding a file to show the diff causes it to disappear)
这可能是由 diff.* Git 变量的自定义引起的. 你可能出于某种原因设置了该变量, 因此应该只通过自定义 magit-git-global-arguments 在 Magit 中撤消该设置.
11.2.7. A.2.7 COMMITEDITMSG 缓冲区中的 Point 是错误的 (Point is wrong in the COMMITEDITMSG buffer)
Magit 和 git-commit.el 都没有在用于编写提交消息的 buffer 中摆弄 point, 所以一定是其他东西在做这件事.
你可能全局启用了一种模式, 该模式在文件访问 buffers 中恢复 point. 这可能有点令人惊讶, 但是当你编写提交消息时, 你实际上是在编辑文件.
所以你必须找出哪个包在做这件事. saveplace, pointback, 和 session 是可能的候选者. 这些代码片段可能会有所帮助:
(setq session-name-disable-regexp "\\(?:\\~'\\.git/[A-Z_]+\\'\\)") (with-eval-after-load 'pointback (lambda () (when (or git-commit-mode git-rebase-mode) (pointback-mode -1))))
11.2.8. A.2.8 Mode-line 信息并不总是最新的 (The mode-line information isn't always up-to-date)
Magit 不负责在 mode-line 中显示的看起来像 Git-master 的版本控制信息. 内置的 "Version Control" 包, 也称为 "VC", 更新该信息, 并且可以被告知更频繁地这样做:
(setq auto-revert-check-vc-info t)
但这样做对性能不利. 有关更多 (过于乐观的) 信息, 请参阅 emacs 中的 "VC Mode Line" 一节.
如果你真的不关心在 mode-line 中看到此信息, 而只是不想看到不正确的信息, 那么考虑干脆不在 mode-line 中显示它:
(setq-default mode-line-format (delete '(vc-mode vc-mode) mode-line-format))
11.2.9. A.2.9 分支和标签共享相同名称破坏了某些东西 (A branch and tag sharing the same name breaks SOMETHING)
或者更一般地说, 模棱两可的 refnames 破坏了某些东西.
Magit 假设 refs 在 "refs/heads/", "refs/tags/", 和 "refs/remotes/" 命名空间中非模棱两可地命名 (即, 当剥离这些前缀时, 所有名称保持唯一). 我们认为不支持模棱两可的 refnames, 并建议你使用非模棱两可的命名方案. 但是, 如果你确实在处理具有模棱两可 refnames 的仓库, 请报告你遇到的任何问题, 以便我们可以调查是否有简单的修复方法.
11.2.10. A.2.10 我的 Git hooks 在命令行上工作但在 Magit 中不行 (My Git hooks work on the command-line but not inside Magit)
当 Magit 调用 git 时, 它会添加一些全局参数, 包括 --literal-pathspecs, 并且由 Magit 启动的 git 进程随后将该设置传递给它自己启动的其他 git 进程. 它通过设置环境变量 GIT_LITERAL_PATHSPECS 来做到这一点, 而不是通过使用 --literal-pathspecs 参数调用子进程. 因此你可以在 hook 脚本中使用 unset GIT_LITERAL_PATHSPECS 覆盖此设置.
11.2.11. A.2.11 从命令行提交时未使用 git-commit-mode (git-commit-mode isn't used when committing from the command-line)
原因是 git-commit.el 尚未加载和/或服务器尚未启动. 当你从 Magit 提交时, 这些事情总是已经处理好了, 因为为了这样做, 必须加载 Magit, 而这样做涉及加载 git-commit 并启动服务器.
如果你想从命令行提交, 那么你必须自己处理这些事情. 你的 init.el 文件应包含:
(require 'git-commit) (server-mode)
你可以使用 (load "/path/to/magit-autoloads.el") 代替 (require 'git-commit). 你可能想这样做, 因为加载 git-commit 会导致 Magit 的大部分内容被加载.
还有一些 (server-mode) 的变体你可能想尝试. 我个人使用:
(use-package server :config (or (server-running-p) (server-mode)))
现在你可以使用:
$ emacs&
$ EDITOR=emacsclient git commit
但是你不能使用:
$ killall emacs $ EDITOR="emacsclient --alternate-editor emacs" git commit
这实际上最终会使用 emacs, 而不是 emacsclient. 如果你这样做, 那么你仍然可以编辑提交消息, 但不会使用 git-commit-mode, 并且你必须退出 emacs 才能完成该过程.
前方同义反复. 如果你想能够使用 emacsclient 连接到正在运行的 emacs 实例, 即使没有 emacs 实例在运行, 那么你不能直接使用 emacsclient.
相反, 你必须创建一个脚本来执行类似以下操作:
尝试使用 emacsclient (不使用 --alternate-editor). 如果成功, 什么也不做. 否则启动 emacs & (并且 init.el 必须调用 server-start) 并再次尝试使用 emacsclient.
11.2.12. A.2.12 跳转到访问文件的缓冲区时 Point 最终位于不可见文本内 (Point ends up inside invisible text when jumping to a file-visiting buffer)
当你对 hunk 键入 RET 以访问相应文件中的相应位置时, 可能会发生这种情况. 这个问题的一个解决方案是使用 global-reveal-mode. 它确保 point 周围的文本总是可见的. 如果这对你的口味来说太激烈了, 那么你可以改用 magit-diff-visit-file-hook 来显示文本, 可能使用 reveal-post-command 或对于 Org buffers 使用 org-reveal.
11.2.13. A.2.13 我不再能够保存弹出窗口默认值 (I am no longer able to save popup defaults)
Magit 过去使用 Magit-Popup 来实现 transient 弹出菜单. 现在它改用 Transient, 它是 Magit-Popup 的继承者.
在旧的 Magit-Popup 菜单中, 可以通过在弹出 buffer 中使用 C-c C-c 来保存用户设置 (例如, 设置 commits 的 gpg 签名密钥). 这将关闭弹出窗口, 但保存设置作为未来弹出窗口的默认值.
当切换到 Transient 菜单时, 此功能现在改为通过 C-x C-s 提供; 当使用 Transient 时, C-x 前缀还有其他选项, 键入时会显示. 有关更多详细信息, 请参阅 https://magit.vc/manual/transient/Saving-Values.html#Saving-Values.
12. 11 调试工具 (Debugging Tools)
Magit 及其依赖项提供了一些调试工具, 如果你在报告问题之前使用这些工具, 我们将非常感激. 报告问题时请包含所有相关输出.
M-x magit-version此命令在 echo area 中显示当前使用的 Magit, Git 和 Emacs 版本. 非交互式地这只返回 Magit 版本.M-x magit-emacs-Q-command此命令在 echo area 中显示调试 shell 命令并将其添加到 kill ring. 将该命令粘贴到 shell 中并运行它. 此 shell 命令启动仅加载 magit 及其依赖项的 emacs. 不加载你的配置或其他已安装的包. 这使得更容易确定问题是出在 Magit 还是其他东西上. 如果你从其 Git 仓库运行 Magit, 那么你应该能够使用make emacs-Q代替此命令的输出.M-x magit-toggle-git-debug此命令切换是否报告额外的 git 错误. Magit 基本上出于两个原因之一调用 git: 为了副作用或对其标准输出做某事. 当运行 git 产生副作用时, 其输出 (包括错误消息) 进入 process buffer, 使用$时会显示该 buffer. 当 git 的输出以某种方式被消耗时, 将其也插入此 buffer 会太昂贵, 但是使用此命令可以暂时启用. 在这种情况下, 如果 git 以非零退出状态返回, 那么至少将其标准错误插入此 buffer. 还要注意, 仅仅因为 git 以非零状态退出并打印错误消息, 通常并不意味着就 Magit 而言这是一个错误, 这也是我们通常隐藏这些错误消息的另一个原因. 某些错误消息是否与某些意外行为相关, 必须根据具体情况进行判断.M-x magit-toggle-verbose-refresh此命令切换 Magit 是否详细刷新 buffers. 启用此功能有助于找出哪些 sections 是瓶颈. 附加输出可以在*Messages*buffer 中找到.M-x magit-toggle-subprocess-record此命令切换是否记录子进程调用. 启用时, 由magit-process-file启动的所有子进程都记录到由magit-process-record-buffer-name指定的 buffer 中, 使用格式magit-process-record-entry-format. 这是为了调试目的. 这是默认记录的补充和区别, 以及使用magit-toggle-git-debug启用的额外记录.M-x magit-debug-git-executable此命令显示一个 buffer, 其中包含有关可用和已用 git 可执行文件的信息, 并且在调查exec-path问题时很有用. 另请参见第 31 页的 [Git Executable].M-x magit-profile-refresh-buffer此命令对刷新当前 Magit buffer 进行性能分析, 然后显示结果.M-x magit-toggle-profiling此命令开始对 Magit 和 Forge 进行性能分析, 或者如果性能分析已经在进行中, 则停止并显示结果.M-x with-editor-debug此命令显示一个 buffer, 其中包含有关可用和已用emacsclient可执行文件的信息, 并且在调查为什么 Magit (或更确切地说是with-editor) 找不到合适的emacsclient可执行文件时很有用. 另请参见with-editor中的 "Debugging" 一节.
请同时参阅第 143 页的附录 A [FAQ].
13. 附录 B 按键索引 (Keystroke Index)
(此处为自动生成的按键索引, 翻译中省略具体条目, 建议在 Emacs 中查看)
14. 附录 C 函数和命令索引 (Function and Command Index)
(此处为自动生成的函数和命令索引, 翻译中省略具体条目, 建议在 Emacs 中查看)
15. 附录 D 变量索引 (Variable Index)
(此处为自动生成的变量索引, 翻译中省略具体条目, 建议在 Emacs 中查看)
Footnotes:
patch-id 是 commit 引入的更改的 hash. 它不同于 commit 本身的 hash, 后者是应用该更改的结果 (即结果 trees 和 blobs) 以及作者和提交者信息, 提交消息和 commit 父级 hashes 的 hash. 另一方面, patch-id hash 仅从添加和删除的行创建, 计算此 hash 时甚至忽略行号和空白更改. 两个 commits 的 patch-ids 可用于回答问题 "这些 commits 是否做了相同的更改?".