git-date-truncate 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. #!/usr/bin/python3
  2. import argparse
  3. import os
  4. import subprocess
  5. parser = argparse.ArgumentParser(
  6. prog='git date-truncate',
  7. description='Truncate dates in the latest commit and drop timezone data.',
  8. )
  9. parser.add_argument('--tips', action='store_true',
  10. help='show useful tips')
  11. group = parser.add_mutually_exclusive_group()
  12. parser.set_defaults(author=None)
  13. group.add_argument('-a', '--author', dest='author', action='store_true',
  14. help='force truncate author date')
  15. group.add_argument('--no-author', dest='author', action='store_false',
  16. help='never truncate author date')
  17. group = parser.add_mutually_exclusive_group()
  18. parser.set_defaults(committer=None)
  19. group.add_argument('-c', '--committer', dest='committer', action='store_true',
  20. help='force truncate committer date')
  21. group.add_argument('--no-committer', dest='committer', action='store_false',
  22. help='never truncate committer date')
  23. args = parser.parse_args()
  24. old_hash, author_name, author_email, author_date, committer_name, committer_email, committer_date = subprocess.run(
  25. 'git show -s --date=raw --format=%h%n%an%n%ae%n%ad%n%cn%n%ce%n%cd HEAD'.split(),
  26. stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, encoding='utf8', check=True,
  27. ).stdout.splitlines()
  28. if args.author is None or args.committer is None:
  29. user_name = subprocess.run(
  30. 'git config user.name'.split(),
  31. stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, encoding='utf8', check=True,
  32. ).stdout.strip()
  33. user_email = subprocess.run(
  34. 'git config user.email'.split(),
  35. stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, encoding='utf8', check=True,
  36. ).stdout.strip()
  37. if args.author is None:
  38. args.author = author_name == user_name and author_email == user_email
  39. if args.committer is None:
  40. args.committer = committer_name == user_name and committer_email == user_email
  41. author_changed = False
  42. if args.author:
  43. t = int(author_date.split()[0])
  44. t = f'{t // 86400 * 86400} +0000'
  45. author_changed = t != author_date
  46. author_date = t
  47. committer_changed = False
  48. if args.committer:
  49. t = int(committer_date.split()[0])
  50. t = f'{t // 86400 * 86400} +0000'
  51. committer_changed = t != committer_date
  52. committer_date = t
  53. if author_changed or committer_changed:
  54. env = dict(os.environ)
  55. env['GIT_AUTHOR_DATE'] = author_date
  56. env['GIT_COMMITTER_DATE'] = committer_date
  57. subprocess.run(
  58. ['git', 'commit', '-q', '--amend', f'--date={author_date}', '--no-edit', '--only'],
  59. env=env, check=True,
  60. )
  61. new_hash = subprocess.run(
  62. 'git show -s --format=%h HEAD'.split(),
  63. stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, encoding='utf8', check=True,
  64. ).stdout.strip()
  65. s = {
  66. (True, False): 'author date',
  67. (False, True): 'committer date',
  68. (True, True): 'author date and committer date',
  69. }[author_changed, committer_changed]
  70. print(f'date-truncate: {old_hash} -> {new_hash} (truncated {s})')
  71. if args.tips:
  72. print(f' (use "git reset {old_hash}" to undo)')