Может ли "git pull -all" обновить все мои локальные ветки?

У меня часто есть как минимум три удаленных ветки: мастер, постановка и производство. У меня есть 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", затем обновляет (ускоряет или сжимает) текущую рабочую ветвь, но не другие локальные ветки.

Я все еще застрял в ручном переключении на каждую локальную ветвь и обновляю.

+437
30 нояб. '10 в 20:20
источник поделиться
21 ответ

Поведение, которое вы описываете для pull --all, точно так, как ожидалось, хотя и не обязательно полезно. Опция передается вместе с git fetch, которая затем извлекает все ссылки из всех пультов, а не только необходимые; pull затем объединяет (или в вашем случае, переустанавливает) соответствующую отдельную ветвь.

Если вы хотите проверить другие ветки, вам придется проверить их. И да, для слияния (и перезагрузки) абсолютно требуется дерево работы, поэтому они не могут быть выполнены без проверки других ветвей. Вы можете завершить описанные шаги в script/alias, если хотите, хотя я бы предложил присоединиться к командам с &&, чтобы один из них потерпел неудачу, он не будет пытаться пахать.

+176
30 нояб. '10 в 20:24
источник

Я использую подкоманду sync hub для автоматизации этого. У меня есть alias git=hub в моем .bash_profile, поэтому я .bash_profile команду:

git sync

Это обновляет все локальные ветки, которые имеют соответствующую ветку восходящего потока. Со страницы руководства:

  • Если локальный филиал устарел, перенесите его вперед;
  • Если локальная ветвь содержит невыпущенную работу, предупредите об этом;
  • Если ветвь кажется объединенной и ее восходящая ветвь была удалена, удалите ее.

Он также обрабатывает сохранение/удаление незафиксированных изменений в текущей ветки.

Раньше я использовал похожий инструмент под названием git-up, но он больше не поддерживается, и git sync делает почти то же самое.

+199
20 мар. '12 в 5:10
источник
другие ответы

Связанные вопросы


Похожие вопросы

Я знаю, что этому вопросу почти 3 года, но я задавал себе тот же вопрос и не нашел никакого готового решения. Итак, я создал собственный сценарий командной оболочки git самостоятельно.

Вот и все, git-ffwd-update делает следующее...

  1. он выдает git remote update для получения последних оборотов
  2. затем использует git remote show для получения списка локальных веток, которые отслеживают удаленную ветку (например, ветки, которые можно использовать с git pull)
  3. затем он проверяет с помощью git rev-list --count <REMOTE_BRANCH>..<LOCAL_BRANCH> сколько коммитов локальная ветвь находится позади удаленной (и впереди наоборот)
  4. если локальная ветвь впереди 1 или более коммитов, она НЕ может быть быстрой -f или перенаправлена и должна быть объединена или перебазирована вручную
  5. если локальная ветвь имеет значение 0, фиксирующее впереди, и 1 или более, фиксирующуюся сзади, это может быть быстро -f или переадресовано 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 $@
+37
31 янв. '12 в 8:15
источник

Не так сложно автоматизировать:

#!/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
+24
30 нояб. '10 в 20:37
источник

Это все еще не автоматическое, поскольку я хотел бы иметь возможность для - и должна быть какая-то проверка, чтобы убедиться, что это может произойти только для быстрых обновлений (поэтому вручную делать притяжение намного безопаснее!!), но оговорки в стороне вы можете:

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

чтобы обновить положение вашего локального ветки, не проверяя его.

Примечание: вы потеряете свою текущую позицию ветки и переместите ее туда, где находится ветвь происхождения, а это означает, что если вам нужно слить, вы потеряете данные!

+17
14 июн. '11 в 2:37
источник

Эта проблема еще не решена (по крайней мере, не легко/без скриптов): см. this post в git списке рассылки Junio ​​C Hamano, объясняющем ситуацию и предоставляющем вызов для простого решения.

Основная причина состоит в том, что вам не нужно это:

С git, который не является древним (т.е. v1.5.0 или новее), нет оснований для имеют локальные "dev" , которые просто отслеживают удаленный. Если вы только хотите для поиска и просмотра, вы можете напрямую проверить ветвь удаленного отслеживания на отдельной головке с "git checkout origin/dev".

Это означает, что единственные случаи, которые нам необходимы, чтобы сделать его удобным для пользователей должны обрабатывать эти локальные ветки, которые "отслеживают" удаленные, когда вы это делаете имеют локальные изменения или когда вы планируете иметь некоторые.

Если у вас есть локальные изменения на "dev" , которые отмечены для отслеживания удаления "dev" , и если вы находитесь на ветке, отличной от "dev" , тогда мы не должны делать что-либо после того, как "git fetch" обновляет "dev" удаленного отслеживания. Это не будет ускоренным переходом вперед

Призыв к решению был для опции или внешних script для обрезать локальные ветки, которые следуют за ветками удаленного отслеживания, а не поддерживать их в актуальном состоянии путем быстрой пересылки, как и оригинал плаката.

Итак, как насчет "git branch --prune --remote=<upstream>", который повторяется локальные ветки, а если

(1) это не текущая ветвь; и
(2) он отмечен для отслеживания некоторой ветки, взятой из <upstream> ; и
(3) он не имеет никаких коммитов сам по себе;

затем удалите эту ветку? "git remote --prune-local-forks <upstream>" - также хорошо; Меня не волнует, какая команда реализует функцию, которая много.

Примечание: с git 2.10 такого решения не существует. Обратите внимание, что подкоманда git remote prune и git fetch --prune относятся к удалению ветки удаленного отслеживания для ветки, которая больше не существует на удаленном компьютере, а не об удалении локальной ветки, которая отслеживает ветвь удаленного отслеживания (для которой ветвь удаленного отслеживания является ветвью вверх по течению).

+11
07 мар. '09 в 23:28
источник

Здесь много ответов, но нет, которые используют 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

Из man-страницы для 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> (без каких-либо +), мы получим выборку, которая обновляет локальный номер ссылки только тогда, когда ее можно быстро переслать.

Примечание: предполагается, что локальная и удаленная ветки называются одинаковыми (и что вы хотите отслеживать все ветки), она должна действительно использовать информацию о том, какие локальные ветки у вас есть и что они установлены до отслеживания.

+11
01 апр. '14 в 16:53
источник

Здесь есть много приемлемых ответов, но некоторые из сантехники могут быть немного непрозрачными для непосвященных. Здесь гораздо более простой пример, который можно легко настроить:

$ 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
+7
18 июн. '13 в 23:59
источник

Вот хороший ответ: Как получить все ветки git

for remote in `git branch -r`; do git branch --track $remote; done
git pull --all
+6
23 янв. '15 в 14:27
источник

Добавьте этот скрипт в .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};
};
+5
16 июл. '13 в 13:48
источник

A script Я написал для своего GitBash. Выполняет следующее:

  • По умолчанию тянет из источника для всех ветвей, которые настроены для отслеживания координат, позволяет указать желаемый другой пульт.
  • Если ваша текущая ветка находится в грязном состоянии, она задерживает ваши изменения и попытается восстановить эти изменения в конце.
  • Для каждой локальной ветки, настроенной для отслеживания удаленной ветки, будет:
    • git checkout branch
    • git pull origin
  • Наконец, вернем вас в исходное состояние ветки и восстановления.

** Я использую это, но не тестировал полностью, используйте на свой страх и риск. См. Пример этого script в файле .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
    }
+3
23 апр. '15 в 16:43
источник

Если вы используете Windows, вы можете использовать PyGitUp, который является клоном git-up для Python. Вы можете установить его с помощью pip с помощью pip install --user git-up или через Scoop, используя scoop install git-up

[4]

+3
25 янв. '16 в 2:22
источник

Просто отправьте обновленный ответ. 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
+3
05 сент. '17 в 17:52
источник

Если refs/heads/master можно быстро переадресовать на refs/remotes/foo/master, вывод

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

должен вернуть идентификатор SHA1, на который указывает refs/heads/master. С этим вы можете собрать script, который автоматически обновляет все локальные ветки, у которых не было никаких отвлекающих коммитов.

Эта небольшая оболочка script (я называю ее 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
+2
08 мар. '09 в 22:26
источник

Чтобы завершить ответ Мэттом Коннолли, это более безопасный способ обновить локальные ссылки на ветку, которые можно быстро перенаправить, не проверяя ветвь. Он не обновляет ветки, которые не могут быть быстро перенаправлены (т.е. Расходились), и не обновляет ветвь, которая в настоящее время проверена (потому что тогда рабочая копия также должна быть обновлена).

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
+2
18 апр. '13 в 9:14
источник

Немного отличается script, что только ветки с быстрым переходом, имена которых совпадают с их ветвью вверх по течению. Он также обновляет текущую ветку, если возможна быстрая перемотка вперед.

Убедитесь, что все ветки ваших ветвей установлены правильно, запустив 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;
+2
27 июн. '14 в 12:21
источник

script из @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

Это, после завершения, оставляет рабочую копию проверенной из той же ветки, как это было до вызова script.

Версия 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
+1
04 февр. '14 в 8:22
источник

Похоже, что многие другие способствовали подобным решениям, но я думал, что разделю то, что я придумал, и пригласить других вносить свой вклад. Это решение имеет приятный красочный выход, изящно обрабатывает ваш текущий рабочий каталог и быстро, потому что он не делает никаких проверок и оставляет ваш рабочий каталог в такт. Кроме того, это всего лишь оболочка script без зависимостей, отличных от 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

Извините, я тоже, похоже, придумал то же имя, что и другой инструмент выше.

+1
15 окт. '15 в 0:02
источник

Это можно сделать, используя ниже script... Сначала он будет получать все ветки и проверку по одному и обновлять сам по себе.

#!/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
+1
16 янв. '18 в 11:36
источник

Следующая однострочная строка ускоряет пересылку всех ветвей, которые имеют ветку восходящего потока, если это возможно, и печатает ошибку в противном случае:

git branch \
  --format "%(if)%(upstream:short)%(then)git push . %(upstream:short):%(refname:short)%(end)" |
  sh

Как это работает?

Он использует пользовательский формат с командой git branch. Для каждой ветки с восходящей веткой она печатает строку со следующим шаблоном:

git push . <remote-ref>:<branch>

Это может быть передано непосредственно в sh (при условии, что имена ветвей правильно сформированы). Опустить | sh | sh чтобы увидеть, что он делает.

Предостережения

Однострочник не будет связываться с вашими пультами. git fetch --all 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. Псевдоним - это сокращение от "ускоренного отслеживания (ветки)".

+1
15 апр. '19 в 19:27
источник

По состоянию на git 2.9:

git pull --rebase --autostash

См. https://git-scm.com/docs/git-rebase

Автоматическое создание временного тайника перед началом операции, и применять его после окончания операции. Это означает, что вы можете запускать rebase на грязной worktree. Однако, используйте с осторожностью: последний тайник приложение после успешной перезагрузки может привести к нетривиальному конфликты.

-1
30 сент. '16 в 9:14
источник

Посмотрите другие вопросы по метке или Задайте вопрос