diff --git a/dev/check-files.sh b/dev/check-files.sh
index b442ae45ad40451440a671be11ec26d47cf7ee1f..5bc87e486f9f75c489d21cf75cf8bef12d43bf57 100755
--- a/dev/check-files.sh
+++ b/dev/check-files.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/bash -eu
 ##########################################################################
 #                                                                        #
 #  This file is part of Frama-C.                                         #
@@ -29,7 +29,7 @@ DO_HDRCK="yes"
 REFERENCE=
 MODE="all"
 
-while [ "$1" != "" ]
+while [ $# -gt 0 ]
 do
     case "$1" in
         "-h"|"-help"|"--help")
@@ -37,8 +37,8 @@ do
             echo "OPTIONS"
             echo "  -h|-help|--help    print this message and exit"
             echo "  -f|--fix           fix files"
-            echo "  -c|--commit        check modified files to be commited only"
-            echo "  -p|--push          check modified files to be pushed only"
+            echo "  -c|--commit        check modified files to be committed only"
+            echo "  -p|--push range    check modified files to be pushed only"
             echo "  --no-headers       do not check headers"
             echo "  --no-lint          do not check lint"
             exit 0
@@ -48,10 +48,12 @@ do
             HDRCK=headers
             ;;
         "-p"|"--push")
-            REFERENCE="origin/$(git rev-parse --abbrev-ref HEAD)"
+            shift
+            DIFF_ARG=$1
             MODE="push"
             ;;
         "-c"|"--commit")
+            DIFF_ARG=--cached
             MODE="commit"
             ;;
         "--no-headers")
@@ -70,53 +72,52 @@ done
 
 if [ "$MODE" = "all" ]; then
   if [ $DO_LINT = "yes" ] ; then
-    make $LINT || exit 1
+    make $LINT
   fi
   if [ $DO_HDRCK = "yes" ] ; then
     # Don't define HDRCK_EXTRA, that is required by external plugins
-    make $HDRCK || exit 1
+    make $HDRCK
   fi
 else
-  STAGED=$(git diff --diff-filter ACMR --name-only --cached $REFERENCE | sort)
-  UNSTAGED=$(git diff --diff-filter DMR --name-only | sort)
+  TMP_STAGED=$(mktemp)
+  TMP_UNSTAGED=$(mktemp)
+  TMP_INTER=$(mktemp)
+  TMP_INPUT=$(mktemp)
 
-  if [ "$STAGED" = "" ];
+  cleanup () {
+    rm -f "$TMP_STAGED" "$TMP_UNSTAGED" "$TMP_INPUT" "$TMP_INTER"
+  }
+  trap cleanup exit
+  git diff -z --diff-filter ACMR --name-only $DIFF_ARG | sort -z > "$TMP_STAGED"
+  git diff -z --diff-filter DMR --name-only | sort -z > "$TMP_UNSTAGED"
+
+  if [ ! -s "$TMP_STAGED" ];
   then
     echo "No staged modification since last $MODE, nothing to do."
     exit 0
   fi
 
-  if [ "$UNSTAGED" != "" ];
+  if [ -s "$TMP_UNSTAGED" ];
   then
-    INTER=$(comm -12 <(ls $STAGED) <(ls $UNSTAGED))
-
-    if [ "$INTER" != "" ];
+    comm -12 --zero-terminated "$TMP_STAGED" "$TMP_UNSTAGED" > "$TMP_INTER"
+    if [ -s "$TMP_INTER" ];
     then
       echo "Cannot validate push."
       echo "The following staged files have been modified, renamed or deleted."
-      for file in $INTER ; do
-        echo "- $file"
-      done
+      while IFS= read -r -d $'\0' f; do
+        echo "- $f"
+      done < "$TMP_INTER"
       exit 1
     fi
   fi
 
-  STAGED=$(echo $STAGED | tr '\n' ' ')
-
-  TMP=$(mktemp)
-
-  cleanup () {
-    rm -f "$TMP"
-  }
-  trap cleanup exit
-
-  if [ $DO_LINT = "yes" ] ; then
-    git check-attr -za $STAGED > "$TMP"
-    make $LINT LINTCK_FILES_INPUT="$TMP" || exit 1
+  if [ $DO_LINT = "yes" -a -s "$TMP_STAGED" ] ; then
+    git check-attr -za --stdin < "$TMP_STAGED" > "$TMP_INPUT"
+    make $LINT LINTCK_FILES_INPUT="$TMP_INPUT"
   fi
-  if [ $DO_HDRCK = "yes" ] ; then
-    git check-attr -z header_spec $STAGED > "$TMP"
+  if [ $DO_HDRCK = "yes" -a -s "$TMP_STAGED" ] ; then
+    git check-attr -z header_spec --stdin < "$TMP_STAGED" > "$TMP_INPUT"
     # Don't define HDRCK_EXTRA, that is required by external plugins
-    make $HDRCK HDRCK_FILES_INPUT="$TMP" || exit 1
+    make $HDRCK HDRCK_FILES_INPUT="$TMP_INPUT"
   fi
 fi
diff --git a/dev/git-hooks/pre-commit.sh b/dev/git-hooks/pre-commit.sh
index 9225fe93451377bcf64eb87f0bf8892838f87e71..5333e2b62eb19f3179948abe78c40a01bdc03680 100755
--- a/dev/git-hooks/pre-commit.sh
+++ b/dev/git-hooks/pre-commit.sh
@@ -23,8 +23,8 @@
 
 # Example of installation of this pre-commit hook (client side):
 # - (cd .git/hooks/ && ln -s ../../dev/git-hooks/pre-commit.sh pre-commit)
-# Note: if you decide to copy the file, the `SCRIPT_DIR` variable must be
-# fixed accordingly.
+
+ROOT=$(git rev-parse --show-toplevel)
 
 echo "Pre-commit Hook..."
 
@@ -36,5 +36,4 @@ then
   exit 0
 fi
 
-SCRIPT_DIR=$(dirname -- "$( readlink -f -- "$0"; )")
-"$SCRIPT_DIR/../check-files.sh" -c || exit 1
+"$ROOT/dev/check-files.sh" -c || exit 1
diff --git a/dev/git-hooks/pre-push.sh b/dev/git-hooks/pre-push.sh
index 2859ac02a2486584c83b00d9082d3be760bba57e..7c42e374e1095dd373906ff8bc922872facffb12 100755
--- a/dev/git-hooks/pre-push.sh
+++ b/dev/git-hooks/pre-push.sh
@@ -21,20 +21,30 @@
 #                                                                        #
 ##########################################################################
 
-# Example of installation of this pre-push hook (client side):
-# - (cd .git/hooks/ && ln -s ../../dev/git-hooks/pre-push.sh pre-push)
-# Note: if you decide to copy the file, the `SCRIPT_DIR` variable must be
-# fixed accordingly.
+ROOT=$(git rev-parse --show-toplevel)
 
 echo "Pre-push Hook..."
 
-STAGED=$(git diff --diff-filter ACMR --name-only --cached origin/$(git rev-parse --abbrev-ref HEAD) | sort)
+empty=$(git hash-object --stdin </dev/null | tr '[0-9a-f]' '0')
 
-if [ "$STAGED" = "" ];
-then
-  echo "No diff since last push, nothing to do"
-  exit 0
-fi
+remote=$1
 
-SCRIPT_DIR=$(dirname -- "$( readlink -f -- "$0"; )")
-"$SCRIPT_DIR/../check-files.sh" -p || exit 1
+while read local_ref local_oid remote_ref remote_oid
+do
+    if test "$local_oid" = "$empty"
+    then
+        # Handle delete
+        :
+    else
+        if test "$remote_oid" = "$empty"
+        then
+            # New branch, examine commits starting
+            # the forking point from master
+            remote_oid=$(git merge-base $local_ref master);
+        fi
+        range="$remote_oid $local_oid";
+        "$ROOT/dev/check-files.sh" -p "$range" || exit 1;
+    fi;
+done
+
+exit 0
diff --git a/tests/misc/with-space.i b/tests/misc/with-space.i
index 5a1eddc52babddf2ba7f1b428715ffaf3db82b9b..12017c6154035a1623793b959f44bbc4c231d754 100644
--- a/tests/misc/with-space.i
+++ b/tests/misc/with-space.i
@@ -2,3 +2,4 @@
  LIBS: ../with\ space/module
    OPT:
  */
+