Проверьте, нужно ли тянуть в Git



Как проверить, изменился ли удаленный репозиторий, и мне нужно вытащить?



сейчас я использую этот простой скрипт:



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


но он довольно тяжелый.



есть ли лучший способ? Идеальное решение будет проверять все удаленные ветви и возвращать имена измененных ветвей и количество новых коммитов в каждой из них.

544   22  

22 ответов:

первым использованием git remote update, чтобы обновить ваши удаленные ссылки. Затем вы можете сделать одну из нескольких вещей, таких как:

  1. git status -uno скажет вам, является ли ветка, которую вы отслеживаете, впереди, позади или разошлась. Если он ничего не говорит, локальные и удаленные одинаковы.

  2. git show-branch *master покажет вам коммиты во всех ветвях, чьи имена заканчиваются на "master" (например мастер и origin / master).

если вы используете -v С git remote update (git remote -v update) вы можете увидеть, какие ветви были обновлены, так что вам не нужно никаких дополнительных команд.

, похоже, вы хотите сделать это в скрипте или программе и в итоге значение true или false. Если это так, есть способы проверить связь между вашим текущим глава фиксация и глава филиала, который вы отслеживаете, хотя с тех пор есть четыре возможные результаты вы не можете свести его к ответу "Да/нет". Однако, если вы готовы сделать pull --rebase тогда вы можете рассматривать "local позади" и "local разошелся" как "нужно тянуть", а два других как "не нужно тянуть".

вы можете получить идентификатор фиксации любого ref с помощью git rev-parse <ref>, так что вы можете сделать это для мастер и origin / master и сравнить их. Если они равны, то ветви одинаковы. Если они неравны, вы хотите знать, что впереди о другом. Используя git merge-base master origin/master скажет вам общий предок обеих ветвей, и если они не разошлись, это будет то же самое, что и один или другой. Если вы получаете три разных идентификатора, ветви разошлись.

чтобы сделать это правильно, например, в скрипте, вам нужно иметь возможность ссылаться на текущую ветвь, а удаленную ветвь она отслеживает. Командной строке-функция установки в /etc/bash_completion.d имеет некоторый полезный код для получения имен ветвей. Однако вам, вероятно, на самом деле не нужно Узнай имена. Git имеет несколько аккуратных сокращений для ссылки на ветви и коммиты (как описано в git rev-parse --help). В частности, вы можете использовать @ для текущей ветви (при условии, что вы не находитесь в состоянии отсоединенной головы) и @{u} для его восходящей ветви (например origin/master). Так что git merge-base @ @{u} вернет (хэш) фиксации, при которой текущая ветвь и ее восходящий поток расходятся и git rev-parse @ и git rev-parse @{u} даст вам хэши из двух советов. Это можно резюмировать следующим образом сценарий:

#!/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 не позволяли @ сам по себе, так что вам, возможно, придется использовать .

строку UPSTREAM=${1:-'@{u}'} позволяет при необходимости передать восходящую ветвь явно, в случае, если вы хотите проверить против другой удаленной ветви, чем тот, который настроен для текущей ветви. Это, как правило, будет иметь вид remotename / branchname. Если параметр не задан, значение по умолчанию @{u}.

скрипт предполагает, что вы сделали git fetch или git remote update во-первых, чтобы обновить ветви отслеживания. Я не встроил это в скрипт, потому что он более гибкий, чтобы иметь возможность выполнять выборку и сравнение как отдельные операции, например, если вы хотите сравнить без выборки, потому что вы уже недавно выбрали.

если у вас есть восходящая ветвь

git fetch <remote>
git status

если у вас нет восходящей ветви

сравните две ветви:

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 тогда нечего сливать.

обратите внимание, что это будет работать, даже если вы находитесь на ветке функции - это не имеет удаленного отслеживания, так как если явно ссылается на origin/master вместо неявного использования ветка вверх по течению вспомнил Git.

Если это для скрипта, вы можете использовать:

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

(Примечание: преимущество этого по сравнению с предыдущими ответами заключается в том, что вам не нужна отдельная команда для получения текущего имени ветви. "HEAD "и" @{u} " (текущая ветка вверх по течению) позаботятся об этом. См. "git rev-parse --help" для получения более подробной информации.)

команда

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

отобразит текущую головку на пульте дистанционного управления - вы можете сравнить ее с предыдущим значением или посмотреть, есть ли у вас SHA в локальном РЕПО.

вот Баш один-лайнер, который сравнивает руководитель текущей ветке совершить хэш в отношении его филиала дистанционное вверх по течению, не тяжелая git fetch или git 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) Баш синтаксис.
  • git rev-parse --abbrev-ref @{u} возвращает сокращенный восходящий ref (например origin/master), который затем преобразуется в разделенные пробелами поля по конвейеру , например,origin master.
  • эта строка подается в git ls-remote который возвращает головную фиксацию удаленной ветви. Эта команда будет взаимодействовать с удаленным репозиторием. Окантованные cut команда извлекает только первое поле (хэш фиксации), удаляя разделенную вкладками ссылочную строку.
  • git rev-parse HEAD возвращает локальный хэш фиксации.
  • синтаксис Bash [ a = b ] && x || y завершает один лайнер: это Баш строка-сравнение= в тестовой конструкции [ test ], следовал по А-списка и списка конструктов && true || false.

Я предлагаю вам пойти посмотреть сценарий https://github.com/badele/gitcheck. я закодировал этот скрипт для проверки в один проход всех ваших репозиториев Git, и он показывает, кто не совершил и кто не толкнул/потянул.

вот пример результата:

Enter image description here

Я основал это решение на комментариях @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

Я думаю, что лучший способ сделать это было бы:

git diff remotes/origin/HEAD

предполагая, что у вас есть этот refspec зарегистрирован. Вы должны, если вы клонировали репозиторий, в противном случае (т. е. если РЕПО было создано de novo локально и перенесено на удаленный), вам нужно явно добавить refspec.

есть много очень многофункциональных и гениальных ответов уже. Чтобы обеспечить некоторый контраст, я мог бы обойтись очень простой линией.

# 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

Я бы сделал так, как предложил Брул. Следующий однострочный скрипт принимает SHA1 вашей последней версии с коммитом и сравнивает его с удаленным источником, а также извлекает изменения только в том случае, если они отличаются. И это еще более легкие решения на основе git pull или git fetch.

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

ниже скрипт работает отлично.

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

если вы запустите этот скрипт, он проверит, нужна ли текущая ветка 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:(\+|\*|$):\:g'
    )\s+" || {
        echo >&2 "Current branch need a 'git pull' before commit"
        exit 1
}

это очень удобно, чтобы положить его в качестве git крюк pre-commit, чтобы избежать

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

когда вы commit до pulling.

чтобы использовать этот код в качестве крючка, просто копировать/вставить скрипт в

.git/hooks/pre-commit

и

chmod +x .git/hooks/pre-commit

Run git fetch (remote) обновить удаленные ссылки, он покажет вам что нового. Затем, когда вы проверяете свой местный филиал, он покажет вам, находится ли он позади вверх по течению.

Я просто хочу опубликовать это как фактический пост, так как это легко пропустить в комментариях.

правильный и лучший ответ на этот вопрос был дан @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
git ls-remote | cut -f1 | git cat-file --batch-check >&-

перечислит все ссылки в любом удаленном устройстве, которое не находится в вашем РЕПО. Чтобы поймать удаленные изменения ref к вещам, которые у вас уже были (например, сброс к предыдущим коммитам), требуется немного больше:

git pack-refs --all
mine=`mktemp`
sed '/^#/d;/^^/{G;s/.\(.*\)\n.* \(.*\)/ ^{}/;};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

вот моя версия скрипта Bash, который проверяет все репозитории в предопределенной папке:

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

Он может различать общие ситуации, такие как pull needed и push needed, и он многопоточен, поэтому выборка происходит сразу. Он имеет несколько команд, таких как pull и status.

поместите символическую ссылку( или скрипт) в папку на вашем пути, тогда она работает как git all status (, etc.). Это только поддерживает origin / master, но его можно редактировать или комбинировать с другим методом.

используя простое регулярное выражение:

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

может быть, это, если вы хотите добавить задачу как 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

Я использую версию сценария, основанного на ответе Стивена Хабермана:

if [ -n "" ]; then
    gitbin="git -C "
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, он может быть вызван с необязательным аргументом directory name локального репозитория Git для выполнения операции. Если скрипт вызывается без аргументов, он предполагает, что текущий каталог является частью репозитория 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

он доступен здесь как хорошо.

прочитав много ответов и несколько сообщений, и потратив полдня на различные перестановки, это то, что я придумал.

Если вы находитесь в Windows, вы можете запустить этот скрипт в Windows, используя Git Bash, предоставленный Git для Windows (установка или перенос).

этот скрипт требует аргументов

- local path e.g. /d/source/project1
- Git URL e.g. https://[email protected]/username/project1.git
- password

if a password should not be entered on the command line in plain text,
then modify the script to check if GITPASS is empty; do not
replace and let Git prompt for a password

скрипт

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

Если есть изменения, напечатанные скриптом, то вы можете перейти к извлечению или вытягиванию. Этот сценарий не может быть эффективным, но он получает работу за меня.

Update-2015-10-30: stderr to dev null для предотвращения печати URL-адреса с паролем на консоль.

#!/bin/bash

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

LOCALPATH=
GITURL=
GITPASS=

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

для пользователей 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')
}

вы можете найти скрипт Phing кто делает это сейчас.

Мне нужно было решение для автоматического обновления моих производственных сред, и мы очень счастливы благодаря этому сценарию, который я делюсь.

скрипт написан в XML и нуждается пинг.

Comments

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