git-extras 0.1.0

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f5ba92b639627411f03a70fb68d6224f2a3b1b78
4
+ data.tar.gz: 9a35848a79d382eb4b558561baadba3050731b02
5
+ SHA512:
6
+ metadata.gz: ec9c52981ed131cb97169f2a807a32f3e4b7cd9e1397ed634102a86d3915057a03a85643219eb0a33edfe54f52234fc7befc585f9f43befe85a87686ed0cc65c
7
+ data.tar.gz: 74d2dda77f0a1e0b386c4f356e343cfb91f77ee234bce9fd67364e75a07bb54db11c3f2e681ce40ee1ac5316e54d507aaf376fa800b25083dc1dc3f40fe0aa69
@@ -0,0 +1 @@
1
+ pkg/
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
@@ -0,0 +1,25 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ git-extras (0.1.0)
5
+ faker
6
+ thor
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ faker (1.6.6)
12
+ i18n (~> 0.5)
13
+ i18n (0.7.0)
14
+ rake (11.2.2)
15
+ thor (0.19.1)
16
+
17
+ PLATFORMS
18
+ ruby
19
+
20
+ DEPENDENCIES
21
+ git-extras!
22
+ rake
23
+
24
+ BUNDLED WITH
25
+ 1.12.5
@@ -0,0 +1,5 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ task default: [
4
+ :release,
5
+ ]
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ p ARGV
4
+ # version=ARGV[1]
5
+ bump = "!f(){ git bump $(git ltag);};f"
6
+
@@ -0,0 +1,295 @@
1
+ #!/usr/bin/env ruby
2
+ line = DATA.readlines.sample
3
+ name = ['Nick', 'Andy', 'Steve', 'Sarah', 'Jason', 'Todd'].sample
4
+ puts line.sub('{{Name}}', name).sub('{{UPPER}}', name.upcase)
5
+
6
+ __END__
7
+ {{UPPER}}, WE WENT OVER THIS. EXPANDTAB.
8
+ {{UPPER}}, WE WENT OVER THIS. C++ IO SUCKS.
9
+ This is the last time we let {{Name}} commit ascii porn in the comments.
10
+ de-misunderestimating
11
+ Some shit.
12
+ add actual words
13
+ I CAN HAZ COMMENTZ.
14
+ giggle.
15
+ Whatever.
16
+ Finished fondling.
17
+ FONDLED THE CODE
18
+ this is how we generate our shit.
19
+ unh
20
+ It works!
21
+ unionfind is no longer being molested.
22
+ Well, it's doing something.
23
+ I'M PUSHING.
24
+ Whee.
25
+ Whee, good night.
26
+ It'd be nice if type errors caused the compiler to issue a type error
27
+ Fucking templates.
28
+ I hate this fucking language.
29
+ marks
30
+ that coulda been bad
31
+ hoo boy
32
+ It was the best of times, it was the worst of times
33
+ Fucking egotistical bastard. adds expandtab to vimrc
34
+ if you're not using et, fuck off
35
+ WHO THE FUCK CAME UP WITH MAKE?
36
+ This is a basic implementation that works.
37
+ By works, I meant 'doesnt work'. Works now..
38
+ Last time I said it works? I was kidding. Try this.
39
+ Just stop reading these for a while, ok..
40
+ Give me a break, it's 2am. But it works now.
41
+ Make that it works in 90% of the cases. 3:30.
42
+ Ok, 5am, it works. For real.
43
+ FOR REAL.
44
+ I don't know what these changes are supposed to accomplish but somebody told me to make them.
45
+ I don't get paid enough for this shit.
46
+ fix some fucking errors
47
+ first blush
48
+ So my boss wanted this button ...
49
+ uhhhhhh
50
+ forgot we're not using a smart language
51
+ include shit
52
+ To those I leave behind, good luck!
53
+ things occurred
54
+ i dunno, maybe this works
55
+ 8==========D
56
+ No changes made
57
+ whooooooooooooooooooooooooooo
58
+ clarify further the brokenness of C++. why the fuck are we using C++?
59
+ (\ /)\n(O.o)\n(> <) Bunny approves these changes.
60
+ .
61
+ Friday 5pm
62
+ changes
63
+ A fix I believe, not like I tested or anything
64
+ Useful text
65
+ pgsql is being a pain
66
+ pgsql is more strict, increase the hackiness up to 11
67
+ c&p fail
68
+ syntax
69
+ {{Name}} sucks
70
+ {{UPPER}} SUCKS
71
+ fix
72
+ just shoot me
73
+ arrrggghhhhh fixed!
74
+ someone fails and it isn't me
75
+ Gross hack because {{Name}} doesn't know how to code
76
+ totally more readable
77
+ better grepping
78
+ fix
79
+ fix bug, for realz
80
+ fix /sigh
81
+ Does this work
82
+ MOAR BIFURCATION
83
+ bifurcation
84
+ REALLY FUCKING FIXED
85
+ FIX
86
+ better ignores
87
+ More ignore
88
+ more ignores
89
+ more ignored words
90
+ more fixes
91
+ really ignore ignored worsd
92
+ fixes
93
+ /sigh
94
+ fix
95
+ fail
96
+ pointless limitation
97
+ eppic fail {{Name}}
98
+ omg what have I done?
99
+ added super-widget 2.0.
100
+ tagging release w.t.f.
101
+ I can't believe it took so long to fix this.
102
+ I must have been drunk.
103
+ This is why the cat shouldn't sit on my keyboard.
104
+ This is why git rebase is a horrible horrible thing.
105
+ ajax-loader hotness, oh yeah
106
+ {{Name}} broke the regex, lame
107
+ small is a real HTML tag, who knew.
108
+ WTF is this.
109
+ Do things better, faster, stronger
110
+ Fixed a bug cause {{Name}} said to
111
+ Use a real JS construct, WTF knows why this works in chromium.
112
+ Added a banner to the default admin page. Please have mercy on me =(
113
+ needs more cow bell
114
+ Switched off unit test X because the build had to go out now and there was no time to fix it properly.
115
+ Updated
116
+ I must sleep... it's working... in just three hours...
117
+ I was wrong...
118
+ Completed with no bugs...
119
+ Fixed a little bug...
120
+ Fixed a bug in NoteLineCount... not seriously...
121
+ woa!! this one was really HARD!
122
+ Made it to compile...
123
+ changed things...
124
+ touched...
125
+ i think i fixed a bug...
126
+ perfect...
127
+ Moved something to somewhere... goodnight...
128
+ oops, forgot to add the file
129
+ Corrected mistakes
130
+ oops
131
+ oops!
132
+ put code that worked where the code that didn't used to be
133
+ Nothing to see here, move along
134
+ I am even stupider than I thought
135
+ I don't know what the hell I was thinking.
136
+ fixed errors in the previous commit
137
+ Committed some changes
138
+ Some bugs fixed
139
+ Minor updates
140
+ Added missing file in previous commit
141
+ bug fix
142
+ typo
143
+ bara bra grejjor
144
+ Continued development...
145
+ Does anyone read this? I'll be at the coffee shop accross the street.
146
+ That's just how I roll
147
+ work in progress
148
+ minor changes
149
+ some brief changes
150
+ assorted changes
151
+ lots and lots of changes
152
+ another big bag of changes
153
+ lots of changes after a lot of time
154
+ LOTS of changes. period
155
+ {{Name}} made me do it
156
+ Test commit. Please ignore
157
+ I'm just a grunt. Don't blame me for this awful PoS.
158
+ I did it for the lulz!
159
+ I'll explain this when I'm sober .. or revert it
160
+ Obligatory placeholder commit message
161
+ A long time ago, in a galaxy far far away...
162
+ Fixed the build.
163
+ Fixing {{Name}}'s bug.
164
+ Fixing {{Name}}'s bugs.
165
+ various changes
166
+ One more time, but with feeling.
167
+ Handled a particular error.
168
+ Fixed unnecessary bug.
169
+ Removed code.
170
+ Added translation.
171
+ Updated build targets.
172
+ Refactored configuration.
173
+ Locating the required gigapixels to render...
174
+ Spinning up the hamster...
175
+ Shovelling coal into the server...
176
+ Programming the flux capacitor
177
+ The last time I tried this the monkey didn't survive. Let's hope it works better this time.
178
+ I should have had a V8 this morning.
179
+ 640K ought to be enough for anybody
180
+ pay no attention to the man behind the curtain
181
+ a few bits tried to escape, but we caught them
182
+ Who has two thumbs and remembers the rudiments of his linear algebra courses? Apparently, this guy.
183
+ workaround for ant being a pile of fail
184
+ Don't push this commit
185
+ rats
186
+ squash me
187
+ fixed mistaken bug
188
+ Final commit, ready for tagging
189
+ -m \'So I hear you like commits ...\'
190
+ epic
191
+ need another beer
192
+ Well the book was obviously wrong.
193
+ lolwhat?
194
+ Another commit to keep my CAN streak going.
195
+ I cannot believe that it took this long to write a test for this.
196
+ TDD: 1, Me: 0
197
+ Yep, {{Name}} was right on this one.
198
+ Yes, I was being sarcastic.
199
+ Apparently works-for-me is a crappy excuse.
200
+ tl;dr
201
+ I would rather be playing SC2.
202
+ Crap. Tonight is raid night and I am already late.
203
+ I know what I am doing. Trust me.
204
+ You should have trusted me.
205
+ Is there an award for this?
206
+ Is there an achievement for this?
207
+ I'm totally adding this to epic win. +300
208
+ This really should not take 19 minutes to build.
209
+ fixed the israeli-palestinian conflict
210
+ SHIT ===> GOLD
211
+ Committing in accordance with the prophecy.
212
+ It compiles! Ship it!
213
+ LOL!
214
+ Reticulating splines...
215
+ SEXY RUSSIAN CODES WAITING FOR YOU TO CALL
216
+ s/import/include/
217
+ extra debug for stuff module
218
+ debug line test
219
+ debugo
220
+ remove debug<br/>all good
221
+ debug suff
222
+ more debug... who overwrote!
223
+ FUCKING {{UPPER}}
224
+ these confounded tests drive me nuts
225
+ For great justice.
226
+ QuickFix.
227
+ oops - thought I got that one.
228
+ removed echo and die statements, lolz.
229
+ somebody keeps erasing my changes.
230
+ doh.
231
+ pam anderson is going to love me.
232
+ added security.
233
+ arrgghh... damn this thing for not working.
234
+ jobs... steve jobs
235
+ and a comma
236
+ this is my quickfix branch and i will use to do my quickfixes
237
+ Fix my stupidness
238
+ and so the crazy refactoring process sees the sunlight after some months in the dark!
239
+ gave up and used tables.
240
+ [Insert your commit message here. Be sure to make it descriptive.]
241
+ Removed test case since code didn't pass QA
242
+ removed tests since i can't make them green
243
+ stuff
244
+ more stuff
245
+ Become a programmer, they said. It'll be fun, they said.
246
+ Same as last commit with changes
247
+ foo
248
+ just checking if git is working properly...
249
+ fixed some minor stuff, might need some additional work.
250
+ just trolling the repo
251
+ All your codebase are belong to us.
252
+ Somebody set up us the bomb.
253
+ should work I guess...
254
+ To be honest, I do not quite remember everything I changed here today. But it is all good, I tell ya.
255
+ well crap.
256
+ herpderp (redux)
257
+ herpderp
258
+ Derp
259
+ derpherp
260
+ Herping the derp
261
+ sometimes you just herp the derp so hard it herpderps
262
+ Derp. Fix missing constant post rename
263
+ Herping the fucking derp right here and now.
264
+ Derp, asset redirection in dev mode
265
+ mergederp
266
+ Derp search/replace fuckup
267
+ Herpy dooves.
268
+ Derpy hooves
269
+ derp, helper method rename
270
+ Herping the derp derp (silly scoping error)
271
+ Herp derp I left the debug in there and forgot to reset errors.
272
+ Reset error count between rows. herpderp
273
+ hey, what's that over there?!
274
+ hey, look over there!
275
+ It worked for me...
276
+ Does not work.
277
+ Either Hot Shit or Total Bollocks
278
+ Arrrrgggg
279
+ Don’t mess with Voodoo
280
+ I expected something different.
281
+ Todo!!!
282
+ This is supposed to crash
283
+ No changes after this point.
284
+ I know, I know, this is not how I’m supposed to do it, but I can't think of something better.
285
+ Don’t even try to refactor it.
286
+ (c) Microsoft 1988
287
+ Please no changes this time.
288
+ Why The Fuck?
289
+ We should delete this crap before shipping.
290
+ Shit code!
291
+ ALL SORTS OF THINGS
292
+ Herpderp, shoulda check if it does really compile.
293
+ I CAN HAZ PYTHON, I CAN HAZ INDENTS
294
+ {{Name}} rebase plx?
295
+ Major fixup.
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ require "faker"
3
+
4
+ types = {
5
+ "hacker" => "Faker::Hacker.say_something_smart",
6
+ "hipster" => "Faker::Hipster.sentences(1)[0]",
7
+ "book" => "Faker::Book.title",
8
+ "doing" => "Faker::Hacker.ingverb + '' '' + Faker::Hacker.adjective",
9
+ "biz" => "Faker::Company.catch_phrase",
10
+ "buzz" => "Faker::Company.buzzword",
11
+ "bs" => "Faker::Company.bs",
12
+ "team" => "Faker::Team.name",
13
+ }
14
+
15
+ puts eval(ARGV[1] ? types[ARGV[1]] : types[types.keys.sample]).capitalize
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ ## git-rank-contributors: a simple script to trace through the logs and
4
+ ## rank contributors by the total size of the diffs they're responsible for.
5
+ ## A change counts twice as much as a plain addition or deletion.
6
+ ##
7
+ ## Output may or may not be suitable for inclusion in a CREDITS file.
8
+ ## Probably not without some editing, because people often commit from more
9
+ ## than one address.
10
+ ##
11
+ ## git-rank-contributors Copyright 2008 William Morgan <wmorgan-git-wt-add@masanjin.net>.
12
+ ## This program is free software: you can redistribute it and/or modify
13
+ ## it under the terms of the GNU General Public License as published by
14
+ ## the Free Software Foundation, either version 3 of the License, or (at
15
+ ## your option) any later version.
16
+ ##
17
+ ## This program is distributed in the hope that it will be useful,
18
+ ## but WITHOUT ANY WARRANTY; without even the implied warranty of
19
+ ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
+ ## GNU General Public License for more details.
21
+ ##
22
+ ## You can find the GNU General Public License at:
23
+ ## http://www.gnu.org/licenses/
24
+
25
+ class String
26
+ def obfuscate; gsub(/@/, " at the ").gsub(/\.(\w+)(>|$)/, ' dot \1s\2') end
27
+ def htmlize; gsub("&", "&amp;").gsub("<", "&lt;").gsub(">", "&gt;") end
28
+ end
29
+
30
+ lines = {}
31
+ verbose = ARGV.delete("-v")
32
+ obfuscate = ARGV.delete("-o")
33
+ htmlize = ARGV.delete("-h")
34
+
35
+ author = nil
36
+ state = :pre_author
37
+ `git log -M -C -C -p --no-color`
38
+ .encode('UTF-8', 'binary', :invalid => :replace, :undef => :replace)
39
+ .split("\n")
40
+ .each do |l|
41
+ case
42
+ when (state == :pre_author || state == :post_author) && l =~ /Author: (.*)$/
43
+ author = $1
44
+ state = :post_author
45
+ lines[author] ||= 0
46
+ when state == :post_author && l =~ /^\+\+\+/
47
+ state = :in_diff
48
+ when state == :in_diff && l =~ /^[\+\-]/
49
+ lines[author] += 1
50
+ when state == :in_diff && l =~ /^commit /
51
+ state = :pre_author
52
+ end
53
+ end
54
+
55
+ lines.sort_by { |a, c| -c }.each do |a, c|
56
+ a = a.obfuscate if obfuscate
57
+ a = a.htmlize if htmlize
58
+ if verbose
59
+ puts "#{a}: #{c} lines of diff"
60
+ else
61
+ puts a
62
+ end
63
+ end
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ release = "!f(){ git tag -a v$(git nn) -m \"$(git last)\" && git push origin master --tags;};f"
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bash
2
+
3
+ root="$(git rev-parse --show-toplevel)"
4
+ file="$(dirname ${root})/$(basename $PWD).tar.gz"
5
+ git archive --format=tar.gz -o ${file} HEAD
6
+ echo "File ${file} created."
@@ -0,0 +1,186 @@
1
+ #!/usr/bin/env ruby
2
+ require "thor"
3
+ require "yaml"
4
+
5
+ DIR = "#{ENV['HOME']}/.git-users"
6
+
7
+ module Git
8
+ module Account
9
+ class CancelledException < Exception
10
+ end
11
+
12
+ class Cli < Thor
13
+
14
+ desc "ls", "List accounts"
15
+ def ls
16
+ getLs do |name|
17
+ puts name
18
+ end
19
+ end
20
+
21
+ desc "all", "Show all settings"
22
+ def all
23
+ rows = []
24
+ rows << ["ACCOUNT", "KEY", "VALUE"]
25
+ Dir["#{DIR}/*.yaml"].each do |file|
26
+ first = false
27
+ name = file.sub("#{DIR}/", "").sub(".yaml", "")
28
+ data = YAML.load_file(file)
29
+ data.each do |k,v|
30
+ if first
31
+ name = ""
32
+ end
33
+
34
+ rows << [name, k, v]
35
+ first = true
36
+ end
37
+ end
38
+ table rows
39
+ end
40
+
41
+ desc "new", "Adds a a new account"
42
+ def new name = nil
43
+ print "Enter the new account name: "
44
+ account = $stdin.readline().chomp
45
+
46
+ print "Enter your name: "
47
+ name = $stdin.readline().chomp
48
+
49
+ print "Enter your email address: "
50
+ email = $stdin.readline().chomp
51
+
52
+ data = {}
53
+ data["user.name"] = name
54
+ data["user.email"] = email
55
+
56
+ puts
57
+ puts "Now you can set more key values."
58
+ begin
59
+ loop do
60
+ print "Enter a key (leave empty to skip): "
61
+ key = $stdin.readline().chomp
62
+ raise CancelledException if key.empty?
63
+
64
+ print "Enter the value for key \033[1m#{key}\033[0m: "
65
+ value = $stdin.readline().chomp
66
+ raise CancelledException if value.empty?
67
+
68
+ data[key] = value
69
+ end
70
+
71
+ rescue CancelledException
72
+ puts "Skipping"
73
+ end
74
+
75
+ file = "#{DIR}/#{account}.yaml"
76
+ File.write(file, data.to_yaml)
77
+ puts `cat #{file}`
78
+ end
79
+
80
+ desc "set NAME KEY VALUE", "Apply a user config"
81
+ def set name, key, value
82
+ file = "#{DIR}/#{name}.yaml"
83
+ data = YAML.load_file(file)
84
+ data[key] = value
85
+ File.write(file, data.to_yaml)
86
+ end
87
+
88
+ desc "rm NAME", "Removes a user account"
89
+ def rm name
90
+ file = "#{DIR}/#{name}.yaml"
91
+ system "rm #{file}"
92
+ end
93
+
94
+ desc "del NAME KEY", "Removes a user config"
95
+ def del name, key
96
+ file = "#{DIR}/#{name}.yaml"
97
+ data = YAML.load_file(file)
98
+ data.delete key
99
+ File.write(file, data.to_yaml)
100
+ end
101
+
102
+ desc "show", "Show current account configuration"
103
+ def show
104
+ rows = []
105
+ rows << ["KEY", "VALUE"]
106
+ name = file.sub("#{DIR}/", "").sub(".yaml", "")
107
+ data = YAML.load_file(file)
108
+ data.each do |k,v|
109
+ rows << [k, v]
110
+ end
111
+ table rows
112
+ end
113
+
114
+ desc "use NAME", "Apply the account setting"
115
+ def use(name)
116
+ file = "#{DIR}/#{name}.yaml"
117
+ data = YAML.load_file(file)
118
+ data.each do |k, v|
119
+ system "git config #{k} #{v}"
120
+ puts "#{k}: " + `git config #{k}`
121
+ end
122
+ end
123
+
124
+ desc "fix", "Fixes the author in the last commit"
125
+ def fix
126
+ user = `git config user.name`.chomp
127
+ email = `git config user.email`.chomp
128
+ system "git commit --amend --author '#{user} <#{email}>'"
129
+ end
130
+
131
+ private
132
+ def getLs
133
+ Dir["#{DIR}/*.yaml"].each do |file|
134
+ name = file.sub("#{DIR}/", "").sub(".yaml", "")
135
+ yield name
136
+ end
137
+ end
138
+
139
+ def table data
140
+ widths = []
141
+ data.each do |line|
142
+ c = 0
143
+ line.each do |col|
144
+ str = col.to_s
145
+ len = str.length
146
+ widths[c] = len if widths[c].nil? || len > widths[c]
147
+ c += 1
148
+ end
149
+ end
150
+
151
+ format = widths.collect{|n| "%-#{n}s"}.join(" ").chomp + "\n"
152
+ data.each do |row|
153
+ printf format, *row
154
+ end
155
+ end
156
+
157
+ def getAll
158
+ rows = []
159
+ rows << ["ACCOUNT", "KEY", "VALUE"]
160
+ Dir["#{DIR}/*.yaml"].each do |file|
161
+ first = false
162
+ name = file.sub("#{DIR}/", "").sub(".yaml", "")
163
+ data = YAML.load_file(file)
164
+ data.each do |k,v|
165
+ if first
166
+ name = ""
167
+ end
168
+
169
+ rows << [name, k, v]
170
+ first = true
171
+ end
172
+ end
173
+ table rows
174
+ end
175
+ end
176
+ end
177
+ end
178
+
179
+
180
+ begin
181
+ Git::Account::Cli.start ARGV
182
+
183
+ rescue SystemExit, Interrupt
184
+ print "Bye"
185
+
186
+ end
@@ -0,0 +1,364 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ HELP = <<EOS
4
+ git-wtf displays the state of your repository in a readable, easy-to-scan
5
+ format. It's useful for getting a summary of how a branch relates to a remote
6
+ server, and for wrangling many topic branches.
7
+
8
+ git-wtf can show you:
9
+ - How a branch relates to the remote repo, if it's a tracking branch.
10
+ - How a branch relates to integration branches, if it's a feature branch.
11
+ - How a branch relates to the feature branches, if it's an integration
12
+ branch.
13
+
14
+ git-wtf is best used before a git push, or between a git fetch and a git
15
+ merge. Be sure to set color.ui to auto or yes for maximum viewing pleasure.
16
+ EOS
17
+
18
+ KEY = <<EOS
19
+ KEY:
20
+ () branch only exists locally
21
+ {} branch only exists on a remote repo
22
+ [] branch exists locally and remotely
23
+
24
+ x merge occurs both locally and remotely
25
+ ~ merge occurs only locally
26
+ (space) branch isn't merged in
27
+
28
+ (It's possible for merges to occur remotely and not locally, of course, but
29
+ that's a less common case and git-wtf currently doesn't display anything
30
+ special for it.)
31
+ EOS
32
+
33
+ USAGE = <<EOS
34
+ Usage: git wtf [branch+] [options]
35
+
36
+ If [branch] is not specified, git-wtf will use the current branch. The possible
37
+ [options] are:
38
+
39
+ -l, --long include author info and date for each commit
40
+ -a, --all show all branches across all remote repos, not just
41
+ those from origin
42
+ -A, --all-commits show all commits, not just the first 5
43
+ -s, --short don't show commits
44
+ -k, --key show key
45
+ -r, --relations show relation to features / integration branches
46
+ --dump-config print out current configuration and exit
47
+
48
+ git-wtf uses some heuristics to determine which branches are integration
49
+ branches, and which are feature branches. (Specifically, it assumes the
50
+ integration branches are named "master", "next" and "edge".) If it guesses
51
+ incorrectly, you will have to create a .git-wtfrc file.
52
+
53
+ To start building a configuration file, run "git-wtf --dump-config >
54
+ .git-wtfrc" and edit it. The config file is a YAML file that specifies the
55
+ integration branches, any branches to ignore, and the max number of commits to
56
+ display when --all-commits isn't used. git-wtf will look for a .git-wtfrc file
57
+ starting in the current directory, and recursively up to the root.
58
+
59
+ IMPORTANT NOTE: all local branches referenced in .git-wtfrc must be prefixed
60
+ with heads/, e.g. "heads/master". Remote branches must be of the form
61
+ remotes/<remote>/<branch>.
62
+ EOS
63
+
64
+ COPYRIGHT = <<EOS
65
+ git-wtf Copyright 2008--2009 William Morgan <wmorgan at the masanjin dot nets>.
66
+ This program is free software: you can redistribute it and/or modify it
67
+ under the terms of the GNU General Public License as published by the Free
68
+ Software Foundation, either version 3 of the License, or (at your option)
69
+ any later version.
70
+
71
+ This program is distributed in the hope that it will be useful, but WITHOUT
72
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
73
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
74
+ more details.
75
+
76
+ You can find the GNU General Public License at: http://www.gnu.org/licenses/
77
+ EOS
78
+
79
+ require 'yaml'
80
+ CONFIG_FN = ".git-wtfrc"
81
+
82
+ class Numeric; def pluralize s; "#{to_s} #{s}" + (self != 1 ? "s" : "") end end
83
+
84
+ if ARGV.delete("--help") || ARGV.delete("-h")
85
+ puts USAGE
86
+ exit
87
+ end
88
+
89
+ ## poor man's trollop
90
+ $long = ARGV.delete("--long") || ARGV.delete("-l")
91
+ $short = ARGV.delete("--short") || ARGV.delete("-s")
92
+ $all = ARGV.delete("--all") || ARGV.delete("-a")
93
+ $all_commits = ARGV.delete("--all-commits") || ARGV.delete("-A")
94
+ $dump_config = ARGV.delete("--dump-config")
95
+ $key = ARGV.delete("--key") || ARGV.delete("-k")
96
+ $show_relations = ARGV.delete("--relations") || ARGV.delete("-r")
97
+ ARGV.each { |a| abort "Error: unknown argument #{a}." if a =~ /^--/ }
98
+
99
+ ## search up the path for a file
100
+ def find_file fn
101
+ while true
102
+ return fn if File.exist? fn
103
+ fn2 = File.join("..", fn)
104
+ return nil if File.expand_path(fn2) == File.expand_path(fn)
105
+ fn = fn2
106
+ end
107
+ end
108
+
109
+ want_color = `git config color.wtf`
110
+ want_color = `git config color.ui` if want_color.empty?
111
+ $color = case want_color.chomp
112
+ when "true"; true
113
+ when "auto"; $stdout.tty?
114
+ end
115
+
116
+ def red s; $color ? "\033[31m#{s}\033[0m" : s end
117
+ def green s; $color ? "\033[32m#{s}\033[0m" : s end
118
+ def yellow s; $color ? "\033[33m#{s}\033[0m" : s end
119
+ def cyan s; $color ? "\033[36m#{s}\033[0m" : s end
120
+ def grey s; $color ? "\033[1;30m#{s}\033[0m" : s end
121
+ def purple s; $color ? "\033[35m#{s}\033[0m" : s end
122
+
123
+ ## the set of commits in 'to' that aren't in 'from'.
124
+ ## if empty, 'to' has been merged into 'from'.
125
+ def commits_between from, to
126
+ if $long
127
+ `git log --pretty=format:"- %s [#{yellow "%h"}] (#{purple "%ae"}; %ar)" #{from}..#{to}`
128
+ else
129
+ `git log --pretty=format:"- %s [#{yellow "%h"}]" #{from}..#{to}`
130
+ end.split(/[\r\n]+/)
131
+ end
132
+
133
+ def show_commits commits, prefix=" "
134
+ if commits.empty?
135
+ puts "#{prefix} none"
136
+ else
137
+ max = $all_commits ? commits.size : $config["max_commits"]
138
+ max -= 1 if max == commits.size - 1 # never show "and 1 more"
139
+ commits[0 ... max].each { |c| puts "#{prefix}#{c}" }
140
+ puts grey("#{prefix}... and #{commits.size - max} more (use -A to see all).") if commits.size > max
141
+ end
142
+ end
143
+
144
+ def ahead_behind_string ahead, behind
145
+ [ahead.empty? ? nil : "#{ahead.size.pluralize 'commit'} ahead",
146
+ behind.empty? ? nil : "#{behind.size.pluralize 'commit'} behind"].
147
+ compact.join("; ")
148
+ end
149
+
150
+ def widget merged_in, remote_only=false, local_only=false, local_only_merge=false
151
+ left, right = case
152
+ when remote_only; %w({ })
153
+ when local_only; %w{( )}
154
+ else %w([ ])
155
+ end
156
+ middle = case
157
+ when merged_in && local_only_merge; green("~")
158
+ when merged_in; green("x")
159
+ else " "
160
+ end
161
+ print left, middle, right
162
+ end
163
+
164
+ def show b
165
+ have_both = b[:local_branch] && b[:remote_branch]
166
+
167
+ pushc, pullc, oosync = if have_both
168
+ [x = commits_between(b[:remote_branch], b[:local_branch]),
169
+ y = commits_between(b[:local_branch], b[:remote_branch]),
170
+ !x.empty? && !y.empty?]
171
+ end
172
+
173
+ if b[:local_branch]
174
+ puts "Local branch: " + green(b[:local_branch].sub(/^heads\//, ""))
175
+
176
+ if have_both
177
+ if pushc.empty?
178
+ puts "#{widget true} in sync with remote"
179
+ else
180
+ action = oosync ? "push after rebase / merge" : "push"
181
+ puts "#{widget false} NOT in sync with remote (you should #{action})"
182
+ show_commits pushc unless $short
183
+ end
184
+ end
185
+ end
186
+
187
+ if b[:remote_branch]
188
+ puts "Remote branch: #{cyan b[:remote_branch]} (#{b[:remote_url]})"
189
+
190
+ if have_both
191
+ if pullc.empty?
192
+ puts "#{widget true} in sync with local"
193
+ else
194
+ action = pushc.empty? ? "merge" : "rebase / merge"
195
+ puts "#{widget false} NOT in sync with local (you should #{action})"
196
+ show_commits pullc unless $short
197
+ end
198
+ end
199
+ end
200
+
201
+ puts "\n#{red "WARNING"}: local and remote branches have diverged. A merge will occur unless you rebase." if oosync
202
+ end
203
+
204
+ def show_relations b, all_branches
205
+ ibs, fbs = all_branches.partition { |name, br| $config["integration-branches"].include?(br[:local_branch]) || $config["integration-branches"].include?(br[:remote_branch]) }
206
+ if $config["integration-branches"].include? b[:local_branch]
207
+ puts "\nFeature branches:" unless fbs.empty?
208
+ fbs.each do |name, br|
209
+ next if $config["ignore"].member?(br[:local_branch]) || $config["ignore"].member?(br[:remote_branch])
210
+ next if br[:ignore]
211
+ local_only = br[:remote_branch].nil?
212
+ remote_only = br[:local_branch].nil?
213
+ name = if local_only
214
+ purple br[:name]
215
+ elsif remote_only
216
+ cyan br[:name]
217
+ else
218
+ green br[:name]
219
+ end
220
+
221
+ ## for remote_only branches, we'll compute wrt the remote branch head. otherwise, we'll
222
+ ## use the local branch head.
223
+ head = remote_only ? br[:remote_branch] : br[:local_branch]
224
+
225
+ remote_ahead = b[:remote_branch] ? commits_between(b[:remote_branch], head) : []
226
+ local_ahead = b[:local_branch] ? commits_between(b[:local_branch], head) : []
227
+
228
+ if local_ahead.empty? && remote_ahead.empty?
229
+ puts "#{widget true, remote_only, local_only} #{name} #{local_only ? "(local-only) " : ""}is merged in"
230
+ elsif local_ahead.empty?
231
+ puts "#{widget true, remote_only, local_only, true} #{name} merged in (only locally)"
232
+ else
233
+ behind = commits_between head, (br[:local_branch] || br[:remote_branch])
234
+ ahead = remote_only ? remote_ahead : local_ahead
235
+ puts "#{widget false, remote_only, local_only} #{name} #{local_only ? "(local-only) " : ""}is NOT merged in (#{ahead_behind_string ahead, behind})"
236
+ show_commits ahead unless $short
237
+ end
238
+ end
239
+ else
240
+ puts "\nIntegration branches:" unless ibs.empty? # unlikely
241
+ ibs.sort_by { |v, br| v }.each do |v, br|
242
+ next if $config["ignore"].member?(br[:local_branch]) || $config["ignore"].member?(br[:remote_branch])
243
+ next if br[:ignore]
244
+ local_only = br[:remote_branch].nil?
245
+ remote_only = br[:local_branch].nil?
246
+ name = remote_only ? cyan(br[:name]) : green(br[:name])
247
+
248
+ ahead = commits_between v, (b[:local_branch] || b[:remote_branch])
249
+ if ahead.empty?
250
+ puts "#{widget true, local_only} merged into #{name}"
251
+ else
252
+ #behind = commits_between b[:local_branch], v
253
+ puts "#{widget false, local_only} NOT merged into #{name} (#{ahead.size.pluralize 'commit'} ahead)"
254
+ show_commits ahead unless $short
255
+ end
256
+ end
257
+ end
258
+ end
259
+
260
+ #### EXECUTION STARTS HERE ####
261
+
262
+ ## find config file and load it
263
+ $config = { "integration-branches" => %w(heads/master heads/next heads/edge), "ignore" => [], "max_commits" => 5 }.merge begin
264
+ fn = find_file CONFIG_FN
265
+ if fn && (h = YAML::load_file(fn)) # yaml turns empty files into false
266
+ h["integration-branches"] ||= h["versions"] # support old nomenclature
267
+ h
268
+ else
269
+ {}
270
+ end
271
+ end
272
+
273
+ if $dump_config
274
+ puts $config.to_yaml
275
+ exit
276
+ end
277
+
278
+ ## first, index registered remotes
279
+ remotes = `git config --get-regexp ^remote\.\*\.url`.split(/[\r\n]+/).inject({}) do |hash, l|
280
+ l =~ /^remote\.(.+?)\.url (.+)$/ or next hash
281
+ hash[$1] ||= $2
282
+ hash
283
+ end
284
+
285
+ ## next, index followed branches
286
+ branches = `git config --get-regexp ^branch\.`.split(/[\r\n]+/).inject({}) do |hash, l|
287
+ case l
288
+ when /branch\.(.*?)\.remote (.+)/
289
+ name, remote = $1, $2
290
+
291
+ hash[name] ||= {}
292
+ hash[name].merge! :remote => remote, :remote_url => remotes[remote]
293
+ when /branch\.(.*?)\.merge ((refs\/)?heads\/)?(.+)/
294
+ name, remote_branch = $1, $4
295
+ hash[name] ||= {}
296
+ hash[name].merge! :remote_mergepoint => remote_branch
297
+ end
298
+ hash
299
+ end
300
+
301
+ ## finally, index all branches
302
+ remote_branches = {}
303
+ `git show-ref`.split(/[\r\n]+/).each do |l|
304
+ sha1, ref = l.chomp.split " refs/"
305
+
306
+ if ref =~ /^heads\/(.+)$/ # local branch
307
+ name = $1
308
+ next if name == "HEAD"
309
+ branches[name] ||= {}
310
+ branches[name].merge! :name => name, :local_branch => ref
311
+ elsif ref =~ /^remotes\/(.+?)\/(.+)$/ # remote branch
312
+ remote, name = $1, $2
313
+ remote_branches["#{remote}/#{name}"] = true
314
+ next if name == "HEAD"
315
+ ignore = !($all || remote == "origin")
316
+
317
+ branch = name
318
+ if branches[name] && branches[name][:remote] == remote
319
+ # nothing
320
+ else
321
+ name = "#{remote}/#{branch}"
322
+ end
323
+
324
+ branches[name] ||= {}
325
+ branches[name].merge! :name => name, :remote => remote, :remote_branch => "#{remote}/#{branch}", :remote_url => remotes[remote], :ignore => ignore
326
+ end
327
+ end
328
+
329
+ ## assemble remotes
330
+ branches.each do |k, b|
331
+ next unless b[:remote] && b[:remote_mergepoint]
332
+ b[:remote_branch] = if b[:remote] == "."
333
+ b[:remote_mergepoint]
334
+ else
335
+ t = "#{b[:remote]}/#{b[:remote_mergepoint]}"
336
+ remote_branches[t] && t # only if it's still alive
337
+ end
338
+ end
339
+
340
+ show_dirty = ARGV.empty?
341
+ targets = if ARGV.empty?
342
+ [`git symbolic-ref HEAD`.chomp.sub(/^refs\/heads\//, "")]
343
+ else
344
+ ARGV.map { |x| x.sub(/^heads\//, "") }
345
+ end.map { |t| branches[t] or abort "Error: can't find branch #{t.inspect}." }
346
+
347
+ targets.each do |t|
348
+ show t
349
+ show_relations t, branches if $show_relations || t[:remote_branch].nil?
350
+ end
351
+
352
+ modified = show_dirty && `git ls-files -m` != ""
353
+ uncommitted = show_dirty && `git diff-index --cached HEAD` != ""
354
+
355
+ if $key
356
+ puts
357
+ puts KEY
358
+ end
359
+
360
+ puts if modified || uncommitted
361
+ puts "#{red "NOTE"}: working directory contains modified files." if modified
362
+ puts "#{red "NOTE"}: staging area contains staged but uncommitted files." if uncommitted
363
+
364
+ # the end!
@@ -0,0 +1,24 @@
1
+ $LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
2
+
3
+ require "date"
4
+ require "git_extras"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "git-extras"
8
+ spec.version = GitExtras::VERSION
9
+ spec.date = (Date.today << 1).to_s
10
+ spec.summary = "A bunch of git utility scripts"
11
+ spec.description = "A bunch of git utility scripts."
12
+ spec.authors = ["ptdorf"]
13
+ spec.email = ["ptdorf@gmail.com"]
14
+ spec.homepage = "https://github.com/ptdorf/git-extras"
15
+ spec.license = "MIT"
16
+ spec.require_paths = ["lib"]
17
+
18
+ spec.files = `git ls-files`.split $/
19
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename f }
20
+
21
+ spec.add_dependency "thor"
22
+ spec.add_dependency "faker"
23
+ spec.add_development_dependency "rake"
24
+ end
@@ -0,0 +1 @@
1
+ require "git_extras/version"
@@ -0,0 +1,5 @@
1
+ module GitExtras
2
+
3
+ VERSION = "0.1.0"
4
+
5
+ end
@@ -0,0 +1,3 @@
1
+ # git-extras
2
+
3
+ A bunch of git utility scripts.
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: git-extras
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - ptdorf
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-07-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: thor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: faker
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: A bunch of git utility scripts.
56
+ email:
57
+ - ptdorf@gmail.com
58
+ executables:
59
+ - git-bump
60
+ - git-commitment
61
+ - git-faker
62
+ - git-names
63
+ - git-release
64
+ - git-tar
65
+ - git-user
66
+ - git-wtf
67
+ extensions: []
68
+ extra_rdoc_files: []
69
+ files:
70
+ - ".gitignore"
71
+ - Gemfile
72
+ - Gemfile.lock
73
+ - Rakefile
74
+ - bin/git-bump
75
+ - bin/git-commitment
76
+ - bin/git-faker
77
+ - bin/git-names
78
+ - bin/git-release
79
+ - bin/git-tar
80
+ - bin/git-user
81
+ - bin/git-wtf
82
+ - git_extras.gemspec
83
+ - lib/git_extras.rb
84
+ - lib/git_extras/version.rb
85
+ - readme.md
86
+ homepage: https://github.com/ptdorf/git-extras
87
+ licenses:
88
+ - MIT
89
+ metadata: {}
90
+ post_install_message:
91
+ rdoc_options: []
92
+ require_paths:
93
+ - lib
94
+ required_ruby_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ requirements: []
105
+ rubyforge_project:
106
+ rubygems_version: 2.6.6
107
+ signing_key:
108
+ specification_version: 4
109
+ summary: A bunch of git utility scripts
110
+ test_files: []