Как перебрать все ветки git, используя скрипт bash

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

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

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

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

Спасибо

 kodaman01 июл. 2019 г., 02:21
@pihentagy Это было написано до связанного вопроса.
 pihentagy24 авг. 2016 г., 14:19

Ответы на вопрос(10)

что я в итоге сделал, применил к вашему вопросу (и вдохновил упоминанием ccpizzatr):

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

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

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

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

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

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

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;
 budiantoip15 нояб. 2018 г., 06:13
именно то, что мне нужно, спасибо

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

Выход:

bamboo
develop
master

Опция -o в Grep (--only-match) ограничивает вывод только совпадающими частями ввода.

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

Изменить: если вы находитесь всостояние "оторванная голова"вам нужно отфильтровать текущую запись:

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

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

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

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

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

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

Решение Вопроса

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

Команда сантехника вы хотитемерзавец для каждого реф:

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

Примечание: вам не нужноremotes/ префикс на удаленном реф, если у вас нет других реф, которые вызываютorigin/master чтобы найти несколько мест в пути поиска имени ссылки (см. «Символическое имя ссылки.…» враздел «Задание версий» git-rev-parse (1)). Если вы пытаетесь явно избежать двусмысленности, используйте полное имя ссылки: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

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

Поскольку вы указалиудар и он поддерживает массивы, вы можете поддерживать безопасность и при этом избегать генерации кишок вашего цикла:

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

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

 Alexander Mills05 авг. 2018 г., 20:02
JSON нужно использовать в инструментах командной строки, я не могу поверить, что Git и другие еще не сделали этого
 Chris Cogdon24 окт. 2017 г., 00:26
Если вывод защищен от новых строк, можно сделать это:git for-each-ref --format='%(refname)' refs/heads | while read x ; do echo === $x === ; done, Обратите внимание, что это ставитwhile петля в подрублю. Если вы хотитеwhile цикл в текущей оболочке, то это:while read x ; do echo === $x === ; done < <( git for-each-ref --format='%(refname)' refs/heads )
 wid13 янв. 2016 г., 15:47
Более простая версия:git for-each-ref refs/heads | cut -d/ -f3-
 John Gietzen04 мая 2016 г., 21:30
@wid: Или простоgit for-each-ref refs/heads --format='%(refname)'
 torek05 авг. 2018 г., 21:13
@ Thayne: этот вопрос старый, но ребята из Git наконец-то решили проблему:for-each-ref теперь поддерживает все селекторы филиалов, такие как--merged а такжеgit branch а такжеgit tag в настоящее время фактически реализованы с точки зренияgit for-each-ref Сам, по крайней мере, для списка существующих дел. (Создание новых веток и тегов не является и не должно быть частьюfor-each-ref.)
 Thayne20 апр. 2015 г., 23:23
Но что, если я хочу использовать один из вариантов фильтрации в git branch, например--mergedДолжен ли я дублировать логику в ветке git? Должен быть лучший способ сделать это.
 Jim Fell17 апр. 2015 г., 23:59
Шутки в сторону. Нет более простого способа сделать это?

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 без звездочки

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

$ git branch
* master
  mybranch
$ 

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

Я не вижу очевидной возможности не печатать звездочку в первую очередь; но вы можете отрубить это:

$(git branch | cut -c 3-)
 LJT19 дек. 2016 г., 00:31
Это решение удаляет *stackoverflow.com/a/12142066/977566
 Nick02 окт. 2010 г., 18:00
Если вы заключите в двойные кавычки, вы можете остановить bash от расширения звездочки - хотя вы все равно захотите удалить его из вывода. Более надежный способ удаления звездочки из любой точки будет$(git branch | sed -e s/\\*//g).
 ccpizza15 апр. 2015 г., 17:50
немного более простая версия tr:$(git branch | tr -d " *")
 jdg08 февр. 2015 г., 19:17
Немного более простая версия sed:$(git branch | sed 's/^..//')
 Andrei-Niculae Petre10 мая 2013 г., 12:28
хорошо, мне очень нравится твой3- решение.

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

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

Ваш ответ на вопрос