How to find the last git commit, excluding commits that only touched a particular line of a particular file? - Stack Overflow

There's a file that contains lots of project configuration, including a line that reads something

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.

Share Improve this question edited Nov 22, 2024 at 19:01 Zorzella asked Nov 20, 2024 at 22:02 ZorzellaZorzella 9,0793 gold badges20 silver badges13 bronze badges 2
  • Last commit in a repo is a flaky concept. You mean the last commit that was pushed, for example? That commit might have been made 2 years ago also, we don't know when a commit was pushed (or pulled) into a repo ... Those are two fast and furious buts to the way you are setting up the question.... more can be brought up – eftshift0 Commented Nov 21, 2024 at 0:04
  • Ok, make it last git commit in the current 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 on git log except that it greps the contents not the messages. – Zorzella Commented Nov 22, 2024 at 19:00
Add a comment  | 

2 Answers 2

Reset to default 0

I 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

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信