Показать историю одного файла во всех ветках

Как я могу показать полную историю одного файла в Git? Когда я использую git log <filename> или gitk <filename>, я получаю только слияния. Я хочу увидеть коммиты из объединенных ветвей, которые влияют на файл. Я пробовал --follow и другие флаги и не могу найти способ.


person Juliana Peña    schedule 21.07.2014    source источник
comment
git log --all --full-history -- path/to/file делает это за вас?   -  person jthill    schedule 22.07.2014
comment
Нет, он просто показывает еще больше слияний...   -  person Juliana Peña    schedule 22.07.2014
comment
М-м-м. добавьте --no-merges, чтобы узнать, не спрятано ли что-нибудь ценное в мякине.   -  person jthill    schedule 22.07.2014
comment
Я узнал проблему! Слияние на самом деле было слиянием поддерева, поэтому история показывала только добавление. Подробный ответ здесь: stackoverflow.com/questions/ 10918244/   -  person Juliana Peña    schedule 22.07.2014


Ответы (2)


Это покажет все версии файла (слияния или нет):

gitk --all <filename>
person Martin G    schedule 22.07.2014

Сводка TL;DR: --all

Во-первых, позвольте мне рассмотреть один общий пункт, который применим ко многим командам git.

git log просматривает указанные вами ревизии, используя git rev-list для их обработки. Причина, по которой вы обычно видите много коммитов, заключается в том, что git rev-list "проходит историю", если только не сказано не делать этого:

$ git rev-list --no-walk HEAD
d1574b852963482d4b482992ad6343691082412f
$ git rev-list HEAD
d1574b852963482d4b482992ad6343691082412f
b9491ea160d12ddfd69a9ddc79ebd264cda20679
676699a0e0cdfd97521f3524c763222f1c30a094
[snip]

Однако ревизии, посещаемые git rev-list, начинаются с указанной вами точки (по умолчанию = HEAD). Таким образом, любые изменения, которые не уже являются частью указанной вами точки или ее истории, опускаются:

        C - D           <-- branchA
      /
A - B - E - F - G       <-- branchB
      \
        H - I - J - M   <-- HEAD=branchC
          \       /
            K - L

На этой диаграмме я поместил три названия ветвей и показал, что HEAD равно branchC. Каждая отдельная буква представляет фиксацию (SHA-1). Родителями любого коммита являются те, которые находятся слева от него, либо прямо слева, либо перемещаются вверх или вниз по ссылкам родительского коммита, которые проходят между коммитами.

В этот момент git log покажет вам коммиты M, L, K, J, I, H, B и A, потому что git loggit rev-list) начнется с HEAD и пойдет в обратном направлении. (Точный порядок этих коммитов зависит от дополнительных аргументов.)

С другой стороны, git log branchB покажет вам коммиты G, F, E, B и A, потому что, начиная с коммита G и перемещаясь назад, выбираются эти коммиты (и никакие другие). Точно так же git log branchA начинается с D и возвращается к A.

Если вы попросите git rev-list просмотреть --all, он начнет со всех ссылок (всех ветвей, всех тегов, всех удаленных ветвей и всех остальных ссылок в пространстве имен refs/) и пойдет в обратном направлении. В этом случае для выбора каждого коммита достаточно только всех ветвей. В репозиториях с тегами --branches может дать вам меньше, чем --all, поскольку могут быть некоторые строки, которые помечены тегами, но не отмечены ветвью. См. (довольно объемную) git rev-list документацию чтобы увидеть все доступные варианты здесь.


Добавление имени файла к git log заставляет его пропускать печать некоторых (многих или большинства) коммитов, которые он посещает, посредством того, что описано в документации как "Упрощение истории". То есть git log сначала выбирает все фиксации, выбранные вашими git rev-list аргументами, но затем показывает меньшее число.

Добавление --follow заставляет git log пытаться заметить случаи, когда файл переименовывается в конкретном коммите, и в этих случаях переключать выбранные ревизии на ревизии с предыдущим именем, как только он переходит через такие коммиты в своем обходе по истории. Другими словами, он пытается настроить упрощение истории, чтобы скорректировать изменения имени. Это обнаружение переименования выполняется динамически (повторно тестируется для каждой пары коммитов). Это работает только при отступлении — кода просто нет для обработки других заказов на коммит.

При использовании git diff у вас больше контроля над тем, что распознается как переименование; с --follow git log вы застряли с скомпилированным значением по умолчанию, равным 50%.

person torek    schedule 22.07.2014
comment
Я пытался использовать git log --all <filename>, и он по-прежнему показывает только слияния. - person Juliana Peña; 22.07.2014
comment
Возможно, файл изменяется только в этих слияниях. Конечно, это редко, но возможно. (Не совсем ясно, что должно означать измененное для слияния, поскольку слияние имеет несколько родителей; git show по умолчанию показывает комбинированные различия для слияний, которые показывают только файлы, измененные в обоих родителях. Я не уверен, что git log делает такой же.) - person torek; 22.07.2014