There's a file that contains lots of project configuration, including a line that reads something like:
bundleVersion: 1.2.3
I want to find what was the last git commit in my current git log
history, excluding commits that only touch that particular line.
I want something like git log -1 --format='%H' --invert-grep --grep='^\s*bundleVersion:\s[a-zA-Z0-9.]+$'
, except this command only grep for stuff in the git message, and I want it to grep the contents of the commit, not the message.
There's a file that contains lots of project configuration, including a line that reads something like:
bundleVersion: 1.2.3
I want to find what was the last git commit in my current git log
history, excluding commits that only touch that particular line.
I want something like git log -1 --format='%H' --invert-grep --grep='^\s*bundleVersion:\s[a-zA-Z0-9.]+$'
, except this command only grep for stuff in the git message, and I want it to grep the contents of the commit, not the message.
2 Answers
Reset to default 0I guess you can pull it off with a script using a recursive technique.
One iteration that uses commit X
looks like this:
1 find the position of the line you pointed to there on the file on commit X
(tip: git show X:the-config-file
, and make sure to use the colon, otherwise what you are asking for is very different)
2 blame (-w) the config file for commit X
, just that line, so that the blame process is faster. That will give you the commit where that line was introduced in the config file. That commit is from now onC
.
3 C
== X
? If C
is NOT X
, then X
is the commit you are looking for.
4 If X
changed more than just that line in the config, then X
is the commit you are looking for.
5 we need to iterate so run the same process recursively using C~
(keep the pigtail) as X
.
The whole process starts using HEAD
as X
.
The fact that you are doing this makes me think that lots of the changes that are committed are just adjustments to this line? If that is the case and the process is slow using git because it's hundreds or thousands of commits, perhaps?), consider writing something that uses libgit2 (writing something in python is not that complex and it improves speed like crazy because of not starting a git process for each git operation).
You can use git diff-tree -r --name-only $commit~ $commit
to efficiently check whether the commit changes only the file you're interested in, git diff-tree -r --numstat $commit~ $commit
to check whether that changes only one line, and git log --no-walk -pretty=format:ignore -G 'pattern'
to test whether that one line change matches your pattern. If the file's at the top level you can leave off the -r
flag. So you want something like this (very lightly smoketested) script:
path=your.noisy.config
pattern=bundleversion:
git rev-list @ | while read commit; do
# if it doesn't change only the one annoyingly noisy path, we're there
if test x"$(git diff-tree -r --name-only $commit~ $commit)" != x"$path"
then break
fi
# if it doesn't only change a single line in it, we're there
set -- $(git diff-tree -r --numstat $commit~ $commit)
test $1$2 != 11 && break
# if that change doesn't match the annoying pattern, we're there
res=$(git log --no-walk --pretty=format:ignore -G "$pattern" $commit)
test x$res != xignore && break
done
echo $commit | git log --no-walk --stdin
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1742325629a4422688.html
git log
history (I tweaked the question to reflect that). Like I said, I want something that is like the--invert-grep --grep
I can use ongit log
except that it greps the contents not the messages. – Zorzella Commented Nov 22, 2024 at 19:00