如何将非快进git合并到未检出的分支?

时间:2012-05-17 14:23:58

标签: git

我在分行a。我想将分支b合并到分支c中。合并不是快进,但也不需要手动解决。 (也就是说,这不是最简单的情况,但它也不是最困难的情况,因此它是Git能够独立完成而不需要人类的合并。)

我有没有办法从bc进行合并,而无需查看任何分支?怎么样?

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

5 个答案:

答案 0 :(得分:8)

如果合并不涉及两个分支上触及的文件,那么我认为您希望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看起来可能是正确的,这取决于您的分支之间的实际差异。

编辑添加了空树基,以处理不相关的树 编辑2 提升我在评论中隐含或隐含的一些有效负载

答案 1 :(得分:5)

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

但是,还有另外一种方法,不需要你改变当前仓库中的任何东西。但是,它确实要求您拥有或创建回购的克隆。基本上,只需克隆您的仓库,然后在克隆中进行合并,然后将其推回到原始仓库。以下是它如何运作的简短示例。

首先,我们需要一个样本仓库来处理。以下命令序列将创建一个。您最终会以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

以下序列将完成合并,而不会干扰当前主分支。把它打包成一个脚本,你有一个很好的“后台合并”命令:

# 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

有问题吗?

答案 2 :(得分:3)

除了@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

答案 3 :(得分:1)

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

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

答案 4 :(得分:-1)

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

  

不,没有。检查目标分支是必要的,以便您解决冲突,以及其他事情(如果Git无法自动合并它们)。

     

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

来做到这一点      

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