13

Let's say I have a file A.cpp, and I notice an error on line 15 of the file. Let's say the error is a "const" on a function that returns a pointer to a member variable, meaning using const on the function is technically correct but semantically wrong. I would like to discuss the semantics with the author who made the change.

Using git, is there a way to find out which revision introduced the "const" token? More specifically, I'd like to know who introduced the token.

"git blame" shows who made the last change to the line, but I would actually like to find the first commit containing the token.

Jon Seigel
  • 12,251
  • 8
  • 58
  • 92
oz10
  • 153,307
  • 27
  • 93
  • 128
  • Can you not diff each revision until it shows up? Sorry, I don't know much about Git, but that's what I'd do for other source control systems. – Mark Allen Dec 07 '09 at 22:39
  • Yes, but that could be very time consuming... the history for the repository goes back at least 3 years with several thousand commits on this file. This seems like a fairly common task, it seems like there would be a better way to do this. – oz10 Dec 07 '09 at 22:42
  • See also [git: finding a commit that introduced a string](http://stackoverflow.com/questions/5816134/git-finding-a-commit-that-introduced-a-string). –  Mar 07 '14 at 07:35

5 Answers5

28

There are a few possible ways of doing it.

  • git blame, or better graphical blame tool (like git gui blame or the blame view in git instaweb / gitweb) to browse history of a line, going back in history until you find appropriate commit.

  • so called "pickaxe search", i.e. git log -S with appropriate token / regexp, to find (list) all commits where number of given tokens changed (which usually means where given token was added or deleted), e.g.:

    git log --reverse -p -S'const int foobar' -- A.cpp
    
  • git bisect where "bad" commit would mean the one with 'const' where there it shouldn't be (testing using e.g. grep).

Alois Mahdal
  • 10,763
  • 7
  • 51
  • 69
Jakub Narębski
  • 309,089
  • 65
  • 217
  • 230
13

git bisect is what you are looking for. With this command you can find quickly what commit introduced the const.

You start the process with git bisect start, then mark an old version without the const as good with git bisect good and and the current one as bisect bad. Then the system will send you to a version in the middle. You can check if the evil const is there, and mark that version good or bad depending on it. Then The process is repeated until you find the bad commit.

nacmartin
  • 2,172
  • 18
  • 15
  • 4
    If you can write a simple script that exits with 1 if the constant is there (i.e. a "bad" state), call `git bisect run myscript`, sit back and enjoy git doing the job for you... – Alois Mahdal May 29 '13 at 17:33
4

The change may not have always been on line 15 of A.cpp, so use the surrounding context. Say it was a definition of const int foobar:

git grep 'const *int *foobar' \
  $(git log --reverse --pretty=format:%H -- A.cpp) -- \
  A.cpp | head -1

This searches forward in time through all commits on the current branch that touch A.cpp and finds the first one that contains the offending pattern. The output will be the commit's SHA-1 and the matching line in its revision of A.cpp.

Once you know the commit, use git show to learn the author.

Greg Bacon
  • 134,834
  • 32
  • 188
  • 245
1

I use QGit for this, select the lines of interest, and filter on that, then you see only the list of change for that line. For a single line it's not to had to jump around a few revisions.

via:

  • open QGit on repository
  • open Tree view
  • find file
  • find line
  • select line of interest
  • press 'filter revision of selected lines' button, looks like a funnel.
Simeon Pilgrim
  • 22,906
  • 3
  • 32
  • 45
1

If the line existed without the const token in some commit that you know, you can start there and use the --reverse flag on git-blame to find the last revision in which the line didn't have the const token. Then just look at the next revision on the file after that.

Amber
  • 507,862
  • 82
  • 626
  • 550