Может ли "git pull --all" обновить все мои локальные филиалы? - PullRequest
425 голосов
/ 30 ноября 2010

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

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

Ответы [ 22 ]

190 голосов
/ 20 марта 2012

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

git sync

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

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

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

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

172 голосов
/ 30 ноября 2010

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

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

34 голосов
/ 31 января 2012

Я знаю, что этому вопросу почти 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 или более коммитов вперед, она может НЕ быть быстро продвинутой и должна быть объединена или перебазирована вручную
  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 $@
24 голосов
/ 30 ноября 2010

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

#!/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
16 голосов
/ 14 июня 2011

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

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

для обновления позиции вашего местного отделения без проверки.

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

11 голосов
/ 08 марта 2009

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

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

С git, который не является древним (то есть v1.5.0 или новее), нет причин для есть местный "dev", который больше просто отслеживает пульт. Если вы только хотите чтобы посмотреть и посмотреть, вы можете проверить удаленную ветку отслеживания напрямую на отдельной ГОЛОВКЕ с "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 предназначены для удаления ветви удаленного отслеживания для ветви, которая больше не существует на удаленной, а не для удаления локальной ветви, которая отслеживает ветку удаленного отслеживания (для которой ветвь удаленного отслеживания является восходящей веткой) .

10 голосов
/ 01 апреля 2014

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

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

7 голосов
/ 19 июня 2013

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

$ 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 голосов
/ 23 января 2015

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

for remote in `git branch -r`; do git branch --track $remote; done
git pull --all
5 голосов
/ 16 июля 2013

Добавьте этот скрипт в .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};
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...