
# CLI 参考手册

Pitmaster 包含一个 CLI，镜像了 git 的部分命令。它会对当前工作目录中的仓库执行操作。

```bash
./vendor/bin/pitmaster <command> [args...]
```

通过 Composer 安装时，脚本位于 `./vendor/bin/pitmaster`；自从 0.2.11 起，它会在那里找到项目的自动加载器。在 Pitmaster 仓库本身的检出目录中，请在 `composer install` 后运行 `./bin/pitmaster`。以下示例使用 `pitmaster` 表示任一路径。不带参数运行时会打印命令列表。

版本解析方式与 `Repository::resolve()` 相同：`HEAD`、分支和标签名称、完整引用名称、完整哈希，以及 `~N` / `^N` 表达式。不接受缩写哈希。克隆、获取和推送操作只能通过 PHP API 执行。

## 命令

### `log`

按时间从新到旧显示提交历史。

```bash
# Default: last 10 commits
pitmaster log

# Limit the number of commits
pitmaster log 25
pitmaster log -n 3
pitmaster log -n3
pitmaster log --max-count 3
pitmaster log --max-count=3
pitmaster log -3

# Commits that touch one file
pitmaster log src/Repository.php
pitmaster log -- src/Repository.php

# Commits reachable from all refs, and one line per commit
pitmaster log --all
pitmaster log --oneline
```

git 限制参数写法（`-n N`、`-nN`、`--max-count N`、`--max-count=N`、`-N`）是在 0.2.11 中添加的。单独的数字是 Pitmaster 对限制参数的简写。第一个其他参数是路径筛选条件；`--` 之后的所有内容都视为路径。任何以 `-` 开头的其他参数都会打印 `fatal: unrecognized argument: <arg>` 并以 128 退出。

输出包含 `commit <hash>`（黄色）、合并提交的 `Merge:` 行、带原始身份信息（姓名、电子邮件、时间戳和时区）的 `Author:`，以及缩进显示的提交消息。`--oneline` 会打印 `abc1234 Subject`。路径筛选条件只匹配一个确切的文件路径，并检查限制数量乘以五的最新提交（[#7](https://github.com/inline0/pitmaster/issues/7)）。

### `show`

显示提交详情以及与第一个父提交之间的差异。

```bash
# Show HEAD
pitmaster show

# Show a specific commit
pitmaster show HEAD~3
pitmaster show v1.0.0
pitmaster show 3f2c1e0b9d6a4f8e7c5b2a1d0e9f8c7b6a5d4e3f
```

显示提交元数据（包含一行 `Date:`），随后显示统一差异。对于带注释的标签，会先显示标签头和消息。只有当标准输出是终端时才会使用颜色。合并提交不显示差异。

### `cat-file`

打印 git 对象的原始内容。

```bash
pitmaster cat-file a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2
```

接受完整哈希。打印对象存储的内容：blob、提交和标签以文本形式显示，树则以二进制形式显示。与 `git cat-file -p` 不同，树不会以易读格式打印。

### `status`

显示工作树状态。

```bash
pitmaster status
pitmaster status --porcelain=v2
```

输出：

```
On branch main

Changes to be committed:
	new file:   src/Feature.php

Changes not staged for commit:
	modified:   src/Existing.php

Untracked files:
	notes.txt
```

已暂存文件以绿色显示；未暂存、未合并和未跟踪文件以红色显示。合并冲突期间会出现 `Unmerged paths:` 部分。分离的 HEAD 会打印 `HEAD detached`，干净的工作树会打印 `nothing to commit, working tree clean`。`--porcelain=v2` 会打印 `Repository::statusPorcelainV2()` 的输出。

### `diff`

显示索引与工作树之间的更改（未暂存的更改）。

```bash
# Unstaged changes
pitmaster diff

# Staged changes (index vs HEAD)
pitmaster diff --cached
pitmaster diff --staged

# Choose the algorithm
pitmaster diff --patience
pitmaster diff --histogram
pitmaster diff --minimal
```

输出为带颜色的统一差异，即使标准输出不是终端也是如此。对于已修改的文本文件，它与 `git diff` 格式相同；新建、删除、二进制、重命名和模式变更的文件则使用不同格式（参见 [差异](https://pitmaster.inline0.dev/zh/docs/operations/diff)）。首次提交前（[#5](https://github.com/inline0/pitmaster/issues/5)），`diff --cached` 不会打印任何内容。

### `add`

暂存文件以供下次提交。

```bash
pitmaster add src/Feature.php
pitmaster add src/Feature.php tests/FeatureTest.php README.md
```

每个文件都会从工作树读取，写入为 blob 对象，并更新索引。参数为文件路径；目录和 `.` 不会展开。

### `commit`

根据已暂存文件创建提交。

```bash
pitmaster commit -m "Add new feature"
```

输出：

```
[main abc1234] Add new feature
```

必须提供 `-m`；但完成已暂停的合并、拣选提交、还原或变基时，会使用预先准备的消息。作者和提交者信息根据环境变量、常量和 `.git/config` 确定，详见 [入门](https://pitmaster.inline0.dev/zh/docs/getting-started)。

### `branch`

列出分支或创建新分支。

```bash
# List all branches (current marked with *)
pitmaster branch

# Create a new branch from HEAD
pitmaster branch feature/new-thing

# Delete a branch
pitmaster branch -d feature/old
pitmaster branch -D feature/old
```

列表输出：

```
  bugfix/typo
  feature/login
* main
```

创建时会打印 `Created branch <name>`，删除时会打印 `Deleted branch <name>`。`-d` 和 `-D` 的行为相同：二者都不会检查分支是否已合并，也都会拒绝删除当前检出的分支。

### `tag`

列出标签或创建新标签。

```bash
# List all tags
pitmaster tag

# Create a lightweight tag at HEAD
pitmaster tag v1.0.0

# Create an annotated tag at HEAD
pitmaster tag v2.0.0 -m "Release version 2.0.0"
```

创建时会打印 `Created tag <name>`。

### `checkout`

切换分支或分离 HEAD。

```bash
# Switch to a branch
pitmaster checkout feature/login

# Detach HEAD at a tag or commit
pitmaster checkout v1.0.0
pitmaster checkout HEAD~2
```

更新 HEAD、索引和工作树，使其与目标一致，并打印 `Switched to '<target>'`。如果本地更改或未跟踪文件位于两个树之间存在差异的路径中，则操作会被拒绝。其他已跟踪文件中的未提交更改会被目标内容覆盖；而 git 会保留这些更改（[#2](https://github.com/inline0/pitmaster/issues/2)）；请先提交或暂存它们。

### `merge`

将一个或多个分支合并到当前 HEAD，或继续/中止正在进行的合并冲突处理。

```bash
# Start a merge
pitmaster merge feature/login

# Merge with a strategy
pitmaster merge -s ours feature/login

# Octopus merge of several branches
pitmaster merge feature/a feature/b

# Continue after resolving conflicts
pitmaster add a.txt
pitmaster merge --continue

# Abort and restore the pre-merge state
pitmaster merge --abort
```

成功时的输出：

```
Merge successful.
```

发生冲突时的输出（写入 stderr，退出代码为 1）：

```
CONFLICT in: src/File.php, src/Other.php
```

`-s` 接受 `ours`、`ort` 和 `recursive`；`ort` 和 `recursive` 都使用默认合并方式。使用 `-s` 时，即使合并因冲突而停止，CLI 也会打印 `Merge successful.` 并以 0 退出（[#21](https://github.com/inline0/pitmaster/issues/21)），因此之后请检查 `status`。没有正在进行的合并时，`merge --continue` 会以 128 退出。合并一个已合并的分支会创建另一个合并提交（[#6](https://github.com/inline0/pitmaster/issues/6)），已跟踪文件中的未提交更改也会像使用 `checkout` 时一样被覆盖。

### `cherry-pick`

将一个提交应用到当前 HEAD 之上，或继续/中止正在进行的冲突处理。

```bash
# Start a cherry-pick
pitmaster cherry-pick feature~1

# Continue after resolving conflicts
pitmaster add a.txt
pitmaster cherry-pick --continue

# Abort and restore HEAD
pitmaster cherry-pick --abort
```

成功时不打印任何内容。没有正在进行的拣选提交时，`--continue` 和 `--abort` 会以 128 退出。

### `revert`

创建还原提交，或继续/中止正在进行的冲突处理。

```bash
# Start a revert
pitmaster revert HEAD~1

# Continue after resolving conflicts
pitmaster add a.txt
pitmaster revert --continue

# Abort and restore HEAD
pitmaster revert --abort
```

成功时不打印任何内容。没有正在进行的还原时，`--continue` 和 `--abort` 会以 128 退出。

### `rebase`

将当前分支变基到另一个引用之上。

```bash
# Start a rebase
pitmaster rebase main

# Continue after resolving conflicts
pitmaster rebase --continue

# Skip the current commit
pitmaster rebase --skip

# Abort and restore the original branch tip
pitmaster rebase --abort
```

成功时不打印任何内容。没有正在进行的变基时，`--continue`、`--skip` 和 `--abort` 会打印 `fatal: no rebase in progress` 并以 128 退出。

### `bisect`

通过二分查找定位引入更改的提交。

```bash
# Start with a bad and a good revision; checks out and prints the first candidate
pitmaster bisect start HEAD v1.0.0

# Mark the checked-out candidate (or a given revision)
pitmaster bisect good
pitmaster bisect bad
pitmaster bisect bad HEAD~3

# End the session and return to the starting branch
pitmaster bisect reset
```

`start`、`good` 和 `bad` 会打印下一个候选项的完整哈希，并检出该候选项。只剩一个可疑提交时，会再次打印同一哈希：该提交就是第一个有问题的提交。与 git 不同，不会打印“is the first bad commit”摘要。

### `stash`

保存和恢复工作目录中的更改。

```bash
# Save current changes (push)
pitmaster stash
pitmaster stash push
pitmaster stash push "Work in progress on login"
pitmaster stash save "Work in progress on login"

# Apply and remove the top stash entry
pitmaster stash pop

# Apply without removing
pitmaster stash apply

# List stash entries
pitmaster stash list

# Drop the top stash entry
pitmaster stash drop
```

消息是 `push` 或 `save` 后面的参数；不支持 `-m`，它会作为消息存储。`pop`、`apply` 和 `drop` 始终使用 `stash@{0}`。它们会打印 `Saved working directory to stash abc1234`、`Applied and dropped stash`、`Applied stash` 和 `Dropped stash`。

暂存列表输出：

```
stash@{0}: On main: Work in progress on login
stash@{1}: WIP on main: abc1234 Add new feature
```

有多个条目时，`drop` 和 `pop` 目前会将条目保留在列表中（[#10](https://github.com/inline0/pitmaster/issues/10)）；`apply` 会覆盖暂存项未涉及文件中的未提交更改（[#11](https://github.com/inline0/pitmaster/issues/11)）。

### `blame`

显示 HEAD 中某个文件逐行对应的作者信息。

```bash
pitmaster blame src/Repository.php
```

输出：

```
a1b2c3d4 (Jane Smith <jane@example.com> ) <?php
a1b2c3d4 (Jane Smith <jane@example.com> )
f5e6d7c8 (Ann Lee <ann@example.com> 1700) declare(strict_types=1);
```

每行显示提交哈希的前 8 个字符和作者身份信息（`Name <email> timestamp timezone`）的前 30 个字符，不足部分不填充。

### `grep`

在当前 HEAD 树中搜索文件内容。

```bash
pitmaster grep "function merge"
pitmaster grep -i -E "h.llo"
```

输出：

```
src/Repository.php:2257:    public function merge(string $branch, string $strategy = 'recursive'): MergeResult
src/Merge/ThreeWayMerge.php:23:    public static function merge(
```

选项必须放在模式之前：

- `-i`、`--ignore-case`：不区分大小写匹配
- `-E`、`--extended-regexp`、`--regex`：将模式视为 PCRE 正则表达式

输出为纯 `path:line:content`，不含颜色。

### `reflog`

按时间从新到旧显示引用日志条目。

```bash
# HEAD reflog (default: 10 entries)
pitmaster reflog

# Another ref, a custom limit, and a format
pitmaster reflog show refs/heads/main
pitmaster reflog -n 5
pitmaster reflog --format="%h %gs"
```

默认格式为 `%gd: %gs`（`HEAD@{0}: commit: Add feature`）。支持的占位符：`%gd` 和 `%gD`（选择器）、`%gs`（消息）、`%H` 和 `%h`（完整和短格式的新哈希）。限制参数接受 `-n N`、`-nN` 和 `--max-count N`；`-n 0` 会打印所有条目。

`pitmaster init` 创建的仓库不会记录引用日志，除非在 `.git/config` 中将 `core.logallrefupdates` 设为 `true`（[#8](https://github.com/inline0/pitmaster/issues/8)）；因此，在启用该设置之前，`reflog` 在这些仓库中不会打印任何内容。

### `refs`

列出所有引用及其哈希。

```bash
pitmaster refs
```

输出：

```
abc123def456... refs/heads/main
789012abc345... refs/heads/feature/login
def456789012... refs/tags/v1.0.0
```

哈希以完整形式打印。

### `reset`

将 HEAD 重置到指定提交。

```bash
# Mixed reset (HEAD + index, default)
pitmaster reset HEAD~1
pitmaster reset --mixed HEAD~1

# Soft reset (HEAD only)
pitmaster reset --soft HEAD~1

# Hard reset (HEAD + index + worktree)
pitmaster reset --hard HEAD~3
```

必须提供一个版本。输出：

```
HEAD is now at abc1234
```

### `init`

初始化新仓库。这是唯一不需要已有仓库的命令。

```bash
# Initialize in the current directory
pitmaster init

# Initialize at a specific path
pitmaster init /path/to/new-project

# Create a SHA-256 repository
pitmaster init --object-format=sha256
pitmaster init /path/to/new-project --object-format=sha256
```

输出：

```
Initialized empty Pitmaster repository in /path/to/new-project/.git/
```

`--object-format` 接受 `sha1`（默认值）和 `sha256`。

## 退出代码

| 代码 | 含义 |
|------|---------|
| 0 | 成功 |
| 1 | 命令错误：用法错误、未知命令、操作失败（`error: <message>`），或合并因冲突而停止 |
| 128 | 不是 git 仓库（`fatal: <message>`）、无法识别的 `log` 参数，或在没有操作进行时使用 `--continue` / `--abort` / `--skip` |
