Вопрос:

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

git bash shell

321824 просмотра

23 ответа

31166 Репутация автора

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

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

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

Но это довольно тяжело.

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

Автор: takeshin Источник Размещён: 15.07.2010 05:32

Ответы (23)


36 плюса

1895 Репутация автора

Команда

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

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

Автор: brool Размещён: 15.07.2010 05:37

9 плюса

28009 Репутация автора

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

git diff remotes/origin/HEAD

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

Автор: Jeet Размещён: 16.07.2010 01:18

789 плюса

10588 Репутация автора

Решение

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

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

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

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

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

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

Чтобы сделать это правильно, например, в скрипте, вы должны иметь возможность ссылаться на текущую ветку и на удаленную ветку, которую она отслеживает. Функция настройки приглашения bash в in /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 не разрешали @сами по себе, поэтому вам, возможно, придется использовать @{0}вместо этого.

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

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

Автор: Neil Mayhew Размещён: 19.07.2010 04:18

4 плюса

10339 Репутация автора

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

Автор: che Размещён: 19.07.2010 04:47

125 плюса

23028 Репутация автора

Если у вас есть ветка upstream

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.

Автор: PlagueHammer Размещён: 09.10.2012 12:46

6 плюса

1573 Репутация автора

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

[ `git log --pretty=%H ...refs/heads/master^` != `git ls-remote origin
-h refs/heads/master |cut -f1` ] && git pull
Автор: Claudio Floreani Размещён: 10.03.2013 05:42

1 плюс

30828 Репутация автора

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

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

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
Автор: jthill Размещён: 11.03.2013 12:40

20 плюса

776 Репутация автора

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

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

Введите описание изображения здесь

Автор: Bruno Adelé Размещён: 27.04.2013 12:08

10 плюса

58550 Репутация автора

Я основал это решение на комментариях @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
Автор: ma11hew28 Размещён: 19.06.2013 01:10

2 плюса

435 Репутация автора

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

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

Он может различать обычные ситуации, такие как «тянуть» и «толкать», и он многопоточный, поэтому выборка происходит сразу. У него есть несколько команд, таких как pull и status.

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

Автор: Henry Schreiner Размещён: 02.07.2013 04:34

57 плюса

776 Репутация автора

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

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

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

Автор: Stephen Haberman Размещён: 30.07.2013 04:23

5 плюса

113171 Репутация автора

Если вы запустите этот скрипт, он проверит, нужна ли текущей ветке 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
Автор: Gilles Quenot Размещён: 31.08.2013 10:29

30 плюса

12842 Репутация автора

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

0 плюса

31948 Репутация автора

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

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, он может быть вызван необязательным аргументом 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

Это доступно и здесь .

Автор: Tuxdude Размещён: 27.04.2015 07:43

9 плюса

1748 Репутация автора

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

# 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
Автор: thuovila Размещён: 06.10.2015 08:32

0 плюса

1277 Репутация автора

Прочитав много ответов и несколько постов и потратив полдня на различные перестановки, я пришел к такому выводу.

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

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

- локальный путь, например / d / source / project1
- Git URL, например, https: //username@bitbucket.org/username/project1.git
- пароль

если пароль не следует вводить в командной строке в виде простого текста,
затем измените скрипт, чтобы проверить, пуст ли 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: stderr в dev null для предотвращения печати URL-адреса с паролем на консоли.

#!/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
Автор: RuntimeException Размещён: 29.10.2015 03:55

-3 плюса

112 Репутация автора

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

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

Сценарий написан на XML и требует Phing .

Автор: Pol Dellaiera Размещён: 24.05.2016 10:42

0 плюса

1 Репутация автора

Может быть, это, если вы хотите добавить задачу как 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
Автор: Altzone Размещён: 22.06.2016 11:49

6 плюса

81 Репутация автора

Приведенный ниже скрипт работает отлично.

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
Автор: Harikrishna Размещён: 23.08.2017 12:01

1 плюс

64 Репутация автора

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

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
Автор: Tomas Kukis Размещён: 07.03.2018 02:50

0 плюса

1820 Репутация автора

Для пользователей 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')
}
Автор: Andrew Grothe Размещён: 24.03.2018 12:49

5 плюса

190 Репутация автора

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

Правильный и лучший ответ на этот вопрос дал @Jake Berger, Большое спасибо, чувак, это нужно всем, и все упускают это в комментариях. Таким образом, для всех, кто борется с этим, это правильный ответ, просто используйте вывод этой команды, чтобы узнать, нужно ли вам делать git pull. если вывод равен 0, то, очевидно, обновлять нечего.

@stackoverflow, дай этому парню колокола. Спасибо @ Джейк Бергер

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
Автор: diegeelvis_SA Размещён: 07.06.2018 08:56

0 плюса

604 Репутация автора

Все такие сложные предложения, в то время как решение очень короткое и простое:

#!/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
Автор: Digital Human Размещён: 11.08.2019 07:05
Вопросы из категории :
32x32