Module: Hub::Commands
Overview
The Commands module houses the git commands that hub lovingly wraps. If a method exists here, it is expected to have a corresponding git command which either gets run before or after the method executes.
The typical flow is as follows:
-
hub is invoked from the command line: $ hub clone rtomayko/tilt
-
The Hub class is initialized: >> hub = Hub.new(‘clone’, ‘rtomayko/tilt’)
-
The method representing the git subcommand is executed with the full args: >> Commands.clone(‘clone’, ‘rtomayko/tilt’)
-
That method rewrites the args as it sees fit: >> args = “git://github.com/” + args + “.git”
> “git://github.com/rtomayko/tilt.git”
-
The new args are used to run
git: >> exec “git”, “clone”, “git://github.com/rtomayko/tilt.git”
An optional after callback can be set. If so, it is run after step 5 (which then performs a system call rather than an exec). See Hub::Args for more information on the after callback.
Defined Under Namespace
Modules: HTTPExceptions
Constant Summary collapse
- API_REPO =
'http://github.com/api/v2/yaml/repos/show/%s/%s'- API_FORK =
'https://github.com/api/v2/yaml/repos/fork/%s/%s'- API_CREATE =
'https://github.com/api/v2/yaml/repos/create'- API_PULL =
'http://github.com/api/v2/json/pulls/%s'- API_PULLREQUEST =
'https://github.com/api/v2/yaml/pulls/%s/%s'- NAME_RE =
/[\w.-]+/- OWNER_RE =
/[a-zA-Z0-9-]+/- NAME_WITH_OWNER_RE =
/^(?:#{NAME_RE}|#{OWNER_RE}\/#{NAME_RE})$/
Constants included from Context
Instance Method Summary collapse
- #alias(args) ⇒ Object
-
#am(args) ⇒ Object
(also: #apply)
$ hub am github.com/defunkt/hub/pull/55 > curl github.com/defunkt/hub/pull/55.patch -o /tmp/55.patch > git am /tmp/55.patch.
-
#browse(args) ⇒ Object
$ hub browse > open github.com/CURRENT_REPO.
-
#checkout(args) ⇒ Object
$ git checkout github.com/defunkt/hub/pull/73 > git remote add -f -t feature git://github:com/mislav/hub.git > git checkout -b mislav-feature mislav/feature.
-
#cherry_pick(args) ⇒ Object
$ git cherry-pick github.com/mislav/hub/commit/a319d88#comments > git remote add -f mislav git://github.com/mislav/hub.git > git cherry-pick a319d88.
-
#clone(args) ⇒ Object
$ hub clone rtomayko/tilt > git clone git://github.com/rtomayko/tilt.
-
#compare(args) ⇒ Object
$ hub compare 1.0..fix > open github.com/CURRENT_REPO/compare/1.0…fix $ hub compare refactor > open github.com/CURRENT_REPO/compare/refactor $ hub compare myfork feature > open github.com/myfork/REPO/compare/feature $ hub compare -u 1.0…2.0 “github.com/CURRENT_REPO/compare/1.0…2.0”.
-
#create(args) ⇒ Object
$ hub create …
-
#fetch(args) ⇒ Object
$ hub fetch mislav > git remote add mislav git://github.com/mislav/REPO.git > git fetch mislav.
-
#fork(args) ⇒ Object
$ hub fork …
-
#help(args) ⇒ Object
(also: #--help)
$ hub help (print improved help text).
-
#hub(args) ⇒ Object
$ hub hub standalone Prints the “standalone” version of hub for an easy, memorable installation sequence:.
-
#init(args) ⇒ Object
$ hub init -g > git init > git remote add origin [email protected]:USER/REPO.git.
-
#pull_request(args) ⇒ Object
$ hub pull-request $ hub pull-request “My humble contribution” $ hub pull-request -i 92 $ hub pull-request github.com/rtomayko/tilt/issues/92.
-
#push(args) ⇒ Object
$ hub push origin,staging cool-feature > git push origin cool-feature > git push staging cool-feature.
-
#remote(args) ⇒ Object
$ hub remote add pjhyett > git remote add pjhyett git://github.com/pjhyett/THIS_REPO.git.
- #run(args) ⇒ Object
-
#submodule(args) ⇒ Object
$ hub submodule add wycats/bundler vendor/bundler > git submodule add git://github.com/wycats/bundler.git vendor/bundler.
-
#version(args) ⇒ Object
(also: #--version)
$ hub version > git version (print hub version).
Methods included from Hub::Context::GitReaderMethods
Instance Method Details
#alias(args) ⇒ Object
582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 |
# File 'lib/hub/commands.rb', line 582 def alias(args) shells = { 'sh' => 'alias git=hub', 'bash' => 'alias git=hub', 'zsh' => 'function git(){hub "$@"}', 'csh' => 'alias git hub', 'fish' => 'alias git hub' } silent = args.delete('-s') if shell = args[1] if silent.nil? puts "Run this in your shell to start using `hub` as `git`:" print " " end else puts "usage: hub alias [-s] SHELL", "" puts "You already have hub installed and available in your PATH," puts "but to get the full experience you'll want to alias it to" puts "`git`.", "" puts "To see how to accomplish this for your shell, run the alias" puts "command again with the name of your shell.", "" puts "Known shells:" shells.map { |key, _| key }.sort.each do |key| puts " " + key end puts "", "Options:" puts " -s Silent. Useful when using the output with eval, e.g." puts " $ eval `hub alias -s bash`" exit end if shells[shell] puts shells[shell] else abort "fatal: never heard of `#{shell}'" end exit end |
#am(args) ⇒ Object Also known as: apply
$ hub am github.com/defunkt/hub/pull/55 > curl github.com/defunkt/hub/pull/55.patch -o /tmp/55.patch > git am /tmp/55.patch
365 366 367 368 369 370 371 372 373 374 375 376 377 |
# File 'lib/hub/commands.rb', line 365 def am(args) if url = args.find { |a| a =~ %r{^https?://(gist\.)?github\.com/} } idx = args.index(url) gist = $1 == 'gist.' # strip extra path from "pull/42/files", "pull/42/commits" url = url.sub(%r{(/pull/\d+)/\w*$}, '\1') unless gist ext = gist ? '.txt' : '.patch' url += ext unless File.extname(url) == ext patch_file = File.join(ENV['TMPDIR'] || '/tmp', "#{gist ? 'gist-' : ''}#{File.basename(url)}") args.before 'curl', ['-#LA', "hub #{Hub::Version}", url, '-o', patch_file] args[idx] = patch_file end end |
#browse(args) ⇒ Object
$ hub browse > open github.com/CURRENT_REPO
$ hub browse – issues > open github.com/CURRENT_REPO/issues
$ hub browse pjhyett/github-services > open github.com/pjhyett/github-services
$ hub browse github-services > open github.com/YOUR_LOGIN/github-services
$ hub browse github-services wiki > open github.com/YOUR_LOGIN/github-services/wiki
501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 |
# File 'lib/hub/commands.rb', line 501 def browse(args) args.shift browse_command(args) do dest = args.shift dest = nil if dest == '--' if dest # $ hub browse pjhyett/github-services # $ hub browse github-services project = github_project dest else # $ hub browse project = current_project end abort "Usage: hub browse [<USER>/]<REPOSITORY>" unless project # $ hub browse -- wiki path = case subpage = args.shift when 'commits' branch = (!dest && current_branch.upstream) || master_branch "/commits/#{branch.short_name}" when 'tree', NilClass branch = !dest && current_branch.upstream "/tree/#{branch.short_name}" if branch and !branch.master? else "/#{subpage}" end project.web_url(path) end end |
#checkout(args) ⇒ Object
$ git checkout github.com/defunkt/hub/pull/73 > git remote add -f -t feature git://github:com/mislav/hub.git > git checkout -b mislav-feature mislav/feature
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 |
# File 'lib/hub/commands.rb', line 305 def checkout(args) if (2..3) === args.length and args[1] =~ %r{https?://github.com/(.+?)/(.+?)/pull/(\d+)} owner, repo, pull_id = $1, $2, $3 load_net_http pull_body = Net::HTTP.get URI(API_PULL % File.join(owner, repo, pull_id)) user, branch = pull_body.match(/"label":\s*"(.+?)"/)[1].split(':', 2) new_branch_name = args[2] || "#{user}-#{branch}" if remotes.include? user args.before ['remote', 'set-branches', '--add', user, branch] args.before ['fetch', user, "+refs/heads/#{branch}:refs/remotes/#{user}/#{branch}"] else args.before ['remote', 'add', '-f', '-t', branch, user, github_project(repo, user).git_url] end args[1..-1] = ['-b', new_branch_name, "#{user}/#{branch}"] end end |
#cherry_pick(args) ⇒ Object
$ git cherry-pick github.com/mislav/hub/commit/a319d88#comments > git remote add -f mislav git://github.com/mislav/hub.git > git cherry-pick a319d88
$ git cherry-pick mislav@a319d88 > git remote add -f mislav git://github.com/mislav/hub.git > git cherry-pick a319d88
$ git cherry-pick mislav@SHA > git fetch mislav > git cherry-pick SHA
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 |
# File 'lib/hub/commands.rb', line 336 def cherry_pick(args) unless args.include?('-m') or args.include?('--mainline') case ref = args.words.last when %r{^(?:https?:)//github.com/(.+?)/(.+?)/commit/([a-f0-9]{7,40})} user, repo, sha = $1, $2, $3 args[args.index(ref)] = sha when /^(\w+)@([a-f0-9]{7,40})$/ user, repo, sha = $1, nil, $2 args[args.index(ref)] = sha else user = nil end if user if user == repo_owner # fetch from origin if the repo belongs to the user args.before ['fetch', origin_remote] elsif remotes.include?(user) args.before ['fetch', user] else args.before ['remote', 'add', '-f', user, git_url(user, repo)] end end end end |
#clone(args) ⇒ Object
$ hub clone rtomayko/tilt > git clone git://github.com/rtomayko/tilt.
$ hub clone -p kneath/hemingway > git clone [email protected]:kneath/hemingway.git
$ hub clone tilt > git clone git://github.com/YOUR_LOGIN/tilt.
$ hub clone -p github > git clone [email protected]:YOUR_LOGIN/hemingway.git
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
# File 'lib/hub/commands.rb', line 176 def clone(args) ssh = args.delete('-p') has_values = /^(--(upload-pack|template|depth|origin|branch|reference)|-[ubo])$/ idx = 1 while idx < args.length arg = args[idx] if arg.index('-') == 0 idx += 1 if arg =~ has_values else # $ hub clone rtomayko/tilt # $ hub clone tilt if arg =~ NAME_WITH_OWNER_RE project = github_project(arg) ssh ||= args[0] != 'submodule' && project.owner == github_user(false) args[idx] = project.git_url(:private => ssh, :https => https_protocol?) end break end idx += 1 end end |
#compare(args) ⇒ Object
$ hub compare 1.0..fix > open github.com/CURRENT_REPO/compare/1.0…fix $ hub compare refactor > open github.com/CURRENT_REPO/compare/refactor $ hub compare myfork feature > open github.com/myfork/REPO/compare/feature $ hub compare -u 1.0…2.0 “github.com/CURRENT_REPO/compare/1.0…2.0”
542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 |
# File 'lib/hub/commands.rb', line 542 def compare(args) args.shift browse_command(args) do if args.empty? branch = current_branch.upstream if branch and not branch.master? range = branch.short_name project = current_project else abort "Usage: hub compare [USER] [<START>...]<END>" end else sha_or_tag = /(\w{1,2}|\w[\w.-]+\w)/ # replaces two dots with three: "sha1...sha2" range = args.pop.sub(/^#{sha_or_tag}\.\.#{sha_or_tag}$/, '\1...\2') project = if owner = args.pop then github_project(nil, owner) else current_project end end project.web_url "/compare/#{range}" end end |
#create(args) ⇒ Object
$ hub create … create repo on github … > git remote add -f origin [email protected]:YOUR_USER/CURRENT_REPO.git
422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 |
# File 'lib/hub/commands.rb', line 422 def create(args) if !is_repo? abort "'create' must be run from inside a git repository" elsif owner = github_user and github_token args.shift = {} [:private] = true if args.delete('-p') new_repo_name = nil until args.empty? case arg = args.shift when '-d' [:description] = args.shift when '-h' [:homepage] = args.shift else if arg =~ /^[^-]/ and new_repo_name.nil? new_repo_name = arg owner, new_repo_name = new_repo_name.split('/', 2) if new_repo_name.index('/') else abort "invalid argument: #{arg}" end end end new_repo_name ||= repo_name repo_with_owner = "#{owner}/#{new_repo_name}" if repo_exists?(owner, new_repo_name) warn "#{repo_with_owner} already exists on GitHub" action = "set remote origin" else action = "created repository" create_repo(repo_with_owner, ) unless args.noop? end url = git_url(owner, new_repo_name, :private => true) if remotes.first != 'origin' args.replace %W"remote add -f origin #{url}" else args.replace %W"remote -v" end args.after 'echo', ["#{action}:", repo_with_owner] end rescue HTTPExceptions display_http_exception("creating repository", $!.response) exit 1 end |
#fetch(args) ⇒ Object
$ hub fetch mislav > git remote add mislav git://github.com/mislav/REPO.git > git fetch mislav
$ hub fetch –multiple mislav xoebus > git remote add mislav … > git remote add xoebus … > git fetch –multiple mislav xoebus
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 |
# File 'lib/hub/commands.rb', line 270 def fetch(args) # $ hub fetch --multiple <name1>, <name2>, ... if args.include?('--multiple') names = args.words[1..-1] # $ hub fetch <name> elsif remote_name = args.words[1] # $ hub fetch <name1>,<name2>,... if remote_name =~ /^\w+(,\w+)+$/ index = args.index(remote_name) args.delete(remote_name) names = remote_name.split(',') args.insert(index, *names) args.insert(index, '--multiple') else names = [remote_name] end else names = [] end names.reject! { |name| name =~ /\W/ or remotes.include?(name) or remotes_group(name) or not repo_exists?(name) } if names.any? names.each do |name| args.before ['remote', 'add', name, git_url(name)] end end end |
#fork(args) ⇒ Object
$ hub fork … hardcore forking action … > git remote add -f YOUR_USER [email protected]:YOUR_USER/CURRENT_REPO.git
397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 |
# File 'lib/hub/commands.rb', line 397 def fork(args) # can't do anything without token and original owner name if github_user && github_token && repo_owner if repo_exists?(github_user) warn "#{github_user}/#{repo_name} already exists on GitHub" else fork_repo unless args.noop? end if args.include?('--no-remote') exit else url = git_url(github_user, repo_name, :private => true) args.replace %W"remote add -f #{github_user} #{url}" args.after 'echo', ['new remote:', github_user] end end rescue HTTPExceptions display_http_exception("creating fork", $!.response) exit 1 end |
#help(args) ⇒ Object Also known as: --help
$ hub help (print improved help text)
635 636 637 638 639 640 641 642 643 644 645 646 |
# File 'lib/hub/commands.rb', line 635 def help(args) command = args.words[1] if command == 'hub' puts hub_manpage exit elsif command.nil? && !args.has_flag?('-a', '--all') ENV['GIT_PAGER'] = '' unless args.has_flag?('-p', '--paginate') # Use `cat`. puts improved_help_text exit end end |
#hub(args) ⇒ Object
$ hub hub standalone Prints the “standalone” version of hub for an easy, memorable installation sequence:
$ gem install hub $ hub hub standalone > ~/bin/hub && chmod 755 ~/bin/hub $ gem uninstall hub
573 574 575 576 577 578 579 580 |
# File 'lib/hub/commands.rb', line 573 def hub(args) return help(args) unless args[1] == 'standalone' require 'hub/standalone' $stdout.puts Hub::Standalone.build exit rescue LoadError abort "hub is running in standalone mode." end |
#init(args) ⇒ Object
$ hub init -g > git init > git remote add origin [email protected]:USER/REPO.git
387 388 389 390 391 392 |
# File 'lib/hub/commands.rb', line 387 def init(args) if args.delete('-g') url = git_url(github_user, repo_name, :private => true) args.after ['remote', 'add', 'origin', url] end end |
#pull_request(args) ⇒ Object
$ hub pull-request $ hub pull-request “My humble contribution” $ hub pull-request -i 92 $ hub pull-request github.com/rtomayko/tilt/issues/92
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
# File 'lib/hub/commands.rb', line 75 def pull_request(args) args.shift = { } force = explicit_owner = false base_project = local_repo.main_project head_project = local_repo.current_project from_github_ref = lambda do |ref, context_project| if ref.index(':') owner, ref = ref.split(':', 2) project = github_project(context_project.name, owner) end [project || context_project, ref] end while arg = args.shift case arg when '-f' force = true when '-b' base_project, [:base] = from_github_ref.call(args.shift, base_project) when '-h' head = args.shift explicit_owner = !!head.index(':') head_project, [:head] = from_github_ref.call(head, head_project) when '-i' [:issue] = args.shift when %r{^https?://github.com/([^/]+/[^/]+)/issues/(\d+)} [:issue] = $2 base_project = github_project($1) else if ![:title] then [:title] = arg else abort "invalid argument: #{arg}" end end end [:project] = base_project [:base] ||= master_branch.short_name if tracked_branch = [:head].nil? && current_branch.upstream if base_project == head_project and tracked_branch.short_name == [:base] $stderr.puts "Aborted: head branch is the same as base (#{[:base].inspect})" warn "(use `-h <branch>` to specify an explicit pull request head)" abort end end [:head] ||= (tracked_branch || current_branch).short_name if head_project.owner != github_user and !tracked_branch and !explicit_owner head_project = github_project(head_project.name, github_user) end remote_branch = "#{head_project.remote}/#{[:head]}" [:head] = "#{head_project.owner}:#{[:head]}" if !force and tracked_branch and local_commits = git_command("rev-list --cherry #{remote_branch}...") $stderr.puts "Aborted: #{local_commits.split("\n").size} commits are not yet pushed to #{remote_branch}" warn "(use `-f` to force submit a pull request anyway)" abort end if args.noop? puts "Would reqest a pull to #{base_project.owner}:#{[:base]} from #{[:head]}" exit end unless [:title] or [:issue] base_branch = "#{base_project.remote}/#{[:base]}" changes = git_command "log --no-color --pretty=medium --cherry %s...%s" % [base_branch, remote_branch] [:title], [:body] = pullrequest_editmsg(changes) { |msg| msg.puts "# Requesting a pull to #{base_project.owner}:#{[:base]} from #{[:head]}" msg.puts "#" msg.puts "# Write a message for this pull request. The first block" msg.puts "# of text is the title and the rest is description." } end pull = create_pullrequest() args.executable = 'echo' args.replace [pull['html_url']] rescue HTTPExceptions display_http_exception("creating pull request", $!.response) exit 1 end |
#push(args) ⇒ Object
$ hub push origin,staging cool-feature > git push origin cool-feature > git push staging cool-feature
475 476 477 478 479 480 481 482 483 484 485 |
# File 'lib/hub/commands.rb', line 475 def push(args) return if args[1].nil? || !args[1].index(',') branch = (args[2] ||= current_branch.short_name) remotes = args[1].split(',') args[1] = remotes.shift remotes.each do |name| args.after ['push', name, branch] end end |
#remote(args) ⇒ Object
$ hub remote add pjhyett > git remote add pjhyett git://github.com/pjhyett/THIS_REPO.git
$ hub remote add -p mojombo > git remote add mojombo [email protected]:mojombo/THIS_REPO.git
$ hub remote add origin > git remote add origin git://github.com/YOUR_LOGIN/THIS_REPO.git
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 |
# File 'lib/hub/commands.rb', line 233 def remote(args) if %w[add set-url].include?(args[1]) name = args.last if name =~ /^(#{OWNER_RE})$/ || name =~ /^(#{OWNER_RE})\/(#{NAME_RE})$/ user, repo = $1, $2 || repo_name end end return unless user # do not touch arguments ssh = args.delete('-p') if args.words[2] == 'origin' && args.words[3].nil? # Origin special case triggers default user/repo user, repo = github_user, repo_name elsif args.words[-2] == args.words[1] # rtomayko/tilt => rtomayko # Make sure you dance around flags. idx = args.index( args.words[-1] ) args[idx] = user else # They're specifying the remote name manually (e.g. # git remote add blah rtomayko/tilt), so just drop the last # argument. args.pop end args << git_url(user, repo, :private => ssh) end |
#run(args) ⇒ Object
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/hub/commands.rb', line 47 def run(args) slurp_global_flags(args) # Hack to emulate git-style args.unshift 'help' if args.empty? cmd = args[0] = (cmd) cmd = [0] if # git commands can have dashes cmd = cmd.sub(/(\w)-/, '\1_') if method_defined?(cmd) and cmd != 'run' args[0, 1] = if send(cmd, args) end rescue Errno::ENOENT if $!..include? "No such file or directory - git" abort "Error: `git` command not found" else raise end end |
#submodule(args) ⇒ Object
$ hub submodule add wycats/bundler vendor/bundler > git submodule add git://github.com/wycats/bundler.git vendor/bundler
$ hub submodule add -p wycats/bundler vendor/bundler > git submodule add [email protected]:wycats/bundler.git vendor/bundler
$ hub submodule add -b ryppl ryppl/pip vendor/bundler > git submodule add -b ryppl git://github.com/ryppl/pip.git vendor/pip
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 |
# File 'lib/hub/commands.rb', line 207 def submodule(args) return unless index = args.index('add') args.delete_at index branch = args.index('-b') || args.index('--branch') if branch args.delete_at branch branch_name = args.delete_at branch end clone(args) if branch_name args.insert branch, '-b', branch_name end args.insert index, 'add' end |
#version(args) ⇒ Object Also known as: --version
$ hub version > git version (print hub version)
628 629 630 |
# File 'lib/hub/commands.rb', line 628 def version(args) args.after 'echo', ['hub version', Version] end |