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


117

Или просто все коммиты, произошедшие между двумя датами? В SVN вы можете сделать что-то вроде

svn diff -r{date}:{date}

сделать это! Кажется, я не могу найти аналог этого Git.

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

Ответы:


160

Вы могли бы использовать git whatchanged --since="1 day ago" -p

Это также требует --untilаргументов.

Документы


Спасибо! Это было то, что я хотел, он даже принимает параметр --committer, хотя он не указан в документации! кроме того, «git whatchanged» не появлялось в «git help»! Понятия не имею, почему ... еще раз спасибо.
Крис

5
Вы должны выбрать этот ответ, чтобы у Сета появилась карма.
Скотт

18
@brbob Я знаю, что на это давным-давно ответили, но только для тех, кто наткнется на это (как и я), Git help говорит: The command is kept primarily for historical reasons; fingers of many people who learned Git long before git log was invented by reading Linux kernel mailing list are trained to type it. Итак, в документации рекомендуется использовать git logвместо git whatchanged; эта последняя команда также использует параметр --no-merge в git log, поэтому они выводят те же результаты.
Ramses

2
git whatchanged - это своего рода псевдоним команды git log согласно документу git log
Винсент

2
git whatchangedустарело в последней версии 2.21.0. Все git whatchangedдостигнутое можно достичь, git logи это сохраняется только по историческим причинам. См. Подробности git-scm.com/docs/git-whatchanged/2.21.0
Деви

60

Предыдущие предложения имеют некоторые недостатки. В принципе, я искал что-то эквивалентное cvs diff -D"1 day ago" -D"2010-02-29 11:11". Собирая все больше и больше информации, я нашел решение.

Вещи, которые я пробовал:

  • git whatchanged --since="1 day ago" -pот сюда

    Но это дает разницу для каждого коммита, даже если в одном файле есть несколько коммитов. Я знаю, что понятие «свидание» в git несколько расплывчатое , я подумал, что должен быть какой-то способ сделать это.

  • git diff 'master@{1 day ago}..masterдает некоторое предупреждение warning: Log for 'master' only goes back to Tue, 16 Mar 2010 14:17:32 +0100.и не показывает все различия.

  • git format-patch --since=yesterday --stdout мне ничего не дает.

  • revs=$(git log --pretty="format:%H" --since="1 day ago");git diff $(echo "$revs"|tail -n1) $(echo "$revs"|head -n1) работает как-то, но кажется сложным и не ограничивается текущей веткой.

В заключение:

Как ни странно, git-cvsserver не поддерживает "cvs diff -D" (без этого он где-то задокументирован).


4
+1 за git rev-list, что во многом помогло решить очень похожую проблему, которую я видел.
me_and

Это не должно быть общепринятым ответом, это более лаконичный и правильный ответ.
ctford

6
@ctford, на мой взгляд, это неверно. Он может сообщать о нескольких различиях для одного файла, а не об одном различии для каждого файла как svn / cvs diff.
Weidenrinde

1
@Weidenrinde +1, это намного
умнее

1
В git diff 'master@{1 day ago}..masterсредства синтаксиса «проверить на reflog и выяснить , где ветвь masterиспользуется для точки в локальном хранилище 1 day ago ». В частности, не будет использоваться фактическая история фиксации текущей ветки master. Это очень редко то, что вам действительно нужно.
Mikko Rantalainen

22

«Дата» - это немного растяжимое понятие в git. У коммита будет дата автора, которая может быть когда-то давно в прошлом, прежде чем кто-то фактически вытянет / зафиксирует фиксацию в своем репозитории, также фиксация может быть перебазирована и обновлена, чтобы быть поверх явно более новой фиксации.

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

Что, вероятно, наиболее полезно для ваших целей, - это дата рефлога в конкретном рассматриваемом репозитории. Если у вас включены рефлоги для каждой ветки (см. Раздел "Ресурсы" git config core.logAllRefUpdates), вы можете использовать ref@{date}синтаксис, чтобы указать, где ветвь находилась в определенное время.

Например

git log -p master@{2009-07-01}..master@{now}

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

git log -p "master@{1 month ago}..master@{yesterday}"

Эти команды покажут все коммиты, которые «появились» в данной ветке репозитория, независимо от того, насколько они «стары» в соответствии с их автором и датами фиксации.

Обратите внимание, что журнал ссылок для каждой ветки специфичен для репозитория, поэтому, если вы запускаете команду журнала на клоне и не тянете (скажем) в течение месяца, тогда извлеките все изменения за последний месяц сразу, тогда все изменения за последний месяц появятся в @{1 hour ago}..@{now}диапазоне. Если вы можете запустить команду log в «центральном» репосторе, на который люди нажимают, тогда он может делать то, что вы хотите.


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

Это может помочь, если он действительно хочет проанализировать то, что было отправлено в определенную ветку в определенном центральном репозитории, и команда журнала была запущена в этом репозитории. Я думаю, что нужно отредактировать ...
CB Bailey

"дата фиксации, которая обновляется, если фиксация изменена или изменена каким-либо образом", на самом деле дата никогда не изменяется; весь коммит заменяется другим коммитом (хотя дерево предположительно могло быть таким же).
hasen

2
@hasen j: Технически ты прав. Коммиты неизменны. Когда вы переустанавливаете или изменяете фиксацию и создаете новую фиксацию, существующее сообщение фиксации, данные об авторе и дата автора часто копируются из старой фиксации, так что это похоже на обновление фиксации с новым идентификатором фиксации и датой фиксации.
CB Bailey

Обратите внимание, что @{time spec}синтаксис всегда ссылается на ваш локальный журнал ссылок . Это не относится к фактической истории фиксации (DAG). Если вы не понимаете разницу, не используйте этот синтаксис!
Микко Ранталайнен

14
git diff --stat @{2013-11-01}..@{2013-11-30}

или

git diff --stat @{2.weeks.ago}..@{last.week}

Это зависит от рефлога? Потому что, если это так, то вы не можете использовать это, если репо, в котором вы запускаете эту команду, новее (т.е. недавно клонировано), чем содержащаяся в нем история фиксации.

2
Да, это полностью зависит от рефлога. И да, это работает только в локальной истории копирования, но это немного удобная команда.
АА.

1
Да, я определенно согласен с тем, что это удобно, если у вас есть достаточно старые записи рефлога, чтобы их поддерживать.

Спасибо, AA. Используя ваш ответ, я смог сделать: git annotate --stat .. @ {2017-08-8} filename | меньше; git annotate --stat .. @ {5.days.ago} имя файла; так что я вижу изменения в контексте.
Крис,

Обратите внимание, что @{time spec}синтаксис всегда ссылается на ваш локальный журнал ссылок . Это не относится к фактической истории фиксации (DAG). Если вы не понимаете разницу, не используйте этот синтаксис!
Микко Ранталайнен

4

возможно

$ git format-patch --committer=<who> --since=yesterday --stdout

это то, что вы хотите (с параметром --stdout или без него)?


1
Быстрый вопрос, используется ли --since дату фиксации?
CB Bailey,

3

Я считаю, что общее решение - использовать:

git rev-list -n1 --first-parent --until=<a date string> <a ref>

Без --first-parent вы можете получить фиксацию из ветки, которая была позже объединена, a refно не была объединена с a date string.

Вот альтернатива с использованием --childrenи grepвместо -n1:

mlm_git_ref_as_of() {
    # # Examples #
    #
    # Show all commits between two dates:
    #
    #     git log $(mlm_git_ref_as_of '2012-05-21 09:00:00-0400')..$(mlm_git_ref_as_of '2012-05-21 17:00:00-0400')
    #
    # Show diffs of all commits between two dates:
    #
    #     git diff $(mlm_git_ref_as_of '2012-05-21 09:00:00-0400')..$(mlm_git_ref_as_of '2012-05-21 17:00:00-0400')
    local as_of="$1"
    local ref="${2:-HEAD}"
    # Get the most recent commit (--children, grep -v ' ') that was on
    # the given branch ($ref, --first-parent) as of a given date
    # ($as_of)
    git rev-list --children --first-parent --until="$as_of" "$ref" | grep -v ' '
}

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


3

Еще один простой способ получить различие всех изменений с определенной даты - просто найти первую фиксацию, Xкоторая произошла в эту дату или после нее, а затем использовать

git diff X

Это имеет то преимущество, что он не зависит от записей рефлога в новом клоне, в отличие от

git diff <reference>@{n}..
git log <reference>@{n}..

решения в


3

Чтобы отслеживать изменения файлов Git в вашей ветке, используйте следующую формулу:

  1. проверить свой филиал.
  2. извлекать и обновлять изменения из удаленного репозитория
  3. смотреть файлы различий от даты до диапазона дат

Формула :

git checkout <branch>
git pull
git diff --stat @{fromDate}..@{toDate}

Обратите внимание, что даты на формате ГГГГ-ММ-ДД :

git diff --stat @{2019-08-20}..@{2019-08-21}

Если вы хотите наблюдать изменения в конкретном файле в определенном временном диапазоне (смотрите разницу в коде), просто перейдите к текущему файлу:

Пример :

git diff @{2019-01-01}..@{2019-01-02} ~/dev/myApp/package.json

2

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

git log --pretty="format:%H %ai" | grep `date +"%Y-%m-%d"` | awk {'print $1'}`

; ·)


2

Вы также можете использовать git-format-patch для подготовки исправлений (различий) и отправки их по электронной почте.

Используйте параметры [с] или [диапазон ревизий], чтобы указать диапазон фиксации.


0

Я добавлю способ, которым я это делаю: git logдата дает вам хэши фиксации для текущей ветки. Затем я просто использую что-то вроде того, git diff 8fgdfg8..565k4l5что дает мне правильную разницу, агрегированную по файлам. Надеюсь, это поможет, хотя и не тестировалось.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.