git-race 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/git-race +34 -20
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 63128ac4bb7efb21c0fbcd9034f613f2525d44e7
|
4
|
+
data.tar.gz: 0a61048d6bccf5e6bd7ec43adf6678f52be12f05
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0a2dff5a49e97485b87d01b30836422bb7acea481156c848b7e1cad6ea978180d1a1dc23218450961c8ba4a9b016847e9ea2cd8c5b592b85ce76a773e158a0d1
|
7
|
+
data.tar.gz: c27e2ae5d187266f5f5c02897c343d5a8cf7e84db42e5fbbb9bceec7c4e5542be675809861629bae77a0a0f23d2de25b9b8edd226a4ca13b3bdf2b1539b9a95f
|
data/bin/git-race
CHANGED
@@ -1,30 +1,44 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
+
require 'date'
|
4
|
+
|
3
5
|
def query(cmd)
|
4
6
|
`#{cmd}`.chomp
|
5
7
|
end
|
6
8
|
|
7
9
|
def command(cmd)
|
8
|
-
#
|
10
|
+
# quietly executes, but does tell you the exit status
|
9
11
|
system("#{cmd} > /dev/null 2>&1")
|
10
12
|
end
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
+
Merge = Struct.new(:branch, :days_till_stale) do
|
15
|
+
def conflict?
|
16
|
+
diff.size > 0
|
17
|
+
end
|
14
18
|
|
15
|
-
def
|
16
|
-
|
17
|
-
@diff = conflicts_from(branch)
|
18
|
-
@author = query("git log -n1 --format='%an <%ae>' #{branch}")
|
19
|
+
def stale?
|
20
|
+
last_touched < stale_cutoff_date
|
19
21
|
end
|
20
22
|
|
21
|
-
def
|
22
|
-
|
23
|
+
def author
|
24
|
+
query("git log -n1 --format='%an <%ae>' #{branch}")
|
23
25
|
end
|
24
26
|
|
25
27
|
private
|
26
28
|
|
27
|
-
def
|
29
|
+
def stale_cutoff_date
|
30
|
+
Date.today - days_till_stale
|
31
|
+
end
|
32
|
+
|
33
|
+
def last_touched
|
34
|
+
Date.parse(log_date)
|
35
|
+
end
|
36
|
+
|
37
|
+
def log_date
|
38
|
+
query("git log -1 --date=iso --format=%cd #{branch}")
|
39
|
+
end
|
40
|
+
|
41
|
+
def diff
|
28
42
|
# you can't dry run a merge, so we have to apply and abort merges
|
29
43
|
command("git merge --no-ff --no-commit #{branch}")
|
30
44
|
query("git diff").tap do
|
@@ -35,22 +49,24 @@ end
|
|
35
49
|
|
36
50
|
MergeRacer = Struct.new(:branch) do
|
37
51
|
MAINLINE = "origin/HEAD" # defaultly origin/master
|
52
|
+
STALE_THRESHOLD = 4 * 7 # days
|
53
|
+
SEPARATOR = "\n"
|
38
54
|
|
39
55
|
def call
|
40
56
|
if dirty?
|
41
57
|
puts "Cowardly refusing to run, please commit your work or update .gitignore"
|
42
58
|
puts "You can figure out what files to modify with\n"
|
43
59
|
puts " git status"
|
44
|
-
elsif
|
60
|
+
elsif recent_conflicts.none?
|
45
61
|
puts "Congratulations! Your branch doesn't conflict with anyone"
|
46
62
|
else
|
47
63
|
puts "Danger! Merge race in progress"
|
48
|
-
|
64
|
+
recent_conflicts.each do |merge|
|
49
65
|
puts "* Conflict: #{branch} with #{merge.branch}, last authored by #{merge.author}"
|
50
66
|
end
|
51
67
|
end
|
52
68
|
|
53
|
-
puts
|
69
|
+
puts SEPARATOR
|
54
70
|
end
|
55
71
|
|
56
72
|
def abort
|
@@ -59,23 +75,21 @@ MergeRacer = Struct.new(:branch) do
|
|
59
75
|
end
|
60
76
|
|
61
77
|
private
|
62
|
-
|
78
|
+
|
63
79
|
def dirty?
|
64
80
|
query("git status --porcelain").length > 0
|
65
81
|
end
|
66
82
|
|
67
|
-
def
|
68
|
-
@
|
83
|
+
def recent_conflicts
|
84
|
+
@recent_conflicts ||= merges.reject(&:stale?).select(&:conflict?)
|
69
85
|
end
|
70
86
|
|
71
87
|
def merges
|
72
|
-
branches_from_merge_base
|
73
|
-
.reject { |b| b.match(MAINLINE) }
|
74
|
-
.map { |b| Merge.new(b) }
|
88
|
+
branches_from_merge_base.map { |branch| Merge.new(branch, STALE_THRESHOLD) }
|
75
89
|
end
|
76
90
|
|
77
91
|
def branches_from_merge_base
|
78
|
-
query("git branch --remotes --
|
92
|
+
query("git branch --remotes --no-merged #{MAINLINE}").split("\n").map(&:strip)
|
79
93
|
end
|
80
94
|
|
81
95
|
def merge_base
|