branch: externals/org
commit 7410e86c6e8fd20013d80cb4d094de6c012d4e2e
Author: Derek Chen-Becker <[email protected]>
Commit: Ihor Radchenko <[email protected]>
git-hooks: Add git hook scripts along with instructions for use
* git-hooks/commit-msg: Add commit-msg hook script. Add a check for two
spaces between sentences. Update the abort message to reference
`CONTRIBUTE.org' instead of `CONTRIBUTE'.
* git-hooks/commit-msg-files.awk: Add commit-msg-files.awk hook script.
Update the abort message to reference `CONTRIBUTE.org' instead of
`CONTRIBUTE'.
* git-hooks/post-commit: Add post-commit hook script.
* git-hooks/pre-push: Add pre-push hook script.
* git-hooks/prepare-commit-msg: Add prepare-commit-msg hook script. Update
the abort message to reference `CONTRIBUTE.org' instead of `CONTRIBUTE'.
* mk/targets.mk: Add a `git' and `cleangit' target to install and remove
the new git hook scripts, respectively. Also add `git' as a dependency for
`all' and `cleangit' as a dependency for `cleanall'.
* CONTRIBUTE.org: Add instructions for utilizing the git hook scripts.
---
CONTRIBUTE.org | 5 ++
git-hooks/commit-msg | 192 +++++++++++++++++++++++++++++++++++++++++
git-hooks/commit-msg-files.awk | 128 +++++++++++++++++++++++++++
git-hooks/post-commit | 47 ++++++++++
git-hooks/pre-commit | 83 ++++++++++++++++++
git-hooks/pre-push | 88 +++++++++++++++++++
git-hooks/prepare-commit-msg | 49 +++++++++++
mk/targets.mk | 14 ++-
8 files changed, 605 insertions(+), 1 deletion(-)
diff --git a/CONTRIBUTE.org b/CONTRIBUTE.org
index 8f94e875bb..93afb08ef0 100644
--- a/CONTRIBUTE.org
+++ b/CONTRIBUTE.org
@@ -16,6 +16,11 @@ You can contribute with bug reports and patches.
See these
[[https://orgmode.org/worg/org-contribute.html#org069b83a][directions]].
+** Git Hooks
+
+We provide several git hook scripts to facilitate validation of commit
+messages and structure. See
[[https://orgmode.org/worg/org-contribute.html#git-hooks][these directions]]
for how to set them up.
+
* As an Org maintainer
We encourage you to volunteer to maintain one of the Org files.
diff --git a/git-hooks/commit-msg b/git-hooks/commit-msg
new file mode 100755
index 0000000000..bff210f14f
--- /dev/null
+++ b/git-hooks/commit-msg
@@ -0,0 +1,192 @@
+#!/bin/sh
+# Check the format of Org mode change log entries.
+
+# Copyright 2014-2025 Free Software Foundation, Inc.
+
+# This file is part of Org mode.
+
+# Org mode is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# Org mode is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with Org mode. If not, see <https://www.gnu.org/licenses/>.
+
+# Written by Paul Eggert.
+
+# Prefer gawk if available, as it handles NUL bytes properly.
+if type gawk >/dev/null 2>&1; then
+ awk=gawk
+else
+ awk=awk
+fi
+
+# Use a UTF-8 locale if available, so that the UTF-8 check works.
+# Use U+00A2 CENT SIGN to test whether the locale works.
+cent_sign_utf8_format='\302\242\n'
+cent_sign=`printf "$cent_sign_utf8_format"`
+replacement_character_utf8_format='\357\277\275\n'
+replacement_character=`printf "$replacement_character_utf8_format"`
+print_at_sign='BEGIN {print substr("'$cent_sign'@", 2)}'
+at_sign=`$awk "$print_at_sign" </dev/null 2>/dev/null`
+if test "$at_sign" != @; then
+ at_sign=`LC_ALL=en_US.UTF-8 $awk "$print_at_sign" </dev/null 2>/dev/null`
+ if test "$at_sign" = @; then
+ LC_ALL=en_US.UTF-8
+ else
+ LC_ALL=C
+ fi
+ export LC_ALL
+fi
+
+# Check the log entry.
+exec $awk \
+ -v at_sign="$at_sign" \
+ -v cent_sign="$cent_sign" \
+ -v file="$1" \
+ -v replacement_character="$replacement_character" \
+'
+ BEGIN {
+ # These regular expressions assume traditional Unix unibyte behavior.
+ # They are needed for old or broken versions of awk, e.g.,
+ # mawk 1.3.3 (1996), or gawk on MSYS (2015), and/or for systems that
+ # cannot use UTF-8 as the codeset for the locale.
+ space = "[ \f\n\r\t\v]"
+ non_space = "[^ \f\n\r\t\v]"
+
+ # The non_print below rejects control characters and surrogates
+ # UTF-8 for: 0x01-0x1f 0x7f 0x80-0x9f 0xd800-0xdbff 0xdc00-0xdfff
+ non_print = "[\1-\37\177]|\302[\200-\237]|\355[\240-\277][\200-\277]"
+
+ # Match HTTP URLs so that we can ignore line length with long URLs
+ http_url = "http[s]?:"
+
+ # Prefer POSIX regular expressions if available, as they do a
+ # better job of checking. Similarly, prefer POSIX negated
+ # expressions if UTF-8 also works.
+ if (" " ~ /[[:space:]]/) {
+ space = "[[:space:]]"
+ if (at_sign == "@" && cent_sign ~ /^[[:print:]]$/) {
+ non_space = "[^[:space:]]"
+ non_print = "[^[:print:]]"
+ }
+ }
+ c_lower = "abcdefghijklmnopqrstuvwxyz"
+ unsafe_gnu_url = "(http|ftp)://([" c_lower ".]*\\.)?(gnu|fsf)\\.org"
+ }
+
+ { input[NR] = $0 }
+
+ /^#/ {
+ # Ignore every line after a scissors line.
+ if (/^# *---* *(>[8%]|[8%]<) *---* *$/) { exit }
+
+ # Ignore comment lines.
+ next
+ }
+
+ !/^.*$/ {
+ print "Invalid character (not UTF-8) in commit message"
+ status = 1
+ }
+
+ /(^|[^\\])`[^'\''`]+`/ {
+ print "Markdown-style quotes in commit message"
+ status = 1
+ }
+
+ /\. [[:alnum:]]/ {
+ print "Two spaces required between sentences."
+ status = 1
+ }
+
+ nlines == 0 && $0 !~ non_space { next }
+
+ { nlines++ }
+
+ nlines == 1 {
+ # Ignore special markers used by "git rebase --autosquash".
+ if (! sub(/^fixup! /, ""))
+ sub(/^squash! /, "")
+
+ if ($0 ~ "^" space) {
+ print "White space at start of commit message'\''s first line"
+ status = 1
+ }
+ }
+
+ nlines == 2 && $0 ~ non_space {
+ print "Nonempty second line in commit message"
+ status = 1
+ }
+
+ {
+ # Expand tabs to spaces for length calculations etc.
+ while (match($0, /\t/)) {
+ before_tab = substr($0, 1, RSTART - 1)
+ after_tab = substr($0, RSTART + 1)
+ $0 = sprintf("%s%*s%s", before_tab, 8 - (RSTART - 1) % 8, "", after_tab)
+ }
+ }
+
+ # Enforce line length unless the line contains a URL
+ $0 !~ http_url {
+ if (78 < length && $0 ~ space) {
+ print "Line longer than 78 characters in commit message"
+ status = 1
+ } else if (140 < length) {
+ print "Word longer than 140 characters in commit message"
+ status = 1
+ }
+ }
+
+ /^Signed-off-by: / {
+ print "'\''Signed-off-by:'\'' in commit message"
+ status = 1
+ }
+
+ $0 ~ unsafe_gnu_url {
+ needs_rewriting = 1
+ }
+
+ $0 ~ non_print {
+ print "Unprintable character in commit message"
+ status = 1
+ }
+ $0 ~ replacement_character {
+ print "Replacement character in commit message"
+ status = 1
+ }
+
+ END {
+ if (nlines == 0) {
+ print "Empty commit message"
+ status = 1
+ }
+ if (status == 0 && needs_rewriting) {
+ for (i = 1; i <= NR; i++) {
+ line = input[i]
+ while (match(line, unsafe_gnu_url)) {
+ prefix = substr(line, 1, RSTART - 1)
+ suffix = substr(line, RSTART)
+ line = prefix "https:" substr(suffix, 5 + (suffix ~ /^http:/))
+ }
+ print line >file
+ }
+ if (close(file) != 0) {
+ print "Cannot rewrite: " file
+ status = 1
+ }
+ }
+ if (status != 0) {
+ print "Commit aborted; please see the file 'CONTRIBUTE.org'"
+ }
+ exit status
+ }
+' <"$1"
diff --git a/git-hooks/commit-msg-files.awk b/git-hooks/commit-msg-files.awk
new file mode 100644
index 0000000000..d6aec09cf2
--- /dev/null
+++ b/git-hooks/commit-msg-files.awk
@@ -0,0 +1,128 @@
+# Check the file list of Org mode change log entries for each commit SHA.
+
+# Copyright 2023-2025 Free Software Foundation, Inc.
+
+# This file is part of Org mode.
+
+# Org mode is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# Org mode is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with Org mode. If not, see <https://www.gnu.org/licenses/>.
+
+### Commentary:
+
+# This script accepts a list of (unabbreviated) Git commit SHAs, and
+# will then iterate over them to check that any files mentioned in the
+# commit message are actually present in the commit's diff. If not,
+# it will print out the incorrect file names and return 1.
+
+# You can also pass "-v reason=pre-push", which will add more-verbose
+# output, indicating the abbreviated commit SHA and first line of the
+# commit message for any improper commits.
+
+### Code:
+
+function get_commit_changes(commit_sha, changes, cmd, i, j, len, \
+ bits, filename) {
+ # Collect all the files touched in the specified commit.
+ cmd = ("git show --name-status --first-parent --format= " commit_sha)
+ while ((cmd | getline) > 0) {
+ for (i = 2; i <= NF; i++) {
+ len = split($i, bits, "/")
+ for (j = 1; j <= len; j++) {
+ if (j == 1)
+ filename = bits[j]
+ else
+ filename = filename "/" bits[j]
+ changes[filename] = 1
+ }
+ }
+ }
+ close(cmd)
+}
+
+function check_commit_msg_files(commit_sha, verbose, changes, good, \
+ cmd, msg, filenames_str, filenames, i) {
+ get_commit_changes(commit_sha, changes)
+ good = 1
+
+ cmd = ("git log -1 --format=%B " commit_sha)
+ while ((cmd | getline) > 0) {
+ if (verbose && ! msg)
+ msg = $0
+
+ # Find file entries in the commit message. We look at any line
+ # starting with "*" (possibly prefixed by "; ") followed by a ":",
+ # possibly on a different line. If we encounter a blank line
+ # without seeing a ":", then we don't treat that as a file entry.
+
+ # Accumulate the contents of a (possible) file entry.
+ if (/^[ \t]*$/)
+ filenames_str = ""
+ else if (/^(; )?\*[ \t]+[[:alnum:]]/)
+ filenames_str = $0
+ else if (filenames_str)
+ filenames_str = (filenames_str $0)
+
+ # We have a file entry; analyze it.
+ if (filenames_str && /:/) {
+ # Delete the leading "*" and any trailing information.
+ sub(/^(; )?\*[ \t]+/, "", filenames_str)
+ sub(/[ \t]*[[(<:].*$/, "", filenames_str)
+
+ # There might be multiple files listed in this entry, separated
+ # by spaces (and possibly a comma). Iterate over each of them.
+ split(filenames_str, filenames, ",[ \t]+")
+ for (i in filenames) {
+ # Remove trailing slashes from any directory entries.
+ sub(/\/$/, "", filenames[i])
+
+ if (length(filenames[i]) && ! (filenames[i] in changes)) {
+ if (good) {
+ # Print a header describing the error.
+ if (verbose)
+ printf("In commit %s \"%s\"...\n", substr(commit_sha, 1, 10),
msg)
+ printf("Files listed in commit message, but not in diff:\n")
+ }
+ printf(" %s\n", filenames[i])
+ good = 0
+ }
+ }
+
+ filenames_str = ""
+ }
+ }
+ close(cmd)
+
+ return good
+}
+
+BEGIN {
+ if (reason == "pre-push")
+ verbose = 1
+}
+
+/^[a-z0-9]{40}$/ {
+ if (! check_commit_msg_files($0, verbose)) {
+ status = 1
+ }
+}
+
+END {
+ if (status != 0) {
+ if (reason == "pre-push")
+ error_msg = "Push aborted"
+ else
+ error_msg = "Bad commit message"
+ printf("%s; please see the file 'CONTRIBUTE.org'\n", error_msg)
+ }
+ exit status
+}
diff --git a/git-hooks/post-commit b/git-hooks/post-commit
new file mode 100755
index 0000000000..0531eefdd7
--- /dev/null
+++ b/git-hooks/post-commit
@@ -0,0 +1,47 @@
+#!/bin/sh
+# Check the file list of Org mode change log entries after committing.
+
+# Copyright 2023-2025 Free Software Foundation, Inc.
+
+# This file is part of Org mode.
+
+# Org mode is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# Org mode is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with Org mode. If not, see <https://www.gnu.org/licenses/>.
+
+### Commentary:
+
+# This hook runs after a commit is finalized and checks that the files
+# mentioned in the commit message match the diff. We perform this in
+# the post-commit phase so that we can be sure we properly detect all
+# the files in the diff (this is difficult during the commit-msg hook,
+# since there's no cross-platform way to detect when a commit is being
+# amended).
+
+# However, since this is a post-commit hook, it's too late to error
+# out and abort the commit: it's already done! As a result, this hook
+# is purely advisory, and instead we error out when trying to push
+# (see "pre-push" in this directory).
+
+### Code:
+
+HOOKS_DIR=`dirname "$0"`
+
+# Prefer gawk if available, as it handles NUL bytes properly.
+if type gawk >/dev/null 2>&1; then
+ awk="gawk"
+else
+ awk="awk"
+fi
+
+git rev-parse HEAD | $awk -v reason=post-commit \
+ -f "$HOOKS_DIR"/commit-msg-files.awk
diff --git a/git-hooks/pre-commit b/git-hooks/pre-commit
new file mode 100755
index 0000000000..b17e9bd31a
--- /dev/null
+++ b/git-hooks/pre-commit
@@ -0,0 +1,83 @@
+#!/bin/sh
+# Check file names in git commits for Org mode.
+
+# Copyright 2014-2025 Free Software Foundation, Inc.
+
+# This file is part of Org mode.
+
+# Org mode is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# Org mode is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with Org mode. If not, see <https://www.gnu.org/licenses/>.
+
+LC_ALL=C
+export LC_ALL
+
+# If this is a system where /bin/sh isn't sufficient to
+# run git-sh-setup, use a working shell as a recourse.
+if test -x "/usr/xpg4/bin/sh" && test -z "$POSIX_SHELL"; then
+ POSIX_SHELL=1
+ export POSIX_SHELL
+ exec "/usr/xpg4/bin/sh" `dirname $0`/pre-commit
+fi
+
+exec >&2
+
+. git-sh-setup
+
+# When doing a two-way merge, ignore problems that came from the other
+# side of the merge.
+head=HEAD
+if test -r "$GIT_DIR"/MERGE_HEAD && test "$GIT_MERGE_CHECK_OTHER" != true; then
+ merge_heads=`cat "$GIT_DIR"/MERGE_HEAD` || exit
+ for merge_head in $merge_heads; do
+ case $head in
+ HEAD) head=$merge_head;;
+ # For multi-head merges, there's no easy way to ignore merged-in
+ # changes. But if you're doing multi-head merges, presumably
+ # you know how to handle any ensuing problems.
+ *) head=HEAD; break;;
+ esac
+ done
+fi
+
+git_diff='git diff --cached --name-only --diff-filter=A'
+
+# 'git diff' will backslash escape tabs and newlines, so we don't have
+# to worry about word splitting here.
+$git_diff $head |
+LC_ALL=C grep -E 'ChangeLog|^-|/-|[^-+./_0-9A-Z_a-z]' |
+while IFS= read -r new_name; do
+ case $new_name in
+ -* | */-*)
+ echo "$new_name: File name component begins with '-'."
+ exit 1;;
+ ChangeLog.android)
+ # This file is explicitly ok.
+ ;;
+ ChangeLog | */ChangeLog)
+ echo "$new_name: Please use git commit messages, not ChangeLog files."
+ exit 1;;
+ *)
+ echo "$new_name: File name does not consist of -+./_ or ASCII letters or
digits."
+ exit 1;;
+ esac
+done
+
+# The '--check' option of git diff-index makes Git complain if changes
+# introduce whitespace errors. This can be a pain when editing test
+# files that deliberately contain lines with trailing whitespace.
+# To work around the problem you can run a command like 'git config
+# core.whitespace -trailing-space'. It may be better to revamp the
+# tests so that trailing spaces are generated on the fly rather than
+# being committed as source.
+
+exec git diff-index --check --cached $head --
diff --git a/git-hooks/pre-push b/git-hooks/pre-push
new file mode 100755
index 0000000000..6a46f3d719
--- /dev/null
+++ b/git-hooks/pre-push
@@ -0,0 +1,88 @@
+#!/bin/sh
+# Check the file list of Org mode change log entries before pushing.
+
+# Copyright 2023-2025 Free Software Foundation, Inc.
+
+# This file is part of Org mode.
+
+# Org mode is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# Org mode is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with Org mode. If not, see <https://www.gnu.org/licenses/>.
+
+### Commentary:
+
+# This hook runs before pushing a series of commits and checks that
+# the files mentioned in each commit message match the diffs. This
+# helps ensure that the resulting change logs are correct, which
+# should prevent errors when generating etc/AUTHORS.
+
+# These checks also happen in the "post-commit" hook (which see), but
+# that hook can't abort a commit; it just advises the committer to fix
+# the commit so that this hook runs without errors.
+
+### Code:
+
+HOOKS_DIR=`dirname "$0"`
+
+# Prefer gawk if available, as it handles NUL bytes properly.
+if type gawk >/dev/null 2>&1; then
+ awk="gawk"
+else
+ awk="awk"
+fi
+
+# Standard input receives lines of the form:
+# <local ref> SP <local sha> SP <remote ref> SP <remote sha> LF
+$awk -v origin_name="$1" '
+ # If the local SHA is all zeroes, ignore it.
+ $2 ~ /^0{40}$/ {
+ next
+ }
+
+ # Check any lines with a valid local SHA and whose remote ref is
+ # main or a release branch. (We want to avoid checking
+ # feature or scratch branches here.)
+ $2 ~ /^[a-z0-9]{40}$/ && $3 ~ /^refs\/heads\/(main|release_[0-9.]+)$/ {
+ newref = $2
+ # If the remote SHA is all zeroes, this is a new object to be
+ # pushed (likely a branch)...
+ if ($4 ~ /^0{40}$/) {
+ back = 0
+ # ... Go backwards until we find a SHA on an origin branch.
+ # Stop trying after 1000 commits, just in case...
+ for (back = 0; back < 1000; back++) {
+ cmd = ("git branch -r -l '\''" origin_name "/*'\''" \
+ " --contains " newref "~" back)
+ rv = (cmd | getline)
+ close(cmd)
+ if (rv > 0)
+ break;
+ }
+
+ cmd = ("git rev-parse " newref "~" back)
+ cmd | getline oldref
+ if (!(oldref ~ /^[a-z0-9]{40}$/)) {
+ # The SHA is misformatted! Skip this line.
+ next
+ }
+ close(cmd)
+ } else if ($4 ~ /^[a-z0-9]{40}$/) {
+ oldref = $4
+ } else {
+ # The SHA is misformatted! Skip this line.
+ next
+ }
+
+ # Print every SHA after oldref, up to (and including) newref.
+ system("git rev-list --first-parent --reverse " oldref ".." newref)
+ }
+' | $awk -v reason=pre-push -f "$HOOKS_DIR"/commit-msg-files.awk
diff --git a/git-hooks/prepare-commit-msg b/git-hooks/prepare-commit-msg
new file mode 100755
index 0000000000..4caf6f50f0
--- /dev/null
+++ b/git-hooks/prepare-commit-msg
@@ -0,0 +1,49 @@
+#!/bin/sh
+# Check the format of Org mode change log entries.
+
+# Copyright 2019-2025 Free Software Foundation, Inc.
+
+# This file is part of Org mode.
+
+# Org mode is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# Org mode is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with Org mode. If not, see <https://www.gnu.org/licenses/>.
+
+COMMIT_MSG_FILE=$1
+COMMIT_SOURCE=$2
+SHA1=$3
+
+# Prefer gawk if available, as it handles NUL bytes properly.
+if type gawk >/dev/null 2>&1; then
+ awk="gawk"
+# Next use /usr/xpg4/bin/awk if available, since the script
+# doesn't support Unix awk.
+elif test -x /usr/xpg4/bin/awk; then
+ awk="/usr/xpg4/bin/awk"
+else
+ awk="awk"
+fi
+
+exec $awk "
+ # Catch the case when someone ran git-commit with -s option,
+ # which automatically adds Signed-off-by.
+ /^Signed-off-by: / {
+ print \"'Signed-off-by:' in commit message\"
+ status = 1
+ }
+ END {
+ if (status != 0) {
+ print \"Commit aborted; please see the file 'CONTRIBUTE.org'\"
+ }
+ exit status
+ }
+" <"$COMMIT_MSG_FILE"
diff --git a/mk/targets.mk b/mk/targets.mk
index 20f2ae504d..cedde05229 100644
--- a/mk/targets.mk
+++ b/mk/targets.mk
@@ -9,6 +9,9 @@ SUBDIRS = $(OTHERDIRS) $(LISPDIRS)
INSTSUB = $(SUBDIRS:%=install-%)
ORG_MAKE_DOC ?= info html pdf
+GITDIR = .git/hooks
+GITHOOKS = commit-msg commit-msg-files.awk post-commit pre-commit
prepare-commit-msg pre-push
+
ifneq ($(wildcard .git),)
# Use the org.el header.
ORGVERSION := $(patsubst %-dev,%,$(shell $(BATCH) --eval "(require
'lisp-mnt)" \
@@ -130,12 +133,21 @@ autoloads: lisp
repro: cleanall autoloads
-@$(REPRO) &
+# Implicit rule to copy Git hooks in
+$(GITDIR)/%: git-hooks/%
+ cp -f $< $@
+
+githooks: $(addprefix $(GITDIR)/,$(GITHOOKS))
+
+cleangithooks:
+ $(RM) $(addprefix $(GITDIR)/,$(GITHOOKS))
+
cleandirs:
$(foreach dir, $(SUBDIRS), $(MAKE) -C $(dir) cleanall;)
clean: cleanlisp cleandoc
-cleanall: cleandirs cleantest
+cleanall: cleandirs cleantest cleangithooks
-$(FIND) . \( -name \*~ -o -name \*# -o -name .#\* \) -exec $(RM) {} +
-$(FIND) $(CLEANDIRS) \( -name \*~ -o -name \*.elc \) -exec $(RM) {} +