web-dev-qa-db-ja.com

Gitでpullが必要かどうかを確認

リモートリポジトリが変更されたのかどうか、どうすれば確認できますか?プルする必要がありますか?

今、私はこの簡単なスクリプトを使います。

git pull --dry-run | grep -q -v 'Already up-to-date.' && changed=1

しかし、それはかなり重いです。

もっと良い方法はありますか?理想的な解決策は、すべてのリモートブランチをチェックし、変更されたブランチの名前とそれぞれの新しいコミットの数を返すことです。

567
takeshin

最初に git remote update を使用して、リモートの参照を最新の状態にします。そうすれば、次のようないくつかのことができます。

  1. git status -unoはあなたが追跡しているブランチが先にあるのか、後ろにあるのか、あるいは分岐したのかを教えてくれます。何も言わなければ、ローカルとリモートは同じです。

  2. git show-branch *masterは、名前が 'master'で終わるすべてのブランチのコミットを表示します(例: master および Origin/master )。

-vgit remote updategit remote -v update)と一緒に使用すると、どのブランチが更新されたかを確認できます。そのため、これ以上のコマンドは必要ありません。

ただし、これをスクリプトまたはプログラムで実行し、最終的にtrue/falseの値にしたいようです。もしそうなら、あなたの現在の _ head _ commitとあなたが追跡しているブランチのヘッドとの関係をチェックする方法があります。 /無回答。しかし、もしあなたがpull --rebaseを実行する準備ができているならば、あなたは "local is behind"と "local has diver"を "プルする必要がある"として扱い、他の二つは "プルする必要がない"と扱うことができます。

git rev-parse <ref>を使用して任意の参照のコミットIDを取得できます。したがって、これを master および Origin/master に対して実行し、それらを比較することができます。それらが等しいならば、枝は同じです。それらが等しくない場合は、どちらが他方より進んでいるかを知りたいと思うでしょう。 git merge-base master Origin/masterを使用すると、両方のブランチの共通の祖先がわかります。それらが分岐していない場合、これはどちらかと同じになります。 3つの異なるIDを取得した場合、ブランチは分岐しています。

たとえばスクリプトでこれを正しく行うには、現在のブランチとそれが追跡しているリモートブランチを参照できる必要があります。 /etc/bash_completion.dのbashプロンプト設定関数には、ブランチ名を取得するための便利なコードがいくつかあります。ただし、実際には名前を取得する必要はおそらくないでしょう。 Gitには(git rev-parse --helpで文書化されているように)ブランチとコミットを参照するためのいくつかの巧妙な短所があります。特に、現在のブランチに@を使用し(デタッチヘッド状態にないと仮定して)、そのアップストリームブランチに@{u}を使用できます(例:Origin/master)。そのため、git merge-base @ @{u}は現在のブランチとその上流の分岐が分岐するコミット(のハッシュ)を返し、git rev-parse @git rev-parse @{u}は2つのヒントのハッシュを返します。これは次のスクリプトに要約できます。

#!/bin/sh

UPSTREAM=${1:-'@{u}'}
LOCAL=$(git rev-parse @)
REMOTE=$(git rev-parse "$UPSTREAM")
BASE=$(git merge-base @ "$UPSTREAM")

if [ $LOCAL = $REMOTE ]; then
    echo "Up-to-date"
Elif [ $LOCAL = $BASE ]; then
    echo "Need to pull"
Elif [ $REMOTE = $BASE ]; then
    echo "Need to Push"
else
    echo "Diverged"
fi

注: 古いバージョンのgitでは@を単独では使用できなかったため、代わりに@{0}を使用する必要があります。

現在のブランチ用に設定されているものとは異なるリモートブランチに対してチェックしたい場合は、UPSTREAM=${1:-'@{u}'}行を使用すると、オプションで上流ブランチを明示的に渡すことができます。これは通常、 remotename/branchname の形式になります。パラメータが指定されていない場合、デフォルト値は@{u}です。

このスクリプトは、追跡ブランチを最新にするために、最初にgit fetchまたはgit remote updateを実行したことを前提としています。これはスクリプトには組み込まれていません。たとえば、すでにフェッチしたためにフェッチせずに比較したい場合など、フェッチと比較を別々の操作として実行できる方が柔軟なためです。

763
Neil Mayhew

上流の支店がある場合

git fetch <remote>
git status

上流の支店がない場合

2つの分岐を比較してください。

git fetch <remote>
git log <local_branch_name>..<remote_branch_name> --oneline

例えば:

git fetch Origin

# See if there are any incoming changes
git log HEAD..Origin/master --oneline

(私はOrigin/masterがあなたのリモートトラッキングブランチであると思います)

上記の出力にコミットが表示されている場合は、変更があります - マージする必要があります。 git logによってコミットがリストされていない場合、マージするものはありません。

これは、機能ブランチ上であっても機能することに注意してください - トラッキングリモートはありません、なぜなら明示的にGitが覚えている upstreamブランチ を使う代わりにOrigin/masterを参照するからです。

121
PlagueHammer

これがスクリプト用の場合は、次のものを使用できます。

git fetch
$(git rev-parse HEAD) == $(git rev-parse @{u})

(注:これに対する前回の回答との利点は、現在のブランチ名を取得するために別のコマンドを使用する必要がないことです。「HEAD」と「@ {u}」(現在のブランチのアップストリーム)に注意してください。詳細は "git rev-parse --help"をご覧ください。)

52

コマンド

git ls-remote Origin -h refs/heads/master

リモートの現在のヘッドをリストします - あなたはそれを前の値と比較するか、あなたがあなたのローカルレポジトリにSHAがあるかどうかを見ることができます。

34
brool

これは現在のブランチのHEADコミットハッシュをリモートのアップストリームブランチと比較するBash one-linerです。重いgit fetchgit pull --dry-run操作は必要ありません。

[ $(git rev-parse HEAD) = $(git ls-remote $(git rev-parse --abbrev-ref @{u} | \
sed 's/\// /g') | cut -f1) ] && echo up to date || echo not up to date

これは、このやや密度の高い行がどのように分解されるかです。

  • コマンドは、$(x) Bash command-substitution 構文を使用してグループ化およびネストされています。
  • git rev-parse --abbrev-ref @{u}は上流の省略形のref(例えばOrigin/master)を返します。これは次にパイプでつながれたsedコマンドによってスペース区切りのフィールドに変換されます。 Origin master
  • この文字列は、リモートブランチのヘッドコミットを返すgit ls-remoteに渡されます。このコマンドはリモートリポジトリと通信します。パイプ付きcutコマンドは、最初のフィールド(コミットハッシュ)だけを抽出し、タブ区切りの参照文字列を削除します。
  • git rev-parse HEADはローカルコミットハッシュを返します。
  • Bash構文[ a = b ] && x || yはワンライナーを完成させます。これはテスト構成体=内のBash 文字列比較[ test ]で、その後にand-listおよびor-list構成体&& true || falseが続きます。
29
wjordan

https://github.com/badele/gitcheck というスクリプトを見に行くことをお勧めします。私はこのスクリプトをすべてのGitリポジトリのワンパスチェックのためにコーディングしました、そしてそれは誰がコミットしていないか、誰がプッシュ/プルしていないかを示しています。

これがサンプルの結果です。

Enter image description here

19
Bruno Adelé

この解決策は、@ jbergerのコメントに基づいています。

if git checkout master &&
    git fetch Origin master &&
    [ `git rev-list HEAD...Origin/master --count` != 0 ] &&
    git merge Origin/master
then
    echo 'Updated!'
else
    echo 'Not updated.'
fi
10
ma11hew28

非常に機能豊富で独創的な答えはすでにたくさんあります。少し対比するために、私は非常に単純な線でそれをすることができました。

# Check return value to see if there are incoming updates.
if ! git diff --quiet remotes/Origin/HEAD; then
 # pull or whatever you want to do
fi
9
thuovila

これを行う最良の方法は次のようになると思います。

git diff remotes/Origin/HEAD

このrefspecが登録されているとします。そうでなければ(つまり、リポジトリがde novoで新規に作成され、リモートにプッシュされたのであれば)リポジトリを複製したなら、refspecを明示的に追加する必要があります。

8
Jeet

下記のスクリプトは完璧に動作します。

changed=0
git remote update && git status -uno | grep -q 'Your branch is behind' && changed=1
if [ $changed = 1 ]; then
    git pull
    echo "Updated successfully";
else
    echo "Up-to-date"
fi
6
Harikrishna

私はbroolによって提案された方法をするでしょう。次の1行のスクリプトは、最後にコミットしたバージョンのSHA1を取得してそれをリモートのOriginのものと比較し、変更が異なる場合にのみ変更を取得します。 git pullまたはgit fetchをベースにしたソリューションは、さらに軽量です。

[ `git log --pretty=%H ...refs/heads/master^` != `git ls-remote Origin
-h refs/heads/master |cut -f1` ] && git pull
6

このスクリプトを実行すると、現在のブランチにgit pullが必要かどうかがテストされます。

#!/bin/bash

git fetch -v --dry-run 2>&1 |
    grep -qE "\[up\s+to\s+date\]\s+$(
        git branch 2>/dev/null |
           sed -n '/^\*/s/^\* //p' |
                sed -r 's:(\+|\*|\$):\\\1:g'
    )\s+" || {
        echo >&2 "Current branch need a 'git pull' before commit"
        exit 1
}

回避するためにGitフックのプリコミットとするのはとても便利です。

Merge branch 'foobar' of url:/path/to/git/foobar into foobar

あなたがcommitの前にpullingするとき。

このコードをフックとして使用するには、次の場所にスクリプトをコピーして貼り付けます。

.git/hooks/pre-commit

そして

chmod +x .git/hooks/pre-commit
5
Gilles Quenot

コメントでこれを見逃しやすいので、私は実際の投稿としてこれを投稿したいだけです。

この質問に対する正解と最善の答えは@Jake Bergerによって与えられました。どうもありがとう、みんなこれを必要としていてみんなコメントでこれを見逃しています。ですから、これに苦労している人は誰でも正しい答えです。このコマンドの出力を使用して、git pullを実行する必要があるかどうかを確認してください。出力が0の場合、明らかに更新するものはありません。

@stackoverflow、この男に鐘を鳴らす。ありがとう@ Jake Berger

git rev-list HEAD...Origin/master --count will give you the total number of "different" commits between the two. – Jake Berger Feb 5 '13 at 19:23
4
diegeelvis_SA

あなたのリモート参照を更新するためにgit fetch (remote)を実行してください、それはあなたに何が新しいかをあなたに示すでしょう。それからあなたがあなたのローカルブランチをチェックアウトするとき、それはそれが上流に遅れているかどうかあなたに示すでしょう。

4
che

これは、事前定義されたフォルダ内のすべてのリポジトリをチェックするBashスクリプトの私のバージョンです。

https://Gist.github.com/henryiii/5841984

プルが必要な場合とプッシュが必要な場合など、一般的な状況を区別できます。また、マルチスレッドであるため、フェッチは一度にすべて行われます。 pullやstatusなど、いくつかのコマンドがあります。

シンボリックリンク(またはスクリプト)をあなたのパスのフォルダに入れると、それはgit all status(など)として機能します。 Origin/masterのみサポートしていますが、編集したり他の方法と組み合わせたりすることができます。

2
Henry Schreiner
git ls-remote | cut -f1 | git cat-file --batch-check >&-

リポジトリにないリモートで参照されているものすべてを一覧表示します。あなたがすでに持っているものへのリモートのrefの変更(例えば、以前のコミットへのリセット)を捉えるにはもう少しかかります:

git pack-refs --all
mine=`mktemp`
sed '/^#/d;/^^/{G;s/.\(.*\)\n.* \(.*\)/\1 \2^{}/;};h' .git/packed-refs | sort -k2 >$mine
for r in `git remote`; do 
    echo Checking $r ...
    git ls-remote $r | sort -k2 | diff -b - $mine | grep ^\<
done
1
jthill

単純な正規表現を使う:

str=$(git status) 
if [[ $str =~ .*Your\ branch\ is\ behind.*by.*commits,\ and\ can\ be\ fast-forwarded ]]; then
    echo `date "+%Y-%m-%d %H:%M:%S"` "Needs pull"
else
    echo "Code is up to date"
fi
1
Tomas Kukis

たくさんの答えと複数の投稿を読んで、そしてさまざまな順列を試す半日を過ごした後、これが私が思いついたものです。

Windowsを使用している場合は、Git for Windowsが提供するGit Bash(インストール用またはポータブル)を使用してWindowsでこのスクリプトを実行できます。

このスクリプトには引数が必要です

  - ローカルパス/d/source/project1
- Git URL。 https://[email protected]/username/project1.git 
  -  password 
 
パスワードをプレーンテキストで入力しない場合は
その後、GITPASSが空かどうかをチェックするようにスクリプトを修正します。 Gitにパスワードの入力を促さないようにしてください。

スクリプトは

- Find the current branch
- Get the SHA1 of the remote on that branch
- Get the SHA1 of the local on that branch
- Compare them.

スクリプトによって印刷された変更がある場合は、フェッチまたはプルに進むことができます。スクリプトは効率的ではないかもしれませんが、それは仕事を私のために終わらせます。

更新 - 2015-10-30:コンソールにパスワード付きのURLを表示しないようにするための標準エラー出力をnullにしました。

#!/bin/bash

# Shell script to check if a Git pull is required.

LOCALPATH=$1
GITURL=$2
GITPASS=$3

cd $LOCALPATH
BRANCH="$(git rev-parse --abbrev-ref HEAD)"

echo
echo git url = $GITURL
echo branch = $BRANCH

# Bash replace - replace @ with :password@ in the GIT URL
GITURL2="${GITURL/@/:$GITPASS@}"
FOO="$(git ls-remote $GITURL2 -h $BRANCH 2> /dev/null)"
if [ "$?" != "0" ]; then
  echo cannot get remote status
  exit 2
fi
FOO_ARRAY=($FOO)
BAR=${FOO_ARRAY[0]}
echo [$BAR]

LOCALBAR="$(git rev-parse HEAD)"
echo [$LOCALBAR]
echo

if [ "$BAR" == "$LOCALBAR" ]; then
  #read -t10 -n1 -r -p 'Press any key in the next ten seconds...' key
  echo No changes
  exit 0
else
  #read -t10 -n1 -r -p 'Press any key in the next ten seconds...' key
  #echo pressed $key
  echo There are changes between local and remote repositories.
  exit 1
fi
0

これを探してこの質問にたどり着くwindowsユーザーのために、私はいくつかの答えをpowershellスクリプトに修正しました。必要に応じて微調整し、.ps1ファイルに保存してオンデマンドで実行するか、必要に応じてスケジュールします。

cd C:\<path to repo>
git remote update                           #update remote
$msg = git remote show Origin               #capture status
$update = $msg -like '*local out of date*'
if($update.length -gt 0){                   #if local needs update
    Write-Host ('needs update')
    git pull
    git reset --hard Origin/master
    Write-Host ('local updated')
} else {
    Write-Host ('no update needed')
}
0
Andrew Grothe

ソリューションが非常に短く簡単である間、そのようなすべての複雑な推測:

#!/bin/bash

BRANCH="<your branch name>"
LAST_UPDATE=`git show --no-notes --format=format:"%H" $BRANCH | head -n 1`
LAST_COMMIT=`git show --no-notes --format=format:"%H" Origin/$BRANCH | head -n 1`

if [ $LAST_COMMIT != $LAST_UPDATE ]; then
        echo "Updating your branch $BRANCH"
        git pull --no-edit
else
        echo "No updates available"
fi
0
Digital Human

あなたがcrontabとしてタスクを追加したいのであれば、おそらくこれ:

#!/bin/bash
dir="/path/to/root"
lock=/tmp/update.lock
msglog="/var/log/update.log"

log()
{
        echo "$(date) ${1:-missing}" >> $msglog
}

if [ -f $lock ]; then
        log "Already run, exiting..."
else
        > $lock
        git -C ~/$dir remote update &> /dev/null
        checkgit=`git -C ~/$dir status`
        if [[ ! "$checkgit" =~ "Your branch is up-to-date" ]]; then
                log "-------------- Update ---------------"
                git -C ~/$dir pull &>> $msglog
                log "-------------------------------------"
        fi
        rm $lock

fi
exit 0
0
Altzone

私はStephen Habermanの答えに基づいたスクリプトのバージョンを使います。

if [ -n "$1" ]; then
    gitbin="git -C $1"
else
    gitbin="git"
fi

# Fetches from all the remotes, although --all can be replaced with Origin
$gitbin fetch --all
if [ $($gitbin rev-parse HEAD) != $($gitbin rev-parse @{u}) ]; then
    $gitbin rebase @{u} --preserve-merges
fi

このスクリプトがgit-fetch-and-rebaseと呼ばれると仮定すると、それは操作を実行するためにローカルGitリポジトリのオプションの引数directory nameで呼び出されることができます。スクリプトが引数なしで呼び出された場合は、現在のディレクトリがGitリポジトリの一部であると見なします。

例:

# Operates on /abc/def/my-git-repo-dir
git-fetch-and-rebase /abc/def/my-git-repo-dir

# Operates on the Git repository which the current working directory is part of
git-fetch-and-rebase

利用可能です ここ

0
Tuxdude