我在分支上a
。我想将分支合并b
到分支c
中。合并不是快进,但也不需要手动解决。(即,这不是最简单的情况,但也不是最困难的情况,因此它是 Git 无需人工即可自行完成的合并。)
有没有办法让我在不检查任何分支的情况下进行这种b
合并c
?如何?
更新:如果您知道可以做到这一点的替代 Git 实现,那也是一个有效的解决方案。但是编写一个以编程方式执行结帐的脚本并不是一个好的解决方案,因为它仍然需要我有一个干净的工作目录。
我在分支上a
。我想将分支合并b
到分支c
中。合并不是快进,但也不需要手动解决。(即,这不是最简单的情况,但也不是最困难的情况,因此它是 Git 无需人工即可自行完成的合并。)
有没有办法让我在不检查任何分支的情况下进行这种b
合并c
?如何?
更新:如果您知道可以做到这一点的替代 Git 实现,那也是一个有效的解决方案。但是编写一个以编程方式执行结帐的脚本并不是一个好的解决方案,因为它仍然需要我有一个干净的工作目录。
如果合并不涉及两个分支上涉及的文件,那么我认为您想要git read-tree
并git write-tree
带有边带 GIT_INDEX_FILE。这应该这样做:
#!/bin/sh
export GIT_INDEX_FILE=.git/aux-merge-index
trap 'rm -f '"'$GIT_INDEX_FILE'" 0 1 2 3 15
set -e
git read-tree -im `git merge-base $2 $1` $2 $1
git write-tree \
| xargs -i@ git commit-tree @ -p $2 -p $1 -m "Merge $1 into $2" \
| xargs git update-ref -m"Merge $1 into $2" refs/heads/$2
您也可以使用git mktree </dev/null
代替merge-base
来将b
和c
视为完全不相关的分支,并使生成的合并合并每个中的文件,而不是将其中任何一个中丢失的文件视为删除。
你说你的合并不是快进,所以你需要阅读read-tree
文档以使上面的序列完全符合你的要求。 --aggressive
看起来可能是对的,这取决于您的分支之间的实际差异是什么。
编辑添加了空树基础来处理不相关的树 编辑 2提升我说过的一些有效负载或在评论中隐含
鉴于您不必清理工作目录的要求,我假设您的意思是您不想清理工作树或索引,即使通过一些脚本也是如此。在这种情况下,您将无法在当前本地存储库的范围内找到解决方案。Git 在合并时广泛使用索引。如果没有冲突,我不确定工作树,但总的来说,合并与当前签出的分支密不可分。
但是,还有另一种方法,它不需要您更改当前存储库中的任何内容。但是,它确实要求您拥有或创建您的 repo 的克隆。基本上,只需克隆您的存储库,然后在克隆中进行合并,然后将其推回原始存储库。这是它如何工作的一个简短示例。
首先,我们需要一个示例 repo 来使用。以下命令序列将创建一个。您最终将获得master
当前分支和其他两个分支,其中的更改已准备好合并,命名为change-foo
和change-bar
.
mkdir background-merge-example
cd background-merge-example
git init
echo 'from master' > foo
echo 'from master' > bar
git add .
git commit -m "add foo and bar in master"
git checkout -b change-foo
echo 'from foo branch' >> foo
git commit -am "update foo in foo branch"
git checkout -b change-bar master
echo 'from bar branch' >> bar
git commit -am "update bar in bar branch"
git checkout master
现在,假设您正在研究master
,并且想要合并change-bar
到change-foo
. 这是我们所处位置的半图形描述:
$ git log --oneline --graph --all
* c60fd41 update bar in bar branch
| * e007aff update foo in foo branch
|/
* 77484e1 add foo and bar in master
以下序列将在不干扰当前 master 分支的情况下完成合并。把它打包成一个脚本,你就有了一个不错的“背景合并”命令:
# clone with absolute instead of relative path, or the remote in the clone will
# be wrong
git clone file://`realpath .` tmp
cd tmp
# this checkout auto-creates a remote-tracking branch in newer versions of git
# older versions will have to do it manually
git checkout change-foo
# creating a tracking branch for the other remote branch is optional
# it just makes the commit message look nicer
git branch --track change-bar origin/change-bar
git merge change-bar
git push origin change-foo
cd ..
rm -rf tmp
简而言之,这会将当前存储库克隆到子目录,进入该目录,进行合并,然后将其推送回原始存储库。完成后它会删除子目录。在大型项目中,您可能希望拥有一个保持最新状态的专用克隆,而不是每次都制作新的克隆。在合并和推送之后,我们最终得到:
$ git log --oneline --graph --all
* 24f1916 Merge branch 'change-bar' into change-foo
|\
| * d7375ac update bar in bar branch
* | fed4757 update foo in foo branch
|/
* 6880cd8 add foo and bar in master
问题?
git read-tree
除了@jthill的非常复杂的答案之外,还有(现在)恕我直言,使用git worktree
. 这是基本方法:
$ git worktree add /tmp/wt c
$ git -C /tmp/wt merge b
$ git worktree remove /tmp/wt
下面是一个小Bash脚本,您可以像这样调用它:
$ worktree-merge c b
worktree-merge
:#!/usr/bin/env bash
log() {
echo -n "LOG: "
echo "$@" >&2
}
escape() {
local string="$1"
echo "${string//[. \/]/-}"
}
cleanup() {
trap "" SIGINT
log "Removing temporary worktree '$1' ..."
git worktree remove --force "$1"
}
prepare_worktree() {
local reference="$1"
local worktree="/tmp/MERGE-INTO-`escape "$reference"`"
log "Creating temporary worktree '$worktree' ..."
trap "cleanup $worktree" EXIT
git worktree add --force "$worktree" "$reference"
}
do_merge() {
local reference="$1"
local worktree="/tmp/MERGE-INTO-`escape "$reference"`"
shift
log "Merging ${@@Q} into ${reference@Q} ..."
git -C "$worktree" merge "$@"
}
prepare_worktree "$1" &&
do_merge "$@" &&
true
即使您的工作目录很脏,您也可以编写脚本。您必须先存储您的更改。
git stash
git checkout c
git merge b
git checkout a
git stash pop
此答案解释了您可以尝试的解决方法。
不,那里没有。必须检查目标分支才能解决冲突等问题(如果 Git 无法自动合并它们)。
但是,如果合并是快进的,您不需要检查目标分支,因为您实际上不需要合并任何东西 - 您所要做的就是更新分支以指向新的首席裁判。您可以使用 git branch -f 执行此操作:
git branch -f branch-b branch-a
将更新分支 b 以指向分支 a 的头部。