Merge, update, and pull Git branches without using checkouts

前端 未结 17 1403
臣服心动
臣服心动 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:09

    just to pull the master without checking out the master I use

    git fetch origin master:master

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

    If you want to keep the same tree as one of the branch you want to merge (ie. not a real "merge"), you can do it like this.

    # Check if you can fast-forward
    if git merge-base --is-ancestor a b; then
        git update-ref refs/heads/a refs/heads/b
        exit
    fi
    
    # Else, create a "merge" commit
    commit="$(git commit-tree -p a -p b -m "merge b into a" "$(git show -s --pretty=format:%T b)")"
    # And update the branch to point to that commit
    git update-ref refs/heads/a "$commit"
    
    0 讨论(0)
  • 2020-11-22 08:18

    Another way to effectively do this is:

    git fetch
    git branch -d branchB
    git branch -t branchB origin/branchB
    

    Because it's a lower case -d, it will only delete it if the data will still exist somewhere. It's similar to @kkoehne's answer except it doesn't force. Because of the -t it will set up the remote again.

    I had a slightly different need than OP, which was to create a new feature branch off develop (or master), after merging a pull request. That can be accomplished in a one-liner without force, but it doesn't update the local develop branch. It's just a matter of checking out a new branch and having it be based off origin/develop:

    git checkout -b new-feature origin/develop
    
    0 讨论(0)
  • 2020-11-22 08:21

    The Short Answer

    As long as you're doing a fast-forward merge, then you can simply use

    git fetch <remote> <sourceBranch>:<destinationBranch>
    

    Examples:

    # Merge local branch foo into local branch master,
    # without having to checkout master first.
    # Here `.` means to use the local repository as the "remote":
    git fetch . foo:master
    
    # Merge remote branch origin/foo into local branch foo,
    # without having to checkout foo first:
    git fetch origin foo:foo
    

    While Amber's answer will also work in fast-forward cases, using git fetch in this way instead is a little safer than just force-moving the branch reference, since git fetch will automatically prevent accidental non-fast-forwards as long as you don't use + in the refspec.

    The Long Answer

    You cannot merge a branch B into branch A without checking out A first if it would result in a non-fast-forward merge. This is because a working copy is needed to resolve any potential conflicts.

    However, in the case of fast-forward merges, this is possible, because such merges can never result in conflicts, by definition. To do this without checking out a branch first, you can use git fetch with a refspec.

    Here's an example of updating master (disallowing non-fast-forward changes) if you have another branch feature checked out:

    git fetch upstream master:master
    

    This use-case is so common, that you'll probably want to make an alias for it in your git configuration file, like this one:

    [alias]
        sync = !sh -c 'git checkout --quiet HEAD; git fetch upstream master:master; git checkout --quiet -'
    

    What this alias does is the following:

    1. git checkout HEAD: this puts your working copy into a detached-head state. This is useful if you want to update master while you happen to have it checked-out. I think it was necessary to do with because otherwise the branch reference for master won't move, but I don't remember if that's really right off-the-top of my head.

    2. git fetch upstream master:master: this fast-forwards your local master to the same place as upstream/master.

    3. git checkout - checks out your previously checked-out branch (that's what the - does in this case).

    The syntax of git fetch for (non-)fast-forward merges

    If you want the fetch command to fail if the update is non-fast-forward, then you simply use a refspec of the form

    git fetch <remote> <remoteBranch>:<localBranch>
    

    If you want to allow non-fast-forward updates, then you add a + to the front of the refspec:

    git fetch <remote> +<remoteBranch>:<localBranch>
    

    Note that you can pass your local repo as the "remote" parameter using .:

    git fetch . <sourceBranch>:<destinationBranch>
    

    The Documentation

    From the git fetch documentation that explains this syntax (emphasis mine):

    <refspec>

    The format of a <refspec> parameter is an optional plus +, followed by the source ref <src>, followed by a colon :, followed by the destination ref <dst>.

    The remote ref that matches <src> is fetched, and if <dst> is not empty string, the local ref that matches it is fast-forwarded using <src>. If the optional plus + is used, the local ref is updated even if it does not result in a fast-forward update.

    See Also

    1. Git checkout and merge without touching working tree

    2. Merging without changing the working directory

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

    Another, admittedly pretty brute way is to just re-create the branch:

    git fetch remote
    git branch -f localbranch remote/remotebranch
    

    This throws away the local outdated branch and re-creates one with the same name, so use with care ...

    0 讨论(0)
  • In your case you can use

    git fetch origin branchB:branchB
    

    which does what you want (assuming the merge is fast-forward). If the branch can't be updated because it requires a non-fast-forward merge, then this fails safely with a message.

    This form of fetch has some more useful options too:

    git fetch <remote> <sourceBranch>:<destinationBranch>
    

    Note that <remote> can be a local repository, and <sourceBranch> can be a tracking branch. So you can update a local branch, even if it's not checked out, without accessing the network.

    Currently, my upstream server access is via a slow VPN, so I periodically connect, git fetch to update all remotes, and then disconnect. Then if, say, the remote master has changed, I can do

    git fetch . remotes/origin/master:master
    

    to safely bring my local master up to date, even if I currently have some other branch checked out. No network access required.

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