git-hub 1.4.1 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
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