How to do a non-fast-forward git merge to a branch that isn't checked out?

前端 未结 5 1841
误落风尘
误落风尘 2021-01-04 11:31

I\'m on branch a. I want to merge branch b into branch c. The merge is not a fast-forward, but it also doesn\'t require manual resolut

5条回答
  •  猫巷女王i
    2021-01-04 12:28

    Given your requirement to not have to clean your working directory, I assume you mean that you don't want to have to clean either your working tree or index, even via some scripting. In that case, you won't find a solution within the bounds of your current local repo. Git uses the index extensively when merging. I'm not sure about the working tree if there are no conflicts, but in general, merging is inextricably tied to the currently-checked-out branch.

    There's another way, though, that wouldn't require you to change anything in your current repo. It does, however, require you to have or create a clone of your repo. Basically, just clone your repo, then do your merge in the clone, and push it back to your original repo. Here's a brief example of how it would work.

    First, we need a sample repo to work with. The following sequence of commands will create one. You'll end up with master as your current branch and two other branches with changes ready to be merged named change-foo and 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
    

    Now, imagine that you're working on master, and you're wanting to merge change-bar into change-foo. Here's a semi-graphical depiction of where we are:

    $ git log --oneline --graph --all
    * c60fd41 update bar in bar branch
    | * e007aff update foo in foo branch
    |/  
    * 77484e1 add foo and bar in master
    

    The following sequence will accomplish the merge without interfering with the current master branch. Pack this into a script, and you've got a nice "background-merge" command:

    # 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
    

    Briefly, that will clone the current repo to a subdirectory, enter that directory, do the merge, then push it back to the original repo. It removes the subdirectory after it's done. In a large project, you might want to have a dedicated clone that's just kept up to date instead of making a fresh clone every time. After the merge and push, we end up at:

    $ 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
    

    Questions?

提交回复
热议问题