From 097fce7827f5444e86ab05b3a32e269cc40e6028 Mon Sep 17 00:00:00 2001 From: laily Date: Thu, 10 Sep 2026 23:04:13 +0800 Subject: [PATCH] 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. --- git/.gitconfig | 3 +- git/git-merge2.sh | 72 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 1 deletion(-) create mode 100755 git/git-merge2.sh diff --git a/git/.gitconfig b/git/.gitconfig index e78c2e2..654866f 100644 --- a/git/.gitconfig +++ b/git/.gitconfig @@ -73,7 +73,8 @@ pt = push origin --tags ph = push origin HEAD pht = push origin --tags - merge2 = !sh -c '_CURRENT_BRANCH=$(git symbolic-ref --short HEAD) && git checkout $1 && git merge $_CURRENT_BRANCH && git checkout $_CURRENT_BRANCH' - + # 把当前分支合进目标分支后回到当前分支;目标已被其它 worktree 占用时在那边 merge + merge2 = !$HOME/.dotfile/git/git-merge2.sh bg = "!f() { git branch | grep $1; }; f" delbr = "!f(){ git branch -D $(git branch | grep \"\b$1\"); };f" can = commit --amend --no-edit diff --git a/git/git-merge2.sh b/git/git-merge2.sh new file mode 100755 index 0000000..3b25d6c --- /dev/null +++ b/git/git-merge2.sh @@ -0,0 +1,72 @@ +#!/bin/bash +# 把当前分支 merge 进目标分支;目标已在其它 worktree 时直接在那边 merge +set -euo pipefail + +usage() { + cat <<'EOF' +用法: git merge2 [git merge 参数...] + +把当前分支合进 ,然后留在当前分支。 + +若 已在其它 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