---
title: "手上改动还没提交，怎么在另一分支复现故障？用 Git worktree"
date: 2026-11-13
slug: git-linked-worktree-isolation
canonical: https://kernelranch.com/blog/2026/11/git-linked-worktree-isolation
markdown_url: https://kernelranch.com/blog/2026/11/git-linked-worktree-isolation.md
tags: ["git", "workflow", "debugging"]
---当前分支有未提交的工作时，可以用 `git worktree add` 在另一个目录检出用于排障的分支。两个工作树共用同一个仓库的提交和分支引用，各自保留工作文件、HEAD 和暂存区。可以一边复现故障，一边保留原来的暂存内容。

## 1. 比较两个工作树的暂存区

将代码保存为 `worktree_lab.py`，用 Python 运行，需 Git。脚本只在临时目录创建仓库和链接工作树。

```python
from pathlib import Path
import subprocess
from tempfile import TemporaryDirectory

with TemporaryDirectory() as tmp:
    root = Path(tmp)
    main = root / "main"
    repair = root / "repair"
    main.mkdir()

    def git(cwd, *args, check=True):
        return subprocess.run(
            ["git", *args], cwd=cwd, capture_output=True, text=True, check=check
        )

    git(main, "init", "-q", "-b", "main")
    git(main, "-c", "user.name=Demo", "-c", "user.email=demo@example.com",
        "-c", "commit.gpgsign=false", "commit", "--allow-empty", "-qm", "base")
    (main / "notes.txt").write_text("draft\n", encoding="utf-8")
    git(main, "add", "notes.txt")

    git(main, "worktree", "add", "-q", "-b", "repair", str(repair), "HEAD")
    assert not (repair / "notes.txt").exists()
    assert git(main, "diff", "--cached", "--name-only").stdout.strip() == "notes.txt"
    assert not git(repair, "diff", "--cached", "--name-only").stdout.strip()
    print("main: notes.txt staged; repair: index clean")

    branch = git(repair, "branch", "--show-current").stdout.strip()
    assert branch == "repair"
    assert git(main, "show-ref", "--verify", "refs/heads/repair").returncode == 0
    blocked = git(main, "switch", "repair", check=False)
    assert blocked.returncode != 0
    assert git(main, "branch", "--show-current").stdout.strip() == "main"
    print("repair branch shared; second checkout blocked")

    git(main, "worktree", "remove", str(repair))
    assert git(main, "show-ref", "--verify", "refs/heads/repair").returncode == 0
    print("repair worktree removed; branch still exists")
```

```text
main: notes.txt staged; repair: index clean
repair branch shared; second checkout blocked
repair worktree removed; branch still exists
```

## 2. 选择分支工作树或分离 HEAD

要在排障过程中提交修复，可以用 `git worktree add -b fix-login ../fix-login <基线>`。只想查看发布标签或运行测试时，可用 `git worktree add --detach ../check-release <标签>`。已在其他工作树检出的分支默认不能再次检出，遇到拒绝时用 `git worktree list` 找到它所在的目录。

在排障目录完成后，先检查 `git status --short`，确认需要的改动已提交或保留，再用 `git worktree remove <目录>` 清理登记和工作文件。随后分支仍存在，可按正常流程合并。各工作树中被忽略的依赖和构建文件通常需要各自准备，实验中的仓库没有这类依赖。

## 小结

同一个仓库可以有多份工作树。用各自的目录和暂存区并行处理改动，用共享分支引用合并成果。

## 数据来源与检索时间

| 来源 | URL | 检索日期 | 对应内容 |
|---|---|---|---|
| Git git-worktree | https://git-scm.com/docs/git-worktree | 2026-11-13 | add、list、remove，以及共享引用和工作树私有状态 |

## 核验说明

- Windows、Python 3.11.9、Git 2.54.0.windows.1 实测暂存隔离、重复检出拒绝及清理后分支仍存在。
