]> git.phdru.name Git - git-scripts.git/blob - set-commit-date.py
67d2c4f98aa069c786ad857c68c37bf9daa89eda
[git-scripts.git] / set-commit-date.py
1 #! /usr/bin/env python
2
3 # Find commit date/time for every commit, list files in the commit
4 # and set the file's modification time to the date/time of the latest commit.
5
6 # Adapted from https://git.wiki.kernel.org/index.php/ExampleScripts#Setting_the_timestamps_of_the_files_to_the_commit_timestamp_of_the_commit_which_last_touched_them  # noqa
7
8 import argparse
9 import os
10 import sys
11 import subprocess
12
13 git_root = subprocess.check_output(['git', 'rev-parse', '--show-toplevel'],
14                                    universal_newlines=True).rstrip('\n')
15 os.chdir(git_root)
16
17 parser = argparse.ArgumentParser(description='Set commit date')
18 parser.add_argument('-a', '--author', '--author-date',
19                     action='store_true')
20 parser.add_argument('-c', '--committer', '--committer-date',
21                     action='store_true')
22 args = parser.parse_args()
23
24 if args.author and args.committer:
25     parser.print_help()
26     sys.exit("Use only one of `-a' or `-c' but not both")
27
28 if args.author:
29     date_format = 'a'
30 else:
31     date_format = 'c'  # This is the default
32
33 separator = '----- GIT LOG SEPARATOR -----'
34
35 git_log = subprocess.Popen(['git', 'log', '-m', '--first-parent',
36                             '--name-status', '--no-color',
37                             '--pretty=tformat:%s%%n%%%st' % (
38                                 separator, date_format)],
39                            stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
40                            universal_newlines=True)
41 changed_files = set()
42 deleted_files = set()
43
44 # stages: 1 - start of commit, 2 - timestamp, 3 - empty line, 4 - files
45 stage = 1
46 for line in git_log.stdout:
47     line = line.strip()
48     if (stage in (1, 4)) and (line == separator):  # Start of a commit
49         stage = 2
50     elif stage == 2:
51         stage = 3
52         time = int(line)
53     elif stage == 3:
54         if line == separator:  # Null-merge (git merge -s ours), no files
55             stage = 2
56             continue
57         stage = 4
58         assert line == '', line
59     elif stage == 4:
60         if line.startswith('A') or line.startswith('M') \
61                 or line.startswith('D'):
62             filename = line.split(None, 2)[1]
63         elif line.startswith('R'):
64             filename = line.split(None, 3)[2]  # renamed to
65         if line.startswith('D') and filename not in changed_files:
66             # The file was not readded
67             deleted_files.add(filename)
68         if filename not in deleted_files and filename not in changed_files:
69             changed_files.add(filename)
70             if os.path.exists(filename) and not os.path.islink(filename):
71                 os.utime(filename, (time, time))
72     else:
73         raise ValueError("stage: %d, line: %s" % (stage, line))
74
75 git_log.wait()
76 git_log.stdout.close()