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

В настоящее время я загружаю последнюю версию, а затем запускаю git status и где я анализирую вывод для Your branch is up to date with 'origin/master' но это кажется действительно хакерским.

Я смотрел на использование git status --porcelain но это включает только изменения файлов, сделанные в системе, а не изменения, сделанные на удаленном компьютере. Меня не волнует, какие изменения были сделаны на самом деле, я просто хочу знать, существуют ли какие-либо изменения (локальные или удаленные).

Как бы я добился этого чисто?

1 ответ

Чтобы программно получить количество коммитов, которые отличаются в текущей ветке от ее восходящего потока, используйте git rev-list --count --left-right HEAD...@{upstream}, или же git rev-list --count master...master@{upstream} например. Обратите внимание на три точки, которые разделяют название ветви или HEAD от branch@{upstream}Вот как git status или же git branch -vv печать ahead 1 или же behind 2 или же up to date или что угодно.

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

Есть еще много чего знать

Если вы пишете этот материал, важно точно знать (или определить), что вы подразумеваете под обновлением.

Чисто локально, т. Е. В одной комбинации хранилище + дерево работы, есть три объекта, о которых стоит подумать:

  • Текущий коммит, он же HEAD,

    Это может быть отдельная ГОЛОВА, где HEAD содержит необработанный идентификатор хеша, или наоборот, на ветке, где HEAD содержит название самой ветви. Когда на ветке, название ветви, например, master, содержит необработанный хэш-идентификатор текущего коммита. В любом случае, HEAD всегда ссылается на текущий коммит.1

    Сам текущий коммит доступен только для чтения (полностью) и является постоянным (в основном - вы можете намеренно отказаться от коммитов, после чего они в конечном итоге удаляются). Вы можете изменить, какой коммит является текущим коммитом (например, git checkout different-commit), но вы не можете изменить коммиты сами. Поскольку коммит не может быть изменен, он никогда не "устаревает" по определению: это то, что есть. Как и любой коммит, текущий коммит имеет некоторые метаданные (кто их сделал, когда и т. Д.) Вместе с полным снимком каждого файла.

    Хранение файлов внутри коммитов осуществляется в специальном формате Git-only (и, конечно, только для чтения).

  • Дерево работы, где вы просто делаете свою работу.

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

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

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

    Файлы в индексе сжимаются в формате Git-only, как и файлы в коммитах. Однако для наших целей принципиальное отличие состоит в том, что файлы в индексе могут быть изменены. Вы можете помещать новые файлы в индекс или также удалять существующие файлы из индекса.

    Все это git add file на самом деле это скопировать файл из рабочего дерева в индекс. Это заменяет предыдущую версию в индексе, так что индекс теперь соответствует рабочему дереву. Или, если вы хотите удалить файл, git rm file удаляет этот файл как из индекса, так и из рабочего дерева.


1 Новый репозиторий вообще не имеет коммитов, поэтому есть исключение из этого правила: HEAD может ссылаться на название ветви, которая просто еще не существует. Это случай в совершенно новом хранилище: HEAD говорит, что текущая ветка master, еще master на самом деле не существует, пока вы не сделаете первый коммит.

(The git checkout --orphan Команда может воссоздать это специальное состояние "на ветви, которая еще не существует" для другой ветви. Это не то, что большинство людей будет делать большую часть времени, но это может появиться в программах, которые проверяют состояние.)


Какие git status делает

Поскольку индекс и рабочее дерево доступны для записи, оба могут быть "грязными" или приводить к тому, что что-то "устареет" каким-то образом. Если вы считаете, что файл рабочего дерева является самым новым, это может быть устаревшая индексная копия, поскольку она не совпадает с копией рабочего дерева. Как только файл рабочего дерева скопирован в индекс, индекс больше не соответствует HEAD коммит, и в какой-то момент потребуется новый коммит.

Какие git status кроме бега git rev-list --count --left-right с ответвлением и его восходящим потоком и получением этих чисел,2 состоит в том, что он работает, по сути, два git diffс (с --name-status так как не интересует подробный патч):

  1. сравнить HEAD индексировать. Что бы здесь ни отличалось, это изменения, которые подготовлены для фиксации, потому что если вы сделали коммит сейчас, Git сделает снимок всего индекса, и этот снимок будет отличаться от текущего коммита именно в этих файлах.

  2. Сравните индекс с рабочим деревом. Что бы здесь ни отличалось, это те изменения, которые не предназначены для фиксации. Как только вы запустите git add для этих файлов индексная копия будет соответствовать копии рабочего дерева, но больше не будет соответствовать HEAD копировать, так что теперь это будут изменения, которые подготовлены для фиксации.


2 Обратите внимание, что git status сначала проверяет, что вы находитесь на ветке, и если да, то на ветке есть восходящий параметр. Кроме того, все это встроено в него, поэтому не нужно запускать отдельную программу, но принцип тот же.


Не отслеживается и, возможно, игнорируется

Теперь мы можем правильно определить, что означает, что файл тоже не отслеживается. Не отслеживаемый файл - это файл, которого нет в индексе. То есть, если мы удаляем файл из индекса (только) с git rm --cachedили если мы создадим файл в рабочем дереве без создания соответствующего файла в индексе, у нас будет файл рабочего дерева, который не имеет ничего с таким же именем в индексе. Это неотслеживаемый файл.

Если файл не отслежен, git status как правило, жалуется на это: различие, которое он выполняет, который сравнивает индекс с рабочим деревом, говорит ах, вот файл в рабочем дереве, которого нет в индексе, и Git скажет вам, что он не отслежен. Если это не отслеживается специально, вы можете иметь git status замолчи об этом, перечислив этот файл - или шаблон имени пути, который соответствует ему - в .gitignore файл. По сути, непосредственно перед тем, как жаловаться, что какой-то файл не отслежен, Git просматривает директивы игнорирования.3 Но если файл находится в индексе, Git никогда не ищет его имя в любом .gitignore,


3 Директивы игнорирования также говорят git add что любое массовое "добавить все" должно избегать добавления этого файла, если он в настоящее время не отслежен.


Upstreams и пульты

Восходящий поток для ветви может быть именем удаленного отслеживания, например origin/master, Эти имена - способ, которым ваш Git запоминает ветви других Git. Чтобы обновить имена удаленного отслеживания для удаленного originты просто бежишь git fetch origin,

Обратите внимание, что вы можете иметь более одного пульта! Если вы добавите второй пульт fred на какой-то второй URL, git fetch fred вызовет Git по этому URL и обновит ваш fred/master и так далее. Поэтому важно бежать git fetch на правый пульт.

Бег git fetch без дополнительного имени извлекает пульт дистанционного управления для текущей ветки или из origin текущая ветвь не имеет восходящего потока или нет текущей ветки, так что обычно это просто вопрос запуска git fetch,

подмодули

Подмодули на самом деле являются просто ссылками на другой репозиторий Git, но это приводит к совершенно новой складке в общем плане. Каждый репозиторий Git имеет свой HEAD, дерево работы и индекс. Они могут быть чистыми или грязными, как и раньше, и если подмодуль не находится в состоянии отсоединенного HEAD, ветвь подмодуля может быть впереди и / или позади его восходящего потока.

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

Чтобы изменить идентификатор хэша, git add в суперпроекте копирует текущий хеш-идентификатор фактического извлеченного подмодуля в индекс в репозитории для суперпроекта (вот так!). Так что если вы переместили субмодуль (через git checkout там), вы переходите обратно к суперпроекту, запускаете git add на пути к субмодулю, и теперь индекс суперпроекта записывает правильный идентификатор хеша, готовый к следующей фиксации суперпроекта.

(Проверка того, находится ли подмодуль на коммите, желаемом индексом суперпроекта, сложнее.)

Другие вопросы по тегам