どのように対して繰り返し処理を実行するよgitの全ての枝を利用bashスクリプト

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

  •  27-09-2019
  •  | 
  •  

質問

たいのですが繰り返し処理を実行し、すべての地方の支店私のリポジトリを使用bashを記述します。いのに対して繰り返し処理を実行するにチェック違いはあると同支店では、一部のリモート。Ex

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

ただ、上記の問いに直面する$(git支店)を与えてくれているフォルダ内のフォルダのリポジトリの店舗のリポジトリ

これは正しい方これらの問題を解決するために?はしおりを付けることができないのですか?

役に立ちましたか?

解決

使用しないでください gitブランチ スクリプトを書くとき。 gitはaを提供します 「配管」インターフェイス これは、スクリプトで使用するために明示的に設計されています(通常のGITコマンドの現在および履歴の多くの実装(追加、チェックアウト、マージなど)と同じインターフェイスを使用)。

あなたが望む配管コマンドはです git for-ref-ref:

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

注:必要ありません remotes/ 原因となる他の参照がない限り、リモート参照のプレフィックス 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

この出力をパイプすることができます sh.

シェルコードを生成するという考えが気に入らない場合は、少し堅牢性をあきらめることができます* そしてこれを行います:

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

* ref名はシェルの単語分割から安全である必要があります(参照 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-)

のbashが組み込み, mapfile, て構築されたこ

gitの全ての枝: git branch --all --format='%(refname:short)'

すべての地域git店 git branch --format='%(refname:short)'

すべてのリモートロ支店 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 )

のOPの特定の状況:

#!/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文字のみで命名されている場合のみ

受け入れられた答えは正しいものであり、実際に使用されるアプローチである必要がありますが、Bashで問題を解決することは、シェルがどのように機能するかを理解するための素晴らしい演習です。追加のテキスト操作を実行せずにbashを使用してこれを行うためのトリックは、シェルによって実行されるコマンドの一部としてgitブランチの出力が拡張されないようにすることです。これにより、アスタリスクがシェル拡張のファイル名拡張(ステップ8)で拡大するのを防ぎます(参照 http://tldp.org/ldp/bash-beginners-guide/html/sect_03_04.html)

バッシュを使用します その間 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

両方のバッシュのアスタリスク 場合 パラメーターでの構成とパラメーターでの置換は、シェルがパターンマッチング文字としてそれらを解釈するのを防ぐために、バックスラッシュで逃げる必要があります。文字通り「*」と一致しているため、スペースも(トークン化を防ぐために)逃げます。

私の意見では覚えておくのが最も簡単なオプション:

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

出力:

bamboo
develop
master

GREPの-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

(私は多くのループを使用しています。特定のことのために、あなたは間違いなく先の尖った変数名["Branch"、など]を使用したいと思うでしょう、ほとんどの場合、私はそれぞれで何かをすることだけに関心があります ライン 入力の。ここでは「ブランチ」の代わりに「ライン」を使用することは、再利用性/筋肉の記憶/効率へのうなずきです。

@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 )

あなたがこの州にいる場合:

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

これは使用します git配管 スクリプト用に設計されたコマンド。また、シンプルで標準です。

参照: GitのBash完成

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top