Как повторять все ветви Git, используя сценарий Bash

StackOverflow https://stackoverflow.com/questions/3846380

  •  27-09-2019
  •  | 
  •  

Вопрос

Как я могу повторить все местные ветви в моем репозитории с помощью сценария Bash. Мне нужно повторить и проверять, есть ли разница между веткой и некоторыми удаленными ветвями. Бывший

for branch in $(git branch); 
do
    git log --oneline $branch ^remotes/origin/master;
done

Мне нужно сделать что-то вроде приведенного выше, но проблема, с которой я сталкиваюсь, это $ (GIT Fivil), дает мне папки внутри папки репозитории вместе с ветвями, присутствующими в репозитории.

Это правильный способ решить эту проблему? Или есть еще один способ сделать это?

Спасибо

Это было полезно?

Решение

Вы не должны использовать Гит-филиал При написании сценариев. Git обеспечивает а Интерфейс "Сантехника" Это явно разработано для использования в сценариях (многие текущие и исторические реализации обычных команд GIT (Add, Checkout, Merge и т. Д.) Используйте этот же интерфейс).

Команда сантехники, которую вы хотите, это Git для каждого:

git for-each-ref --shell \
  --format='git log --oneline %(refname) ^origin/master' \
  refs/heads/

Примечание: вам не нужны remotes/ префикс на удаленном режиме, если у вас нет других Refs, которые вызывают origin/master Чтобы совпадать с несколькими местами в пути поиска нанятия Ref (см. «Символическое имя] ...» в Раздел «Указание ревизий» Git-Rev-Parse (1)). Если вы пытаетесь придумать избежать неоднозначности, затем перейдите с полным названием Ref: refs/remotes/origin/master.

Вы получите вывод, как это:

git log --oneline 'refs/heads/master' ^origin/master
git log --oneline 'refs/heads/other' ^origin/master
git log --oneline 'refs/heads/pu' ^origin/master

Вы можете использовать этот вывод в штерива.

Если вам не нравится идея генерации кода оболочки, вы можете сдаться немного надежности* И сделать это:

for branch in $(git for-each-ref --format='%(refname)' refs/heads/); do
    git log --oneline "$branch" ^origin/master
done

* Имена Ref должны быть в безопасности от расщепления слов оболочки (см. Git-Check-Ref-формат (1)). Лично я бы придерживался бывшей версии (сгенерированный код оболочки); Я более уверен, что ничто не может случиться с этим.

С момента указания башмак И он поддерживает массивы, вы можете поддерживать безопасность и по-прежнему избегать генерации мужеств вашей петли:

branches=()
eval "$(git for-each-ref --shell --format='branches+=(%(refname))' refs/heads/)"
for branch in "${branches[@]}"; do
    # …
done

Вы могли бы сделать что-то похожее с $@ Если вы не используете оболочку, которая поддерживает массивы (set -- инициализировать и set -- "$@" %(refname) добавить элементы).

Другие советы

Это потому что git branch Отмечает нынешнюю ветку со звездочкой, например:

$ git branch
* master
  mybranch
$ 

так $(git branch) расширяется до EG * master mybranch, а потом * Расширяется до списка файлов в текущем каталоге.

Я не вижу очевидный вариант для не печатать звездочку в первую очередь; Но вы можете отрезать его:

$(git branch | cut -c 3-)

Bash встроенный, mapfile, построен для этого

Все филиалы Git: git branch --all --format='%(refname:short)'

Все местные ветви Git: git branch --format='%(refname:short)'

Все дистанционные ветви GIT: git branch --remotes --format='%(refname:short)'

Итайте через все ветви Git: mapfile -t -C my_callback -c 1 < <( get_branches )

пример:

my_callback () {
  INDEX=${1}
  BRANCH=${2}
  echo "${INDEX} ${BRANCH}"
}
get_branches () {
  git branch --all --format='%(refname:short)'
}
# mapfile -t -C my_callback -c 1 BRANCHES < <( get_branches ) # if you want the branches that were sent to mapfile in a new array as well
# echo "${BRANCHES[@]}"
mapfile -t -C my_callback -c 1 < <( get_branches )

Для конкретной ситуации ОП:

#!/usr/bin/env bash


_map () {
  ARRAY=${1?}
  CALLBACK=${2?}
  mapfile -t -C "${CALLBACK}" -c 1 <<< "${ARRAY[@]}"
}


get_history_differences () {
  REF1=${1?}
  REF2=${2?}
  shift
  shift
  git log --oneline "${REF1}" ^"${REF2}" "${@}"
}


has_different_history () {
  REF1=${1?}
  REF2=${2?}
  HIST_DIFF=$( get_history_differences "${REF1}" "${REF2}" )
  return $( test -n "${HIST_DIFF}" )
}


print_different_branches () {
  read -r -a ARGS <<< "${@}"
  LOCAL=${ARGS[-1]?}
  for REMOTE in "${SOME_REMOTE_BRANCHES[@]}"; do
    if has_different_history "${LOCAL}" "${REMOTE}"; then
      # { echo; echo; get_history_differences "${LOCAL}" "${REMOTE}" --color=always; } # show differences
      echo local branch "${LOCAL}" is different than remote branch "${REMOTE}";
    fi
  done
}


get_local_branches () {
  git branch --format='%(refname:short)'
}


get_different_branches () {
  _map "$( get_local_branches )" print_different_branches
}


# read -r -a SOME_REMOTE_BRANCHES <<< "${@}" # use this instead for command line input
declare -a SOME_REMOTE_BRANCHES
SOME_REMOTE_BRANCHES=( origin/master remotes/origin/another-branch another-remote/another-interesting-branch )
DIFFERENT_BRANCHES=$( get_different_branches )

echo "${DIFFERENT_BRANCHES}"

источник: Перечислите все местные филиалы Git без звездочки

Я повторяю, как это, например:

for BRANCH in `git branch --list|sed 's/\*//g'`;
  do 
    git checkout $BRANCH
    git fetch
    git branch --set-upstream-to=origin/$BRANCH $BRANCH
  done
git checkout master;

Я бы предложил$(git branch|grep -o "[0-9A-Za-z]\+") Если ваши локальные ветви называются цифрами, только буквами AZ и / или AZ AZ

Принятый ответ правильный и действительно должен быть использован подход, но решение проблемы в Bash - это отличное упражнение в понимании того, как раковины работают. Трюк для этого с использованием Bash без выполнения дополнительных текстовых манипуляций, состоит в том, чтобы гарантировать, что вывод филиала GIT никогда не расширяется как часть команды, которая будет выполнена оболочкой. Это предотвращает расширение звездочки в расширении имени файла (этап 8) расширения оболочки (см. http://tldp.org/ldp/bash-beginners-guide/html/sect_03_04.html.)

Используйте Bash пока Построить с помощью команды чтения, чтобы нарезать ветвь GIT в строки. «*» Будет прочитан как буквальный характер. Используйте оператор регистра, чтобы сопоставить его, уделяя особое внимание образующим шаблонам.

git branch | while read line ; do                                                                                                        
    case $line in
        \*\ *) branch=${line#\*\ } ;;  # match the current branch
        *) branch=$line ;;             # match all the other branches
    esac
    git log --oneline $branch ^remotes/origin/master
done

Звездочки в оба Bash кейс Конструкция и в замене параметра необходимо избежать обратной косой черты для предотвращения интерпретации оболочки в виде символов сопоставления шаблонов. Пространства также сбежаются (для предотвращения токенизации), потому что вы буквально сопоставляете «*».

Самый простой вариант, чтобы помнить, на мой взгляд:

git branch | grep "[^* ]+" -Eo

Выход:

bamboo
develop
master

Опция GreeP -O (- ито-сопоставление) ограничивает вывод только для соответствующих частей ввода.

Поскольку ни пространство, ни * не действительны в именах ветвей GIT, это возвращает список филиалов без дополнительных символов.

Редактировать: если вы находитесь в «Отсоединенная головка», Вам нужно будет отфильтровать текущую запись:

git branch --list | grep -v "HEAD detached" | grep "[^* ]+" -oE

То, что я покончил, обратился к вашему вопросу (& вдохновлен упоминанием CCPizza tr):

git branch | tr -d ' *' | while IFS='' read -r line; do git log --oneline "$line" ^remotes/origin/master; done

(Я использую пока много петлей. В то время как для конкретных вещей, которые вы определенно захотите использовать название указанного переменной [«Филиал», например, в большинстве случаев, когда я только обеспокоен делать что-то с каждым линия ввода. Используя «строку» здесь вместо «филиала», является кивком для повторного использования / мышечной памяти / эффективности.)

Расширяясь от ответа @ Финна (спасибо!), Следующее позволит вам повторять ветки без создания скрипта промежуточного оболочка. Это достаточно надежно, если в филиальном имени нет нивчиков :)

git for-each-ref --format='%(refname)' refs/heads  | while read x ; do echo === $x === ; done

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

while read x ; do echo === $x === ; done < <( git for-each-ref --format='%(refname)' refs/heads )

Если вы в этом состоянии:

git branch -a

* master

  remotes/origin/HEAD -> origin/master

  remotes/origin/branch1

  remotes/origin/branch2

  remotes/origin/branch3

  remotes/origin/master

И вы запускаете этот код:

git branch -a | grep remotes/origin/*

for BRANCH in `git branch -a | grep remotes/origin/*` ;

do
    A="$(cut -d'/' -f3 <<<"$BRANCH")"
    echo $A

done        

Вы получите этот результат:

branch1

branch2

branch3

master

Будь проще

Простой способ получить филиал имя в петле с помощью сценария Bash.

#!/bin/bash

for branch in $(git for-each-ref --format='%(refname)' refs/heads/); do
    echo "${branch/'refs/heads/'/''}" 
done

Выход:

master
other

Ответ Googlian, но без использования для

git for-each-ref --format='%(refname:lstrip=-1)' refs/heads/
for branch in "$(git for-each-ref --format='%(refname:short)' refs/heads)"; do
    ...
done

Это использует Гит сантехники Команды, предназначенные для сценариев. Это также просто и стандартно.

Ссылка: Завершение Bash Git

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top