我通常至少有3个远程分支:master、staging和production。我有3个本地分支来跟踪这些远程分支。
更新我所有的本地分支是乏味的:
git fetch --all
git rebase origin/master
git checkout staging
git rebase origin/staging
git checkout production
git rebase origin/production
我很想做一个“git pull -all”,但我还没能让它工作。它似乎做了一个“fetch -all”,然后更新(快进或合并)当前工作的分支,但不包括其他本地分支。
我仍然需要手动切换到每个本地分支并进行更新。
这个问题(目前)还没有解决,至少在没有脚本的情况下不容易解决:参见Junio C Hamano在git邮件列表上发布的这篇文章,解释了这种情况并提供了一个简单的解决方案。
主要的理由是你不需要这个:
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
解决方案需要一个选项或外部脚本,以修剪当前远程跟踪分支的本地分支,而不是像最初的海报所要求的那样,通过快进来保持它们的最新状态。
那么,“git branch -prune -remote=<upstream>”如何呢
本地分支,如果
(1)不是目前的分支机构;而且
(2)标记为从<上游>取的某个分支;而且
(三)自身无过错;
然后把那根树枝去掉?“git remote——prune-local-forks <upstream>”是
还好;我不关心哪个命令实现了这个特性
多。
注意:从git 2.10开始就没有这样的解决方案了。注意,git remote prune子命令和git fetch——prune是关于删除不再存在于远程上的分支的远程跟踪分支,而不是关于删除跟踪远程跟踪分支的本地分支(其中远程跟踪分支是上游分支)。
这里有很多答案,但没有一个是使用git-fetch直接更新本地ref,这比检查分支简单得多,也比git-update-ref更安全。
这里我们使用git-fetch来更新非当前分支,而git pull——ff-only用于当前分支。它:
不需要检查分支机构
仅在可以快进的情况下更新分支
当它不能快进时会报告吗
就是这样:
#!/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
从git-fetch的manpage:
<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.
通过指定git fetch <remote> <ref>:<ref>(没有任何+),我们得到一个只在本地ref可以快进时更新它的fetch。
注意,这假设本地分支和远程分支的名称相同(并且您希望跟踪所有分支),它实际上应该使用关于您拥有哪些本地分支以及它们被设置为跟踪的内容的信息。
这个问题(目前)还没有解决,至少在没有脚本的情况下不容易解决:参见Junio C Hamano在git邮件列表上发布的这篇文章,解释了这种情况并提供了一个简单的解决方案。
主要的理由是你不需要这个:
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
解决方案需要一个选项或外部脚本,以修剪当前远程跟踪分支的本地分支,而不是像最初的海报所要求的那样,通过快进来保持它们的最新状态。
那么,“git branch -prune -remote=<upstream>”如何呢
本地分支,如果
(1)不是目前的分支机构;而且
(2)标记为从<上游>取的某个分支;而且
(三)自身无过错;
然后把那根树枝去掉?“git remote——prune-local-forks <upstream>”是
还好;我不关心哪个命令实现了这个特性
多。
注意:从git 2.10开始就没有这样的解决方案了。注意,git remote prune子命令和git fetch——prune是关于删除不再存在于远程上的分支的远程跟踪分支,而不是关于删除跟踪远程跟踪分支的本地分支(其中远程跟踪分支是上游分支)。
我为我的giitbash写的脚本。完成以下任务:
默认情况下,为跟踪原点而设置的所有分支从原点提取,允许您根据需要指定不同的远程。
如果您的当前分支处于脏状态,那么它将存储您的更改,并在结束时尝试恢复这些更改。
对于每个用于跟踪远程分支的本地分支,将:
Git结帐分支
Git拉源
最后,将您返回到原始分支并恢复状态。
**我使用这个,但没有彻底测试,使用自负风险。在.bash_alias文件中可以看到该脚本的示例。
# 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
}