I often have at least 3 remote branches: master, staging and production. I have 3 local branches that track those remote branches.
Updating all my local branches is tedious:
git fetch --all
git rebase origin/master
git checkout staging
git rebase origin/staging
git checkout production
git rebase origin/production
I'd love to be able to just do a "git pull -all", but I haven't been able to get it to work. It seems to do a "fetch --all", then updates (fast forward or merges) the current working branch, but not the other local branches.
I'm still stuck manually switching to each local branch and updating.
git fetch. On its own, git fetch updates all the remote tracking branches in local repository. No changes are actually reflected on any of the local working branches.
Git offers a feature referred to as a worktree, and what it does is allow you to have multiple branches running at the same time. It does this by creating a new directory for you with a copy of your git repository that is synced between the two directories where they are stored.
Use the git clone Command to Clone All Branches in Git Clone your repository with the git clone command. Then navigate to the directory where your project is located. Use the git branch command to view local branches. This command will only show you local branches.
I use the sync
subcommand of hub to automate this. I have alias git=hub
in my .bash_profile
, so the command I type is:
git sync
This updates all local branches that have a matching upstream branch. From the man page:
- If the local branch is outdated, fast-forward it;
- If the local branch contains unpushed work, warn about it;
- If the branch seems merged and its upstream branch was deleted, delete it.
It also handles stashing/unstashing uncommitted changes on the current branch.
I used to use a similar tool called git-up, but it's no longer maintained, and git sync
does almost exactly the same thing.
The behavior you describe for pull --all
is exactly as expected, though not necessarily useful. The option is passed along to git fetch, which then fetches all refs from all remotes, instead of just the needed one; pull
then merges (or in your case, rebases) the appropriate single branch.
If you want to check out other branches, you're going to have to check them out. And yes, merging (and rebasing) absolutely require a work tree, so they cannot be done without checking out the other branches. You could wrap up your described steps into a script/alias if you like, though I'd suggest joining the commands with &&
so that should one of them fail, it won't try to plow on.
I know this question is almost 3 years old, but I asked myself the very same question and did not found any ready made solution. So, I created a custom git command shell script my self.
Here it goes, the git-ffwd-update
script does the following...
git remote update
to fetch the lates revs git remote show
to get a list of local branches that track a remote branch (e.g. branches that can be used with git pull
)git rev-list --count <REMOTE_BRANCH>..<LOCAL_BRANCH>
how many commit the local branch is behind the remote (and ahead vice versa)git branch -f <LOCAL_BRANCH> -t <REMOTE_BRANCH>
the script can be called like:
$ git ffwd-update
Fetching origin
branch bigcouch was 10 commit(s) behind of origin/bigcouch. resetting local branch to remote
branch develop was 3 commit(s) behind of origin/develop. resetting local branch to remote
branch master is 6 commit(s) behind and 1 commit(s) ahead of origin/master. could not be fast-forwarded
The full script, should be saved as git-ffwd-update
and needs to be on the PATH
.
#!/bin/bash
main() {
REMOTES="$@";
if [ -z "$REMOTES" ]; then
REMOTES=$(git remote);
fi
REMOTES=$(echo "$REMOTES" | xargs -n1 echo)
CLB=$(git rev-parse --abbrev-ref HEAD);
echo "$REMOTES" | while read REMOTE; do
git remote update $REMOTE
git remote show $REMOTE -n \
| awk '/merges with remote/{print $5" "$1}' \
| while read RB LB; do
ARB="refs/remotes/$REMOTE/$RB";
ALB="refs/heads/$LB";
NBEHIND=$(( $(git rev-list --count $ALB..$ARB 2>/dev/null) +0));
NAHEAD=$(( $(git rev-list --count $ARB..$ALB 2>/dev/null) +0));
if [ "$NBEHIND" -gt 0 ]; then
if [ "$NAHEAD" -gt 0 ]; then
echo " branch $LB is $NBEHIND commit(s) behind and $NAHEAD commit(s) ahead of $REMOTE/$RB. could not be fast-forwarded";
elif [ "$LB" = "$CLB" ]; then
echo " branch $LB was $NBEHIND commit(s) behind of $REMOTE/$RB. fast-forward merge";
git merge -q $ARB;
else
echo " branch $LB was $NBEHIND commit(s) behind of $REMOTE/$RB. resetting local branch to remote";
git branch -f $LB -t $ARB >/dev/null;
fi
fi
done
done
}
main $@
It's not so hard to automate:
#!/bin/sh
# Usage: fetchall.sh branch ...
set -x
git fetch --all
for branch in "$@"; do
git checkout "$branch" || exit 1
git rebase "origin/$branch" || exit 1
done
This still isn't automatic, as I wish there was an option for - and there should be some checking to make sure that this can only happen for fast-forward updates (which is why manually doing a pull is far safer!!), but caveats aside you can:
git fetch origin
git update-ref refs/heads/other-branch origin/other-branch
to update the position of your local branch without having to check it out.
Note: you will be losing your current branch position and moving it to where the origin's branch is, which means that if you need to merge you will lose data!
There are a lot of answers here but none that use git-fetch
to update the local ref directly, which is a lot simpler than checking out branches, and safer than git-update-ref
.
Here we use git-fetch
to update non-current branches and git pull --ff-only
for the current branch. It:
and here it is:
#!/bin/bash
currentbranchref="$(git symbolic-ref HEAD 2>&-)"
git branch -r | grep -v ' -> ' | while read remotebranch
do
# Split <remote>/<branch> into remote and branchref parts
remote="${remotebranch%%/*}"
branchref="refs/heads/${remotebranch#*/}"
if [ "$branchref" == "$currentbranchref" ]
then
echo "Updating current branch $branchref from $remote..."
git pull --ff-only
else
echo "Updating non-current ref $branchref from $remote..."
git fetch "$remote" "$branchref:$branchref"
fi
done
From the manpage for git-fetch
:
<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.
By specifying git fetch <remote> <ref>:<ref>
(without any +
) we get a fetch that updates the local ref only when it can be fast-forwarded.
Note: this assumes the local and remote branches are named the same (and that you want to track all branches), it should really use information about which local branches you have and what they are set up to track.
This issue is not solved (yet), at least not easily / without scripting: see this post on git mailing list by Junio C Hamano explaining situation and providing call for a simple solution.
The major reasoning is that you shouldn't need this:
With git that is not ancient (i.e. v1.5.0 or newer), there is no reason to have local "dev" that purely track the remote anymore. If you only want to go-look-and-see, you can check out the remote tracking branch directly on a detached HEAD with "
git checkout origin/dev
".Which means that the only cases we need to make it convenient for users are to handle these local branches that "track" remote ones when you do have local changes, or when you plan to have some.
If you do have local changes on "dev" that is marked to track the remove "dev", and if you are on a branch different from "dev", then we should not do anything after "
git fetch
" updates the remote tracking "dev". It won't fast forward anyway
The call for a solution was for an option or external script to prune local branches that follow now remote-tracking branches, rather than to keep them up-to-date by fast-forwarding, like original poster requested.
So how about "
git branch --prune --remote=<upstream>
" that iterates over local branches, and if(1) it is not the current branch; and
(2) it is marked to track some branch taken from the <upstream>; and
(3) it does not have any commits on its own;then remove that branch? "
git remote --prune-local-forks <upstream>
" is also fine; I do not care about which command implements the feature that much.
Note: as of git 2.10 no such solution exists. Note that the git remote prune
subcommand, and git fetch --prune
are about removing remote-tracking branch for branch that no longer exists on remote, not about removing local branch that tracks remote-tracking branch (for which remote-tracking branch is upstream branch).
There are plenty of acceptable answers here, but some of the plumbing may be be a little opaque to the uninitiated. Here's a much simpler example that can easily be customized:
$ cat ~/bin/git/git-update-all
#!/bin/bash
# Update all local branches, checking out each branch in succession.
# Eventually returns to the original branch. Use "-n" for dry-run.
git_update_all() {
local run br
br=$(git name-rev --name-only HEAD 2>/dev/null)
[ "$1" = "-n" ] && shift && run=echo
for x in $( git branch | cut -c3- ) ; do
$run git checkout $x && $run git pull --ff-only || return 2
done
[ ${#br} -gt 0 ] && $run git checkout "$br"
}
git_update_all "$@"
If you add ~/bin/git
to your PATH
(assuming the file is ~/bin/git/git-update-all
), you can just run:
$ git update-all
I came across the same issue of this question...
Wondering myself about it, I did a small alias function inside my .bashrc
file:
gitPullAll() {
for branch in `git branch | sed -E 's/^\*/ /' | awk '{print $1}'`; do
git checkout $branch
git pull -p
printf "\n"
done
echo "Done"
}
Worked for me (:
Add this script to .profile
on Mac OS X:
# Usage:
# `git-pull-all` to pull all your local branches from origin
# `git-pull-all remote` to pull all your local branches from a named remote
function git-pull-all() {
START=$(git symbolic-ref --short -q HEAD);
for branch in $(git branch | sed 's/^.//'); do
git checkout $branch;
git pull ${1:-origin} $branch || break;
done;
git checkout $START;
};
function git-push-all() {
git push --all ${1:-origin};
};
Here is a good answer: How to fetch all git branches
for remote in `git branch -r`; do git branch --track $remote; done
git pull --all
A script I wrote for my GitBash. Accomplishes the following:
git checkout branch
git pull origin
** I use this but have not tested thoroughly, use at own risk. See an example of this script in a .bash_alias file here.
# Do a pull on all branches that are tracking a remote branches, will from origin by default.
# If current branch is dirty, will stash changes and reply after pull.
# Usage: pullall [remoteName]
alias pullall=pullAll
function pullAll (){
# if -h then show help
if [[ $1 == '-h' ]]
then
echo "Description: Pulls new changes from upstream on all branches that are tracking remotes."
echo
echo "Usage: "
echo "- Default: pullall"
echo "- Specify upstream to pull from: pullall [upstreamName]"
echo "- Help: pull-all -h"
else
# default remote to origin
remote="origin"
if [ $1 != "" ]
then
remote=$1
fi
# list all branches that are tracking remote
# git branch -vv : list branches with their upstreams
# grep origin : keep only items that have upstream of origin
# sed "s/^.."... : remove leading *
# sed "s/^"..... : remove leading white spaces
# cut -d" "..... : cut on spaces, take first item
# cut -d splits on space, -f1 grabs first item
branches=($(git branch -vv | grep $remote | sed "s/^[ *]*//" | sed "s/^[ /t]*//" | cut -d" " -f1))
# get starting branch name
startingBranch=$(git rev-parse --abbrev-ref HEAD)
# get starting stash size
startingStashSize=$(git stash list | wc -l)
echo "Saving starting branch state: $startingBranch"
git stash
# get the new stash size
newStashSize=$(git stash list | wc -l)
# for each branch in the array of remote tracking branches
for branch in ${branches[*]}
do
echo "Switching to $branch"
git checkout $branch
echo "Pulling $remote"
git pull $remote
done
echo "Switching back to $startingBranch"
git checkout $startingBranch
# compare before and after stash size to see if anything was stashed
if [ "$startingStashSize" -lt "$newStashSize" ]
then
echo "Restoring branch state"
git stash pop
fi
fi
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With