diff --git a/check_source/check_header_duplicate.py b/check_source/check_header_duplicate.py
new file mode 100755
index 0000000000000000000000000000000000000000..d5af3b71e8004d46133c4add0f4687fed9eadfd3
--- /dev/null
+++ b/check_source/check_header_duplicate.py
@@ -0,0 +1,111 @@
+#!/usr/bin/env python3
+
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program 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 2
+# of the License, or (at your option) any later version.
+#
+# This program 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 this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# Contributor(s): Campbell Barton
+#
+# ***** END GPL LICENSE BLOCK *****
+
+# <pep8 compliant>
+
+"""
+Run this script to check if headers are included multiple times.
+
+    python3 check_header_duplicate.py ../../
+
+Now build the code to find duplicate errors, resolve them manually.
+
+Then restore the headers to their original state:
+
+    python3 check_header_duplicate.py --restore ../../
+"""
+
+# Use GCC's __INCLUDE_LEVEL__ to find direct duplicate includes
+
+UUID = 0
+
+
+def source_filepath_guard(filepath):
+    global UUID
+
+    footer = """
+#if __INCLUDE_LEVEL__ == 1
+#  ifdef _DOUBLEHEADERGUARD_%d
+#    error "duplicate header!"
+#  endif
+#endif
+
+#if __INCLUDE_LEVEL__ == 1
+#  define _DOUBLEHEADERGUARD_%d
+#endif
+""" % (UUID, UUID)
+    UUID += 1
+
+    with open(filepath, 'a', encoding='utf-8') as f:
+        f.write(footer)
+
+
+def source_filepath_restore(filepath):
+    import os
+    os.system("git co %s" % filepath)
+
+
+def scan_source_recursive(dirpath, is_restore):
+    import os
+    from os.path import join, splitext
+
+    # ensure git working dir is ok
+    os.chdir(dirpath)
+
+    def source_list(path, filename_check=None):
+        for dirpath, dirnames, filenames in os.walk(path):
+
+            # skip '.svn'
+            if dirpath.startswith("."):
+                continue
+
+            for filename in filenames:
+                filepath = join(dirpath, filename)
+                if filename_check is None or filename_check(filepath):
+                    yield filepath
+
+    def is_source(filename):
+        ext = splitext(filename)[1]
+        return (ext in {".hpp", ".hxx", ".h", ".hh"})
+
+
+    def is_ignore(filename):
+        pass
+
+    for filepath in sorted(source_list(dirpath, is_source)):
+        print("file:", filepath)
+        if is_ignore(filepath):
+            continue
+
+        if is_restore:
+            source_filepath_restore(filepath)
+        else:
+            source_filepath_guard(filepath)
+
+
+def main():
+    import sys
+    is_restore = ("--restore" in sys.argv[1:])
+    scan_source_recursive(sys.argv[-1], is_restore)
+
+if __name__ == "__main__":
+    main()