KernelRanch
返回文章列表

手上改动还没提交,怎么在另一分支复现故障?用 Git worktree

2026-11-13 #git#workflow#debugging

当前分支有未提交的工作时,可以用 git worktree add 在另一个目录检出用于排障的分支。两个工作树共用同一个仓库的提交和分支引用,各自保留工作文件、HEAD 和暂存区。可以一边复现故障,一边保留原来的暂存内容。

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

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

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")
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-worktreehttps://git-scm.com/docs/git-worktree2026-11-13add、list、remove,以及共享引用和工作树私有状态

核验说明

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