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 CHANGED
@@ -30,7 +30,7 @@ Install
30
30
 
31
31
  `hub` is most easily installed as a standalone script:
32
32
 
33
- curl -s http://defunkt.github.com/hub/standalone > ~/bin/hub &&
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 http://github.com/CURRENT_REPO
194
+ > open https://github.com/CURRENT_REPO
195
195
 
196
196
  $ git browse -- issues
197
- > open http://github.com/CURRENT_REPO/issues
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 http://github.com/YOUR_USER/resque
203
+ > open https://github.com/YOUR_USER/resque
207
204
 
208
205
  $ git browse resque network
209
- > open http://github.com/YOUR_USER/resque/network
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 http://github.com/CURRENT_REPO/compare/refactor
211
+ > open https://github.com/CURRENT_REPO/compare/refactor
218
212
 
219
213
  $ git compare 1.0...1.1
220
- > open http://github.com/CURRENT_REPO/compare/1.0...1.1
214
+ > open https://github.com/CURRENT_REPO/compare/1.0...1.1
221
215
 
222
216
  $ git compare -u fix
223
- > (http://github.com/CURRENT_REPO/compare/fix)
217
+ > (https://github.com/CURRENT_REPO/compare/fix)
224
218
 
225
219
  $ git compare other-user patch
226
- > open http://github.com/other-user/REPO/compare/patch
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
- * `webhelper` (`gem install webhelper`)
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
- Author
332
- ------
331
+ Authors
332
+ -------
333
333
 
334
- Chris Wanstrath :: chris@ozmm.org :: @defunkt
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
@@ -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
- # With no arguments, returns the `after` callback.
18
- #
19
- # With a single argument, sets the `after` callback.
20
- # Can be set to a string or a proc.
21
- #
22
- # If proc:
23
- # The proc is executed after the git command is executed. For
24
- # example, the `hub version` command sets the following proc to
25
- # print its information after running `git version`:
26
- #
27
- # after { puts "hub version #{version_number}" }
28
- #
29
- # If string:
30
- # The string is assumed to be a command and executed after the
31
- # git command is executed:
32
- #
33
- # after "echo 'hub version #{version_number}'"
34
- def after(command = nil, &block)
35
- @after ||= block ? block : command
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 self
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
@@ -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 name = args.words[1]
152
+ elsif remote_name = args.words[1]
153
153
  # $ hub fetch <name1>,<name2>,...
154
- if name =~ /^\w+(,\w+)+$/
155
- index = args.index(name)
156
- args.delete(name)
157
- names = name.split(',')
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 = [name]
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
- commands = names.map { |name| "git remote add #{name} #{github_url(:user => name)}" }
174
- commands << args.to_exec.join(' ')
175
- args.replace commands.shift.split(' ')
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
- scheme, user, repo, sha = $1, $2, $3, $4
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
- scheme, user, repo, sha = nil, $1, nil, $2
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.replace ['fetch', default_remote]
206
+ args.before ['fetch', default_remote]
212
207
  elsif remotes.include?(user)
213
- args.replace ['fetch', user]
208
+ args.before ['fetch', user]
214
209
  else
215
- secure = scheme == 'https:'
216
- remote_url = github_url(:user => user, :repo => repo, :private => secure)
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 => File.basename(Dir.pwd))
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
- after = "git push #{remotes.shift} #{branch}"
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 http://github.com/CURRENT_REPO
322
+ # > open https://github.com/CURRENT_REPO
320
323
  #
321
324
  # $ hub browse -- issues
322
- # > open http://github.com/CURRENT_REPO/issues
325
+ # > open https://github.com/CURRENT_REPO/issues
323
326
  #
324
327
  # $ hub browse pjhyett/github-services
325
- # > open http://github.com/pjhyett/github-services
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 http://github.com/YOUR_LOGIN/github-services
331
+ # > open https://github.com/YOUR_LOGIN/github-services
332
332
  #
333
333
  # $ hub browse github-services wiki
334
- # > open http://wiki.github.com/YOUR_LOGIN/github-services
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 http://github.com/CURRENT_REPO/compare/1.0...fix
372
+ # > open https://github.com/CURRENT_REPO/compare/1.0...fix
378
373
  # $ hub compare refactor
379
- # > open http://github.com/CURRENT_REPO/compare/refactor
374
+ # > open https://github.com/CURRENT_REPO/compare/refactor
380
375
  # $ hub compare myfork feature
381
- # > open http://github.com/myfork/REPO/compare/feature
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
- # prints "http://github.com/CURRENT_REPO/compare/1.0...2.0"
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
- secure = args.delete('-p')
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 => secure}.update(params))
569
+ args.push github_url({:web => true, :private => true}.update(params))
577
570
  end
578
571
 
579
572
 
@@ -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
- url = GIT_CONFIG["config remote.#{remote}.url"]
16
+ urls = GIT_CONFIG["config --get-all remote.#{remote}.url"].to_s.split("\n")
15
17
 
16
- if url && url.to_s =~ %r{\bgithub\.com[:/](.+)/(.+).git$}
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] || File.basename(Dir.pwd)
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] == 'wiki'
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
@@ -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.respond_to?(cmd)
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
- # Returns the current after callback, which (if set) is run after
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
- args.to_exec.join(' ')
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.after?
54
- execute_with_after_callback
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 the target git command then executes the `after` callback.
62
- #
63
- # See the `Hub::Args` class for more information on the `after`
64
- # callback.
65
- def execute_with_after_callback
66
- after = args.after
67
- if system(*args.to_exec)
68
- after.respond_to?(:call) ? after.call : exec(after)
69
- exit
70
- else
71
- exit 1
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