что - git remove tag




Может ли «git pull--all» обновить все мои локальные филиалы? (14)

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

for remote in `git branch -r`; do git branch --track $remote; done
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», затем обновляет (перемотает вперед или объединяет) текущую рабочую ветвь, но не другие локальные ветви.

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


Добавьте этот скрипт в .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};
};

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

[


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

$ 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 "[email protected]"

Если вы добавляете ~/bin/git в свой PATH (при условии, что файл ~/bin/git/git-update-all ), вы можете просто запустить:

$ git update-all

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

Убедитесь, что все ветви ваших веток настроены правильно, запустив 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 2.9:

git pull --rebase --autostash

Смотрите https://git-scm.com/docs/git-rebase

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


Похоже, что многие другие предоставили аналогичные решения, но я подумал, что поделюсь тем, что я придумал, и приглашаю других внести свой вклад. Это решение имеет приятный красочный вывод, изящно обрабатывает ваш текущий рабочий каталог и быстро, потому что оно не делает никаких проверок и оставляет ваш рабочий каталог в такте. Кроме того, это всего лишь сценарий оболочки без каких-либо зависимостей, кроме 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 [email protected]{u}&>/dev/null; then
        REMOTE=$(git rev-parse --quiet --verify [email protected]{u})
        BASE=$(git merge-base $branch [email protected]{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-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, пожалуйста, смотрите его ответ here )

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

Сценарий от @larsmans, немного улучшен:

#!/bin/sh

set -x
CURRENT=`git rev-parse --abbrev-ref HEAD`
git fetch --all
for branch in "[email protected]"; 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 "[email protected]"; 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

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

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

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

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

#!/bin/sh
# Usage: fetchall.sh branch ...

set -x
git fetch --all
for branch in "[email protected]"; do
    git checkout "$branch"      || exit 1
    git rebase "origin/$branch" || exit 1
done

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

git sync

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

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

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

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


Примечание. Несмотря на то, что я опубликовал собственное решение, я бы порекомендовал использовать git-up , что также является приемлемым ответом.

Я знаю, что этому вопросу почти 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 -l -f <LOCAL_BRANCH> -t <REMOTE_BRANCH> помощью 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="[email protected]";
  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 [email protected]




git