2011-01-24 3 views
61

Итак, я нашел вопрос о том, как просмотреть историю изменений файла, но история изменений этого файла огромна, и меня действительно интересуют только изменения конкретного метода. Так можно ли увидеть историю изменений только для этого конкретного метода?Git - как просмотреть историю изменений метода/функции?

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

Язык, с которым я сейчас работаю, - Objective-C, и SCM, который я использую в настоящее время, является git, но мне было бы интересно узнать, существует ли эта функция для любого SCM/языка.

+1

Я видел такую ​​функциональность в предложении Git GSoG. –

+0

Это предложение, о котором вы говорили? http://lists-archives.org/git/715169-gsoc-draft-proposal-line-level-history-browser.html –

+1

Возможный дубликат [Получить журнал фиксации для определенной строки в файле?] (http: //stackoverflow.com/questions/8435343/retrieve-the-commit-log-for-a-specific-line-in-a-file) – lpapp

ответ

2

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

+0

Он показывает только последнюю версию, хотя .. – poke

+4

с 'git gui виной' вы можете перемещаться по более старым версиям. –

8

git log имеет опцию '-G', которая может использоваться для поиска всех отличий.

-G Ищите различия, чья добавленная или удаленная строка соответствует данным <regex>.

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

$ git log --oneline -G'^int commit_tree' 
40d52ff make commit_tree a library function 
81b50f3 Move 'builtin-*' into a 'builtin/' subdirectory 
7b9c0a6 git-commit-tree: make it usable from other builtins 
+4

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

+0

Если вы хотите больше контекста, вы можете заменить '--oneline' на' -p' – lfender6445

+2

Но что, если в результате было сделано 20 строк в методе? – nafg

13

Использование git gui blame трудно использовать в сценариях, и в то время как git log -G и git log --pickaxe может каждый показать вам, когда определение метода появились или исчезли, я не нашел способ сделать их список все изменения сделаны в корпусе вашего метода.

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

Ключ состоит в том, чтобы Git удалил из файла все строки, кроме тех, которые вас интересуют, перед выполнением каких-либо операций diff. Тогда , git diff и т. Д. Будут видеть только интересующую вас область.

Вот схема того, что я делаю на другом языке; вы можете настроить его для своих нужд.

  • Написать короткий скрипт (или другую программу), которая принимает один аргумент - имя исходного файла - и выводит только интересная часть этого файла (или ничего, если ни один из них не интересно) , Например, вы можете использовать sed следующим образом:

    #!/bin/sh 
    sed -n -e '/^int my_func(/,/^}/ p' "$1" 
    
  • Определение Git textconv фильтр для нового сценария. (Более подробную информацию см. В справочной странице gitattributes.) Имя фильтра и расположение команды могут быть любыми, что вам нравится.

    $ git config diff.my_filter.textconv /path/to/my_script 
    
  • Скажите Git использовать этот фильтр перед расчетом различия для файла в вопросе.

    $ echo "my_file diff=my_filter" >> .gitattributes 
    
  • Теперь, если вы используете -G. (обратите внимание на .) перечислить все коммиты, которые производят видимые изменения при применении вашего фильтра, вы будете иметь именно те коммиты, которые вы заинтересованы. Есть другие варианты которые используют подпрограммы diff Git, такие как --patch, также получат это ограниченное представление.

    $ git log -G. --patch my_file 
    
  • Voilà!

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

$ git config diff.my_filter.textconv "/path/to/my_command other_func" 

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

+1

Принять несколько аргументов для меня не помогло, но, положив имя функции в трудные работы, отлично, и это действительно потрясающе! – qwertzguy

+0

Блестящий, хотя мне интересно, как (в) удобно переключаться между множеством разных методов. Кроме того, знаете ли вы о программе, которая может вытащить всю C-подобную функцию? – nafg

7

Ближайшей вещь, которую вы можете сделать, это определить положение вашей функции в файле (например, ваша функция i_am_buggy находится на линии 241-263 из foo/bar.c), затем запустить что-то эффект:

git log -p -L 200,300:foo/bar.c 

Это откроет меньше (или эквивалентный пейджер). Теперь вы можете ввести /i_am_buggy (или ваш пейджер-эквивалент) и начать выполнять изменения.

Это может даже работать, в зависимости от вашего стиля кода:

git log -p -L /int i_am_buggy\(/,+30:foo/bar.c 

Это ограничивает поиск с первым попаданием этого регулярного выражения (в идеале вашей функции декларации) до тридцати строк после этого. Аргумент end также может быть регулярным выражением, хотя обнаруживает , что с regexp's является предложением iffier.

+0

Сладкий! FYI, это новое в Git v1.8.4. (Угадайте, я должен обновиться.) Хотя более точное решение было бы приятным ... например, если кто-то скрипрует ответ Пола Уиттекера. –

+0

@GregPrice [По-видимому, края поиска могут быть даже регулярными выражениями) (http://git-scm.com/docs/git-log), поэтому вы можете, по крайней мере, иметь более или менее точную начальную точку. – badp

+0

О, ничего себе. На самом деле: вместо написания собственного регулярного выражения вы можете просто сказать '-L ': int myfunc: foo/bar.c" и ограничивать функцию с этим именем. Это фантастика - спасибо за указатель! Теперь, если только обнаружение функции было немного более надежным ... –

41

Последние версии git log узнали специальную форму параметра -L:

-L: < имя_функции>: < Файл>

проследить эволюцию диапазона линии, заданной "<start>,<end>" (или имя функции regex <funcname>) в пределах <file>. Вы не можете указывать ограничители пути. В настоящее время это ограничивается прогулкой, начиная с одной ревизии, т. Е. Вы можете дать только нулевые или одни положительные аргументы ревизии. Вы можете указать эту опцию несколько раз.
...
Если “:<funcname>” дается вместо <start> и <end>, это регулярное выражение, которое означает диапазон от первой имя_функции линии, которая соответствует <funcname>, до следующей имя_функции линии. “:<funcname>” поиск с конца предыдущего -L диапазона, если таковой имеется, в противном случае с начала файла. “^:<funcname>” выполняется поиск с начала файла.

Другими словами: если вы попросите Git до git log -L :myfunction:path/to/myfile.c, он теперь с радостью распечатает историю изменений этой функции.

+4

это может работать для объектного c из коробки, но если вы делаете это для других языков (например, Python, Ruby и т. Д.), Вам может потребоваться добавить соответствующие конфигурации внутри файла .gitattributes, чтобы git распознавал объявления функций/методов на этом языке. Для python используйте * .py diff = python, для использования ruby ​​* .rb diff = ruby ​​ – samaspin

+0

Как git отслеживает функцию? – nn0p

+0

@ nn0p Я предполагаю наличие синтаксического знания нескольких языков и, следовательно, знание того, как изолировать функцию и отслеживать ее изменения. – JasonGenX

Смежные вопросы