“git拉——all”;更新我所有的本地分支?

我通常至少有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”,然后更新(快进或合并)当前工作的分支,但不包括其他本地分支。

我仍然需要手动切换到每个本地分支并进行更新。

336786 次浏览

这个问题(目前)还没有解决,至少在没有脚本的情况下不容易解决:参见Junio C Hamano在git邮件列表上的这篇文章来解释情况并提供一个简单的解决方案。

主要的理由是你不需要这个:

对于不是古老的git(即v1.5.0或更新版本),没有理由这样做 让本地“开发人员”完全跟踪远程。如果你只想 要查看,您可以直接查看远程跟踪分支

这意味着我们需要为用户提供方便的唯一情况 是否要处理这些“跟踪”远程分支的本地分支 有局部变化,或者当你计划有一些。

如果你在“dev”上有本地更改,标记为跟踪删除 “dev”,如果您在不同于“dev”的分支上,那么我们不应该这样做 在“git fetch”更新远程跟踪“dev”之后做任何事情。它 无论如何都不会快进

对于解决方案的要求是为修剪本地分支提供一个选项或外部脚本,这些分支现在遵循远程跟踪分支,而不是像最初的海报所要求的那样通过快进来保持它们的最新。

那么“git branch --prune --remote=<upstream>”如何迭代 本地分支,if

.

(1)它不是当前分支;和< br > (2)它被标记为跟踪从上游取的某个分支<;和< br > (3)它本身没有提交;

然后移除那个分支?“# EYZ0” 还好;我不关心哪个命令实现了这个特性 多。< / p >

<强>注意:< / >强在git 2.10中没有这样的解决方案。注意,git remote prune子命令和git fetch --prune是关于删除远程上不再存在的分支的远程跟踪分支,而不是关于删除跟踪远程跟踪分支的本地分支(其中远程跟踪分支是上游分支)。

如果refs /头/主人可以快进到refs /遥控器/ foo /主人,则输出

git merge-base refs/heads/master refs/remotes/foo/master

应该返回refs /头/主人所指向的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

您为pull --all描述的行为完全符合预期,尽管不一定有用。该选项被传递给git fetch,然后从所有远程获取所有引用,而不仅仅是需要的一个;pull然后合并(或者在您的情况下,重新创建)适当的单个分支。

如果你想查看其他分支机构,你就必须查看它们。是的,合并(和重基)绝对需要一个工作树,所以没有检查其他分支就不能完成。如果愿意,您可以将所描述的步骤打包到脚本/别名中,不过我建议使用&&来连接命令,这样即使其中一个命令失败,它也不会尝试继续执行。

自动化并不难:

#!/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

这仍然不是自动的,因为我希望有一个选项-应该有一些检查,以确保这只能发生在快进更新(这就是为什么手动做拉更安全!!),但注意事项:

git fetch origin
git update-ref refs/heads/other-branch origin/other-branch

更新本地分支的位置,而无需签出。

注意:你将丢失你当前的分支位置,并将其移动到原点的分支所在的位置,这意味着如果你需要合并,你将丢失数据!

我知道这个问题已经提了将近3年了,但我也问过自己同样的问题,但没有找到任何现成的解决方案。所以,我自己创建了一个自定义的git命令shell脚本。

在这里,git-ffwd-update脚本执行以下操作……

  1. 它发出一个git remote update来获取后期转速
  2. 然后使用git remote show来获得跟踪远程分支的本地分支列表(例如,可以与git pull一起使用的分支)
  3. 然后用git rev-list --count <REMOTE_BRANCH>..<LOCAL_BRANCH>检查有多少本地分支在远程的后面(反之亦然)
  4. 如果本地分支提前1个或多个提交,它可以快进,需要手工合并或重基
  5. 如果本地分支在前面有0个提交,后面有1个或多个提交,则可以使用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 $@

我使用中心中的# EYZ0子命令来实现自动化。我有alias git=hub在我的.bash_profile,所以我键入的命令是:

git sync

这将更新具有匹配上游分支的所有本地分支。从手册页:

  • 如果本地分支已经过时,快进;
  • 如果本地分支包含未推送的工作,请对此发出警告;
  • 如果分支显示为已合并,且上游分支已被删除,则删除该分支。

它还处理在当前分支上存储/解存储未提交的更改。

我曾经使用过一个类似的工具,名为活力,但现在不再维护它,而git sync几乎做完全相同的事情。

为了完成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

这里有很多可以接受的答案,但对于外行来说,有些管道可能有点不透明。下面是一个可以轻松定制的简单示例:

$ 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

在Mac OS X上添加这个脚本.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};
};

来自@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

这里有很多答案,但没有一个使用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的取回。

注意,这假设本地分支和远程分支的名称相同(并且您希望跟踪所有分支),它实际上应该使用关于您拥有哪些本地分支以及它们被设置为跟踪的内容的信息。

一个略有不同的脚本,它只快进与上游分支名称匹配的分支。如果可以快进,它还会更新当前分支。

通过运行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;

这里有一个很好的答案:如何获取所有git分支

for remote in `git branch -r`; do git branch --track $remote; done
git pull --all

我为我的GitBash写的脚本。完成以下任务:

  • 默认情况下,为跟踪原点而设置的所有分支从原点提取,允许您根据需要指定不同的远程。
  • 如果您的当前分支处于脏状态,那么它将存储您的更改,并在结束时尝试恢复这些更改。
  • 对于每个用来跟踪远程分支的本地分支将:
    • # EYZ0
    • # EYZ0
    • 李< / ul > < / >
    • 最后,将您返回到原始分支并恢复状态。

    **我使用这个,但没有彻底测试,使用自负风险。在.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
    }
    

似乎很多人都提供了类似的解决方案,但我想分享一下我的想法,并邀请其他人来贡献。这个解决方案有一个漂亮的彩色输出,优雅地处理您当前的工作目录,并且速度很快,因为它不做任何检出,并巧妙地保留您的工作目录。此外,它只是一个shell脚本,除了git之外没有其他依赖项。(目前只在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

对不起,我似乎也想出了与上面其他工具相同的名字。

如果你在Windows上,你可以使用PyGitUp,这是Python中git-up的克隆。您可以使用皮普pip install --user git-up安装它,或者通过独家新闻scoop install git-up安装它

(< img src = " https://i.stack.imgur.com/7AjEC.png " alt = " 4) " >

从git 2.9开始:

# EYZ0

看到# EYZ0

在操作开始前自动创建一个临时存储, 操作结束后再应用。这意味着你可以跑 基于一个肮脏的工作树。然而,小心使用:最后的收藏 应用程序在成功的重基后可能会导致非平凡 冲突。< / p >

只是发布一个更新的答案。git-up不再维护,如果你阅读文档,他们是提到这个功能现在在git中是可用的

从Git 2.9开始,Git pull -rebase -autostash基本上做了同样的事情。

因此,如果你更新到Git 2.9或更高版本,你可以使用这个别名而不是安装Git -up:

# EYZ0

你也可以为Git 2.9的每个git pull设置这个选项(谢谢@VonC,请参阅他的答案在这里)

git config --global pull.rebase true
git config --global rebase.autoStash true

它可以使用下面的脚本…它将首先获取所有分支,逐个签出并自行更新。

#!/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

如果可能,以下一行代码将快速前进所有具有上游分支的分支,否则打印错误:

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 fetchgit 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。别名是“快进跟踪(分支)”的缩写。

我也遇到过同样的问题……

想知道自己,我做了一个小的别名函数在我的.bashrc文件:

gitPullAll() {
for branch in `git branch | sed -E 's/^\*/ /' | awk '{print $1}'`; do
git checkout $branch
git pull -p
printf "\n"
done
echo "Done"
}

为我工作过

事实上,使用git# EYZ0,它可以工作:

[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

在主分支中,您可以更新所有其他分支。@Cascabel

我不知道哪个版本破坏/修复了它,在2.17(我使用的),它可以工作。

“git pull -all”可以更新我所有的本地分支吗?

不,它不能。对于快进,我只是编写了一个小工具。# EYZ0

该工具的优点:

  1. 在一个存储库中支持多个远程。(hub sync目前不支持多个遥控器。)
  2. 支持在本地分支和相应的远程跟踪分支上使用不同的名称。
  3. 比其他获取每个分支的远程脚本快得多。
  4. 没有容易出错的正则表达式解析/编辑。

你不能只使用一个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
  1. git fetch --all && ... =>从所有远程获取所有引用,如果没有错误,则继续执行下一个命令。

  2. git branch的输出中,sed取带有*的行并将其移动到末尾(因此当前分支将在最后更新)。然后tr简单地删除*

  3. 对于从上一个命令中获得的每个分支名称,签出该分支并尝试使用快进合并。如果失败,则调用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'

或者如果你害怕混淆' and ',或者你只是喜欢在编辑器中保持语法的可读性,你可以将它声明为一个函数:

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'部分的解释的人:

  • /*/ =>搜索带*的行。

  • 如果它在最后一行,退出(我们不需要做任何事情,因为当前分支已经是列表中的最后一个)。

  • 否则,将该行保存在保持缓冲区中,并将其删除在当前列表位置。

  • 当它到达最后一行时,追加保持缓冲区的内容。

不知道这是否是好吧,但如果我想快进多个分支,我通常会调用

git pull origin master staging production

如果我想推送多个分支,我会调用

git push origin master staging production

但只有当所有提到的分支都不需要任何形式的合并时,两者才有效。

以上答案都没有考虑到可能存在多个worktrees的可能性。使用git update-refgit branch -f更新当前在其他工作树中签出的分支将会产生意想不到的副作用。

考虑一下我处理工作树的解决方案:

#! /usr/bin/env bash
set -euo pipefail


# Read the default remote from config, defaulting to "origin".
DEFAULT_REMOTE=$(git config --default origin --get clone.defaultRemoteName)


# Use first argument as remote name, fallback to default.
REMOTE=${1:-$DEFAULT_REMOTE}


# Resolve the rev that HEAD points at, so that we can give it
# a special treatment.
HEAD_REV=$(git rev-parse HEAD)


# Format that allows us to easily grep for local branches that are behind,
# and have an upstream at $REMOTE.
FORMAT="%(upstream:trackshort)%(upstream:remotename)|%(refname:short)"


# Get a list of revs that are checked out. We don't want to
# update refs that are pointing at them.
set +e
WORKTREE_REVS=$(git worktree list --porcelain | grep -Po "HEAD \K(.+)" | grep -v "$HEAD_REV")
set -e


git fetch $REMOTE


for BRANCH in $(git for-each-ref refs/heads --format="$FORMAT" | grep -Po "<$REMOTE\|\K(.+)")
do
BRANCH_REV=$(git rev-parse $BRANCH)
if [ "$BRANCH_REV" = "$HEAD_REV" ]
then
# This branch is currently checked out "here". Forward it carefully.
set +e
git merge --no-autostash --ff-only $BRANCH@{u}
set -e
elif grep -q "$BRANCH_REV" <<< "$WORKTREE_REVS"
then
# This branch is currently checked out by another. Leave it alone.
echo "$BRANCH skipped, because it is checked out in another worktree. Use 'git worktree list' to diagnose."
else
# This branch is not checked out. Just update it!
git update-ref refs/heads/$BRANCH $BRANCH@{u}
echo "$BRANCH forwarded"
fi
done