git-hub 1.4.1 → 1.5.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.
- data/README.md +20 -20
- data/lib/hub/args.rb +48 -26
- data/lib/hub/commands.rb +43 -50
- data/lib/hub/context.rb +14 -9
- data/lib/hub/runner.rb +28 -27
- data/lib/hub/version.rb +1 -1
- data/man/hub.1 +103 -108
- data/man/hub.1.html +116 -161
- data/man/hub.1.ronn +49 -31
- data/test/fakebin/git +5 -1
- data/test/helper.rb +11 -0
- data/test/hub_test.rb +188 -140
- metadata +10 -25
data/README.md
CHANGED
@@ -30,7 +30,7 @@ Install
|
|
30
30
|
|
31
31
|
`hub` is most easily installed as a standalone script:
|
32
32
|
|
33
|
-
curl
|
33
|
+
curl http://chriswanstrath.com/hub/standalone -sLo ~/bin/hub &&
|
34
34
|
chmod 755 ~/bin/hub
|
35
35
|
|
36
36
|
Assuming `~/bin/` is in your `$PATH`, you're ready to roll:
|
@@ -191,39 +191,33 @@ Creates a new public github repository and adds the remote `origin` at
|
|
191
191
|
### git browse
|
192
192
|
|
193
193
|
$ git browse
|
194
|
-
> open
|
194
|
+
> open https://github.com/CURRENT_REPO
|
195
195
|
|
196
196
|
$ git browse -- issues
|
197
|
-
> open
|
197
|
+
> open https://github.com/CURRENT_REPO/issues
|
198
198
|
|
199
199
|
$ git browse schacon/ticgit
|
200
|
-
> open http://github.com/schacon/ticgit
|
201
|
-
|
202
|
-
$ git browse -p schacon/ticgit
|
203
200
|
> open https://github.com/schacon/ticgit
|
204
201
|
|
205
202
|
$ git browse resque
|
206
|
-
> open
|
203
|
+
> open https://github.com/YOUR_USER/resque
|
207
204
|
|
208
205
|
$ git browse resque network
|
209
|
-
> open
|
210
|
-
|
211
|
-
$ git browse -p resque
|
212
|
-
> open https://github.com:YOUR_USER/resque
|
206
|
+
> open https://github.com/YOUR_USER/resque/network
|
213
207
|
|
214
208
|
### git compare
|
215
209
|
|
216
210
|
$ git compare refactor
|
217
|
-
> open
|
211
|
+
> open https://github.com/CURRENT_REPO/compare/refactor
|
218
212
|
|
219
213
|
$ git compare 1.0...1.1
|
220
|
-
> open
|
214
|
+
> open https://github.com/CURRENT_REPO/compare/1.0...1.1
|
221
215
|
|
222
216
|
$ git compare -u fix
|
223
|
-
> (
|
217
|
+
> (https://github.com/CURRENT_REPO/compare/fix)
|
224
218
|
|
225
219
|
$ git compare other-user patch
|
226
|
-
> open
|
220
|
+
> open https://github.com/other-user/REPO/compare/patch
|
227
221
|
|
228
222
|
### git submodule
|
229
223
|
|
@@ -249,7 +243,7 @@ GitHub Login
|
|
249
243
|
------------
|
250
244
|
|
251
245
|
To get the most out of `hub`, you'll want to ensure your GitHub login
|
252
|
-
is stored locally in your Git config.
|
246
|
+
is stored locally in your Git config or environment variables.
|
253
247
|
|
254
248
|
To test it run this:
|
255
249
|
|
@@ -262,6 +256,12 @@ If you see nothing, you need to set the config setting:
|
|
262
256
|
For commands that require write access to GitHub (such as `fork`), you'll want to
|
263
257
|
setup "github.token" as well. See [local GitHub config guide][2] for more information.
|
264
258
|
|
259
|
+
Want to use environment variables instead of a local gitconfig?
|
260
|
+
|
261
|
+
* `GITHUB_USER` - If set, this will be used instead of the `github.user` config
|
262
|
+
value to determine your GitHub username.
|
263
|
+
* `GITHUB_TOKEN` - If set, this will be used instead of the `github.token` config
|
264
|
+
value to determine your GitHub API token.
|
265
265
|
|
266
266
|
Configuration
|
267
267
|
-------------
|
@@ -315,7 +315,7 @@ contribute to `hub`:
|
|
315
315
|
* `turn` (`gem install turn`)
|
316
316
|
* `mg` (`gem install mg`)
|
317
317
|
* `ronn` (`gem install ronn`)
|
318
|
-
* `
|
318
|
+
* `webmock` (`gem install webmock`)
|
319
319
|
|
320
320
|
Meta
|
321
321
|
----
|
@@ -328,10 +328,10 @@ Meta
|
|
328
328
|
* Gems: <http://gemcutter.org/gems/git-hub>
|
329
329
|
|
330
330
|
|
331
|
-
|
332
|
-
|
331
|
+
Authors
|
332
|
+
-------
|
333
333
|
|
334
|
-
|
334
|
+
<https://github.com/defunkt/hub/contributors>
|
335
335
|
|
336
336
|
[0]: http://help.github.com/forking/
|
337
337
|
[1]: http://github.com/defunkt/hub/issues
|
data/lib/hub/args.rb
CHANGED
@@ -12,27 +12,33 @@ module Hub
|
|
12
12
|
super
|
13
13
|
@executable = ENV["GIT"] || "git"
|
14
14
|
@after = nil
|
15
|
+
@skip = false
|
16
|
+
@original_args = args.first
|
17
|
+
@chain = [nil]
|
15
18
|
end
|
16
19
|
|
17
|
-
#
|
18
|
-
#
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
#
|
24
|
-
#
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
#
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
20
|
+
# Adds an `after` callback.
|
21
|
+
# A callback can be a command or a proc.
|
22
|
+
def after(cmd_or_args = nil, args = nil, &block)
|
23
|
+
@chain.insert(-1, normalize_callback(cmd_or_args, args, block))
|
24
|
+
end
|
25
|
+
|
26
|
+
# Adds a `before` callback.
|
27
|
+
# A callback can be a command or a proc.
|
28
|
+
def before(cmd_or_args = nil, args = nil, &block)
|
29
|
+
@chain.insert(@chain.index(nil), normalize_callback(cmd_or_args, args, block))
|
30
|
+
end
|
31
|
+
|
32
|
+
# Tells if there are multiple (chained) commands or not.
|
33
|
+
def chained?
|
34
|
+
@chain.size > 1
|
35
|
+
end
|
36
|
+
|
37
|
+
# Returns an array of all commands.
|
38
|
+
def commands
|
39
|
+
chain = @chain.dup
|
40
|
+
chain[chain.index(nil)] = self.to_exec
|
41
|
+
chain
|
36
42
|
end
|
37
43
|
|
38
44
|
# Skip running this command.
|
@@ -45,15 +51,10 @@ module Hub
|
|
45
51
|
@skip
|
46
52
|
end
|
47
53
|
|
48
|
-
# Boolean indicating whether an `after` callback has been set.
|
49
|
-
def after?
|
50
|
-
!!@after
|
51
|
-
end
|
52
|
-
|
53
54
|
# Array of `executable` followed by all args suitable as arguments
|
54
55
|
# for `exec` or `system` calls.
|
55
|
-
def to_exec
|
56
|
-
[executable].concat
|
56
|
+
def to_exec(args = self)
|
57
|
+
[executable].concat args
|
57
58
|
end
|
58
59
|
|
59
60
|
# All the words (as opposed to flags) contained in this argument
|
@@ -73,5 +74,26 @@ module Hub
|
|
73
74
|
def flags
|
74
75
|
self - words
|
75
76
|
end
|
77
|
+
|
78
|
+
# Tests if arguments were modified since instantiation
|
79
|
+
def changed?
|
80
|
+
chained? or self != @original_args
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
def normalize_callback(cmd_or_args, args, block)
|
86
|
+
if block
|
87
|
+
block
|
88
|
+
elsif args
|
89
|
+
[cmd_or_args].concat args
|
90
|
+
elsif Array === cmd_or_args
|
91
|
+
self.to_exec cmd_or_args
|
92
|
+
elsif cmd_or_args
|
93
|
+
cmd_or_args
|
94
|
+
else
|
95
|
+
raise ArgumentError, "command or block required"
|
96
|
+
end
|
97
|
+
end
|
76
98
|
end
|
77
99
|
end
|
data/lib/hub/commands.rb
CHANGED
@@ -149,16 +149,16 @@ module Hub
|
|
149
149
|
if args.include?('--multiple')
|
150
150
|
names = args.words[1..-1]
|
151
151
|
# $ hub fetch <name>
|
152
|
-
elsif
|
152
|
+
elsif remote_name = args.words[1]
|
153
153
|
# $ hub fetch <name1>,<name2>,...
|
154
|
-
if
|
155
|
-
index = args.index(
|
156
|
-
args.delete(
|
157
|
-
names =
|
154
|
+
if remote_name =~ /^\w+(,\w+)+$/
|
155
|
+
index = args.index(remote_name)
|
156
|
+
args.delete(remote_name)
|
157
|
+
names = remote_name.split(',')
|
158
158
|
args.insert(index, *names)
|
159
159
|
args.insert(index, '--multiple')
|
160
160
|
else
|
161
|
-
names = [
|
161
|
+
names = [remote_name]
|
162
162
|
end
|
163
163
|
else
|
164
164
|
names = []
|
@@ -170,11 +170,9 @@ module Hub
|
|
170
170
|
}
|
171
171
|
|
172
172
|
if names.any?
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
args.shift # don't want "git"
|
177
|
-
args.after commands.join('; ')
|
173
|
+
names.each do |name|
|
174
|
+
args.before ['remote', 'add', name, github_url(:user => name)]
|
175
|
+
end
|
178
176
|
end
|
179
177
|
end
|
180
178
|
|
@@ -192,40 +190,49 @@ module Hub
|
|
192
190
|
def cherry_pick(args)
|
193
191
|
unless args.include?('-m') or args.include?('--mainline')
|
194
192
|
case ref = args.words.last
|
195
|
-
when %r{^(https?:)//github.com/(.+?)/(.+?)/commit/([a-f0-9]{7,40})}
|
196
|
-
|
193
|
+
when %r{^(?:https?:)//github.com/(.+?)/(.+?)/commit/([a-f0-9]{7,40})}
|
194
|
+
user, repo, sha = $1, $2, $3
|
197
195
|
args[args.index(ref)] = sha
|
198
196
|
when /^(\w+)@([a-f1-9]{7,40})$/
|
199
|
-
|
197
|
+
user, repo, sha = $1, nil, $2
|
200
198
|
args[args.index(ref)] = sha
|
201
199
|
else
|
202
200
|
user = nil
|
203
201
|
end
|
204
202
|
|
205
203
|
if user
|
206
|
-
# cherry-pick comes after the fetch
|
207
|
-
args.after args.to_exec.join(' ')
|
208
|
-
|
209
204
|
if user == repo_owner
|
210
205
|
# fetch from origin if the repo belongs to the user
|
211
|
-
args.
|
206
|
+
args.before ['fetch', default_remote]
|
212
207
|
elsif remotes.include?(user)
|
213
|
-
args.
|
208
|
+
args.before ['fetch', user]
|
214
209
|
else
|
215
|
-
|
216
|
-
|
217
|
-
args.replace ['remote', 'add', '-f', user, remote_url]
|
210
|
+
remote_url = github_url(:user => user, :repo => repo, :private => false)
|
211
|
+
args.before ['remote', 'add', '-f', user, remote_url]
|
218
212
|
end
|
219
213
|
end
|
220
214
|
end
|
221
215
|
end
|
222
216
|
|
217
|
+
# $ hub am https://github.com/defunkt/hub/pull/55
|
218
|
+
# > curl https://github.com/defunkt/hub/pull/55.patch -o /tmp/55.patch
|
219
|
+
# > git am /tmp/55.patch
|
220
|
+
def am(args)
|
221
|
+
if url = args.find { |a| a =~ %r{^https?://github\.com/} }
|
222
|
+
idx = args.index(url)
|
223
|
+
url += '.patch' unless File.extname(url) == '.patch'
|
224
|
+
patch_file = File.join(ENV['TMPDIR'], File.basename(url))
|
225
|
+
args.before 'curl', ['-#LA', "hub #{Hub::Version}", url, '-o', patch_file]
|
226
|
+
args[idx] = patch_file
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
223
230
|
# $ hub init -g
|
224
231
|
# > git init
|
225
232
|
# > git remote add origin git@github.com:USER/REPO.git
|
226
233
|
def init(args)
|
227
234
|
if args.delete('-g')
|
228
|
-
url = github_url(:private => true, :repo =>
|
235
|
+
url = github_url(:private => true, :repo => current_dirname)
|
229
236
|
args.after "git remote add origin #{url}"
|
230
237
|
end
|
231
238
|
end
|
@@ -306,35 +313,25 @@ module Hub
|
|
306
313
|
remotes = args[1].split(',')
|
307
314
|
args[1] = remotes.shift
|
308
315
|
|
309
|
-
|
310
|
-
|
311
|
-
while remotes.length > 0
|
312
|
-
after += "; git push #{remotes.shift} #{branch}"
|
316
|
+
remotes.each do |name|
|
317
|
+
args.after ['push', name, branch]
|
313
318
|
end
|
314
|
-
|
315
|
-
args.after after
|
316
319
|
end
|
317
320
|
|
318
321
|
# $ hub browse
|
319
|
-
# > open
|
322
|
+
# > open https://github.com/CURRENT_REPO
|
320
323
|
#
|
321
324
|
# $ hub browse -- issues
|
322
|
-
# > open
|
325
|
+
# > open https://github.com/CURRENT_REPO/issues
|
323
326
|
#
|
324
327
|
# $ hub browse pjhyett/github-services
|
325
|
-
# > open
|
326
|
-
#
|
327
|
-
# $ hub browse -p pjhyett/github-fi
|
328
|
-
# > open https://github.com/pjhyett/github-fi
|
328
|
+
# > open https://github.com/pjhyett/github-services
|
329
329
|
#
|
330
330
|
# $ hub browse github-services
|
331
|
-
# > open
|
331
|
+
# > open https://github.com/YOUR_LOGIN/github-services
|
332
332
|
#
|
333
333
|
# $ hub browse github-services wiki
|
334
|
-
# > open
|
335
|
-
#
|
336
|
-
# $ hub browse -p github-fi
|
337
|
-
# > open https://github.com/YOUR_LOGIN/github-fi
|
334
|
+
# > open https://github.com/YOUR_LOGIN/github-services/wiki
|
338
335
|
def browse(args)
|
339
336
|
args.shift
|
340
337
|
browse_command(args) do
|
@@ -357,8 +354,6 @@ module Hub
|
|
357
354
|
|
358
355
|
# $ hub browse -- wiki
|
359
356
|
case subpage = args.shift
|
360
|
-
when 'wiki'
|
361
|
-
params[:web] = 'wiki'
|
362
357
|
when 'commits'
|
363
358
|
branch = (!dest && tracked_branch) || 'master'
|
364
359
|
params[:web] = "/commits/#{branch}"
|
@@ -374,15 +369,13 @@ module Hub
|
|
374
369
|
end
|
375
370
|
|
376
371
|
# $ hub compare 1.0...fix
|
377
|
-
# > open
|
372
|
+
# > open https://github.com/CURRENT_REPO/compare/1.0...fix
|
378
373
|
# $ hub compare refactor
|
379
|
-
# > open
|
374
|
+
# > open https://github.com/CURRENT_REPO/compare/refactor
|
380
375
|
# $ hub compare myfork feature
|
381
|
-
# > open
|
382
|
-
# $ hub compare -p myfork topsecret
|
383
|
-
# > open https://github.com/myfork/REPO/compare/topsecret
|
376
|
+
# > open https://github.com/myfork/REPO/compare/feature
|
384
377
|
# $ hub compare -u 1.0...2.0
|
385
|
-
#
|
378
|
+
# "https://github.com/CURRENT_REPO/compare/1.0...2.0"
|
386
379
|
def compare(args)
|
387
380
|
args.shift
|
388
381
|
browse_command(args) do
|
@@ -569,11 +562,11 @@ help
|
|
569
562
|
# and `compare`. Yields a block that returns params for `github_url`.
|
570
563
|
def browse_command(args)
|
571
564
|
url_only = args.delete('-u')
|
572
|
-
|
565
|
+
$stderr.puts "Warning: the `-p` flag has no effect anymore" if args.delete('-p')
|
573
566
|
params = yield
|
574
567
|
|
575
568
|
args.executable = url_only ? 'echo' : browser_launcher
|
576
|
-
args.push github_url({:web => true, :private =>
|
569
|
+
args.push github_url({:web => true, :private => true}.update(params))
|
577
570
|
end
|
578
571
|
|
579
572
|
|
data/lib/hub/context.rb
CHANGED
@@ -2,6 +2,8 @@ module Hub
|
|
2
2
|
# Provides methods for inspecting the environment, such as GitHub user/token
|
3
3
|
# settings, repository info, and similar.
|
4
4
|
module Context
|
5
|
+
private
|
6
|
+
|
5
7
|
# Caches output when shelling out to git
|
6
8
|
GIT_CONFIG = Hash.new do |cache, cmd|
|
7
9
|
result = %x{git #{cmd}}.chomp
|
@@ -11,9 +13,9 @@ module Hub
|
|
11
13
|
# Parses URLs for git remotes and stores info
|
12
14
|
REMOTES = Hash.new do |cache, remote|
|
13
15
|
if remote
|
14
|
-
|
16
|
+
urls = GIT_CONFIG["config --get-all remote.#{remote}.url"].to_s.split("\n")
|
15
17
|
|
16
|
-
if
|
18
|
+
if urls.find { |u| u =~ %r{\bgithub\.com[:/](.+)/(.+).git$} }
|
17
19
|
cache[remote] = { :user => $1, :repo => $2 }
|
18
20
|
else
|
19
21
|
cache[remote] = { }
|
@@ -34,13 +36,13 @@ module Hub
|
|
34
36
|
end
|
35
37
|
|
36
38
|
def repo_name
|
37
|
-
REMOTES[default_remote][:repo] ||
|
39
|
+
REMOTES[default_remote][:repo] || current_dirname
|
38
40
|
end
|
39
41
|
|
40
42
|
# Either returns the GitHub user as set by git-config(1) or aborts
|
41
43
|
# with an error message.
|
42
44
|
def github_user(fatal = true)
|
43
|
-
if user = GIT_CONFIG['config github.user']
|
45
|
+
if user = ENV['GITHUB_USER'] || GIT_CONFIG['config github.user']
|
44
46
|
user
|
45
47
|
elsif fatal
|
46
48
|
abort("** No GitHub user set. See #{LGHCONF}")
|
@@ -48,7 +50,7 @@ module Hub
|
|
48
50
|
end
|
49
51
|
|
50
52
|
def github_token(fatal = true)
|
51
|
-
if token = GIT_CONFIG['config github.token']
|
53
|
+
if token = ENV['GITHUB_TOKEN'] || GIT_CONFIG['config github.token']
|
52
54
|
token
|
53
55
|
elsif fatal
|
54
56
|
abort("** No GitHub token set. See #{LGHCONF}")
|
@@ -119,10 +121,7 @@ module Hub
|
|
119
121
|
repo ||= repo_name
|
120
122
|
secure = options[:private]
|
121
123
|
|
122
|
-
if options[:web]
|
123
|
-
scheme = secure ? 'https:' : 'http:'
|
124
|
-
'%s//wiki.github.com/%s/%s/' % [scheme, user, repo]
|
125
|
-
elsif options[:web]
|
124
|
+
if options[:web]
|
126
125
|
scheme = secure ? 'https:' : 'http:'
|
127
126
|
path = options[:web] == true ? '' : options[:web].to_s
|
128
127
|
'%s//github.com/%s/%s%s' % [scheme, user, repo, path]
|
@@ -138,5 +137,11 @@ module Hub
|
|
138
137
|
url % [user, repo]
|
139
138
|
end
|
140
139
|
end
|
140
|
+
|
141
|
+
DIRNAME = File.basename(Dir.pwd)
|
142
|
+
|
143
|
+
def current_dirname
|
144
|
+
DIRNAME
|
145
|
+
end
|
141
146
|
end
|
142
147
|
end
|
data/lib/hub/runner.rb
CHANGED
@@ -11,11 +11,11 @@ module Hub
|
|
11
11
|
@args = Args.new(args)
|
12
12
|
|
13
13
|
# Hack to emulate git-style
|
14
|
-
@args.unshift 'help' if @args.grep(/^[^-]|version/).empty?
|
14
|
+
@args.unshift 'help' if @args.grep(/^[^-]|version|exec-path$|html-path/).empty?
|
15
15
|
|
16
16
|
# git commands can have dashes
|
17
17
|
cmd = @args[0].sub(/(\w)-/, '\1_')
|
18
|
-
Commands.send(cmd, @args) if Commands.
|
18
|
+
Commands.send(cmd, @args) if Commands.method_defined?(cmd)
|
19
19
|
end
|
20
20
|
|
21
21
|
# Shortcut
|
@@ -23,22 +23,23 @@ module Hub
|
|
23
23
|
new(*args).execute
|
24
24
|
end
|
25
25
|
|
26
|
-
#
|
27
|
-
# the target git command.
|
28
|
-
#
|
29
|
-
# See the `Hub::Args` class for more information on the `after`
|
30
|
-
# callback.
|
31
|
-
def after
|
32
|
-
args.after.to_s
|
33
|
-
end
|
34
|
-
|
35
|
-
# A string representation of the git command we would run if
|
36
|
-
# #execute were called.
|
26
|
+
# A string representation of the command that would run.
|
37
27
|
def command
|
38
28
|
if args.skip?
|
39
29
|
''
|
40
30
|
else
|
41
|
-
|
31
|
+
commands.join('; ')
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# An array of all commands as strings.
|
36
|
+
def commands
|
37
|
+
args.commands.map do |cmd|
|
38
|
+
if cmd.respond_to?(:join)
|
39
|
+
cmd.map { |c| c.index(' ') ? "'#{c}'" : c }.join(' ')
|
40
|
+
else
|
41
|
+
cmd.to_s
|
42
|
+
end
|
42
43
|
end
|
43
44
|
end
|
44
45
|
|
@@ -50,25 +51,25 @@ module Hub
|
|
50
51
|
# execution if they don't make sense.
|
51
52
|
def execute
|
52
53
|
unless args.skip?
|
53
|
-
if args.
|
54
|
-
|
54
|
+
if args.chained?
|
55
|
+
execute_command_chain
|
55
56
|
else
|
56
57
|
exec(*args.to_exec)
|
57
58
|
end
|
58
59
|
end
|
59
60
|
end
|
60
61
|
|
61
|
-
# Runs
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
62
|
+
# Runs multiple commands in succession; exits at first failure.
|
63
|
+
def execute_command_chain
|
64
|
+
commands = args.commands
|
65
|
+
commands.each_with_index do |cmd, i|
|
66
|
+
if cmd.respond_to?(:call) then cmd.call
|
67
|
+
elsif i == commands.length - 1
|
68
|
+
# last command in chain
|
69
|
+
exec(*cmd)
|
70
|
+
else
|
71
|
+
exit($?.exitstatus) unless system(*cmd)
|
72
|
+
end
|
72
73
|
end
|
73
74
|
end
|
74
75
|
end
|