fix: make git merge2 work across worktrees

Checkout of the target branch fails when it is already used by another
worktree. Detect that worktree and merge there instead.
This commit is contained in:
2026-09-10 23:04:13 +08:00
parent a834c46b89
commit 097fce7827
2 changed files with 74 additions and 1 deletions
+72
View File
@@ -0,0 +1,72 @@
#!/bin/bash
# 把当前分支 merge 进目标分支;目标已在其它 worktree 时直接在那边 merge
set -euo pipefail
usage() {
cat <<'EOF'
用法: git merge2 <branch> [git merge 参数...]
把当前分支合进 <branch>,然后留在当前分支。
若 <branch> 已在其它 worktree 里 checkout,则在那个 worktree 里 merge,
不会在当前目录 checkout(避免 "already used by worktree")。
EOF
}
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
usage
exit 0
fi
if [[ $# -lt 1 ]]; then
usage >&2
exit 1
fi
current="$(git symbolic-ref --short HEAD)"
target="$1"
shift
if [[ "$current" == "$target" ]]; then
echo "已经在 $target 上" >&2
exit 1
fi
# porcelain 含主 worktree;%(worktreepath) 只填 linked worktree,不能用
worktree_for_branch() {
local branch="$1"
local wt=""
local line
while IFS= read -r line || [[ -n "$line" ]]; do
case "$line" in
worktree\ *)
wt="${line#worktree }"
;;
"branch refs/heads/${branch}")
printf '%s\n' "$wt"
return 0
;;
"")
wt=""
;;
esac
done < <(git worktree list --porcelain)
return 1
}
# alias / 子进程会继承当前 worktree 的 GIT_DIR,必须清掉才能 git -C 到另一个 worktree
merge_in_worktree() {
local wt="$1"
shift
env -u GIT_DIR -u GIT_WORK_TREE git -C "$wt" merge "$@"
}
wt="$(worktree_for_branch "$target" || true)"
if [[ -n "$wt" ]]; then
echo "在 worktree 中 merge $current -> $target: $wt"
merge_in_worktree "$wt" "$current" "$@"
else
git checkout "$target"
git merge "$current" "$@"
git checkout "$current"
fi