Git фиксирует для каждого толчка - PullRequest
1 голос
/ 19 сентября 2019

Есть ли способ получить список коммитов для последней версии?Например, давайте предположим, что я делаю 10 локальных коммитов, но одним нажатием. Есть ли команда git, показывающая только эти 10 коммитов?

Ответы [ 4 ]

1 голос
/ 19 сентября 2019

Вы говорите

Я делаю 10 локальных коммитов

, поэтому давайте предположим, что вы сделали один из

git clone whatever
git pull

непосредственно перед тем, как сделали

# edit stuff
git commit -a
# repeat 9 more times

, а затем

git push

Теперь вы можете увидеть эти 10 коммитов с помощью команды

git log origin/master@{1}..origin/master

Но если вы сделали

git fetch

в любое время между вашими коммитами вы испортили список ссылок на то, где origin/master был, когда вы начали свою локальную работу.Вам нужно будет помнить, как часто origin/master изменялось на git fetch и настраивать {1} на {2} (он подсчитывает, сколько обновлений - не ревизий - вы хотите вернуться).

1 голос
/ 19 сентября 2019

Короткий ответ: вы не можете делать то, что хотите, надежно: сам Git не записывает git push действий.Но есть некоторые вещи, которые вы можете сделать.В частности, в Git , выполняющем git push или в Git , получающем git push, во время самого нажатия , вы может получить эту информацию.Как сохранить его, разобраться с ним и использовать его позже, зависит только от вас.

(Я также утверждаю, что это не очень хорошая идея: не пытайтесь группировать вещи с помощью push, сгруппируйте их другим способом. Например, в системе CI сгруппируйте их по request , с запросами, которые обновляются динамически. Если в запросе сборки # 30 зафиксированы A, B и C как "новый, так как запрос был создан "пять секунд идут из-за предыдущего нажатия, но теперь вместо него есть A, B и D, выполните проверку CI ABD, а не ABC, а затем одну из remove-C-add-D. Читатьоставшуюся часть этого ответа, чтобы понять, что здесь происходит.)

Хук предварительного толчка

Git, отправляющий коммиты, будет запускать хук предварительного толчка, если он присутствует.Хук предварительного толчка на отправляющем Git получает четыре информационных элемента за, ну, на данный момент, давайте назовем это «за штуку»:

  • local ref
  • local OID / SHA-1 / hash
  • remote ref
  • remote OID / SHA-1 / hash

Допустим, вы сделали:

git push origin refs/heads/master:refs/tags/v1.1

ЗдесьТаким образом, локальный ref равен refs/heads/master.Идентификатор хеша, который сегодня является хешем SHA-1, но внутренняя часть Git теперь вызывает «OID» (имеется в виду идентификатор объекта) для проверки на будущее, когда Git переключается на SHA-256, но вы можете просто назвать его «хеш», чтобы избежатьСиндром TLA 1 - любой хеш-идентификатор коммита, идентифицируемый вашим refs/heads/master.Удаленная ссылка будет refs/tags/v1.1, а удаленный хэш, вероятно, будет состоять из всех нулей, так как это, вероятно, новый легкий тег, который вы хотите создать.

Если вы запустите вместо:

git push origin master develop

ваш крюк получит две штук.Один упомянул бы refs/heads/master дважды, а другой упомянул бы refs/heads/develop дважды: локальную и удаленную ветку master, а также локальную и удаленную ветку develop, которую вы продвигаете в одной большой операции git push.Хеш-идентификаторы будут такими же для вашего локального master и для их master, а также для вашего локального develop и для их develop.

Используя эти хеш-идентификаторы, вы можете увидеть, какой коммит (s) являются новыми для них.Если их хэш-идентификатор находится в вашем Git-репозитории, вы также можете увидеть, просите ли вы удалить любые коммиты или, точнее, сделать их недоступными .Подробнее о достижимости см. Think Like (a) Git .

Некоторые из этих хеш-идентификаторов могут быть полностью нулевыми.Такой хэш-идентификатор означает «такого имени нет».Для git push хеш remote будет иметь все нули, если вы попросите Git удалить ссылку. локальный хеш будет иметь все нули, если у вас нет ссылки (что имеет смысл только в том случае, если вы также просите их удалить).


1 TLA означает трехбуквенное сокращение.Сравните с ETLA, который представляет собой расширенный TLA с более чем тремя буквами.


ловушки до получения, обновления и пост-получения

Git, который получает коммиты, ипри запросе обновить свои ссылки будут запускаться ловушки до получения и после получения, если они существуют.Они получат столько «штуковин», сколько будет запросов на обновление.Он также будет запускать ловушку обновления, если она существует, один раз за штуку.

Хук предварительного получения получает три информационных элемента за штуку:

  • текущий (старый) OID /хэш
  • предлагаемый новый OID / хэш
  • ссылка

Хэш current сообщает вам, что представляет имя в данный момент.Например, в нашем примере создания тега текущий хеш будет иметь все нули.Предложенный новый хеш - это идентификатор объекта, который запрашивающий Git просит вас, получающий Git, использовать в качестве нового хеш-идентификатора для обновленной ссылки.Ссылка, конечно, является ссылкой, подлежащей обновлению.

В нашем примере с двумя ветвями для обновления двумя хэшами для refs/heads/master будут текущий master коммит ипредлагаемый новый master коммит.Оба они, скорее всего, будут действительными хешами, а не все нули, но не более одного может быть все нули.Старый хэш равен нулю, если у вас, получающего Git, еще нет ссылки (т. Е. Ветвь master для вас совершенно новая);новый хэш равен нулю, если вас, получающего Git, просят удалить ссылку.

Задача ловушки перед нажатием - прочитать все предложенные обновления и проверьте, все ли в порядке.Если это так, ловушка предварительного толчка должна выйти из 0 («истина» в shell-exit-status-speak).Если нет, крючок предварительного толкания может распечатать вывод, предназначенный для информирования пользователя, выполняющего git push , почему отклонение толчка - этот пользователь увидит этот вывод со словом remote:, застрявшим перед ним.- и затем выйдите из нуля, чтобы отклонить весь push.

В то время, когда запускается ловушка предварительного приема, получающий Git имеет доступ к всем предложенным объектам.То есть, если парень, выполняющий толчок, выполнил git push origin master develop, и это означало отправку трех новых master коммитов и одного нового develop коммита, ловушка предварительного получения на сервере запускается после на сервересобрал все четыре новых коммита и любые другие объекты, требуемые этими коммитами.Новые объекты находятся «на карантине», где-то в зоне ожидания.Если push-уведомление отклонено, область карантина отбрасывается без включения фиксаций в главный репозиторий. 2 На этом этапе push-уведомление Весь отменяется.

Еслиловушка предварительного приема позволяет нажать - или не существует - - переходит к следующему этапу, на котором принимающий Git фактически обновляет каждую ссылку, по одному за раз.В это время получающий Git запускает хук update для каждой ссылки, предоставляя ей (в качестве аргументов, а не как stdin) ссылку, старый хэш и новый хэш (обратите внимание на другой порядок).Хук обновления может проверять элементы как прежде, а затем либо принять, либо отклонить это конкретное обновление .Независимо от того, отклонено ли обновление, получение продолжается со следующей ссылкой.Таким образом, хук обновлений имеет только локальное представление - по одной ссылке за раз - но более детальный контроль принятия / отклонения.

Наконец, после того, как все обновления были сделаны или отклонены, если any ссылки были обновлены, получающий Git запускает хук post-receive, если он существует.Это получает тот же тип строк stdin, что и ловушка предварительного приема.Крюк должен выйти из нуля, потому что толчок уже сделан.Блокировки для различных обновлений ссылок были сняты, поэтому ловушка не должна искать имена ссылок в репозитории Git - они могли уже измениться из-за другого нажатия!


2 Эта «область карантина» была новой в Git 2.13;до этого новые объекты входили даже в том случае, если они оказались неиспользованными, но их нужно было выбросить позже.На действительно больших серверах (например, GitHub) это причиняет много боли.


Перечисление коммитов

С учетом старого хеш-идентификатора и нового хеш-идентификатора, команда:

git rev-list $old..$new

перечисляет все коммиты, которые доступны с $new, но не с $old.Например, для git push это только что добавленные новые коммиты.

Его аналог:

git rev-list $new..$old

перечисляет коммиты, достижимые из $old, которые более недоступны из $new.Это коммиты , удаленные, например, нажатием.

ПримечаниеЭто возможно сделать одновременно!Обновление может удалить один коммит и заменить его новым и улучшенным вариантом.

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

git rev-list $old...$new

Чтобы сделать этот вывод полезным, вы должны добавить --left-right, чтобы вставить маркеры , о которых коммиты доступны только с $old, а какие доступны только с $new.

Вы можете получить счет достижимых коммитов с использованием git rev-list --count.Добавление --left-right к трехточечному варианту дает вам два счета: например, git status вычисляет счет впереди и сзади, например.(Ну, * git status имеет скомпилированный код, так что это проще, чем это было бы в скрипте, но это позволяет вам делать то, что git status делает в скрипте.)

Заключение

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

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

  • обновить существующие подпрограммы, которые не были в состоянии, чтобы они были более способными
  • добавить новые подпрограммы для выполненияновая вещь
  • добавить интеграцию верхнего уровня, которая использует старые и новые процедуры по-новому

В этом случае вместо перехода от:

...--o--*   <-- master

до:

...--o--*--A--B--C   <-- master

, где A - C - новые коммиты, которые выполняют эти три шага, рассмотрите толчок нового графика как:

...--o--*---------M   <-- master
         \       /
          A--B--C

Здесь M - это новый коммит слияния .Установите для его сообщения слияния (лучший вариант) интегрируйте новую функцию .Установите для сообщений фиксации для A, B и C значение , чтобы дополнить существующие подпрограммы , , добавить новые подпрограммы и объединить старые и новые подпрограммы для поддержки новой функции .Этот пузырь слияния - цепочка A-B-C - изолирует эту функцию, поэтому, если что-то действительно ужасно, вы можете отменить все слияние, вернув M, а если что-то немного сломано, вы можете проверить коммиты A через C индивидуально, чтобы выяснить, что.Вы можете сделать одно или оба из них - отменить все слияние или нет;Тест фиксируется индивидуально или нет - потому что вся информация сохраняется навсегда в графике.

0 голосов
/ 26 сентября 2019

Спасибо за поддержку всем, особенно @torek за его умный и интересный ответ, вот как я это сделал с gitlab API и python:

import json
import requests

def checkAsset(obj):
    status=0
    #status=0 modified, status=1 new file, status=2 deleted
    if (obj['new_path']==obj['old_path'] and obj['new_file']==False):
        status=0
    elif (obj['new_path']==obj['old_path'] and obj['new_file']==True):
        status=1
    elif (obj['new_path']==obj['old_path'] and obj['deleted_file']==True):
        status=2
    else:
        status=0
    return status


headers = {'Private-Token': 'XXXXXXXXXXXXXX'}
#this API gives you all commits grouped by pushes
pushes= "https://gitlab.XXXXX/api/v4/projects/{{projectID}}/events??target_type=issue&action=pushed"

r = requests.get(pushes, headers=headers)

latestPushes=json.loads(r.content)

lastPush=latestPushes[0]
i=0
while lastPush['push_data']['ref']!= 'master':
    i+=1
    lastPush=latestPushes[i]

commitNumber=lastPush['push_data']['commit_count']
if (commitNumber > 30):
    raise Exception("Could not compare, too many commits in one push")
initCommit=lastPush['push_data']['commit_from']
latestCommit=lastPush['push_data']['commit_to']

compareApi= "https://gitlab.XXXXXXXXXXX/api/v4/projects/{{projectID}}/repository/compare?from="+str(initCommit)+"&to="+str(latestCommit)

r = requests.get(compareApi, headers=headers)

compareJson=json.loads(r.content)

diffs=compareJson['diffs']

Mlist=[]
Alist=[]
Dlist=[]
for asset in diffs:
        status=checkAsset(asset)
        if status==0:
            Mlist.append(asset['new_path'].encode('ascii','ignore'))
        elif status==1:
            Alist.append(asset['new_path'].encode('ascii','ignore'))
        else:
            Dlist.append(asset['new_path'].encode('ascii','ignore'))
0 голосов
/ 19 сентября 2019

Вы можете проверить историю коммитов, используя следующую команду.

git log
...