Проверьте, нужно ли тянуть в Git
Как проверить, изменился ли удаленный репозиторий, и мне нужно вытащить?
сейчас я использую этот простой скрипт:
git pull --dry-run | grep -q -v 'Already up-to-date.' && changed=1
но он довольно тяжелый.
есть ли лучший способ? Идеальное решение будет проверять все удаленные ветви и возвращать имена измененных ветвей и количество новых коммитов в каждой из них.
22 ответов:
первым использованием
git remote update, чтобы обновить ваши удаленные ссылки. Затем вы можете сделать одну из нескольких вещей, таких как:
git status -unoскажет вам, является ли ветка, которую вы отслеживаете, впереди, позади или разошлась. Если он ничего не говорит, локальные и удаленные одинаковы.
git show-branch *masterпокажет вам коммиты во всех ветвях, чьи имена заканчиваются на "master" (например мастер и origin / master).если вы используете
, похоже, вы хотите сделать это в скрипте или программе и в итоге значение true или false. Если это так, есть способы проверить связь между вашим текущим глава фиксация и глава филиала, который вы отслеживаете, хотя с тех пор есть четыре возможные результаты вы не можете свести его к ответу "Да/нет". Однако, если вы готовы сделать-vСgit remote update(git remote -v update) вы можете увидеть, какие ветви были обновлены, так что вам не нужно никаких дополнительных команд.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, и он показывает, кто не совершил и кто не толкнул/потянул.
вот пример результата:
Я основал это решение на комментариях @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