Может ли "git pull --all" обновить все мои локальные филиалы?
У меня часто есть как минимум 3 удаленных филиала: мастер, постановка и производство. У меня есть 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", затем обновляет (перемотает вперед или объединяет) текущую рабочую ветвь, но не другие локальные ветви.
Я все еще застрял, вручную переключаясь на каждую локальную ветку и обновляясь
30 ответов
Поведение, которое вы описываете для pull --all
именно так, как и ожидалось, но не обязательно полезно. Опция передается в git fetch, который затем выбирает все ссылки со всех пультов, а не только необходимые; pull
затем объединяет (или, в вашем случае, перебазирует) соответствующую отдельную ветку.
Если вы хотите проверить другие ветви, вам придется проверить их. И да, для слияния (и перебазировки) абсолютно необходимо рабочее дерево, поэтому их нельзя выполнить без проверки других ветвей. Вы можете обернуть описанные шаги в скрипт / псевдоним, если хотите, хотя я бы посоветовал объединить команды с &&
так что если один из них потерпит неудачу, он не попытается вспахать.
Я использую sync
подкоманда хаба для автоматизации этого. Концентратор псевдоним как git
Итак, команда, которую я набираю:
git sync
Это обновляет все локальные ветви, которые имеют соответствующую ветку восходящего потока. Со страницы руководства:
- Если местный филиал устарел, перенесите его вперед;
- Если локальная ветвь содержит невыпущенную работу, предупредите об этом;
- Если ветвь кажется объединенной и ее восходящая ветвь была удалена, удалите ее.
Он также обрабатывает сохранение / удаление незафиксированных изменений в текущей ветви.
Раньше я использовал похожий инструмент под названием git-up, но он больше не поддерживается, и git sync
делает почти то же самое.
Примечание. Несмотря на то, что я опубликовал собственное решение, я бы порекомендовал использовать git-up, что также является приемлемым ответом.
Я знаю, что этому вопросу почти 3 года, но я задавал себе тот же вопрос и не нашел никакого готового решения. Итак, я создал собственный сценарий командной оболочки git самостоятельно.
Вот и все, git-ffwd-update
скрипт делает следующее...
- это выдает
git remote update
чтобы получить последние обороты - затем использует
git remote show
получить список локальных веток, которые отслеживают удаленную ветку (например, ветки, которые можно использовать сgit pull
) - Затем он проверяет с
git rev-list --count <REMOTE_BRANCH>..<LOCAL_BRANCH>
сколько коммитов локальная ветка находится за удалённой (а впереди наоборот) - если локальная ветвь впереди 1 или более коммитов, она НЕ может быть быстро продвинута и должна быть объединена или перебазирована вручную
- если локальная ветвь имеет 0 коммитов вперед и 1 или более коммитов позади, она может быть быстро переслана
git branch -l -f <LOCAL_BRANCH> -t <REMOTE_BRANCH>
скрипт можно назвать так:
$ git ffwd-update
Fetching origin
branch bigcouch was 10 commit(s) behind of origin/bigcouch. reseting local branch to remote
branch develop was 3 commit(s) behind of origin/develop. reseting 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 branch -l|awk '/^\*/{print $2}');
echo "$REMOTES" | while read REMOTE; do
git remote update $REMOTE
git remote show $REMOTE -n \
| awk '/merges with remote/{print $5" "$1}' \
| while read line; do
RB=$(echo "$line"|cut -f1 -d" ");
ARB="refs/remotes/$REMOTE/$RB";
LB=$(echo "$line"|cut -f2 -d" ");
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. reseting local branch to remote";
git branch -l -f $LB -t $ARB >/dev/null;
fi
fi
done
done
}
main $@
Это не так сложно автоматизировать
#!/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
обновить положение вашего местного отделения без необходимости проверять его.
Примечание: вы потеряете свою текущую позицию ветвления и переместите ее туда, где находится ветвь источника, что означает, что если вам нужно объединить, вы потеряете данные!
Здесь много ответов, но ни один из них не использует 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
:
<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>
(без всяких +
) мы получаем выборку, которая обновляет локальную ссылку только тогда, когда ее можно быстро переслать.
Примечание: это предполагает, что локальные и удаленные ветви названы одинаково (и что вы хотите отслеживать все ветви), оно должно действительно использовать информацию о том, какие локальные ветви у вас есть и что они настроены для отслеживания.
Эта проблема не решена (пока), по крайней мере, не легко / без сценариев: см. Этот пост в списке рассылки git от Junio C Hamano, объясняющий ситуацию и обеспечивающий простое решение.
Основная причина в том, что вам не нужно это:
С git, который не является древним (т.е. v1.5.0 или новее), нет никакой причины иметь локальный "dev", который больше просто отслеживает удаленный. Если вы хотите просто посмотреть и посмотреть, вы можете проверить ветку удаленного отслеживания непосредственно на отдельном HEAD с помощью "
git checkout origin/dev
".Это означает, что единственные случаи, когда нам нужно, чтобы пользователям было удобно, это обрабатывать локальные ветви, которые "отслеживают" удаленные, когда у вас есть локальные изменения или когда вы планируете их иметь.
Если у вас есть локальные изменения в "dev", помеченные для отслеживания удаления "dev", и если вы находитесь на ветке, отличной от "dev", то мы не должны ничего делать после "
git fetch
"обновляет удаленное отслеживание" dev ".
Призыв к решению был для опции или внешнего сценария, чтобы обрезать локальные ветви, которые теперь следуют за удаленными ветвями отслеживания, вместо того, чтобы поддерживать их в актуальном состоянии с помощью быстрой перемотки вперед, как запрошенный оригинальный плакат.
Так как насчет "
git branch --prune --remote=<upstream>
", который перебирает локальные ветви, и если(1) это не текущая ветка; а также
(2) он отмечен для отслеживания некоторой ветви, взятой из; а также
(3) он не имеет никаких коммитов сам по себе;затем удалить эту ветку? "
git remote --prune-local-forks <upstream>
"также хорошо; мне все равно, какая команда реализует эту функцию так много.
Примечание: с git 2.10 такого решения не существует. Обратите внимание, что git remote prune
подкоманда и git fetch --prune
речь идет об удалении ветви удаленного отслеживания для ветви, которая больше не существует на удаленной, а не об удалении локальной ветви, которая отслеживает ветку удаленного отслеживания (для которой ветка удаленного отслеживания является восходящей веткой).
Здесь есть много приемлемых ответов, но некоторые из них могут быть немного непрозрачными для непосвященных. Вот гораздо более простой пример, который можно легко настроить:
$ 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
Вот хороший ответ: Как получить все ветки git
for remote in `git branch -r`; do git branch --track $remote; done
git pull --all
Я столкнулся с той же проблемой этого вопроса...
Задумываясь об этом, я сделал небольшую функцию псевдонима внутри .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"
}
Работал для меня (:
Добавить этот скрипт в .profile
в 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};
};
Вы не можете сделать это с помощью только одной команды 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
=> Когда он достигнет последней строки, добавьте содержимое буфера удержания.
Скрипт, который я написал для моего GitBash. Выполняется следующее:
- По умолчанию тянет от источника для всех ветвей, которые настроены на отслеживание происхождения, позволяет при желании указать другой пульт.
- Если ваша текущая ветвь находится в грязном состоянии, то она сохраняет ваши изменения и попытается восстановить эти изменения в конце.
- Для каждой локальной ветви, настроенной для отслеживания удаленной ветви, будет:
git checkout branch
git pull origin
- Наконец, вернем вас в исходную ветку и восстановим состояние.
** Я использую это, но не проверил полностью, используйте на свой страх и риск. Смотрите пример этого скрипта в файле.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
}
Просто выкладываю обновленный ответ. git-up
больше не поддерживается, и если вы читаете документацию, они упоминают, что функциональность теперь доступна в git.
Начиная с Git 2.9, git pull --rebase --autostash делает то же самое.
Соответственно, если вы обновитесь до Git 2.9 или новее, вы можете использовать этот псевдоним вместо установки git-up:
git config --global alias.up 'pull --rebase --autostash'
Вы также можете установить это для каждого git pull
а также с Git 2.9 (спасибо @VonC, пожалуйста, смотрите его ответ здесь)
git config --global pull.rebase true
git config --global rebase.autoStash true
Немного другой скрипт, который только быстро переходит вперед ветвями, чьи имена совпадают с их ветвью вверх по течению. Он также обновляет текущую ветку, если возможна перемотка вперед.
Убедитесь, что все ветви ваших веток настроены правильно, запустив git branch -vv
, Установите ветку upstream с помощью 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 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
, Псевдоним - это сокращение от "ускоренного отслеживания (ветки)".
Это можно сделать с помощью приведенного ниже сценария... Сначала он извлечет все ветви и оформит заказ один за другим и обновит сам.
#!/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 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
Сценарий от @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
Если refs /heads / master можно быстро переадресовывать на refs / remotes / foo / master, вывод
git merge-base refs/heads/master refs/remotes/foo/master
должен вернуть идентификатор SHA1, на который указывает refs /heads / master. Благодаря этому вы можете собрать скрипт, который автоматически обновляет все локальные ветви, к которым не применены отклоняющие коммиты.
Этот небольшой скрипт оболочки (я назвал его 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
Похоже, что многие другие предложили подобные решения, но я подумал, что поделюсь тем, что я придумал, и приглашаю других внести свой вклад. Это решение имеет приятный красочный вывод, изящно обрабатывает ваш текущий рабочий каталог и быстро, потому что оно не делает никаких проверок и оставляет ваш рабочий каталог в такте. Кроме того, это всего лишь сценарий оболочки без каких-либо зависимостей, кроме 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
Извините, но мне кажется, что я придумал то же имя, что и другой инструмент выше.
Не знаю, нормально ли это , но если я хочу перемотать несколько ветвей вперед, я обычно звоню
git pull origin master staging production
Также, если я хочу нажать несколько веток, я позвоню
git push origin master staging production
Но оба работают только в том случае, если все упомянутые ветки не нуждаются в каком-либо слиянии.
Я использую следующий псевдоним:
[alias]
sync = !git pull --ff-only && git fetch . $(git for-each-ref --format='%(push):%(refname)' refs/heads --exclude="refs/heads/$(git rev-parse --abbrev-ref HEAD)")
Этот псевдоним работает как в Unix, так и в Windows. Он просто запускает следующие две команды:
git pull --ff-only
git fetch . $(git for-each-ref --format='%(push):%(refname)' refs/heads --exclude="refs/heads/$(git rev-parse --abbrev-ref HEAD)")
- Первая команда обновляет все удаленные ветки и обновляет текущую ветку, если обновление является перемоткой вперед.
- Вторая команда позволяет обновить все существующие локальные ветки до их удаленных аналогов, если они есть, и обновление выполняется с перемоткой вперед. Он работает исключительно локально, поскольку точка указывает git выполнить выборку из текущего репозитория. См. документацию .
- The
git for-each-ref --format="%(push):%(refname)" refs/heads
создает строку с для каждой существующей локальной ветки, тем самым сообщаяgit fetch
чтобы обновить эту локальную ветку, используя локальную копию удаленной ветки, в которую она помещается. Например,<refspec>
произведено дляmaster
ветка следующая:-
refs/remotes/origin/master:refs/heads/master
-
- The
--exclude="refs/heads/$(git rev-parse --abbrev-ref HEAD)"
используется для исключения выбора текущей веткиgit for-each-ref
, чтобы git fetch не сообщал, что не может обновить ветку, которая в данный момент извлечена.
- The
Этот псевдоним может не работать с версиями git до 2.42. В частности, я тестировал git 2.36.1 и не смог заставить его работать.
Старый ответ
Я использую следующий псевдоним:
[alias]
sync = !git fetch && git fetch -u . $(git for-each-ref --format='%(push):%(refname)' refs/heads)
Этот псевдоним работает как в Unix, так и в Windows. Он просто запускает следующие две команды:
git fetch
git fetch -u . $(git for-each-ref --format="%(push):%(refname)" refs/heads)
- Первая команда обновляет удаленные ветки.
- Второй
fetch
Команда позволяет обновить все существующие локальные ветки до их удаленных аналогов, если они есть, и обновление выполняется с перемоткой вперед. Вторая команда действует чисто локально, поскольку период.
сообщает git выполнить выборку из текущего репозитория.- The
-u
(--update-head-ok
) сообщает git, что можно перемотать текущую ветку вперед.- Обратите внимание, что git не будет обновлять файлы в вашем рабочем каталоге, поэтому все изменения файлов, произошедшие в вашей ветке, будут отображаться как поэтапные изменения. Таким образом, вам придется отменить их и отменить изменения в вашем репозитории.
- The
Я создаю этот псевдоним, которому нужен еще один шаг, чтобы стать идеальным, но он может кому-то помочь:
sync = !"stashed=\"$( git stash )\" && \
for branch in main live next $( git branch --show-current ); \
do git checkout $branch && git pull; \
done && [ -z \"${stashed##Saved*}\" ] && git stash pop"
Этот псевдоним:
- делает автосохранение в текущей ветке.
- Ознакомьтесь с перечисленными ветками по порядку и извлеките.
- Извлеките исходную ветку и также вытащите ее.
- Вытащите тайник, если это было сделано (со сложной логикой сопоставления для работы с пеплом).
Надеюсь, кто-нибудь найдет это полезным.
Может ли "git pull --all" обновить все мои локальные ветки?
Нет, не может. Для быстрой перемотки я просто написал небольшой инструмент. https://github.com/changyuheng/git-fast-forward-all
Преимущества этого средства:
- Поддерживает несколько пультов в одном репозитории. (
hub sync
на данный момент не поддерживает несколько пультов.) - Поддерживает разные имена в локальной ветке и соответствующей ветке удаленного отслеживания.
- Намного быстрее, чем другие сценарии, которые извлекают удаленный доступ для каждой отдельной ветки.
- Отсутствие подверженного ошибкам анализа / редактирования регулярных выражений.
Ни один из приведенных выше ответов не рассматривает возможность существования нескольких рабочих деревьев. Обновление веток с
git update-ref
или же
git 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
Эта команда поможет.
for branch in `git branch | sed 's/\*//g'`; do git checkout $branch && git rebase origin/$branch; done
for branch in `git branch | sed 's/\*//g'`; do git checkout $branch && git reset --hard origin/$branch; done
for branch in `git branch | sed 's/\*//g'`; do git checkout $branch && git reset --hard origin/$branch && git pull; done
По состоянию на git 2.9:
git pull --rebase --autostash
Смотрите https://git-scm.com/docs/git-rebase
Автоматически создайте временный тайник до начала операции и примените его после завершения операции. Это означает, что вы можете запустить rebase на грязном рабочем дереве. Однако используйте с осторожностью: окончательное приложение-хранилище после успешной перезагрузки может привести к нетривиальным конфликтам.
Фактически, с помощью 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
В основной ветке вы можете обновить все остальные ветки. @Cascabel
Я не знаю, какая версия ломает / исправляет, в 2.17(которую я использую) она может работать.