「git pull --all」ですべてのローカルブランチを更新できますか?


473

私は、少なくとも3つのリモートブランチ(マスター、ステージング、プロダクション)を持っていることがよくあります。これらのリモートブランチを追跡する3つのローカルブランチがあります。

私のすべてのローカルブランチを更新するのは面倒です:

git fetch --all
git rebase origin/master
git checkout staging
git rebase origin/staging
git checkout production
git rebase origin/production

"git pull -all"だけを実行したいのですが、実行できませんでした。「fetch --all」を実行してから、現在の作業ブランチを更新(早送りまたはマージ)しますが、他のローカルブランチは更新しないようです。

それでも手動で各ローカルブランチに切り替えて更新するのに困っています。


8
早送りの場合にのみローカル追跡ブランチの自動更新が必要ですか?Ypuすべきです。マージすると、解決する必要がある競合が発生する可能性があるためです...
JakubNarębski2009年

34
これをいじくるためにコンサルタントの時間を保守的に300ドルと仮定すると、この単一の問題は77,476のビュー数を使用して、会社に23,242,800ドルのコストをかけます。次に、この質問stackoverflow.com/questions/179123/…とその他すべての質問を検討します。ワオ。
ルークPuplett 2014年

16
@Lukeあなたが聞いた最初の人で、Gitを実現するために費やした時間によって企業のコストがどのように増加するかを指摘しました。これらの単純なことは自動的に行われるべきであり、非常に単純であるべきです。フォーラムを読むためにブラウザを開く必要はありません、IMO。
サミュエル

13
@LukePuplett SOのgitにはMercurialに比べて約9倍の質問があり、前者の大半は「gitで<簡単な操作>を行うにはどうすればよいですか」のようです。これは、gitの設計が不適切、文書化が不十分、直感的でない、または3つすべてであることを示しています。
Ian Kemp

26
@IanKemp SOの人口統計を知らずにその主張をしても安全かどうかはわかりません。ここでMercurialが一般的に使用されていない場合、またはユーザーが他のフォーラムを使用してそれについて質問した場合も、同じ結果が得られるはずです。:)アセンブリに比べてJavascriptの質問は最大51倍あります。そのため、これらの種類のメトリックだけでツールを判断することは必ずしも正確ではない場合があります。
danShumway、2015年

回答:


188

説明する動作pull --allは期待どおりですが、必ずしも有用ではありません。オプションはgit fetchに渡され、必要なものだけでなく、すべてのリモートからすべての参照をフェッチします。pull次に、適切な単一のブランチをマージします(場合によっては、リベースします)。

他のブランチをチェックアウトしたい場合は、それらをチェックアウトする必要があります。そして、はい、マージ(およびリベース)には絶対に作業ツリーが必要なので、他のブランチをチェックアウトしないと作業ツリーを実行できません。必要に応じて、説明したステップをスクリプト/エイリアスにまとめることもできますが、コマンドを結合して、コマンドの&&1つが失敗した場合でも、耕さないようにすることをお勧めします。


2
コマンドラインの例を挙げれば、私は投票します。私はgithubでこの問題を抱えています。UIにブランチを作成しました。今、私は地元の人にブランチを見せてもらう必要があります。git pull --all; git branch ...
argh

@mariotti何をしようとしているかに依存しますが、コメントからは明確ではありません。新しい質問をするのが一番です。
Cascabel 2016年

1
または@Jefromi ..例を挙げてください。私は実際にあなたに同意しました。
mariotti 2016年

3
@mariottiこの回答の要点は、組み込みコマンドは実際にはOPが要求したことを実行しないため、それらが持っていた一連のステップが必要です。これらの手順を自動化することは可能ですが(たとえば、Johnの回答を参照)、それらは実行する必要があります。したがって、実行しようとしていることがOPとまったく同じである場合、実際に示す例はありません。別のことを実行しようとしている場合は、新しい質問をする必要があります。それがStackOverflowのしくみです。(そして、あなたのコメントは不明確ですが、私の最高の推測は、あなたがここでOPとは異なる何かを望んでいるということなので、そうです、新しい質問です。)
Cascabel

はい、多少異なります。しかし、あなたの答えはコンテキストにぴったりでした。そして、私はあなたの答えのためだけにもう尋ねる必要はないかもしれません。ただ:受け入れられた回答はgit-upを使用しています。これはgitコマンドラインへのインターフェースにすぎません(私はそう思います)。gitコマンドの数行でそれを明示的にできることを望んでいました。現在の答えはgitではありません。
mariotti 2016年

206

これを自動化するには、hubsyncサブコマンドを使用します。私はにいるので、入力するコマンドは次のとおりです。alias git=hub.bash_profile

git sync

これにより、一致する上流ブランチを持つすべてのローカルブランチが更新されます。manページから:

  • ローカルブランチが古くなっている場合は、早送りしてください。
  • ローカルブランチにプッシュされていない作業が含まれている場合は、警告します。
  • ブランチがマージされているようで、その上流のブランチが削除されている場合は、削除します。

また、現在のブランチでコミットされていない変更のスタッシュ/スタッシュ解除も処理します。

以前はgit-upと呼ばれる同様のツールを使用していましたが、もはやメンテナンスされておらず、git syncほぼ同じことを行います。


15
Windowsはどうですか?
バイオレットキリン2015年

6
@ TrentonD.Adamsのコミット日と作成者の日付は異なる概念です。リベースはコミット日を変更しますが、作成者の日付は変更しません(作成者の日付も変更される競合を除きます)。作成者の日付は、コミットのツリーがいつ作成されたかを反映しており、競合のないリベース中に変更してはなりません。リベースは常に新しいコミットを作成するため、コミット日付が変更されます。したがって、コミット日付は常に正しい順序になります。
開発者2015

16
git-upの自動リベース動作をオフにするには、を実行しgit config --global git-up.rebase.auto falseます。
Dan Loewenherz、2015

18
@MaxYankov共有履歴のリベースは通常避けられます。プル中にローカルコミットをリベースしても問題はありません。
開発者

23
ローカルコミットをリベースすると、履歴が書き換えられ、実際よりもシンプルになります。リベースを使用すると、自動的にマージされてもコンパイルされないコード、またはさらに悪いことに、コンパイルされても機能しないコードが表示されることがあります。マージはあなたが働いた方法を認めます:あなたは変更を実装して他の人の変更を組み込む前にそれらをテストしました、そしてマージコミットは非常に有用なポイントです:それはあなたが異なるシャゲセットがうまくうまく動作することを確認する場所です。リベースにより、このプロセスは決して起こらないように見えますが、これは単に真実ではなく、非常に危険な習慣です。
Max Yankov

39

私はこの質問がほぼ3年前のものであることを知っていますが、私自身にも同じ質問をしたところ、既成の解決策は見つかりませんでした。そこで、私は自分でカスタムgitコマンドシェルスクリプトを作成しました。

ここで、git-ffwd-updateスクリプトは次のことを行います...

  1. それは発行します git remote updateは遅い回転をフェッチため
  2. 次に、を使用git remote showして、リモートブランチを追跡するローカルブランチのリストを取得します(例:git pull
  3. それからチェックします git rev-list --count <REMOTE_BRANCH>..<LOCAL_BRANCH>、ローカルブランチがリモートの背後にあるコミットの数をます(その逆も同様です)。
  4. ローカルブランチが1つ以上コミットされている場合、それはできません早送りすると、ニーズが手でマージやリベースされます
  5. ローカルブランチが0コミット先で、1つ以上のコミット先である場合、次のようにして早送りできます。 git branch -f <LOCAL_BRANCH> -t <REMOTE_BRANCH>

スクリプトは次のように呼び出すことができます:

$ git ffwd-update
Fetching origin
 branch bigcouch was 10 commit(s) behind of origin/bigcouch. resetting local branch to remote
 branch develop was 3 commit(s) behind of origin/develop. resetting local branch to remote
 branch master is 6 commit(s) behind and 1 commit(s) ahead of origin/master. could not be fast-forwarded

完全なスクリプトはとして保存する必要があり、に置く必要がgit-ffwd-updateありますPATH

#!/bin/bash

main() {
  REMOTES="$@";
  if [ -z "$REMOTES" ]; then
    REMOTES=$(git remote);
  fi
  REMOTES=$(echo "$REMOTES" | xargs -n1 echo)
  CLB=$(git rev-parse --abbrev-ref HEAD);
  echo "$REMOTES" | while read REMOTE; do
    git remote update $REMOTE
    git remote show $REMOTE -n \
    | awk '/merges with remote/{print $5" "$1}' \
    | while read RB LB; do
      ARB="refs/remotes/$REMOTE/$RB";
      ALB="refs/heads/$LB";
      NBEHIND=$(( $(git rev-list --count $ALB..$ARB 2>/dev/null) +0));
      NAHEAD=$(( $(git rev-list --count $ARB..$ALB 2>/dev/null) +0));
      if [ "$NBEHIND" -gt 0 ]; then
        if [ "$NAHEAD" -gt 0 ]; then
          echo " branch $LB is $NBEHIND commit(s) behind and $NAHEAD commit(s) ahead of $REMOTE/$RB. could not be fast-forwarded";
        elif [ "$LB" = "$CLB" ]; then
          echo " branch $LB was $NBEHIND commit(s) behind of $REMOTE/$RB. fast-forward merge";
          git merge -q $ARB;
        else
          echo " branch $LB was $NBEHIND commit(s) behind of $REMOTE/$RB. resetting local branch to remote";
          git branch -f $LB -t $ARB >/dev/null;
        fi
      fi
    done
  done
}

main $@

1
このスクリプトをありがとう。誰かがそのスクリプトをWindowsバッチに変換できる可能性はありますか?
サーリコ2012

@Saarikoなぜ通常のWindowsシェルでgitを使用したくないのですか?cygwinのようなものを使用する場合、このスクリプトは正常に動作します...(私はテストしていませんが)
muhqu

@RyanWilcoxおかげで、私は毎日(仕事日)のように使っています... ;-) git関連のスクリプトとエイリアスについては、私のdot-filesを確認することをお勧めします: github.com/muhqu/dotfiles
muhqu

@muhquスクリプトを使用しようとしていますが、なぜ最初に機能したのかわかりませんが、現時点では「期待どおり」に機能していません。たとえば、これを見てください。スクリプトを実行した後、masterがまだ78コミット遅れているのはなぜですか?
BPL、2016年

1
@muhqu新しいgitバージョンでは、-tと-lを1つのgit branch呼び出し内で一緒に使用することは想定されていません。-lを削除して呼び出しをに変更するとgit branch -f $LB -t $ARB >/dev/null;、スクリプトは正常に機能します。
Radek Liska、

24

自動化はそれほど難しくありません。

#!/bin/sh
# Usage: fetchall.sh branch ...

set -x
git fetch --all
for branch in "$@"; do
    git checkout "$branch"      || exit 1
    git rebase "origin/$branch" || exit 1
done

4
スクリプトでエイリアスを使用しないことをお勧めします。これも実際には何もフェッチせず、すでにフェッチしたコンテンツにリベースするだけです。に変更git rebase origin/$branchしてgit pull、適切な追跡ブランチ(おそらく起点にある)からフェッチし、構成で決定されたとおりにマージまたはリベースするようにする必要があります。
Cascabel

@Jefromi:を忘れていましたfetch。編集した; OPまでの追加機能/修正。
Fred Foo

8
通常のプル(マージ)に設定されているブランチを誤ってリベースしないように、使用pull(またはチェックbranch.<branch>.rebase)したいと思うかもしれません。
Cascabel 2010年

1
set -e代わりに|| exit 1を使用して、最初のエラーでインタープリターを終了することを検討してください。
crishoj

18

これはまだ自動ではありません。選択肢があったらいいのにと思います-そして、これが早送り更新でのみ発生することを確認するためのチェックが必要です(そのため、手動でプルを実行する方がはるかに安全です!!)。ただし、次のことはできます。

git fetch origin
git update-ref refs/heads/other-branch origin/other-branch

チェックアウトせずにローカルブランチの位置を更新する。

注:現在のブランチの位置が失われ、オリジンのブランチがある場所に移動されます。つまり、マージする必要がある場合、データが失われます。


1
これはまさに私が探していたソリューションです。通常、複数のブランチにプッシュされていない変更はありません。リモートと一致するようにさまざまなローカルブランチを更新したいだけです。このソリューションは、私の通常の削除/再チェックアウト方法よりもはるかに優れています!
デイブナイト

1
1つのコマンドに結合:git fetch origin other-branch:other-branch
fabb

12

ここには多くの答えがありますがgit-fetch、ローカル参照を直接更新するために使用するものはありません。これは、ブランチをチェックアウトするよりもはるかに簡単で、より安全ですgit-update-ref

ここではgit-fetch、非現在のブランチと現在のブランチを更新するために使用しgit pull --ff-onlyます。それ:

  • ブランチをチェックアウトする必要はありません
  • 早送りできる場合にのみブランチを更新します
  • 早送りできない場合に報告します

そしてここにあります:

#!/bin/bash
currentbranchref="$(git symbolic-ref HEAD 2>&-)"
git branch -r | grep -v ' -> ' | while read remotebranch
do
    # Split <remote>/<branch> into remote and branchref parts
    remote="${remotebranch%%/*}"
    branchref="refs/heads/${remotebranch#*/}"

    if [ "$branchref" == "$currentbranchref" ]
    then
        echo "Updating current branch $branchref from $remote..."
        git pull --ff-only
    else
        echo "Updating non-current ref $branchref from $remote..."
        git fetch "$remote" "$branchref:$branchref"
    fi
done

のマンページからgit-fetch

   <refspec>
       The format of a <refspec> parameter is an optional plus +, followed by the source ref <src>,
       followed by a colon :, followed by the destination ref <dst>.

       The remote ref that matches <src> is fetched, and if <dst> is not empty string, the local ref
       that matches it is fast-forwarded using <src>. If the optional plus + is used, the local ref is
       updated even if it does not result in a fast-forward update.

git fetch <remote> <ref>:<ref>(何も指定せずに+)指定することで、ローカル転送を早送りできる場合にのみローカル参照を更新するフェッチを取得します。

:これは、ローカルブランチとリモートブランチに同じ名前が付けられている(そしてすべてのブランチを追跡する)ことを前提としています。実際には、ローカルブランチと追跡するために設定されているものに関する情報を使用する必要があります。


1
「ブランチを早送りできる場合のみ更新する」 -早送りの意味は何ですか?すべてのブランチで最新のソースが必要な場合、なぜ高速転送を気にする必要があるのですか?GitとそのFanboiを笑わせるようなこのようなこと。これを1つのコマンドで実行することはできません。代わりc*nに、(1の代わりに)ステップを実行する必要があります。ここで、cは、繰り返されるコマンドnの数であり、分岐の数です。
jww 2016年

@jww世界で最も使用されているVCSである場合、「GitとそのFanboiで笑う」[sic]は役に立ちません。しかし、余談ですが、この種の「グローバルプル」スクリプトのコンテキストでは、マージの競合がある場合、現在以外のブランチに変更を加えないようにするのが賢明だと思います。
Ville

これは役に立ちました、ありがとう。私が気に入らなかったのは、リモートブランチ(興味のないブランチを含む)ごとにローカルにブランチを作成することだけだったので、すでにローカルにあるブランチに制限するように変更git branch -r | grep -v ' -> ' | while read remotebranchgit branch -r | grep -v ' -> ' | grep -f <(git branch | cut -c 3- | awk '{print "\\S*/"$0"$"}') | while read remotebranchました。またgit fetch --prune、何かを行う前にリモートブランチのリストを更新するために最初にを追加しました。これにより、警告がいくつか回避されます。
ネイト・クック

11

この問題は(まだ)解決されていません、少なくとも簡単ではありません/スクリプトなし:状況を説明し、簡単な解決策を提供する、Jumio C Hamanoによるgitメーリングリストのこの投稿を参照してください。

主な理由は、これは必要ないということです。

古くないgit(つまりv1.5.0以降)では、リモートを純粋に追跡するローカルの「dev」を使用する理由はありません。見回したいだけの場合は、「git checkout origin/dev」を使用して、切り離されたHEADのリモート追跡ブランチを直接チェックアウトできます。

つまり、ユーザーに便利にする必要がある唯一のケースは、ローカルの変更がある場合、またはローカルで変更する予定がある場合に、リモートブランチを「追跡」するこれらのローカルブランチを処理することです。

削除「dev」を追跡するようにマークされている「dev」のローカル変更があり、「dev」とは異なるブランチにいる場合、「」git fetchがリモート追跡「dev」を更新した後は何もすべきではありません。 。とにかく早送りしません

解決策の要求は、オプションまたは外部スクリプトが、現在のリモート追跡ブランチに続くローカルブランチを、元の投稿者が要求したように、早送りで最新に保つのではなくプルーニングすることでした。

ではgit branch --prune --remote=<upstream>、ローカルブランチを反復する「」はどうでしょうか。

(1)現在のブランチではありません。そして
(2)<上流>から取られたいくつかの支店を追跡するためにマークされています。そして
(3)それは自分自身でコミットをしていません。

次にそのブランチを削除しますか?「git remote --prune-local-forks <upstream>」も問題ありません。どのコマンドが機能をそれほど実装しているかは気にしません。

注: git 2.10以降、そのようなソリューションは存在しません。git remote pruneサブコマンドは、git fetch --pruneリモートに存在しなくなったブランチのリモート追跡ブランチの削除に関するものであり、リモート追跡ブランチを追跡するローカルブランチ(リモート追跡ブランチが上流ブランチである)の削除に関するものではないことに注意してください。


リンクを投稿するだけでなく、リンクを参考にして実際のコンテンツ投稿してください。そのリンクは今死んでいる。残念ながら、有望に聞こえました。(この回答は2009年からだったので、今後の参考のためのメモにすぎません。)
マイケル、2017年

感謝します(そして何年も経ってからすごい、速い応答)。このスレッドは、元の誤解ではなく「単純なソリューションを提供する」ではなく、「単純なソリューションの呼び出し」であることがわかりました。
マイケル

@michael_n:展開された...うーん、今度は投稿が要求された解決策に関するものではないことがわかりましたが、それは問題に関するものでした(XY問題の場合)。
JakubNarębski2017年

うーん、デタッチされたヘッドでのピークはもっと簡単にできるはずです。特にステータスに有用な情報が表示され、何らかのフィードバック(プルされたコミットなど)でワークスペースを早送りする必要があります。次に、読み取り専用のローカルブランチの代わりになります。
eckes '06 / 06/15

9

ここには受け入れられる答えがたくさんありますが、一部の配管は、初心者には少し不透明かもしれません。これは、簡単にカスタマイズできるはるかに単純な例です。

$ cat ~/bin/git/git-update-all
#!/bin/bash
# Update all local branches, checking out each branch in succession.
# Eventually returns to the original branch. Use "-n" for dry-run.
git_update_all() {
  local run br
  br=$(git name-rev --name-only HEAD 2>/dev/null)
  [ "$1" = "-n" ] && shift && run=echo

  for x in $( git branch | cut -c3- ) ; do
     $run git checkout $x && $run git pull --ff-only || return 2
  done

  [ ${#br} -gt 0 ] && $run git checkout "$br"
}

git_update_all "$@"

にを追加~/bin/gitした場合PATH(ファイルがであると想定~/bin/git/git-update-all)、次のコマンドを実行できます。

$ git update-all

ありがとう!あなたは私をbashで遊ぶ時間を節約しました...
8ctopus

5

次のスクリプト.profileMac OS Xに追加します

# Usage:
#   `git-pull-all` to pull all your local branches from origin
#   `git-pull-all remote` to pull all your local branches from a named remote

function git-pull-all() {
    START=$(git symbolic-ref --short -q HEAD);
    for branch in $(git branch | sed 's/^.//'); do
        git checkout $branch;
        git pull ${1:-origin} $branch || break;
    done;
    git checkout $START;
};

function git-push-all() {
    git push --all ${1:-origin};
};

1
これはすべての変更を最初に隠し、次にそれらを復元するべきではありませんか?
2016

5

ここに良い答えがあります:すべてのgitブランチをフェッチする方法

for remote in `git branch -r`; do git branch --track $remote; done
git pull --all

なぜあなたは、の代わりにgit fetchand を提案するのですか?git pullgit pull
syntagma

ありがとう。プルはすべてのリモートからすべてのブランチをフェッチするようです。変更されました
milkovsky

8
これはすべてのリモートをフェッチしますが、現在のブランチのみをマージします。10個のリモートがある場合は、それぞれを手動でチェックアウトしてマージする必要があります。
mpoisot 16

これを行うと、すべてのリモートブランチがorigin/プレフィックス付きでローカルに作成されます
Yassine ElBadaoui 2017年

3

私のGitBash用に作成したスクリプト。以下を達成します。

  • デフォルトでは、起点を追跡するように設定されているすべてのブランチの起点からのプルにより、必要に応じて別のリモートを指定できます。
  • 現在のブランチがダーティな状態にある場合は、変更を隠しておき、最後にこれらの変更を復元しようとします。
  • リモートブランチを追跡するように設定されているローカルブランチごとに、次のことを行います。
    • git checkout branch
    • git pull origin
  • 最後に、元のブランチに戻り、状態を復元します。

**私はこれを使用していますが、十分にテストしていません。自己責任で使用してください。このスクリプトの例については、こちらの .bash_aliasファイルをご覧ください

    # Do a pull on all branches that are tracking a remote branches, will from origin by default.
    # If current branch is dirty, will stash changes and reply after pull.
    # Usage: pullall [remoteName]
    alias pullall=pullAll
    function pullAll (){
     # if -h then show help
     if [[ $1 == '-h' ]]
    then
      echo "Description: Pulls new changes from upstream on all branches that are tracking remotes."
      echo 
      echo "Usage: "
      echo "- Default: pullall"
      echo "- Specify upstream to pull from: pullall [upstreamName]"
      echo "- Help: pull-all -h"
    else

     # default remote to origin
     remote="origin"
     if [ $1 != "" ]
     then
       remote=$1
     fi

     # list all branches that are tracking remote
     # git branch -vv : list branches with their upstreams
     # grep origin : keep only items that have upstream of origin
     # sed "s/^.."... : remove leading *
     # sed "s/^"..... : remove leading white spaces
     # cut -d" "..... : cut on spaces, take first item
     # cut -d splits on space, -f1 grabs first item
     branches=($(git branch -vv | grep $remote | sed "s/^[ *]*//" | sed "s/^[ /t]*//" | cut -d" " -f1))

     # get starting branch name
     startingBranch=$(git rev-parse --abbrev-ref HEAD)

     # get starting stash size
     startingStashSize=$(git stash list | wc -l)

     echo "Saving starting branch state: $startingBranch"
     git stash

     # get the new stash size
     newStashSize=$(git stash list | wc -l)

     # for each branch in the array of remote tracking branches
     for branch in ${branches[*]}
     do
       echo "Switching to $branch"
       git checkout $branch

       echo "Pulling $remote"
       git pull $remote

     done

     echo "Switching back to $startingBranch"
     git checkout $startingBranch

     # compare before and after stash size to see if anything was stashed
     if [ "$startingStashSize" -lt "$newStashSize" ]
     then
       echo "Restoring branch state"
       git stash pop
     fi
    fi
    }

同等のWindows batファイルを提供できますか?
Jaffy 2015

1
@Jaffyどれだけの時間が手元にあるのかわからないし、バッチで流暢に話せるわけでもないが、やってみることができる。ここに私の進捗状況を投稿します。他の人が介入して手助けできるでしょうか?
philosowaffle 2015


3

更新された回答を投稿するだけです。git-upはもはやメンテナンスされておらず、ドキュメントを読んだ場合、機能がgitで利用できるようになった記載されています

Git 2.9以降、git pull --rebase --autostashは基本的に同じことを行います。

したがって、Git 2.9以降に更新する場合は、git-upをインストールする代わりにこのエイリアスを使用できます。

git config --global alias.up 'pull --rebase --autostash'

git pullGit 2.9以降でもこれを設定できます(@VonCに感謝します

git config --global pull.rebase true
git config --global rebase.autoStash true

1
エイリアスは必要ありません。単純なgitプルで十分であり、適切な構成:stackoverflow.com/a/40067353/6309
VonC

グレートコールのおかげでうち@VonC私は私の答えを更新しました:)もPRを提出する可能性があるgit-up、彼らはその言及していないので、ドキュメント
8月

これにより、すべてのローカルブランチが一度に更新されるわけではないため、主にを使用しましたgit-up
レイ

ドキュメントが更新さgit-up:)
8月

3

私はこの質問の同じ問題に出くわしました...

それについて疑問に思って、私は自分の.bashrcファイル内で小さなエイリアス関数を 実行しました:

gitPullAll() {
    for branch in `git branch | sed -E 's/^\*/ /' | awk '{print $1}'`; do
        git checkout $branch
        git pull -p
        printf "\n"
    done
    echo "Done"
}

私のために働いた(:


2

場合レフリー/ヘッド/マスターはに高速転送することができ、参考文献/リモコン/ fooの/マスターの出力

git merge-base refs/heads/master refs/remotes/foo/master

refs / heads / masterが指すSHA1 IDを返す必要があります。これにより、迂回コミットが適用されていないすべてのローカルブランチを自動的に更新するスクリプトを作成できます。

この小さなシェルスクリプト(私はgit-can-ffと呼んでいます)は、その実行方法を示しています。

#!/bin/sh

set -x

usage() {
    echo "usage: $(basename $0) <from-ref> <to-ref>" >&2
    exit 2
}

[ $# -ne 2 ] && usage

FROM_REF=$1
TO_REF=$2

FROM_HASH=$(git show-ref --hash $FROM_REF)
TO_HASH=$(git show-ref --hash $TO_REF)
BASE_HASH=$(git merge-base $FROM_REF $TO_REF)

if [ "$BASE_HASH" = "$FROM_HASH" -o \
     "$BASE_HASH" = "$FROM_REF" ]; then
    exit 0
else
    exit 1
fi

そのコメントは何を意味しますか?
hillu 2009年

私自身はhilluが提案するスクリプトを書くことができず、git-merge-baseを使用するのに十分なgit知識がないと確信しています。
ノーマンラムジー

2
とても親切に提供されたスクリプトを利用するのに十分なほどモデルを理解していません。人を傭兵に変えたいと思うようにするのに十分です。
ノーマンラムジー

Tommi Virtanenの記事「コンピューター科学者のためのGit」は、Gitのモデルと用語に慣れるのに非常に役立ちました。
hillu 2009年

2

Matt Connollyの回答を完了するには、これは、ブランチをチェックアウトせずに、早送りできるローカルブランチ参照を更新するためのより安全な方法です。早送りできない(つまり分岐した)ブランチは更新されません。また、現在チェックアウトされているブランチは更新されません(作業コピーも更新される必要があるため)。

git fetch

head="$(git symbolic-ref HEAD)"
git for-each-ref --format="%(refname) %(upstream)" refs/heads | while read ref up; do
    if [ -n "$up" -a "$ref" != "$head" ]; then
        mine="$(git rev-parse "$ref")"
        theirs="$(git rev-parse "$up")"
        base="$(git merge-base "$ref" "$up")"
        if [ "$mine" != "$theirs" -a "$mine" == "$base" ]; then
            git update-ref "$ref" "$theirs"
        fi
    fi
done

2

名前が上流のブランチと一致するブランチのみを早送りするわずかに異なるスクリプト。早送りが可能な場合は、現在のブランチも更新します。

を実行して、すべてのブランチの上流ブランチが正しく設定されていることを確認してくださいgit branch -vv。上流のブランチをgit branch -u origin/yourbanchname

ファイルとchmod 755にコピーして貼り付けます。

#!/bin/sh

curbranch=$(git rev-parse --abbrev-ref HEAD)

for branch in $(git for-each-ref refs/heads --format="%(refname:short)"); do
        upbranch=$(git config --get branch.$branch.merge | sed 's:refs/heads/::');
        if [ "$branch" = "$upbranch" ]; then
                if [ "$branch" = "$curbranch" ]; then
                        echo Fast forwarding current branch $curbranch
                        git merge --ff-only origin/$upbranch
                else
                        echo Fast forwarding $branch with origin/$upbranch
                        git fetch . origin/$upbranch:$branch
                fi
        fi
done;

2

次のワンライナーは、可能な場合は上流のブランチを持つすべてのブランチを早送りし、そうでない場合はエラーを出力します。

git branch \
  --format "%(if)%(upstream:short)%(then)git push . %(upstream:short):%(refname:short)%(end)" |
  sh

どのように機能しますか?

git branchコマンドでカスタム形式を使用します。上流のブランチを持つ各ブランチについて、次のパターンで行を出力します。

git push . <remote-ref>:<branch>

これは直接パイプすることができますsh(ブランチ名が整形式であると仮定)。省略します| sh何れているかを確認します。

注意事項

ワンライナーはリモコンに連絡しません。git fetchまたはgit fetch --allを実行する前に発行してください。

現在チェックアウトされているブランチは、次のようなメッセージで更新されません

! [remote rejected] origin/master -> master (branch is currently checked out)

このため、あなたは定期的に頼ることができますgit pull --ff-only

エイリアス

次のコードをに追加して、このコマンド.gitconfiggit fft実行します。

[alias]
        fft = !sh -c 'git branch --format \"%(if)%(upstream:short)%(then)git push . %(upstream:short):%(refname:short)%(end)\" | sh' -

myも参照してください.gitconfig。エイリアスは、「早送りトラッキング(ブランチ)」の省略形です。


これは良い解決策ですがhub@ Johnによって提案された解決策を使用し出力を向上させると思います。
Didier L

これは高速でシンプルで、実際に機能します。git pushそれはあなたが期待するものとは全く逆なので、私は困惑しています。秘密は何ですか?
BrandonLWhite

@BrandonLWhite:質問が理解できません。あなたは何を期待していgit pushますか?
krlmlr

git pushアップロードのセマンティクスがあります-上流に送信したいローカルのコミットがあります。 git pullダウンロードのセマンティクスがあります-ローカルブランチにいくつかのアップストリームリモートコミットを取得したいと考えています。リモートからローカルに新しいコミットをダウンロードすることについて話しているので、それgit pullは明らかな選択です。しかし、いいえ、このトリックはを使用しgit pushます。git pushリモートの変更をローカルブランチにプルするにはどうすればよいですか?
BrandonLWhite

git pushこれは、早送り更新である限り、ローカルブランチの更新にも使用できます。
krlmlr

1

@larsmansのスクリプト。少し改善されました。

#!/bin/sh

set -x
CURRENT=`git rev-parse --abbrev-ref HEAD`
git fetch --all
for branch in "$@"; do
  if ["$branch" -ne "$CURRENT"]; then
    git checkout "$branch" || exit 1
    git rebase "origin/$branch" || exit 1
  fi
done
git checkout "$CURRENT" || exit 1
git rebase "origin/$CURRENT" || exit 1

これは、終了後、作業コピーを同じブランチからチェックアウトしたままにします、スクリプトが呼び出される前ままにします。

git pullバージョン:

#!/bin/sh

set -x
CURRENT=`git rev-parse --abbrev-ref HEAD`
git fetch --all
for branch in "$@"; do
  if ["$branch" -ne "$CURRENT"]; then
    git checkout "$branch" || exit 1
    git pull || exit 1
  fi
done
git checkout "$CURRENT" || exit 1
git pull || exit 1

1

他の多くの人が同様の解決策を提供してくれたようですが、私が思いついたものを共有し、他の人に貢献してくれるように勧めたいと思いました。このソリューションはカラフルな出力があり、現在の作業ディレクトリを適切に処理し、チェックアウトを行わないため高速であり、作業ディレクトリをそのまま残します。また、git以外の依存関係のない単なるシェルスクリプトです。(これまでのところOSXでのみテスト済み)

#!/usr/bin/env bash

gitup(){    
RED='\033[33;31m'
YELLO='\033[33;33m'
GREEN='\033[33;32m'
NC='\033[0m' # No Color

HEAD=$(git rev-parse HEAD)
CHANGED=$(git status --porcelain | wc -l)

echo "Fetching..."
git fetch --all --prune &>/dev/null
for branch in `git for-each-ref --format='%(refname:short)' refs/heads`; do

    LOCAL=$(git rev-parse --quiet --verify $branch)
    if [ "$HEAD" = "$LOCAL" ] && [ $CHANGED -gt 0 ]; then
        echo -e "${YELLO}WORKING${NC}\t\t$branch"
    elif git rev-parse --verify --quiet $branch@{u}&>/dev/null; then
        REMOTE=$(git rev-parse --quiet --verify $branch@{u})
        BASE=$(git merge-base $branch $branch@{u})

        if [ "$LOCAL" = "$REMOTE" ]; then
           echo -e "${GREEN}OK${NC}\t\t$branch" 
        elif [ "$LOCAL" = "$BASE" ]; then
            if [ "$HEAD" = "$LOCAL" ]; then
                git merge $REMOTE&>/dev/null
            else
                git branch -f $branch $REMOTE
            fi
            echo -e "${GREEN}UPDATED${NC}\t\t$branch"
        elif [ "$REMOTE" = "$BASE" ]; then
            echo -e "${RED}AHEAD${NC}\t\t$branch"
        else
            echo -e "${RED}DIVERGED${NC}\t\t$branch"
        fi
    else
        echo -e "${RED}NO REMOTE${NC}\t$branch"
    fi
done
}

https://github.com/davestimpert/gitup

申し訳ありませんが、上記の他のツールと同じ名前が付いているようです。


2
これを書いたのはあなたですか?もしそうなら、あなたの所属を明らかにしてください。してくださいこの詳細を読む詳細については。具体的に は教えないで-見せて!; スクリプトのどの部分をどのように/なぜ問題を解決するのか教えてください。
Keale

1
はい、書きました。上記のソースを含めて、.bashrcまたは.zshrcに簡単にコピーして貼り付けます。
Stimp

これは素晴らしいソリューションであり、うまく機能します。誰も気づかなかったのですか?
Ville

1

以下のスクリプトを使用して実行できます...最初にすべてのブランチとチェックアウトを1つずつフェッチし、それ自体を更新します。

#!/bin/bash
git branch -r | grep -v '\->' | while read remote; do git branch --track 
"${remote#origin/}" "$remote"; done

set -x
CURRENT=`git rev-parse --abbrev-ref HEAD`
git fetch --all
branch_name=$(git branch | awk '{print $1" "}' | grep -v '*' | xargs)
for branch in $branch_name; do
   git checkout "$branch" || exit 1
   git rebase "origin/$branch" || exit 1
   git pull origin $branch|| exit 1
done
git checkout "$CURRENT" || exit 1
git pull || exit 1

回答を採点するためのいくつかの説明を追加します
fool-dev

1

gitコマンドを1つだけで実行することはできませんが、1つのbash行で自動化できます。

すべてのブランチを1行で安全に更新するために、ここに私がすることがあります:

git fetch --all && for branch in $(git branch | sed '/*/{$q;h;d};$G' | tr -d '*') ; do git checkout $branch && git merge --ff-only || break ; done
  • 1つのブランチを早送りできない場合、またはエラーが発生した場合は、停止してそのブランチにとどまるため、制御を取り戻し、手動でマージできます。

  • すべてのブランチを早送りできる場合、ブランチは現在のブランチで終わり、更新前の場所に残ります。

説明:

読みやすくするために、数行に分割できます。

git fetch --all && \
for branch in $(git branch | sed '/*/{$q;h;d};$G' | tr -d '*')
    do git checkout $branch && \
    git merge --ff-only || break
done
  1. git fetch --all && ... =>すべてのリモートからすべての参照をフェッチし、エラーがなければ次のコマンドを続行します。

  2. git branch | sed '/*/{$q;h;d};$G' | tr -d '*'=>の出力からはgit branchsedAとラインを取ります*(現在のブランチが最後に更新されるように)と最後に移動します。次に、tr単に削除し*ます。

  3. for branch in $(...) ; do git checkout $branch && git merge --ff-only || break ; done=>前のコマンドで取得した各ブランチ名について、このブランチをチェックアウトし、早送りでマージしてみてください。失敗した場合、breakが呼び出され、コマンドはここで停止します。

もちろん交換できます git merge --ff-onlygit rebaseそれがあなたが望むものであるならます。

最後に、あなたはそれをあなたのbashrcに置くことができますエイリアスとして。

alias git-pull-all='git fetch --all && for branch in $(git branch | sed '\''/*/{$q;h;d};$G'\'' | tr -d "*") ; do git checkout $branch && git merge --ff-only || break ; done'

または、 'と "をいじることを恐れている場合、または単にエディターで構文の読みやすさを維持したい場合は、それを関数として宣言できます。

git-pull-all()
{
    git fetch --all && for branch in $(git branch | sed '/*/{$q;h;d};$G' | tr -d '*') ; do git checkout $branch && git merge --ff-only || break ; done
}

ボーナス:

sed '/*/{$q;h;d};$G'部分の説明が欲しい人のために:

  • /*/=>で行を検索し*ます。

  • {$q =>最後の行にある場合は、終了します(現在のブランチは既にリストの最後のブランチなので、何もする必要はありません)。

  • ;h;d} =>それ以外の場合は、行を保持バッファに格納し、現在のリスト位置から削除します。

  • ;$G =>最後の行に達したら、保留バッファの内容を追加します。


あなたは、無限の線のすべての狂気を回避し、スクリプトの上部に&&設定することで回避できset -eます。
mcepl

0

「git pull --all」ですべてのローカルブランチを更新できますか?

いいえ、できません。早送りのために、そのための小さなツールを書いただけです。https://github.com/changyuheng/git-fast-forward-all

このツールの利点:

  1. 1つのリポジトリで複数のリモートをサポートします。(hub sync現在、複数のリモコンはサポートされていません。)
  2. ローカルブランチと対応するリモートトラッキングブランチで異なる名前を持つことをサポートします。
  3. 単一のブランチごとにリモートでフェッチする他のスクリプトよりもはるかに高速です。
  4. エラーが発生しやすい正規表現の解析/編集はありません。

1
を使用することで、ネットワークへのアクセスを回避できgit fetch . refspecます。.現在のリポジトリからではなく、リモート1からフェッチすると言います。
hugomg

-1

git 2.9以降:

git pull --rebase --autostash

https://git-scm.com/docs/git-rebaseを参照してください

操作が始まる前に一時的な隠し場所を自動的に作成し、操作が終了した後に適用します。これは、ダーティなワークツリーでリベースを実行できることを意味します。ただし、注意して使用してください。リベースが成功した後の最後のstashアプリケーションは、重要な競合を引き起こす可能性があります。


-1

実際、git version 1.8.3.1では、次のように機能します。

[root@test test]# git br
* master
  release/0.1
  update
[root@test test]# git pull --rebase
remote: Enumerating objects: 9, done.
remote: Counting objects: 100% (9/9), done.
remote: Compressing objects: 100% (9/9), done.
remote: Total 9 (delta 2), reused 0 (delta 0)
Unpacking objects: 100% (9/9), done.
From http://xxx/scm/csdx/test-git
   d32ca6d..2caa393  release/0.1 -> origin/release/0.1
Current branch master is up to date.
[root@test test]# git --version
git version 1.8.3.1

マスターブランチでは、他のすべてのブランチを更新できます。ゆうた

私はどのバージョンがそれを壊す/修正するのか分かりません、2.17(私が使う)では、それはうまくいくことができます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.