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 merge origin/branchB
However, I would also like to keep a local copy of branch B, as I may occasionally check out the branch without first merging with my branch A. For this, I would do:
git checkout branchB
git checkout branchA
Is there a way to do the above in one command, and without having to switch branch back and forth? Should I be using
git update-ref for that? How?
The Short Answer
As long as you're doing a fast-forward merge, then you can simply use
git fetch <remote> <sourceBranch>:<destinationBranch>
# 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:
sync = !sh -c 'git checkout --quiet HEAD; git fetch upstream master:master; git checkout --quiet -'
What this alias does is the following:
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.
git fetch upstream master:master: this fast-forwards your local
master to the same place as
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>
git fetch documentation that explains this syntax (emphasis mine):
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
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.
Git checkout and merge without touching working tree
Merging without changing the working directory