Как перебирать все ветви git с помощью скрипта bash



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



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


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



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



спасибо

859   8  

8 ответов:

вы не должны использовать git branch при написании скриптов. Git предоставляет "сантехника" интерфейс который явно предназначен для использования в сценариях (многие текущие и исторические реализации обычных команд Git (add, checkout, merge и т. д.) используйте этот же интерфейс).

сантехника команда, которую вы хотите git for-each-ref:

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

Примечание: вам не нужно remotes/ префикс на удаленном ref если у вас нет других ссылок, которые вызывают 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

* Имена ссылок должны быть защищены от разделения слов оболочки (см. git-check-ref-format (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) расширяет, например,* master mybranch, а потом * расширяется до списка файлов в текущем каталоге.

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

$(git branch | cut -c 3-)

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

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

используйте bash пока построить с помощью команды чтения, чтобы нарезать вывод ветви 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;

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

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

выход:

bamboo
develop
master

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

поскольку ни пробел, ни * не допустимы в именах ветвей 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

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

расширение от ответа @finn (спасибо!), следующее позволит вам перебирать ветви без создания промежуточного сценария оболочки. Он достаточно надежен, пока в названии ветки нет новых строк:)

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 )

Comments

    Ничего не найдено.