Может ли "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 ]

3 голосов
/ 05 сентября 2017

Просто отправляю обновленный ответ. 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 голосов
/ 25 января 2016

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

[4]

3 голосов
/ 23 апреля 2015

Сценарий, который я написал для моего 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
    }
2 голосов
/ 09 марта 2009

Если 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
2 голосов
/ 18 апреля 2013

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

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
1 голос
/ 24 апреля 2019

Я сталкивался с той же проблемой этого вопроса ...

Удивляясь этому, я сделал маленькую функцию псевдонима внутри моего .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"
}

я (:

1 голос
/ 16 января 2018

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

#!/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 голос
/ 15 октября 2015

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

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

Убедитесь, что восходящие ветви всех ваших веток настроены правильно, запустив 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;
1 голос
/ 04 февраля 2014

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