123

bashスクリプトを使用して、リポジトリ内のすべてのローカルブランチを反復処理するにはどうすればよいですか。繰り返して、ブランチといくつかのリモートブランチの間に違いがあるかどうかを確認する必要があります。元

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

上記のようなことをする必要がありますが、私が直面している問題は、$(git branch)によって、リポジトリに存在するブランチとともにリポジトリフォルダ内のフォルダが表示されることです。

これはこの問題を解決する正しい方法ですか?またはそれを行う別の方法はありますか?

ありがとうございました

4

15 に答える 15

180

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

必要な配管コマンドはgitfor-each-refです:

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

remotes/注:参照名検索パスの複数の場所に一致する他の参照がない限り、リモート参照にプレフィックス は必要ありません( git-rev-parseの「リビジョンの指定」セクションのorigin/master「シンボリック参照名…」を参照)。(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

この出力をshにパイプできます。

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

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

*参照名は、シェルの単語分割から安全である必要があります(git-check-ref-format(1)を参照)。個人的には、以前のバージョン(生成されたシェルコード)を使用します。私はそれで不適切なことは何も起こり得ないと確信しています。

bashを指定し、それが配列をサポートしているので、安全性を維持しながら、ループの内臓を生成することを回避できます。

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

$@配列をサポートするシェルを使用していない場合(set --初期化およびset -- "$@" %(refname)要素の追加)と同様のことを行うことができます。

于 2010-10-02T21:24:21.333 に答える
53

これはgit branch、現在のブランチをアスタリスクでマークするためです。例:

$ git branch
* master
  mybranch
$ 

したがって$(git branch)、たとえば* master mybranchに展開し、次に*現在のディレクトリ内のファイルのリストに展開します。

そもそもアスタリスクを印刷しないための明白なオプションがわかりません。しかし、あなたはそれを切り落とすことができます:

$(git branch | cut -c 3-)
于 2010-10-02T15:49:47.523 に答える
16

bashmapfileビルトイン、、はこのために構築されています

すべての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 )

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ブランチを一覧表示します

于 2018-11-12T22:30:00.733 に答える
6

たとえば、次のように繰り返します。

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;
于 2016-03-21T11:40:51.277 に答える
5

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

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

出力:

bamboo
develop
master

Grepの-oオプション(--only-matching)は、出力を入力の一致する部分のみに制限します。

Gitブランチ名ではスペースも*も有効ではないため、これは余分な文字を含まないブランチのリストを返します。

編集:「ヘッドが外れた」状態の場合は、現在のエントリを除外する必要があります。

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

于 2017-08-01T14:00:11.627 に答える
4

$(git branch|grep -o "[0-9A-Za-z]\+")あなたの地元の支店が数字、az、および/またはAZ文字のみで名前が付けられているかどうかをお勧めし ます

于 2012-07-20T03:43:00.063 に答える
4

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

gitブランチの出力を行に分割するには、readコマンドでbashwhile構文を使用します。'*'はリテラル文字として読み込まれます。一致するパターンに特に注意して、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

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

于 2016-01-30T08:32:11.933 に答える
4

単純にする

bashスクリプトを使用してループ内のブランチ名を取得する簡単な方法。

#!/bin/bash

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

出力:

master
other
于 2019-04-10T10:29:24.107 に答える
3

私がやったこと、あなたの質問に適用された(そしてccpizzaの言及に触発されたtr):

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

(私はwhileループをよく使用します。特定の場合は、ポイントされた変数名[たとえば、 "branch"]を使用する必要がありますが、ほとんどの場合、入力の各行で何かを実行することだけに関心があります。ここで「ブランチ」の代わりに「ライン」を使用すると、再利用性/筋肉の記憶/効率が向上します。)

于 2018-01-30T18:36:39.220 に答える
3

グーグリアンの答えですが

git for-each-ref --format='%(refname:lstrip=-1)' refs/heads/
于 2019-07-18T10:13:21.887 に答える
3
for branch in "$(git for-each-ref --format='%(refname:short)' refs/heads)"; do
    ...
done

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

参照:GitのBashの完了

于 2019-09-01T17:19:37.313 に答える
2

この状態の場合:

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
于 2019-03-07T03:53:46.270 に答える
1

@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 )
于 2017-10-23T22:31:09.100 に答える
1

ローカルリポジトリのヘッド(ブランチ)を一覧表示します

git show-ref --heads
  • git show-ref-ローカルリポジトリに参照を一覧表示します
    • --headsリストのみheads(タグではない)

これは、次のような頭を一覧表示します

682e47c01dc8d0f4e4102f183190a48aaf34a3f0 refs/heads/main
....

そのため、名前だけに関心がある場合は、次のようなものを使用して、必要なsed出力を取得できます。

git show-ref --heads | sed 's/.*refs\/heads\///'

ブランチを反復処理します

この出力を使用すると、ボートを浮かせるものなら何でも、bashループ、xargsを使用して、簡単に繰り返すことができます。

for SHA in $(git show-ref --heads | awk '{ print $1 }'); do
 echo "magic! $SHA"
done
  • git show-ref --heads上記のようにブランチを取得します
  • awk '{ print $1 }'SHAを取得する
  • echo "magic! $SHA"<-これはあなたがあなたの魔法をする場所です
于 2021-05-31T16:38:17.690 に答える
0
#/bin/bash
for branch in $(git branch -r); 
do
    echo $branch
done
于 2021-10-13T18:56:36.403 に答える