【问题标题】:How to do a non-fast-forward git merge to a branch that isn't checked out?如何对未签出的分支进行非快进 git 合并?
【发布时间】:2012-05-25 03:21:26
【问题描述】:

我在分支a。我想将分支b 合并到分支c。合并不是快进,但也不需要手动解决。 (即,这不是最简单的情况,但也不是最困难的情况,因此它是 Git 无需人工即可自行完成的合并。)

有没有办法让我从 b 合并到 c 而无需检查任何分支?怎么样?

更新:如果您知道可以做到这一点的替代 Git 实现,那也是一个有效的解决方案。但是编写一个以编程方式执行结帐的脚本并不是一个好的解决方案,因为它仍然需要我有一个干净的工作目录。

【问题讨论】:

  • stackoverflow.com/questions/6548046/…(你应该可以git push bspec cspec。)
  • git push . 中的点是什么意思?
  • 另外,请注意我在我的问题中指定合并可能不是快进。这还能用吗?
  • 点的意思是“当前路径规范”,所以这就是你要放在你的分支 b 中的地方。不确定它是否适用于非快进合并,试一试,看看我猜?
  • 现在试过了,不行。但我很高兴你让我知道这个语法,它在快进的情况下对我很有用。

标签: git


【解决方案1】:

可以编写脚本,即使您的工作目录很脏。您必须先存储更改。

git stash
git checkout c
git merge b
git checkout a
git stash pop

【讨论】:

  • 我还建议使用git stash,这就是我经常使用的与 OP 所做的几乎相同的事情。
  • 在 Windows 上存储速度很慢(我正在使用它),所以不得不等待这么长时间对我没有吸引力。
  • 那我觉得没有其他选择了,反正你要合并的分支必须是当前分支。没有存储或提交,你就不能离开你当前的分支a...或者那里的一些 git 专家有更好的解决方案?
  • 不幸的是@RamRachum,我认为没有适合您的完美解决方案。你可以试试 Mercurial,我听说它在 Windows 上运行良好。
  • 我今天试了一下,听说它要出来了,但我认为它不能解决我的问题。不管我有什么问题,它都没有键盘快捷键,这对我来说是个大问题。
【解决方案2】:

鉴于您不必清理工作目录的要求,我假设您的意思是您不想清理工作树或索引,即使通过一些脚本也是如此。在这种情况下,您将无法在当前本地存储库的范围内找到解决方案。 Git 在合并时广泛使用索引。如果没有冲突,我不确定工作树,但总的来说,合并与当前签出的分支密不可分。

不过,还有另一种方法,它不需要您更改当前存储库中的任何内容。但是,它确实要求您拥有或创建您的 repo 的克隆。基本上,只需克隆您的存储库,然后在克隆中进行合并,然后将其推回原始存储库。下面是一个简短的例子来说明它是如何工作的。

首先,我们需要一个示例代码库。以下命令序列将创建一个。你最终会得到master 作为你当前的分支,另外两个分支已经准备好被合并,分别命名为change-foochange-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

简而言之,这会将当前 repo 克隆到一个子目录,进入该目录,进行合并,然后将其推送回原始 repo。完成后它会删除子目录。在大型项目中,您可能希望拥有一个保持最新状态的专用克隆,而不是每次都制作新的克隆。在合并和推送之后,我们最终得到:

$ 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

问题?

【讨论】:

  • 感谢您的广泛报道。我还在消化这个。同时有几个问题: 1. 我记得读过关于 git clone 的 3 种类型:标准、完整副本和共享。 (术语可能与 git-gui 不同。)我只使用了完整副本。我应该为此使用其他任何一种吗? 2. 听说Git也允许“裸”repos,这里没有工作目录。 Git 是否允许在此类 repos 上进行合并?如果是这样,这对于临时存储库会是一个不错的选择吗?
  • 3 种类型:浅层、裸露、“正常”。在这种情况下,不建议使用 git 存储库的浅拷贝(克隆时使用 --depth 选项)。我不保证您将能够使用浅拷贝执行 2 个分支的合并,特别是如果您错过了 2 个分支的共同父级。但是,是的,git 允许在浅克隆(不是裸存储库)上进行合并,因为您可以使用 git pull。在这种情况下,我会做一个完整/简单的克隆。
  • 关于您上面的陈述,“Git 在合并时广泛使用索引”:您是否认为有一种方法可以在 Git 将进行合并的同一个 repo 中创建一个辅助索引文件,而不是创建另一个仓库?
  • 我不会说,但这只是一个有根据的猜测。我想你可能会通过一些创造性的符号链接来逃脱,但你也有可能完全破坏你的存储库。您的要求让我认为您必须查看 Git 源代码才能获得真正的答案,这是我从未跨越的界限。对不起,我无能为力。鉴于我自己的经验和这里缺乏其他答案,我的最终建议是改变你做事的方式,这样你就不需要弄清楚如何去做。听起来很麻烦。
【解决方案3】:

如果合并不涉及两个分支上涉及的文件,那么我认为您希望 git read-treegit 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-basebc 视为完全不相关的分支,并使生成的合并合并每个中的文件,而不是将其中缺少的文件视为删除。

您说您的合并不是快进,因此您需要阅读 read-tree 文档以使上述序列完全符合您的要求。 --aggressive 看起来可能是对的,这取决于您的分支之间的实际差异。

edit 添加了空树基础来处理不相关的树 edit 2 提升一些我说过或隐含在评论中的有效负载

【讨论】:

  • 好了,我的脑洞大开。愿意解释一下你在这里做了什么吗?
  • 索引几乎只是对象数据库的缩略图,并结合了工作树中文件的时间戳。 read-tree 从指定的树加载索引。 -i 表示忽略工作树,-m 表示进行简单的合并。 write-tree 将索引状态放入 repo,commit-tree 为此提交,update-ref 更新 ref。您必须阅读有关 read-tree 合并选项的文档,此处设置的内容是在任何情况下都不会删除文件,这可能不是您想要的。如果您想传播任一分支上的删除,请取出 git mktree </dev/null 参数。
  • 好吧,我终于有时间试一试了。我只需要将I@ 修复为i@ 就可以了! (错字?)如果这可以可靠地工作,它肯定比辅助回购方法更好。现在有几个问题: 1. 我希望它使用完全标准的合并策略。可以? 2. 我们可以让它为合并创建一个标准的提交消息吗?
  • 另外,我不明白如何在 3 路合并中使用空树基础。您不需要 2 个提交的共同父项吗?
  • 另外,如果/当您执行exit 1 时,您不会留下一个肮脏的GIT_INDEX_FILE 设置吗?
【解决方案4】:

answer 解释了一个您可以尝试的解决方法。

不,没有。除其他事项外(如果 Git 无法自动合并它们),必须检查目标分支以允许您解决冲突。

但是,如果合并是快进的,则无需检查目标分支,因为您实际上不需要合并任何内容 - 您只需将分支更新为指向新的头部参考。你可以用 git branch -f:

git branch -f branch-b branch-a
将更新 branch-b 以指向 branch-a 的头部。

【讨论】:

  • (a) 他说这不是快进,(b) 这将留下破碎的历史
  • 你是对的。我误读了这个问题,因为它 IS 快进了。我的错。
  • 此外还有no安全检查。如果一开始没有快进会怎样?
【解决方案5】:

除了@jthill 提供的非常复杂的git read-tree 答案之外,还有(现在)恕我直言,使用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

【讨论】:

    猜你喜欢
    • 2015-07-22
    • 1970-01-01
    • 2020-10-20
    • 2021-08-15
    • 2021-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-15
    相关资源
    最近更新 更多