问题
How would you write a pre-push hook that rejects pushing when the overall diff introduces a specific word/sentence/string?
Motivating use-case:
- committing
TODO
notes (marking tasks to complete before pushing) - letting git prevent me from forgetting to address said notes when pushing
Notes:
- I have seen a lot of different questions and answers but none come close. The ones that try quickly fail on edge cases (e.g. this and this).
- notice that "overall diff" means that commits adding
TODO
would be allowed as long as the string was removed in subsequent commits being pushed (such that the overall delta did not contain it) - the main difficulty is finding a range to pass to
git diff
that works in all cases. - only additions of
TODO
are to be blocked, removals should be allowed in the diff - modifications of lines previously containing
TODO
that maintain it, imply aTODO
addition (even if simultaneous with a removal) and should therefore be blocked (rationale: no objective way to distinguish whether the introducedTODO
is the same as the removed one). - such a hook should cope with all valid pushes, checking only deltas corresponding to ranges of new commits (e.g. nothing to check in
push --delete
). Some particular cases to consider:- new branches
- deleted branches
- renamed branches
- branching off of something other than master (so no
merge-base origin/master
) - splits/merges
- tags
- force pushes
- Bonus variation: prevent pushing any commits adding
TODO
(rather than in the overall diff).
回答1:
Could try something like the following.
#!/usr/bin/env ruby
branchName = `git rev-parse --abbrev-ref HEAD`.strip
log = `git reflog show --no-abbrev #{branchName} --format='\%h'`.split("\n")
range = "#{log.last}..#{log.first}".gsub("'", "")
`git diff --name-only --diff-filter=ACMR #{range}`.each_line do |file|
file = file.chomp
command = "git show #{log.first}:#{file}".gsub("'", "")
content = `#{command}`
if ( content =~ /TODO/ )
puts "'#{file}' contains TODO"
exit 1
end
end
exit 0
This will search the content of any new, added, modified, or renamed files for the word TODO. If it finds the word it will exit and output the name of the file that contains the matching regex.
This will work for new branches, but it does have issues if you rebase your branch as in that case it may pull in other people's changes.
来源:https://stackoverflow.com/questions/54480609/git-pre-push-hook-to-reject-string-addition-in-overall-changes