我经常至少有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”,然后更新(快进或合并)当前工作分支,而不是其他本地分支。
我仍然无法手动切换到每个本地分支并进行更新。
答案 0 :(得分:189)
我使用sync
subcommand hub来自动执行此操作。我的alias git=hub
中有.bash_profile
,因此我输入的命令是:
git sync
这将更新具有匹配上游分支的所有本地分支。从手册页:
- 如果本地分支已过时,请快进;
- 如果本地分支包含未完成的工作,请提醒它;
- 如果分支似乎已合并且其上游分支已删除,请将其删除。
它还处理在当前分支上存储/取消搁置未提交的更改。
我过去常常使用名为git-up的类似工具,但它不再维护,git sync
几乎完全相同。
答案 1 :(得分:165)
您为pull --all
描述的行为完全符合预期,但不一定有用。该选项被传递给git fetch,然后从所有遥控器获取所有引用,而不仅仅是所需的引用; pull
然后合并(或在您的情况下,rebase)适当的单个分支。
如果你想查看其他分支机构,你将不得不检查它们。是的,合并(和重新定位)绝对需要一个工作树,所以如果不检查其他分支就无法完成。如果你愿意的话,你可以把你描述的步骤包装成一个脚本/别名,虽然我建议你用&&
加入这些命令,这样如果其中一个失败了,它就不会尝试使用。
答案 2 :(得分:33)
我知道这个问题已经快3年了,但我问自己同样的问题并没有找到任何现成的解决方案。所以,我自己创建了一个自定义git命令shell脚本。
在这里,git-ffwd-update
脚本执行以下操作...
git remote update
来获取lates revs git remote show
获取跟踪远程分支的本地分支列表(例如,可以与git pull
一起使用的分支)git rev-list --count <REMOTE_BRANCH>..<LOCAL_BRANCH>
检查遥控器后面的本地分支提交了多少(反之亦然)git branch -f <LOCAL_BRANCH> -t <REMOTE_BRANCH>
脚本可以像:
一样调用$ 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
完整脚本应保存为git-ffwd-update
,并且需要位于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 $@
答案 3 :(得分:24)
自动化并不是那么难:
#!/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
答案 4 :(得分:16)
这仍然不是自动的,因为我希望有一个选项 - 并且应该进行一些检查以确保这只会发生在快进更新中(这就是为什么手动执行拉动更安全! !),但除了警告之外,你可以:
git fetch origin
git update-ref refs/heads/other-branch origin/other-branch
更新本地分支的位置,而无需将其检出。
注意:您将失去当前的分支位置并将其移动到原始分支的位置,这意味着如果您需要合并,则会丢失数据!
答案 5 :(得分:11)
这个问题尚未解决(至少不容易/没有脚本):Junio C Hamano在git邮件列表中查看 this post ,解释情况并提供简单解决方案的调用
主要原因是你不应该这样:
使用不古老的git(即v1.5.0或更新版本),没有理由 有本地“开发”,纯粹跟踪遥控器。如果你只想要 去看看,你可以直接检查远程跟踪分支 在一个带有“
git checkout origin/dev
”的独立HEAD上。这意味着我们需要的唯一案例才能方便用户 当你这样做时,要处理这些“跟踪”远程分支的本地分支 有本地更改,或者您计划有一些更改。
如果您对“dev”进行了本地更改,则会标记为跟踪删除 “dev”,如果你在与“dev”不同的分支上,那么我们就不应该这样做 在“
git fetch
”更新远程跟踪“dev”后执行任何操作。它 不管怎么说都不会快进
对解决方案的要求是针对修剪本地分支机构的选项或外部脚本,这些分支机构现在跟踪远程跟踪分支机构,而不是通过快速转发使其保持最新状态,例如请求原始海报。
那么迭代的“
git branch --prune --remote=<upstream>
”怎么样呢 当地分支机构,如果(1)它不是当前的分支;和
(2)标记为跟踪从&lt; upstream&gt;取得的一些分支;和
(3)它本身没有任何提交;然后删除那个分支? “
git remote --prune-local-forks <upstream>
”是 也很好;我不关心哪个命令实现了该功能 得多。
注意: 从git 2.10开始,没有这样的解决方案。请注意,git remote prune
子命令和git fetch --prune
是关于删除远程不再存在的分支的远程跟踪分支,而不是删除跟踪远程跟踪分支的本地分支(针对哪个远程跟踪分支)是上游分支。)
答案 6 :(得分:10)
这里有很多答案,但没有一个使用git-fetch
直接更新本地引用,这比检查分支简单得多,比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
的联机帮助页:
<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。
注意:这假定本地和远程分支的名称相同(并且您要跟踪所有分支),它应该真正使用有关您拥有的本地分支及其设置的信息跟踪。
答案 7 :(得分:7)
这里有很多可以接受的答案,但有些管道可能对于不熟悉的人来说有些不透明。这是一个可以轻松定制的更简单的示例:
$ 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 "$@"
如果您将~/bin/git
添加到PATH
(假设文件为~/bin/git/git-update-all
),则可以运行:
$ git update-all
答案 8 :(得分:7)
这是一个很好的答案:How to fetch all git branches
for remote in `git branch -r`; do git branch --track $remote; done
git pull --all
答案 9 :(得分:5)
在Mac OS X上将this script添加到.profile
:
# 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};
};
答案 10 :(得分:3)
只需发布更新的答案。 git-up
已不再维护,如果您阅读了文档,则会mention the functionality is now available in git。
从Git 2.9开始,git pull --rebase --autostash的功能基本相同。
因此,如果你更新到Git 2.9或更高版本,你可以使用这个别名而不是安装git-up:
git config --global alias.up 'pull --rebase --autostash'
您也可以为Git 2.9中的每个git pull
设置此功能(感谢@VonC,请参阅他的回答here)
git config --global pull.rebase true
git config --global rebase.autoStash true
答案 11 :(得分:3)
如果您使用的是Windows,则可以使用PyGitUp,这是Python的git-up
的克隆。您可以使用pip install --user git-up
使用pip或scoop install git-up
使用{{1}}
[
答案 12 :(得分:3)
我为GitBash撰写的剧本。完成以下任务:
git checkout branch
git pull origin
**我使用此功能但未经过彻底测试,请自担风险使用。请参阅.bash_alias文件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
}
答案 13 :(得分:2)
要完成Matt Connolly的答案,这是一种更安全的方式来更新可以快进的本地分支引用,而无需检查分支。它不会更新无法快速转发的分支(即已经分叉的分支),并且它不会更新当前已检出的分支(因为那时工作副本也应该更新)。
git fetch
head="$(git symbolic-ref HEAD)"
git for-each-ref --format="%(refname) %(upstream)" refs/heads | while read ref up; do
if [ -n "$up" -a "$ref" != "$head" ]; then
mine="$(git rev-parse "$ref")"
theirs="$(git rev-parse "$up")"
base="$(git merge-base "$ref" "$up")"
if [ "$mine" != "$theirs" -a "$mine" == "$base" ]; then
git update-ref "$ref" "$theirs"
fi
fi
done
答案 14 :(得分:2)
如果 refs / heads / master 可以快速转发到 refs / remotes / foo / master ,则输出
git merge-base refs/heads/master refs/remotes/foo/master
应返回 refs / heads / master 指向的SHA1 ID。有了这个,您可以组合一个脚本,自动更新所有没有应用转移提交的本地分支。
这个小shell脚本(我称之为 git-can-ff )说明了如何完成它。
#!/bin/sh
set -x
usage() {
echo "usage: $(basename $0) <from-ref> <to-ref>" >&2
exit 2
}
[ $# -ne 2 ] && usage
FROM_REF=$1
TO_REF=$2
FROM_HASH=$(git show-ref --hash $FROM_REF)
TO_HASH=$(git show-ref --hash $TO_REF)
BASE_HASH=$(git merge-base $FROM_REF $TO_REF)
if [ "$BASE_HASH" = "$FROM_HASH" -o \
"$BASE_HASH" = "$FROM_REF" ]; then
exit 0
else
exit 1
fi
答案 15 :(得分:1)
我碰到过同样的问题...
对此我感到很奇怪,我在providers: [
StatusBar
, SplashScreen
文件中做了一个小的别名功能:
.bashrc
为我工作(:
答案 16 :(得分:1)
可以使用以下脚本完成...它将首先获取所有分支并逐个检出并自行更新。
#!/bin/bash
git branch -r | grep -v '\->' | while read remote; do git branch --track
"${remote#origin/}" "$remote"; done
set -x
CURRENT=`git rev-parse --abbrev-ref HEAD`
git fetch --all
branch_name=$(git branch | awk '{print $1" "}' | grep -v '*' | xargs)
for branch in $branch_name; do
git checkout "$branch" || exit 1
git rebase "origin/$branch" || exit 1
git pull origin $branch|| exit 1
done
git checkout "$CURRENT" || exit 1
git pull || exit 1
答案 17 :(得分:1)
您不能仅使用一个git命令来执行此操作,而是可以使用一条bash行使其自动化。
要用一行安全地更新所有分支,这是我的工作:
git fetch --all && for branch in $(git branch | sed '/*/{$q;h;d};$G' | tr -d '*') ; do git checkout $branch && git merge --ff-only || break ; done
如果它不能快进一个分支或遇到错误,它将停止并留在该分支中,以便您可以收回控制权并手动合并。
如果所有分支都可以快速转发,它将以您当前所在的分支结束,从而使您离开更新前的位置。
说明:
为了获得更好的可读性,可以将其分为几行:
git fetch --all && \
for branch in $(git branch | sed '/*/{$q;h;d};$G' | tr -d '*')
do git checkout $branch && \
git merge --ff-only || break
done
git fetch --all && ...
=>从所有远程获取所有引用,如果没有错误,则继续执行下一个命令。
git branch | sed '/*/{$q;h;d};$G' | tr -d '*'
=>从git branch
的输出中,sed
以带有*
的行并将其移到末尾(以便当前分支将在最后更新)。然后tr
只需删除*
。
for branch in $(...) ; do git checkout $branch && git merge --ff-only || break ; done
=>对于从上一条命令获得的每个分支名称,请检出该分支并尝试与快进合并。如果失败,将调用break
,命令在此处停止。
当然,如果需要,可以将git merge --ff-only
替换为git rebase
。
最后,您可以将其作为别名放在 bashrc 中:
alias git-pull-all='git fetch --all && for branch in $(git branch | sed '\''/*/{$q;h;d};$G'\'' | tr -d "*") ; do git checkout $branch && git merge --ff-only || break ; done'
或者如果您担心弄乱'和',或者只想在编辑器中保持语法可读性,则可以将其声明为函数:
git-pull-all()
{
git fetch --all && for branch in $(git branch | sed '/*/{$q;h;d};$G' | tr -d '*') ; do git checkout $branch && git merge --ff-only || break ; done
}
奖金:
对于那些希望在sed '/*/{$q;h;d};$G'
部分进行解释的人:
/*/
=>搜索带有*
的行。
{$q
=>如果它在最后一行,请退出(我们不需要做任何事情,因为当前分支已经是列表中的最后一个)。
;h;d}
=>否则,将该行存储在保留缓冲区中,并在当前列表位置将其删除。
;$G
=>当到达最后一行时,附加保留缓冲区的内容。
答案 18 :(得分:1)
看起来很多人都提供了类似的解决方案,但我想我会分享我的想法并邀请其他人做出贡献。这个解决方案有一个漂亮的彩色输出,优雅地处理您当前的工作目录,并且速度快,因为它不会进行任何检查,并且保持您的工作目录。此外,它只是一个没有git之外的依赖项的shell脚本。 (目前仅在OSX上测试过)
#!/usr/bin/env bash
gitup(){
RED='\033[33;31m'
YELLO='\033[33;33m'
GREEN='\033[33;32m'
NC='\033[0m' # No Color
HEAD=$(git rev-parse HEAD)
CHANGED=$(git status --porcelain | wc -l)
echo "Fetching..."
git fetch --all --prune &>/dev/null
for branch in `git for-each-ref --format='%(refname:short)' refs/heads`; do
LOCAL=$(git rev-parse --quiet --verify $branch)
if [ "$HEAD" = "$LOCAL" ] && [ $CHANGED -gt 0 ]; then
echo -e "${YELLO}WORKING${NC}\t\t$branch"
elif git rev-parse --verify --quiet $branch@{u}&>/dev/null; then
REMOTE=$(git rev-parse --quiet --verify $branch@{u})
BASE=$(git merge-base $branch $branch@{u})
if [ "$LOCAL" = "$REMOTE" ]; then
echo -e "${GREEN}OK${NC}\t\t$branch"
elif [ "$LOCAL" = "$BASE" ]; then
if [ "$HEAD" = "$LOCAL" ]; then
git merge $REMOTE&>/dev/null
else
git branch -f $branch $REMOTE
fi
echo -e "${GREEN}UPDATED${NC}\t\t$branch"
elif [ "$REMOTE" = "$BASE" ]; then
echo -e "${RED}AHEAD${NC}\t\t$branch"
else
echo -e "${RED}DIVERGED${NC}\t\t$branch"
fi
else
echo -e "${RED}NO REMOTE${NC}\t$branch"
fi
done
}
https://github.com/davestimpert/gitup
很抱歉,我似乎也提出了与上面其他工具相同的名称。
答案 19 :(得分:1)
略有不同的脚本,只有快速转发的分支名称与其上游分支匹配。如果可以快进,它还会更新当前分支。
通过运行git branch -vv
确保正确设置所有分支的上游分支。使用git branch -u origin/yourbanchname
复制粘贴到文件和chmod 755:
#!/bin/sh
curbranch=$(git rev-parse --abbrev-ref HEAD)
for branch in $(git for-each-ref refs/heads --format="%(refname:short)"); do
upbranch=$(git config --get branch.$branch.merge | sed 's:refs/heads/::');
if [ "$branch" = "$upbranch" ]; then
if [ "$branch" = "$curbranch" ]; then
echo Fast forwarding current branch $curbranch
git merge --ff-only origin/$upbranch
else
echo Fast forwarding $branch with origin/$upbranch
git fetch . origin/$upbranch:$branch
fi
fi
done;
答案 20 :(得分:1)
来自@larsmans的剧本,有点改进:
#!/bin/sh
set -x
CURRENT=`git rev-parse --abbrev-ref HEAD`
git fetch --all
for branch in "$@"; do
if ["$branch" -ne "$CURRENT"]; then
git checkout "$branch" || exit 1
git rebase "origin/$branch" || exit 1
fi
done
git checkout "$CURRENT" || exit 1
git rebase "origin/$CURRENT" || exit 1
在完成之后,将这个工作副本从同一分支中检出,就像调用脚本之前一样。
git pull
版本:
#!/bin/sh
set -x
CURRENT=`git rev-parse --abbrev-ref HEAD`
git fetch --all
for branch in "$@"; do
if ["$branch" -ne "$CURRENT"]; then
git checkout "$branch" || exit 1
git pull || exit 1
fi
done
git checkout "$CURRENT" || exit 1
git pull || exit 1
答案 21 :(得分:0)
如果可能,以下单行快速前移所有具有上游分支的分支,否则显示错误:
git branch \
--format "%(if)%(upstream:short)%(then)git push . %(upstream:short):%(refname:short)%(end)" |
sh
它通过git branch
命令使用自定义格式。对于具有上游分支的每个分支,它将打印具有以下模式的行:
git push . <remote-ref>:<branch>
这可以直接通过管道传递到sh
中(假设分支名称格式正确)。忽略| sh
以查看其工作情况。
单线不会与您的遥控器联系。在运行之前发出git fetch
或git fetch --all
。
当前已检出的分支不会用类似消息的更新
! [remote rejected] origin/master -> master (branch is currently checked out)
为此,您可以求助于常规git pull --ff-only
。
将以下内容添加到您的.gitconfig
中,以便git fft
执行此命令:
[alias]
fft = !sh -c 'git branch --format \"%(if)%(upstream:short)%(then)git push . %(upstream:short):%(refname:short)%(end)\" | sh' -
另请参阅我的.gitconfig
。别名是“快进跟踪(分支)”的简写。
答案 22 :(得分:0)
“ git pull --all”可以更新我的所有本地分支吗?
不,它不能。对于快速转发,我只是编写了一个小工具来实现。 https://github.com/changyuheng/git-fast-forward-all
此工具的优点:
hub sync
目前不支持多个遥控器。)答案 23 :(得分:-1)
从git 2.9开始:
git pull --rebase --autostash
请参阅https://git-scm.com/docs/git-rebase
在操作开始前自动创建临时存储, 并在操作结束后应用它。这意味着您可以运行 在肮脏的工作树上贬值。但是,小心使用:最后藏匿 成功改组后的申请可能会导致非平凡 冲突。
答案 24 :(得分:-1)
实际上,使用git version 1.8.3.1
可以正常工作:
[root@test test]# git br
* master
release/0.1
update
[root@test test]# git pull --rebase
remote: Enumerating objects: 9, done.
remote: Counting objects: 100% (9/9), done.
remote: Compressing objects: 100% (9/9), done.
remote: Total 9 (delta 2), reused 0 (delta 0)
Unpacking objects: 100% (9/9), done.
From http://xxx/scm/csdx/test-git
d32ca6d..2caa393 release/0.1 -> origin/release/0.1
Current branch master is up to date.
[root@test test]# git --version
git version 1.8.3.1
在master分支中,您可以更新所有其他分支。 @Cascabel
我不知道哪个版本可以破解/修复它,在2.17(我使用的版本)中,它可以工作。