-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathgit-retimestamp
More file actions
executable file
·162 lines (134 loc) · 5.48 KB
/
git-retimestamp
File metadata and controls
executable file
·162 lines (134 loc) · 5.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#!/usr/bin/env python
################################################################################
#
# Description:
# ------------
# Resets the timestamps of all commits in the currently checked out branch
# to the current time.
#
# The only reason you'd want to do this is to ensure that GitHub displays
# the commits in pull requests in the correct order (i.e. according to the
# parent-child relationship of the commits and not according to the time
# when a commit was originally made). As such, this is only relevant to
# code that is hosted on GitHub. Moreover, this script would become
# obsolete if GitHub one day stops making nonsensical statements about
# git rebases altering the space-time continuum and instead just fixes its
# code. For more information, refer to:
# https://help.github.com/articles/why-are-my-commits-in-the-wrong-order/
#
# Usage:
# ------
# (first place this script in one of the directories in $PATH)
# $> cd path/to/your/repo
# $> git retimestamp
#
################################################################################
import argparse
import git
import sys
################################################################################
#
# Prints an error message and exits with an error status code
#
# Params:
# msg = message to be printed before exiting
#
################################################################################
def die(msg):
print msg
sys.exit(1)
################################################################################
#
# Displays a list of commits that will be re-timestamped, so that the user can
# confirm that the correct commits will be targeted
#
# Params:
# base = the base of the branch
# branch_name = the name of the branch
#
# Returns:
# the number of commits in the branch, relative to the base of the branch
#
################################################################################
def display_commits_list(base, branch_name):
commits_list = git.get_commits_list(base, branch_name)
# Show the user how many (and which) commits will be modified
num_commits = len(commits_list)
if num_commits == 1:
print "The timestamps of the following commit will be reset to the current time:"
else:
print "The timestamps of the following {} commits will be reset to the current time:".format(num_commits)
commit_num = 0
if num_commits > 9:
# Show only the top and bottom 3 commits
for commit in commits_list[0:3]:
commit_num += 1
commit_hash, commit_title = commit.split(' ', 1)
sys.stdout.write(' ' + str(commit_num) + '. (\033[34m' +
commit_hash + '\033[0m) ' + commit_title)
if commit_num == 1:
sys.stdout.write(" \033[32m<-- old HEAD of '" + branch_name +
"'\033[0m\n")
else:
sys.stdout.write('\n')
print " ..."
print " ... << {} more commits >> ...".format(num_commits - 6)
print " ..."
commit_num = num_commits - 3
for commit in commits_list[-3:]:
commit_num += 1
commit_hash, commit_title = commit.split(' ', 1)
sys.stdout.write(' ' + str(commit_num) + '. (\033[34m' +
commit_hash + '\033[0m) ' + commit_title + '\n')
else:
# Show all commits
for commit in commits_list:
commit_num += 1
commit_hash, commit_title = commit.split(' ', 1)
sys.stdout.write(' ' + str(commit_num) + '. (\033[34m' +
commit_hash + '\033[0m) ' + commit_title)
if commit_num == 1:
sys.stdout.write(" \033[32m<-- old HEAD of '" + branch_name +
"'\033[0m\n")
else:
sys.stdout.write('\n')
return num_commits
# Set up command line arguments
parser = argparse.ArgumentParser(usage='%(prog)s [ARGUMENTS]',
description='Set timestamps of all commits in a branch to the current time')
parser.add_argument('-b', '--base', default='upstream/master',
help='branch (or git ref) to use as the base of the branch '
"(defaults to 'upstream/master')")
args = vars(parser.parse_args())
if not git.in_repo():
die("Not a git repository. Aborting")
if not git.is_valid_commit(args['base']):
die("Invalid base '{}'. Aborting.".format(args['base']))
branch_name = git.get_current_branch()
if not branch_name:
die("No branch is currently checked out. Aborting.")
num_commits = display_commits_list(args['base'], branch_name)
# Ask for confirmation
proceed = raw_input("Proceed (y/n)? ")
if proceed != 'y' and proceed != 'Y':
die("Aborting.")
if git.is_gpg_signing_enabled():
author_email = git.get_user_email()
if not author_email:
die("Failed to get the author email address. Aborting.")
gpg_sign_argument = '--gpg-sign=' + author_email
else:
gpg_sign_argument = ''
commits_range_argument = 'HEAD~' + str(num_commits)
# Perform the actual resetting of the timestamps
try:
if gpg_sign_argument:
git.run_command('rebase', '--ignore-date', gpg_sign_argument,
commits_range_argument)
else:
git.run_command('rebase', '--ignore-date', commits_range_argument)
except git.GitException as e:
print "Git command '{}' failed with the following error:".format(e.args[0])
die(e.args[1].rstrip('\n'))
print "Re-timestamp complete."
# vim: set tw=80 :