Как мне найти самый последний git commit, который изменил файл?

180

Я хочу найти самый последний коммит, который изменил исходный файл.

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

Как мне найти последний коммит, который коснулся данного файла в моем git-репозитории?

Кори Кляйн
источник

Ответы:

230

git log поддерживает просмотр истории определенных файлов (и каталогов), поэтому вы можете назвать это так:

git log my/file.c

Если вы действительно хотите перечислить только один последний коммит, например, чтобы использовать его в скрипте, используйте -n 1параметр:

git log -n 1 --pretty=format:%H -- my/file.c

--pretty=format:%hговорит git logпоказывать только хеш коммита. --Separater останавливает имя файла от того , чтобы интерпретировать как коммит имя, только в случае , если это неоднозначно.

Джо Лисс
источник
12
Если вы хотите узнать, когда файл в последний раз изменялся независимо от ветви, вы можете рассмотреть все ветви, добавив эту --allопцию.
KC
44

Если вы просто хотите найти самый последний коммит, то вам не нужен git-log, вам нужен git-rev-listсписок объектов фиксации, изменяющих этот файл, в этом пути фиксации, начиная с самого последнего (в хронологическом порядке). Проще говоря:

git rev-list -1 <commit> <filename>

В git-rev-listвашем случае вы просто поставляете:

  • Количество коммитов для включения или -1 только для самых последних,
  • Ветвь (или идентификатор коммита), с которой нужно начать оглядываться назад, HEAD, если вы уже на ней, или --all, если вы хотите все известные коммиты, и
  • Относительный путь к вашему файлу.

Это просто возвращает самый последний идентификатор фиксации в текущей ветви, чтобы изменить этот файл, например: 215095e2e338525be0baeeebdf66bfbb304e7270

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

git rev-list origin/user/bob/testbranch -1 src/bfiles/*.txt

... Что скажет вам, что было самым последним изменением в сопоставлении символов подстановки в истории этой ветви. Опции для rev-list являются экстремальными, это одна из самых важных команд, поэтому вы можете включать или исключать практически любые критерии, которые вы можете себе представить.

Конечно, обратитесь к странице руководства git-rev-list (1) .

Майкл Эриксон
источник
Вы действительно не объяснили, почему использование git-logуступает.
Петр Доброгост
7
Я бы не сказал, уступает, просто он предоставляет постороннюю информацию по умолчанию. git-rev-list просто возвращает идентификатор фиксации, который вам нужен, если вы собираетесь передать ответ в скрипт или другой процесс автоматизации. git-log возвращает информацию о выбранных коммитах, сначала используя git-rev-list для сбора идентификаторов коммитов, затем собирая информацию о каждом коммите. Если вы просто собираетесь отфильтровать информацию о коммите и использовать идентификаторы, то вы можете просто использовать git-rev-list в первую очередь. Поскольку log основан на rev-list, он принимает большинство одинаковых параметров фильтра.
Майкл Эриксон
3
git-logэто фарфор, git-rev-listэто сантехника.
blitzen9872
27

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

git log -n 1 --pretty=format:%h -- <path>

Это может быть полезно для получения хеша коммита для последующего использования с git describe.

Например (на случай, если это кому-нибудь пригодится)…

Я создаю идентификатор текущей версии, учитывая последнюю фиксацию для изменения любого исходного файла (при условии, что вы помечаете версии такими тегами mycode-1.2.1):

COMMIT=$(git log -n 1 --pretty=format:%h -- *.c *.h)
if VN=$(git describe --always --abbrev=5 --match "mycode-*" $COMMIT 2>/dev/null) &&
case "$VN" in
mycode-*)
    git update-index -q --refresh
    test -z "$(git diff-index --name-only HEAD *.c *.h)" ||
    VN="$VN-mod" ;;
*) VN="mycode-unknown-g$VN" ;;
esac
then
    continue
else
VN="mycode-unknown"
fi

Это производит идентификаторы как:

  • mycode-1.2.1 - когда текущее состояние исходных файлов соответствует теговой версии
  • mycode-1.2.1-g3k7s2 - когда текущее состояние исходных файлов соответствует фиксации после теговой версии
  • mycode-1.2.1-g3k7s2-mod - когда текущее состояние исходных файлов было изменено с момента последнего коммита после теговой версии
  • mycode-unknown - когда еще не создан тег версии
TheBamf
источник
5
$VNвыглядит как какая-то кошмарная нежить SVN
ThorSummoner
10

Я не уверен, что это то, что вы хотите, но если вы делаете, git log <thefile>чтобы получить коммиты, которые изменили этот файл. Вы можете выбрать самый верхний. Это должен быть тот, кого вы ищете.

Нуфал Ибрагим
источник
4
если вы используете git log -n1 -- <thefile>(или перенаправляете вывод, head -1если хотите тратить ресурсы), вам не нужно вручную выбирать верхнюю строку (см. ответ Джо Лисса )
Тобиас Кинцлер,
4
Хорошая точка зрения. Я думаю, что вы также можете пропустить -nи использовать -1напрямую.
Нуфал Ибрагим
3

Чтобы получить только ссылку на одну строку, попробуйте:

git log -n1 --oneline <path> | awk '{print $1;}'
fastmultiplication
источник
2

Как только у вас будет идентификатор SHA для коммита, который вы хотите использовать git log FILENAME, вы сможете git show SHA_ID_HEREувидеть, что вы сделали для этого коммита. Вам даже не нужно вводить весь идентификатор; первых 6 символов должно быть достаточно.

Джо
источник
4
это немного больше, чем запрашивал ОП, но, к вашему сведению, вы можете объединить это в одну git show $(git log -1 --pretty="%H" -- FILENAME)
строчку