Merge, update, and pull Git branches without using checkouts

前端 未结 17 1375
臣服心动
臣服心动 2020-11-22 07:42

I work on a project that has 2 branches, A and B. I typically work on branch A, and merge stuff from branch B. For the merging, I would typically do:

git mer         


        
相关标签:
17条回答
  • 2020-11-22 08:27

    For many cases (such as merging), you can just use the remote branch without having to update the local tracking branch. Adding a message in the reflog sounds like overkill and will stop it being quicker. To make it easier to recover, add the following into your git config

    [core]
        logallrefupdates=true
    

    Then type

    git reflog show mybranch
    

    to see the recent history for your branch

    0 讨论(0)
  • 2020-11-22 08:28

    You can simply git pull origin branchB into your branchA and git will do the trick for you.

    0 讨论(0)
  • 2020-11-22 08:29

    It is absolutely possible to do any merge, even non-fast forward merges, without git checkout. The worktree answer by @grego is a good hint. To expand on that:

    cd local_repo
    git worktree add _master_wt master
    cd _master_wt
    git pull origin master:master
    git merge --no-ff -m "merging workbranch" my_work_branch
    cd ..
    git worktree remove _master_wt
    

    You have now merged the local work branch to the local master branch without switching your checkout.

    0 讨论(0)
  • 2020-11-22 08:30

    As Amber said, fast-forward merges are the only case in which you could conceivably do this. Any other merge conceivably needs to go through the whole three-way merge, applying patches, resolving conflicts deal - and that means there need to be files around.

    I happen to have a script around I use for exactly this: doing fast-forward merges without touching the work tree (unless you're merging into HEAD). It's a little long, because it's at least a bit robust - it checks to make sure that the merge would be a fast-forward, then performs it without checking out the branch, but producing the same results as if you had - you see the diff --stat summary of changes, and the entry in the reflog is exactly like a fast forward merge, instead of the "reset" one you get if you use branch -f. If you name it git-merge-ff and drop it in your bin directory, you can call it as a git command: git merge-ff.

    #!/bin/bash
    
    _usage() {
        echo "Usage: git merge-ff <branch> <committish-to-merge>" 1>&2
        exit 1
    }
    
    _merge_ff() {
        branch="$1"
        commit="$2"
    
        branch_orig_hash="$(git show-ref -s --verify refs/heads/$branch 2> /dev/null)"
        if [ $? -ne 0 ]; then
            echo "Error: unknown branch $branch" 1>&2
            _usage
        fi
    
        commit_orig_hash="$(git rev-parse --verify $commit 2> /dev/null)"
        if [ $? -ne 0 ]; then
            echo "Error: unknown revision $commit" 1>&2
            _usage
        fi
    
        if [ "$(git symbolic-ref HEAD)" = "refs/heads/$branch" ]; then
            git merge $quiet --ff-only "$commit"
        else
            if [ "$(git merge-base $branch_orig_hash $commit_orig_hash)" != "$branch_orig_hash" ]; then
                echo "Error: merging $commit into $branch would not be a fast-forward" 1>&2
                exit 1
            fi
            echo "Updating ${branch_orig_hash:0:7}..${commit_orig_hash:0:7}"
            if git update-ref -m "merge $commit: Fast forward" "refs/heads/$branch" "$commit_orig_hash" "$branch_orig_hash"; then
                if [ -z $quiet ]; then
                    echo "Fast forward"
                    git diff --stat "$branch@{1}" "$branch"
                fi
            else
                echo "Error: fast forward using update-ref failed" 1>&2
            fi
        fi
    }
    
    while getopts "q" opt; do
        case $opt in
            q ) quiet="-q";;
            * ) ;;
        esac
    done
    shift $((OPTIND-1))
    
    case $# in
        2 ) _merge_ff "$1" "$2";;
        * ) _usage
    esac
    

    P.S. If anyone sees any issues with that script, please comment! It was a write-and-forget job, but I'd be happy to improve it.

    0 讨论(0)
  • 2020-11-22 08:30

    You can only do this if the merge is a fast-forward. If it's not, then git needs to have the files checked out so it can merge them!

    To do it for a fast-forward only:

    git fetch <branch that would be pulled for branchB>
    git update-ref -m "merge <commit>: Fast forward" refs/heads/<branch> <commit>
    

    where <commit> is the fetched commit, the one you want to fast-forward to. This is basically like using git branch -f to move the branch, except it also records it in the reflog as if you actually did the merge.

    Please, please, please don't do this for something that's not a fast-forward, or you'll just be resetting your branch to the other commit. (To check, see if git merge-base <branch> <commit> gives the branch's SHA1.)

    0 讨论(0)
  • 2020-11-22 08:31

    Enter git-forward-merge:

    Without needing to checkout destination, git-forward-merge <source> <destination> merges source into destination branch.

    https://github.com/schuyler1d/git-forward-merge

    Only works for automatic merges, if there are conflicts you need to use the regular merge.

    0 讨论(0)
提交回复
热议问题