diff --git a/core/models/caves.py b/core/models/caves.py
index 03d5208..f0cba32 100644
--- a/core/models/caves.py
+++ b/core/models/caves.py
@@ -24,12 +24,12 @@ from django.shortcuts import render
 
 from troggle.core.models.troggle import TroggleModel, Person, Expedition, DataIssue
 from troggle.core.models.survex import SurvexStation
+from troggle.core.utils import writetrogglefile
 
 '''The model declarations for Areas, Caves and Entrances. Also LogBookENtry, QM, PersonTrip
 '''
 
-todo='''- Move utility function into utils.py
-
+todo='''
 - Find out why we have separate objects CaveSlug and EntranceSlug and why
   these are not just a single field on the Model. Do we ever need more
   than one slug per cave or entrance? Surely that would break everything??
@@ -39,35 +39,6 @@ todo='''- Move utility function into utils.py
 - Restore constraint:   unique_together = (("area", "kataster_number"), ("area", "unofficial_number"))
 '''
 
-def writetrogglefile(filepath, filecontent):
-    '''Set permissions to rw-rw-r-- and commit the new saved file to git
-    Callers to cave.writeDataFile() or entrance.writeDataFile() should handle the exception PermissionsError explicitly
-    '''
-    # GIT see also core/views/expo.py editexpopage()
-    # GIT see also core/views/uploads.py dwgupload()
-    filepath = Path(filepath)
-    cwd = filepath.parent
-    filename = filepath.name
-    git = settings.GIT
-
-    # as the wsgi process www-data, we have group write-access but are not owner, so cannot chmod.
-    # do not trap exceptions, pass them up to the view that called this function
-    print(f'WRITING{cwd}---{filename} ')
-    with open(filepath, "w") as f:
-        f.write(filecontent)
-    #os.chmod(filepath, 0o664) # set file permissions to rw-rw-r--
-    # should replace .call with .run and capture_output=True
-    sp = subprocess.run([git, "add", filename], cwd=cwd, capture_output=True, check=True, text=True)
-    if sp.returncode != 0:
-        print(f'git ADD {cwd}:\n\n' + str(sp.stderr) + '\n\n' + str(sp.stdout)  + '\n\nreturn code: ' + str(sp.returncode))
-
-    sp = subprocess.run([git, "commit", "-m", f'Troggle online: cave or entrance edit -{filename}'], cwd=cwd, capture_output=True, check=True, text=True)
-    if sp.returncode != 0:
-        print(f'git COMMIT {cwd}:\n\n' + str(sp.stderr) + '\n\n' + str(sp.stdout)  + '\n\nreturn code: ' + str(sp.returncode))
-    # not catching and re-raising any exceptions yet, inc. the stderr etc.,. We should do that.
-
-
-
 class Area(TroggleModel):
     short_name = models.CharField(max_length=100)
     name = models.CharField(max_length=200, blank=True, null=True)
diff --git a/core/utils.py b/core/utils.py
index 4d0de2f..269d719 100644
--- a/core/utils.py
+++ b/core/utils.py
@@ -80,6 +80,32 @@ def GetListDir(sdir):
     return res
 
 
+def writetrogglefile(filepath, filecontent):
+    '''Set permissions to rw-rw-r-- and commit the new saved file to git
+    Callers to cave.writeDataFile() or entrance.writeDataFile() should handle the exception PermissionsError explicitly
+    '''
+    # GIT see also core/views/expo.py editexpopage()
+    # GIT see also core/views/uploads.py dwgupload()
+    filepath = Path(filepath)
+    cwd = filepath.parent
+    filename = filepath.name
+    git = settings.GIT
+
+    # as the wsgi process www-data, we have group write-access but are not owner, so cannot chmod.
+    # do not trap exceptions, pass them up to the view that called this function
+    print(f'WRITING{cwd}---{filename} ')
+    with open(filepath, "w") as f:
+        f.write(filecontent)
+    #os.chmod(filepath, 0o664) # set file permissions to rw-rw-r--
+    sp = subprocess.run([git, "add", filename], cwd=cwd, capture_output=True, check=True, text=True)
+    if sp.returncode != 0:
+        print(f'git ADD {cwd}:\n\n' + str(sp.stderr) + '\n\n' + str(sp.stdout)  + '\n\nreturn code: ' + str(sp.returncode))
+
+    sp = subprocess.run([git, "commit", "-m", f'Troggle online: cave or entrance edit -{filename}'], cwd=cwd, capture_output=True, check=True, text=True)
+    if sp.returncode != 0:
+        print(f'git COMMIT {cwd}:\n\n' + str(sp.stderr) + '\n\n' + str(sp.stdout)  + '\n\nreturn code: ' + str(sp.returncode))
+    # not catching and re-raising any exceptions yet, inc. the stderr etc.,. We should do that.
+
 
 def save_carefully(objectType, lookupAttribs={}, nonLookupAttribs={}):
     """Looks up instance using lookupAttribs and carries out the following: