2

I have a pre-commit hook to run a python script that will modify the staged files and re-add those files with git add . at the end of the script.

The pre-commit look like this:

#!/bin/sh
python2.7 .git/hooks/editfile.py

The python script look like this:

import os
import mmap
import sys
import subprocess

def getmodifiedfiles():
  files = []
  args = ['git', 'diff', 'HEAD', '--name-only', '-r', '--diff-filter=M']
  with open(os.devnull, 'w') as b:
     files = subprocess.check_output(args, stderr=b).splitlines()

  files = [i for i in files if os.path.isfile(i)]
  return files

def updaterevision(line):
    strVer = line.split("$Revision: ")[1].split()[0]
    version = [x for x in strVer.split('.')]
    ver = [int(i) for i in version]

    if ver[1] == 99:
      ver[0] += 1
      ver[1] = 0
    else:
      ver[1] += 1

    strVer = "%d.%02d" % (ver[0], ver[1])
    return str.replace(line, line.split("$Revision: ")[1].split()[0], strVer)

def main(args):
  filelist = getmodifiedfiles()  
  
  for file in filelist :
    lines = open(file).readlines()

    i = 0
    for line in lines:
        if '$Revision:' in line:
          lines[idx] = updaterevision(line)
        
        i += 1

  with open(file, 'w') as r:
    r.writelines(lines)          

  args = ['git', 'add', '.']
  subprocess.call(args)
  
if __name__ == '__main__':
    main(sys.argv)

It works as expected with git commit -m "msg" command, when git status I got the following result:

On branch master
Your branch is ahead of 'origin/master' by 1 commit.

nothing to commit (working directory clean)

But if commit using git commit <filename> or git commit -m "msg" <filename>, I got the following result which I don't want:

On branch master
Changes to be committed:
   (use "git reset HEAD <file>..." to unstage)

   modified:   filename.py

Changes not staged for commit:
   (use "git add <file>..." to update what will be committed)
   (use "git checkout -- <file>..." to discard changes in working directory)

   modified:   filename.py

What are the different? I don't want to fix user to only use the first command to commit. Any ideas?

hexacool
  • 71
  • 1
  • 6

1 Answers1

1

Unfortunately, with your file-rewriting pre-commit hook, the only thing you can do is to stay away from git commit <files...> and only use git-add-then-git-commit.

That said, you're not completely out of hope. Since your hook script is intended for rewriting files (setting "version information"), using filters is a better idea.

Check this answer out: https://stackoverflow.com/a/17360528/5958455

Basically you set your script as a "clean filter" so it gets applied whenever a matching file is staged. This luckily includes your use case of git commit <file...>.

iBug
  • 35,554
  • 7
  • 89
  • 134
  • I tried git config --global filter.updateHeader.clean editfile.py, then I got this error: cannot fork to run external filter 'editfile.py' and external filter 'editfile.py' failed. Where should I place the editfile.py? – hexacool Jan 18 '21 at 08:58
  • @hexacool The path should be relative to the "project root", i.e. where the `.git` directory is. If you're unsure, use absolute path. – iBug Jan 18 '21 at 09:19
  • I placed the script file at the project root it doesn't work. Tried absolute path, it show fatal: cannot exec: /home/username/projectname/editfile.py' :Permission denied when run the script. – hexacool Jan 18 '21 at 13:34
  • @hexacool Apparently you forgot `chmod 755` or similar. – iBug Jan 18 '21 at 13:59