Who deleted my change in git?
Here was my problem for the last 30 minutes: I had a couple of changes that disappeared in one of my files, and I don't know when that happened. And I want to know who did that!
I started looking for the revisions having my files:
git grep <searched_string> $(git rev-list --al开发者_如何学Cl) -- <file>
is the path to the file or a wildcard like *.gsp
I got a bunch of revisions, I look at the last one, and try to get it's children (thinking the first child should be the first revision where my changes disappeared)
git rev-list --children <revision_id>
is the 40 chars from the beginning of the last line of the previous command
Getting close! I am looking at the beginning of the output, and take the first child and then run
git log <revision_id_s_first_child> --stat
Then I look at the output and find my file and who did the change! (it turned out, I was to blame...)
Is there anyway to do that faster (git blame would not show what has been deleted) ?
git blame
has a --reverse
option that takes a range of commits and shows you the last commit where a line existed before it was deleted. So, you find a commit you know the lines were there, let's say abcdef01
for example, and to show the last commit before the delete, do:
git blame --reverse abcdef01..HEAD -- <file>
If you know some substring that would be in the line that was removed, then you can use the -G
option to git log
to find commits that introduced a change that added or removed lines containing that substring. e.g. if you knew that the word "pandemic" was in the line that disappeared, you can do:
git log -Gpandemic -p
(The parameter to -G
can be a regular expression.) This option was added rather recently to git - if it doesn't work, try -S
instead, which has slightly different semantics, but should have a similar effect.
Note that since Git 2.11 (Q4 2016), you won't have to specify ..HEAD
if you want to look at commits between a specific one and the current one.
So Karl Bielefeldt's answer would then be:
git blame --reverse abcdef01 -- <file>
See commit d993ce1 (14 Jun 2016) by Junio C Hamano (gitster
).
(Merged by Junio C Hamano -- gitster
-- in commit 1172e16, 10 Oct 2016)
blame: dwim "
blame --reverse OLD
" as "blame --reverse OLD..
"It is a common mistake to say "
git blame --reverse OLD path
", expecting that the command line is dwimmed as if asking how lines in path in an old revision OLD have survived up to the current commit.Instead of always requiring both ends of a range, we could DWIM "
OLD
", which could be a misspelt "OLD..
", to be a range that ends at the current commit.
git blame --reverse
now include:
--reverse <rev>..<rev>:
Walk history forward instead of backward.
Instead of showing the revision in which a line appeared, this shows the last revision in which a line has existed.
This requires a range of revision likeSTART..END
where the path to blame exists inSTART
.
git blame --reverse START
is taken asgit blame --reverse START..HEAD
for convenience.
(Note of the note: "dwim" is an acronym for "Do What I Mean" (not what I say))
git blame --reverse can get you close to where the line is deleted. But it actually doesn't point to the revision where the line is deleted. It points to the last revision where the line was present. Then if the following revision is a plain commit, you are lucky and you got the deleting revision. OTOH, if the following revision is a merge commit, then things can get a little wild. As part of the effort to create difflame I tackled this very problem so if you already have python installed on your box and you are willing to give it a try, then don't wait any longer and let me know how it goes.
https://github.com/eantoranz/difflame
精彩评论