*** DONE git: post-commit hook for determining large number of deleted lines in Org-mode :blog:emacs:pim:diy:software: CLOSED: [2014-08-20 Wed 18:34] :PROPERTIES: :CREATED: [2014-08-20 Wed 18:24] :ID: 2014-08-20-org-losses-determining-post-commit :END: :LOGBOOK: - State "DONE" from "DONE" [2023-09-02 Sat 09:20] - State "DONE" from "DONE" [2020-01-01 Wed 22:41] - State "DONE" from "NEXT" [2014-08-20 Wed 18:34] :END: - Updates - 2020-01-01: Modified version using =appendorgheading= - 2023-09-02: Updated link to gitwatch repository Maybe you have faced the very same issue: when large [[http://orgmode.org][Org mode]] hierarchies are folded, it might happen that you overwrite or delete large parts of your Org mode file without noticing. This is not a big deal if you happen to have your Org mode files within a [[http://git-scm.com/][git]] repository. All changes to my Org mode files even get committed automatically using [[https://github.com/gitwatch/gitwatch][gitwatch]]. Everything that happened to your Org mode files can be revoked. However, you have to *recognize* the deleted lines in order to be able to restore them. And this is where this small trick can help you: using the [[http://git-scm.com/book/en/Customizing-Git-Git-Hooks][post-commit hook]] below, you get a warning on your daily agenda when you check in a commit that deleted more than a given number of lines. **** Implementation In order to make it work, you have to adopt the script below. Please change the content of ~OUTFILE~ to a file which is part of your ~org-agenda-files~. Any warning message generated by the script gets appended to it. With a recurring time-stamp (of the commit), you can not miss the message: it is placed on your daily agenda. You might also want to adopt the value of ~THRESHOLD~. Its value represents the number of lines that might get deleted within a single file without any warning. #+BEGIN_EXAMPLE #!/bin/sh # # An example hook script that is called after a successful # commit is made. # # To enable this hook, rename this file to "post-commit". ## current/last commit: CURRENT_HASH=`git rev-parse HEAD` ## the commit before: PREVIOUS_HASH=`git rev-parse HEAD^1` ## the file where the message(s) are being written to: OUTFILE="${HOME}/org/errors_orgmode_commits.org" ## number of lines that are OK to be deleted in one single file: THRESHOLD=250 MESSAGE="** commit ${CURRENT_HASH} deleted more than ${THRESHOLD} lines in a file!" DETAILS="#+BEGIN_SRC sh :results output cd ${HOME}/org echo \"commit ${CURRENT_HASH}\" git diff --stat \"${PREVIOUS_HASH}\" \"${CURRENT_HASH}\" #+END_SRC" ## manual test with: ## git diff --stat `git rev-parse HEAD^1` `git rev-parse HEAD` git diff --numstat "${PREVIOUS_HASH}" "${CURRENT_HASH}" | \ cut -f 2 | \ while read line do test "$line" -gt "${THRESHOLD}" && \ echo "${MESSAGE}\n<`date '+%Y-%m-%d %H:%M'` +1d>\n\n${DETAILS}\n" >> \ "${OUTFILE}"; \ done #end #+END_EXAMPLE So when you recognize a warning on your agenda, click on it and optionally do a ~C-c C-c~ on the babel snippet which is below the heading. It gives your details on the commit. After you have resolved the issue, just delete the heading of the resolved error in the error Org mode file manually. **** Implementation Using =appendorgheading= Using the method described [[id:2019-12-31-appendorgheading][in this article]], the post-commit hook looks like this: : #!/bin/sh : # : # An example hook script that is called after a successful : # commit is made. : # : # To enable this hook, rename this file to "post-commit". : : ## current/last commit: : CURRENT_HASH=$(git rev-parse HEAD) : : ## the commit before: : PREVIOUS_HASH=$(git rev-parse HEAD^1) : : ## number of lines that are OK to be deleted in one single file: : THRESHOLD=200 : : TMPFILE="$(mktemp)" : : TITLE="commit ${CURRENT_HASH} deleted more than ${THRESHOLD} lines in a file!" : echo "#+BEGIN_SRC sh : gitk ${CURRENT_HASH} : #+END_SRC : : #+BEGIN_EXAMPLE : `cd ${HOME}/org ; git diff --stat \"${PREVIOUS_HASH}\" \"${CURRENT_HASH}\"` : #+END_EXAMPLE" > "${TMPFILE}" : : ## manual test with: : ## git diff --stat `git rev-parse HEAD^1` `git rev-parse HEAD` : : git diff --numstat "${PREVIOUS_HASH}" "${CURRENT_HASH}" | \ : cut -f 2 | \ : while read line : do test "$line" -gt "${THRESHOLD}" && \ : /usr/local/bin/appendorgheading --title "${TITLE}" --filecontent "${TMPFILE}" : done : : rm "${TMPFILE}" : #end