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:
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 upstream/master.
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
Git checkout and merge without touching working tree
Merging without changing the working directory