20

In a repo I have multiple branches, among them "master" and "develop", which are set up to track remote branches "origin/master" and "origin/develop".

Is it possible to specify that I want both master and develop to be merged(fast-forwarded) at once?

When I do git pull now I get something like this:

remote: Counting objects: 92, done.
remote: Compressing objects: 100% (56/56), done.
remote: Total 70 (delta 29), reused 28 (delta 8)
Unpacking objects: 100% (70/70), done.
From scm.my-site.com:my-repo
   5386563..902fb45  develop    -> origin/develop
   d637d67..ba81fb2  master     -> origin/master
Updating 5386563..902fb45
Fast-forward

all the remote branches are fetched, but only the branch I'm currently on is merged with its corresponding remote branch.

So I have to do git checkout master ...

Switched to branch 'master'
Your branch is behind 'origin/master' by 106 commits, and can be fast-forwarded.

...and then git pull again, and then switch back to develop, to get the desired result.

I know I can make aliases/scripts that does these steps. But I want to avoid that if possible, as it is error prone and not very efficient.
Edit: ok let me rephrase that. My goal was not to discourage or frown upon script/alias customizing of git. I would just prefer a builtin solution if it exists :)

3
  • I tried git pull origin refs/heads/develop:refs/remotes/origin/develop refs/heads/master:refs/remotes/origin/master but that caused the remote master to be merged into develop..
    – Superole
    Jul 23, 2013 at 15:44
  • 1
    Why would it be error-prone or inefficient? Git is intended to be customized like this. BTW, to avoid having to check out each branch, you may want to split your pull into a fetch followed by a merge into each branch.
    – jjlin
    Jul 23, 2013 at 19:53
  • @jjlin well if I can do it without checking out each branch that may help on the efficiency. It is error prone because the matrix of things that can go wrong and the effects it can have on the rest of the script is somewhat complex. I'm not saying it's infeasible to make it safe, but it would be a trade-off. So I'd prefer a builtin solution if it exists :)
    – Superole
    Jul 24, 2013 at 7:39

4 Answers 4

15

You can set up an alias that uses git fetch with refspecs to fast-forward merge your branches with just one command. Set this up as an alias in your user .gitconfig file:

[alias]
    sync = "!sh -c 'git checkout --quiet --detach HEAD && \
                    git fetch origin master:master develop:develop ; \
                    git checkout --quiet -'"

Usage: git sync.

Here is why it works:

  1. git checkout --quiet HEAD directly checks out your current commit, putting you into detached head state. This way, if you're on master or develop, you detach your working copy from those branch pointers, allowing them to be moved (Git won't allow you to move the branch references while your working copy has them checked out).

  2. git fetch origin master:master develop:develop uses refspecs with fetch to fast-forward the master and develop branches in your local repo. The syntax basically tells Git "here is a refspec of the form <source>:<destination>, take <destination> and fast-forward it to the same point as <source>". So the sources in the alias are the branches from origin, while the destinations are the local repo versions of those branches.

  3. Finally, git checkout --quiet - checks out the branch you were last on, regardless of whether or not there was a failure in the previous commands. So if you were on master when you ran git sync, and everything succeeds, you'll leave detached head state and check out the newly updated master.

See also my answer to git: update a local branch without checking it out?.

5
  • I don't quite understand the detached-magic here, why can't the pointer to master be moved when develop is checked out? ...anyway I tried this, and it seems to work except now I get "Your branch is ahead of 'origin/develop' by 1 commit."
    – Superole
    Aug 6, 2013 at 8:06
  • ...which is solved the next time I pull
    – Superole
    Aug 6, 2013 at 8:08
  • @Superole which branch is ahead of origin/develop when you use the alias? It wouldn't make sense if it was your local develop branch. Also, the pointer for master can be moved if it's develop that is checked out, the point is that if it's master that is checked out, then you can't fast-forward master because that would affect your working copy, so that's why you detach the working copy from it first by using git checkout head. I saw another answer that described it as "standing on a rock", you have to get off the rock before you can move it. Aug 6, 2013 at 8:24
  • it was indeed my local develop. And the reason must be that this fetch does not update the tracking branches. As I understand it; a pull will fetch into origin/develop, and then merge that into develop.
    – Superole
    Aug 8, 2013 at 9:31
  • It is very important that this answer causes fatal: bad config line xx in file xxx. which is caused by the semicolon. you have to wrap the whole command in double quote to avoid this issue. Feb 14, 2017 at 3:57
2

Install git-up. It gives you the command git-up which will pull all local branches in your repository.

3
  • sweet! I will check that out for sure.
    – Superole
    Nov 27, 2015 at 14:01
  • 3
    heh :P The statements Windows support is predictably absent. and a rigorous proof has yet to be formulated that it will definitely not mess with your git setup, delete data or post inane drivel to Hacker News on your behalf., combined with the need for Ruby, drove me away. I like the concept though.
    – Superole
    Nov 27, 2015 at 15:30
  • Glad there's a method at all ... kinda sucky, though that every single method requires some third-party tool. Such as this one and the ones with some shell command "recipe" or an alias making use of a particular (platform-specific) shell. Feb 14, 2018 at 18:48
2
git fetch --update-head-ok origin master:master develop:develop

This is a shorter version of @40XUserNotFound answer, beware that it may move your HEAD, be sure you have a clean working directory before running this command.

--update-head-ok does what this answer doing by detaching HEAD, instead it simply tells fetch it's ok to move HEAD (where your working directory is).

2
  • 1
    Cool! This looks like it's working! I wonder why they state in the docs that this is purely for the internal use for git pull to communicate with git fetch, and unless you are implementing your own Porcelain you are not supposed to use it?
    – Superole
    Apr 15, 2021 at 13:39
  • I think it is because it might result in data lost, it moves the HEAD without checking if it in sync with upstream repo. But the provided answer does the same, so I think it is cool to use for this specific case
    – PMN
    Apr 19, 2021 at 16:01
1

It seems that there is no builtin option for git to pull into multiple branches. At least not in version 1.8.0. although @Cupcake's answer is close to it.

However @jjlin's comment made me realize that at least I don't need to pull twice.

So a slightly more efficient sequence would be:

git pull
git checkout master
git merge origin/master
git checkout -

Inevitably I ended up creating an alias, but decided to leave the pull out of it, and focused on just fast-forwarding a different branch.

[alias]
ffwd = "!_() { git checkout $1 && git merge --ff-only origin/$1 && git checkout -; }; _"

Of course, with no testing this alias assumes that I supply a valid name of a ff'able branch as 1st argument, and has undefined behaviour otherwise. It is also not optimal for use-cases with more than two branches, but it will get me what I need for now.

git pull
git ffwd master

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.