3 # This file is generated code. DO NOT send patches for it. 
   5 # Original source files with comments are at: 
   6 # https://github.com/defunkt/hub 
  10   Version 
= VERSION 
= '1.10.3' 
  15     attr_accessor 
:executable 
  19       @executable = ENV["GIT"] || "git" 
  22       @original_args = args
.first
 
  26     def after(cmd_or_args 
= nil, args 
= nil, &block
) 
  27       @chain.insert(-1, normalize_callback(cmd_or_args
, args
, block
)) 
  30     def before(cmd_or_args 
= nil, args 
= nil, &block
) 
  31       @chain.insert(@chain.index(nil), normalize_callback(cmd_or_args
, args
, block
)) 
  40       chain
[chain
.index(nil)] = self.to_exec
 
  60     def to_exec(args 
= self) 
  61       Array(executable
) + args
 
  64     def add_exec_flags(flags
) 
  65       self.executable 
= Array(executable
).concat(flags
) 
  69       reject 
{ |arg
| arg
.index('-') == 0 } 
  77       chained
? or self !
= @original_args 
  81       pattern 
= flags
.flatten
.map 
{ |f
| Regexp
.escape(f
) }.join('|') 
  82       !
grep(/^#{pattern}(?:=|$)/).empty
? 
  87     def normalize_callback(cmd_or_args
, args
, block
) 
  91         [cmd_or_args
].concat args
 
  92       elsif Array 
=== cmd_or_args
 
  93         self.to_exec cmd_or_args
 
  97         raise ArgumentError
, "command or block required" 
 105     CONFIG_FILES 
= %w(~
/.ssh/config 
/etc/ssh_config 
/etc/ssh
/ssh_config
) 
 107     def initialize files 
= nil 
 108       @settings = Hash
.new 
{|h
,k
| h
[k
] = {} } 
 109       Array(files 
|| CONFIG_FILES
).each 
do |path
| 
 110         file 
= File
.expand_path path
 
 111         parse_file file 
if File
.exist
? file
 
 115     def get_value hostname
, key
 
 116       key 
= key
.to_s
.downcase
 
 117       @settings.each 
do |pattern
, settings
| 
 118         if pattern
.match
? hostname 
and found 
= settings
[key
] 
 126       def initialize pattern
 
 127         @pattern = pattern
.to_s
.downcase
 
 130       def to_s() @pattern end 
 131       def ==(other
) other
.to_s 
== self.to_s 
end 
 137           elsif @pattern !~ 
/[?*]/ 
 138             lambda 
{ |hostname
| hostname
.to_s
.downcase 
== @pattern } 
 140             re 
= self.class.pattern_to_regexp 
@pattern 
 141             lambda 
{ |hostname
| re 
=~ hostname 
} 
 146         matcher
.call hostname
 
 149       def self.pattern_to_regexp pattern
 
 150         escaped 
= Regexp
.escape(pattern
) 
 151         escaped
.gsub!
('\*', '.*') 
 152         escaped
.gsub!
('\?', '.') 
 158       host_patterns 
= [HostPattern
.new('*')] 
 160       IO
.foreach(file
) do |line
| 
 162         when /^\s*(#|$)/ then next 
 166           key, value = line.strip.split(/\s+/, 2) 
 171         value 
= $1 if value 
=~ 
/^"(.*)"$/ 
 175           host_patterns 
= value
.split(/\s+/).map 
{|p
| HostPattern
.new p 
} 
 177           record_setting key
, value
, host_patterns
 
 182     def record_setting key
, value
, patterns
 
 183       patterns
.each 
do |pattern
| 
 184         @settings[pattern
][key
] ||= value
 
 192 require 'forwardable' 
 197     attr_reader 
:config, :oauth_app_url 
 199     def initialize config
, options
 
 201       @oauth_app_url = options
.fetch(:app_url) 
 205       def self.===(exception
) 
 206         exception
.class.ancestors
.map 
{|a
| a
.to_s 
}.include? 'Net::HTTPExceptions' 
 212       'github.com' == host 
? 'api.github.com' : host
 
 215     def repo_info project
 
 216       get 
"https://%s/repos/%s/%s" % 
 217         [api_host(project
.host
), project
.owner
, project
.name
] 
 220     def repo_exists
? project
 
 221       repo_info(project
).success
? 
 224     def fork_repo project
 
 225       res 
= post 
"https://%s/repos/%s/%s/forks" % 
 226         [api_host(project
.host
), project
.owner
, project
.name
] 
 227       res
.error! 
unless res
.success
? 
 230     def create_repo project
, options 
= {} 
 231       is_org 
= project
.owner !
= config
.username(api_host(project
.host
)) 
 232       params 
= { :name => project
.name
, :private => !!options
[:private] } 
 233       params
[:description] = options
[:description] if options
[:description] 
 234       params
[:homepage]    = options
[:homepage]    if options
[:homepage] 
 237         res 
= post 
"https://%s/orgs/%s/repos" % [api_host(project
.host
), project
.owner
], params
 
 239         res 
= post 
"https://%s/user/repos" % api_host(project
.host
), params
 
 241       res
.error! 
unless res
.success
? 
 245     def pullrequest_info project
, pull_id
 
 246       res 
= get 
"https://%s/repos/%s/%s/pulls/%d" % 
 247         [api_host(project
.host
), project
.owner
, project
.name
, pull_id
] 
 248       res
.error! 
unless res
.success
? 
 252     def create_pullrequest options
 
 253       project 
= options
.fetch(:project) 
 255         :base => options
.fetch(:base), 
 256         :head => options
.fetch(:head) 
 260         params
[:issue] = options
[:issue] 
 262         params
[:title] = options
[:title] if options
[:title] 
 263         params
[:body]  = options
[:body]  if options
[:body] 
 266       res 
= post 
"https://%s/repos/%s/%s/pulls" % 
 267         [api_host(project
.host
), project
.owner
, project
.name
], params
 
 269       res
.error! 
unless res
.success
? 
 274       module ResponseMethods
 
 275         def status() code
.to_i 
end 
 276         def data?() content_type 
=~ 
/\bjson\b/ end 
 277         def data() @data ||= JSON
.parse(body
) end 
 278         def error_message
?() data? and data['errors'] || data['message'] end 
 279         def error_message() error_sentences 
|| data['message'] end 
 280         def success
?() Net
::HTTPSuccess === self end 
 282           data['errors'].map 
do |err
| 
 284             when 'custom'        then err
['message'] 
 285             when 'missing_field' then "field '%s' is missing" % err
['field'] 
 287           end.compact 
if data['errors'] 
 292         perform_request url
, :Get, &block
 
 295       def post url
, params 
= nil 
 296         perform_request url
, :Post do |req
| 
 298             req
.body 
= JSON
.dump params
 
 299             req
['Content-Type'] = 'application/json;charset=utf-8' 
 301           yield req 
if block_given
? 
 302           req
['Content-Length'] = byte_size req
.body
 
 307         if    str
.respond_to
? :bytesize then str
.bytesize
 
 308         elsif str
.respond_to
? :length   then str
.length
 
 313       def post_form url
, params
 
 314         post(url
) {|req
| req
.set_form_data params 
} 
 317       def perform_request url
, type
 
 318         url 
= URI
.parse url 
unless url
.respond_to
? :host 
 321         req 
= Net
::HTTP.const_get(type
).new 
request_uri(url
) 
 322         http 
= configure_connection(req
, url
) do |host_url
| 
 323           create_connection host_url
 
 326         apply_authentication(req
, url
) 
 327         yield req 
if block_given
? 
 330           res 
= http
.start 
{ http
.request(req
) } 
 331           res
.extend ResponseMethods
 
 333         rescue SocketError 
=> err
 
 334           raise Context
::FatalError, "error with #{type.to_s.upcase} #{url} (#{err.message})" 
 339         str 
= url
.request_uri
 
 340         str 
= '/api/v3' << str 
if url
.host !
= 'api.github.com' 
 344       def configure_connection req
, url
 
 345         if ENV['HUB_TEST_HOST'] 
 346           req
['Host'] = url
.host
 
 349           url
.host
, test_port 
= ENV['HUB_TEST_HOST'].split(':') 
 350           url
.port 
= test_port
.to_i 
if test_port
 
 355       def apply_authentication req
, url
 
 356         user 
= url
.user 
|| config
.username(url
.host
) 
 357         pass 
= config
.password(url
.host
, user
) 
 358         req
.basic_auth user
, pass
 
 361       def create_connection url
 
 362         use_ssl 
= 'https' == url
.scheme
 
 365         if proxy 
= config
.proxy_uri(use_ssl
) 
 366           proxy_args 
<< proxy
.host 
<< proxy
.port
 
 369             proxy_args
.concat proxy
.userinfo
.split(':', 2).map 
{|a
| CGI
.unescape a 
} 
 373         http 
= Net
::HTTP.new(url
.host
, url
.port
, *proxy_args
) 
 375         if http
.use_ssl 
= use_ssl
 
 376           http
.verify_mode 
= OpenSSL
::SSL::VERIFY_NONE 
 383       def apply_authentication req
, url
 
 384         if (req
.path 
=~ 
/\/authorizations
$/) 
 387           user 
= url
.user 
|| config
.username(url
.host
) 
 388           token 
= config
.oauth_token(url
.host
, user
) { 
 389             obtain_oauth_token url
.host
, user
 
 391           req
['Authorization'] = "token #{token}" 
 395       def obtain_oauth_token host
, user
 
 396         res 
= get 
"https://#{user}@#{host}/authorizations" 
 397         res
.error! 
unless res
.success
? 
 399         if found 
= res
.data.find 
{|auth
| auth
['app']['url'] == oauth_app_url 
} 
 402           res 
= post 
"https://#{user}@#{host}/authorizations", 
 403             :scopes => %w
[repo
], :note => 'hub', :note_url => oauth_app_url
 
 404           res
.error! 
unless res
.success
? 
 415       def_delegator 
:@data, :[], :get 
 416       def_delegator 
:@data, :[]=, :set 
 418       def initialize filename
 
 420         @data = Hash
.new 
{|d
, host
| d
[host
] = [] } 
 421         load 
if File
.exist
? filename
 
 425         unless entry 
= get(host
).first
 
 427           return nil if user
.nil? or user
.empty
? 
 428           entry 
= entry_for_user(host
, user
) 
 433       def fetch_value host
, user
, key
 
 434         entry 
= entry_for_user host
, user
 
 435         entry
[key
.to_s
] || begin 
 437           if value 
and !value
.empty
? 
 438             entry
[key
.to_s
] = value
 
 447       def entry_for_user host
, username
 
 449         entries
.find 
{|e
| e
['user'] == username 
} or 
 450           (entries 
<< {'user' => username
}).last
 
 454         existing_data 
= File
.read(@filename) 
 455         @data.update YAML
.load(existing_data
) unless existing_data
.strip
.empty
? 
 459         FileUtils
.mkdir_p File
.dirname(@filename) 
 460         File
.open(@filename, 'w', 0600) {|f
| f 
<< YAML
.dump(@data) } 
 470       def normalize_host host
 
 472         'api.github.com' == host 
? 'github.com' : host
 
 476         return ENV['GITHUB_USER'] unless ENV['GITHUB_USER'].to_s
.empty
? 
 477         host 
= normalize_host host
 
 478         @data.fetch_user host 
do 
 479           if block_given
? then yield 
 480           else prompt 
"#{host} username" 
 485       def api_token host
, user
 
 486         host 
= normalize_host host
 
 487         @data.fetch_value host
, user
, :api_token do 
 488           if block_given
? then yield 
 489           else prompt 
"#{host} API token for #{user}" 
 494       def password host
, user
 
 495         return ENV['GITHUB_PASSWORD'] unless ENV['GITHUB_PASSWORD'].to_s
.empty
? 
 496         host 
= normalize_host host
 
 497         @password_cache["#{user}@#{host}"] ||= prompt_password host
, user
 
 500       def oauth_token host
, user
, &block
 
 501         @data.fetch_value 
normalize_host(host
), user
, :oauth_token, &block
 
 509       def prompt_password host
, user
 
 510         print 
"#{host} password for #{user} (never stored): " 
 521         tty_state 
= `stty -g` 
 522         system 
'stty raw -echo -icanon isig' if $
?.success
? 
 524         while char 
= $stdin.getbyte 
and !
(char 
== 13 or char 
== 10) 
 525           if char 
== 127 or char 
== 8 
 526             pass
[-1,1] = '' unless pass
.empty
? 
 533         system 
"stty #{tty_state}" unless tty_state
.empty
? 
 536       def proxy_uri(with_ssl
) 
 537         env_name 
= "HTTP#{with_ssl ? 'S' : ''}_PROXY" 
 538         if proxy 
= ENV[env_name
] || ENV[env_name
.downcase
] and !proxy
.empty
? 
 539           proxy 
= "http://#{proxy}" unless proxy
.include? '://' 
 548 require 'forwardable' 
 555     NULL 
= defined?(File
::NULL) ? File
::NULL : File
.exist
?('/dev/null') ? '/dev/null' : 'NUL' 
 558       attr_reader 
:executable 
 560       def initialize(executable 
= nil, &read_proc
) 
 561         @executable = executable 
|| 'git' 
 562         read_proc 
||= lambda 
{ |cache
, cmd
| 
 563           result 
= %x{#{command_to_string(cmd)} 2>#{NULL}}.chomp
 
 564           cache
[cmd
] = $
?.success
? && !result
.empty
? ? result 
: nil 
 566         @cache = Hash
.new(&read_proc
) 
 569       def add_exec_flags(flags
) 
 570         @executable = Array(executable
).concat(flags
) 
 573       def read_config(cmd
, all 
= false) 
 574         config_cmd 
= ['config', (all 
? '--get-all' : '--get'), *cmd
] 
 575         config_cmd 
= config_cmd
.join(' ') unless cmd
.respond_to
? :join 
 583       def stub_config_value(key
, value
, get 
= '--get') 
 584         stub_command_output 
"config #{get} #{key}", value
 
 587       def stub_command_output(cmd
, value
) 
 588         @cache[cmd
] = value
.nil? ? nil : value
.to_s
 
 598         args 
= Shellwords
.shellwords(args
) if args
.respond_to
? :to_str 
 599         Array(executable
) + 
Array(args
) 
 602       def command_to_string(cmd
) 
 603         full_cmd 
= to_exec(cmd
) 
 604         full_cmd
.respond_to
?(:shelljoin) ? full_cmd
.shelljoin 
: full_cmd
.join(' ') 
 608     module GitReaderMethods
 
 611       def_delegator 
:git_reader, :read_config, :git_config 
 612       def_delegator 
:git_reader, :read, :git_command 
 614       def self.extended(base
) 
 615         base
.extend Forwardable
 
 616         base
.def_delegators 
:'self.class', :git_config, :git_command 
 620     class Error 
< RuntimeError
; end 
 621     class FatalError 
< Error
; end 
 626       @git_reader ||= GitReader
.new 
ENV['GIT'] 
 629     include GitReaderMethods
 
 630     private :git_config, :git_command 
 632     def local_repo(fatal 
= true) 
 633       @local_repo ||= begin 
 635           LocalRepo
.new git_reader
, current_dir
 
 637           raise FatalError
, "Not a git repository" 
 644       :current_project, :upstream_project, 
 645       :repo_owner, :repo_host, 
 646       :remotes, :remotes_group, :origin_remote 
 648     def_delegator 
:local_repo, :name, :repo_name 
 649     def_delegators 
:local_repo, *repo_methods
 
 650     private :repo_name, *repo_methods
 
 654         local_repo
.master_branch
 
 656         Branch
.new 
nil, 'refs/heads/master' 
 660     class LocalRepo 
< Struct
.new(:git_reader, :dir) 
 661       include GitReaderMethods
 
 664         if project 
= main_project
 
 672         if project 
= main_project
 
 678         project 
= main_project 
and project
.host
 
 682         remote 
= origin_remote 
and remote
.project
 
 686         if branch 
= current_branch 
and upstream 
= branch
.upstream 
and upstream
.remote
? 
 687           remote 
= remote_by_name upstream
.remote_name
 
 693         upstream_project 
|| main_project
 
 697         if branch 
= git_command('symbolic-ref -q HEAD') 
 698           Branch
.new 
self, branch
 
 703         Branch
.new 
self, 'refs/heads/master' 
 708           list 
= git_command('remote').to_s
.split("\n") 
 709           main 
= list
.delete('origin') and list
.unshift(main
) 
 710           list
.map 
{ |name
| Remote
.new 
self, name 
} 
 714       def remotes_group(name
) 
 715         git_config 
"remotes.#{name}" 
 722       def remote_by_name(remote_name
) 
 723         remotes
.find 
{|r
| r
.name 
== remote_name 
} 
 727         hosts 
= git_config('hub.host', :all).to_s
.split("\n") 
 728         hosts 
<< default_host
 
 729         hosts 
<< "ssh.#{default_host}" 
 732       def self.default_host
 
 733         ENV['GITHUB_HOST'] || main_host
 
 741       def_delegators 
:'self.class', :default_host, :main_host 
 744         @ssh_config ||= SshConfig
.new
 
 748     class GithubProject 
< Struct
.new(:local_repo, :owner, :name, :host) 
 749       def self.from_url(url
, local_repo
) 
 750         if local_repo
.known_hosts
.include? url
.host
 
 751           _
, owner
, name 
= url
.path
.split('/', 4) 
 752           GithubProject
.new(local_repo
, owner
, name
.sub(/\.git$/, ''), url
.host
) 
 756       attr_accessor 
:repo_data 
 758       def initialize(*args
) 
 760         self.name 
= self.name
.tr(' ', '-') 
 761         self.host 
||= (local_repo 
|| LocalRepo
).default_host
 
 762         self.host 
= host
.sub(/^ssh\./i
, '') if 'ssh.github.com' == host
.downcase
 
 766         repo_data 
? repo_data
.fetch('private') : 
 767           host !
= (local_repo 
|| LocalRepo
).main_host
 
 770       def owned_by(new_owner
) 
 772         new_project
.owner 
= new_owner
 
 781         name_with_owner 
== other
.name_with_owner
 
 785         local_repo
.remotes
.find 
{ |r
| r
.project 
== self } 
 788       def web_url(path 
= nil) 
 789         project_name 
= name_with_owner
 
 790         if project_name
.sub!
(/\.wiki$/, '') 
 791           unless '/wiki' == path
 
 792             path 
= if path 
=~ 
%r
{^
/commits/} then '/_history' 
 793                    else path
.to_s
.sub(/\w+/, '_\0') 
 795             path 
= '/wiki' + path
 
 798         "https://#{host}/" + project_name + path
.to_s
 
 801       def git_url(options 
= {}) 
 802         if options
[:https] then "https://#{host}/" 
 803         elsif options
[:private] or private? then "git@#{host}:" 
 804         else "git://#{host}/" 
 805         end + name_with_owner + 
'.git' 
 809     class GithubURL 
< URI
::HTTPS 
 813       def_delegator 
:project, :name, :project_name 
 814       def_delegator 
:project, :owner, :project_owner 
 816       def self.resolve(url
, local_repo
) 
 818         if %[http https
].include? u
.scheme 
and project 
= GithubProject
.from_url(u
, local_repo
) 
 819           self.new(u
.scheme
, u
.userinfo
, u
.host
, u
.port
, u
.registry
, 
 820                    u
.path
, u
.opaque
, u
.query
, u
.fragment
, project
) 
 822       rescue URI
::InvalidURIError 
 826       def initialize(*args
) 
 832         path
.split('/', 4)[3] 
 836     class Branch 
< Struct
.new(:local_repo, :name) 
 840         name
.sub(%r
{^refs
/(remotes
/)?.+
?/}, '') 
 844         short_name 
== 'master' 
 848         if branch 
= local_repo
.git_command("rev-parse --symbolic-full-name #{short_name}@{upstream}") 
 849           Branch
.new local_repo
, branch
 
 854         name
.index('refs/remotes/') == 0 
 858         name 
=~ 
%r
{^refs
/remotes
/([^
/]+
)} and $1 or 
 859           raise Error
, "can't get remote name from #{name.inspect}" 
 863     class Remote 
< Struct
.new(:local_repo, :name) 
 867         other
.respond_to
?(:to_str) ? name 
== other
.to_str 
: super 
 871         urls
.each_value 
{ |url
| 
 872           if valid 
= GithubProject
.from_url(url
, local_repo
) 
 880         return @urls if defined? @urls 
 882         local_repo
.git_command('remote -v').to_s
.split("\n").map 
do |line
| 
 883           next if line !~ 
/^(.+?)\t(.+) \((.+)\)$/ 
 884           remote
, uri
, type 
= $1, $2, $3 
 885           next if remote !
= self.name
 
 886           if uri 
=~ 
%r
{^
[\w-
]+
://} or uri 
=~ 
%r
{^
([^
/]+
?):} 
 887             uri 
= "ssh://#{$1}/#{$'}" if $1 
 889               @urls[type
] = uri_parse(uri
) 
 890             rescue URI
::InvalidURIError 
 899         uri
.host 
= local_repo
.ssh_config
.get_value(uri
.host
, 'hostname') { uri
.host 
} 
 900         uri
.user 
= local_repo
.ssh_config
.get_value(uri
.host
, 'user') { uri
.user 
} 
 906     def github_project(name
, owner 
= nil) 
 907       if owner 
and owner
.index('/') 
 908         owner
, name 
= owner
.split('/', 2) 
 909       elsif name 
and name
.index('/') 
 910         owner
, name 
= name
.split('/', 2) 
 913         owner 
||= github_user
 
 916       if local_repo(false) and main_project 
= local_repo
.main_project
 
 917         project 
= main_project
.dup
 
 918         project
.owner 
= owner
 
 922         GithubProject
.new(local_repo(false), owner
, name
) 
 926     def git_url(owner 
= nil, name 
= nil, options 
= {}) 
 927       project 
= github_project(name
, owner
) 
 928       project
.git_url({:https => https_protocol
?}.update(options
)) 
 931     def resolve_github_url(url
) 
 932       GithubURL
.resolve(url
, local_repo
) if url 
=~ 
/^https?:/ 
 936       git_config('--bool hub.http-clone') == 'true' 
 940       git_config('hub.protocol') == 'https' or http_clone
? 
 943     def git_alias_for(name
) 
 944       git_config 
"alias.#{name}" 
 948       git_command("rev-list --cherry-pick --right-only --no-merges #{a}...#{b}") 
 958       git_command 
'rev-parse -q --git-dir' 
 966       editor 
= git_command 
'var GIT_EDITOR' 
 967       editor 
= ENV[$1] if editor 
=~ 
/^\$(\w+)$/ 
 968       editor 
= File
.expand_path editor 
if (editor 
=~ 
/^[~.]/ or editor
.index('/')) and editor !~ 
/["']/ 
 974         browser = ENV['BROWSER'] || ( 
 975           osx? ? 'open' : windows? ? %w[cmd /c start] : 
 976           %w[xdg-open cygstart x-www-browser firefox opera mozilla netscape].find { |comm| which comm } 
 979         abort "Please set 
$BROWSER to a web launcher to use this command
." unless browser 
 985         RbConfig::CONFIG['host_os'].to_s.include?('darwin') 
 990         RbConfig::CONFIG['host_os'] =~ /msdos|mswin|djgpp|mingw|windows/ 
 994         exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : [''] 
 995         ENV['PATH'].split(File::PATH_SEPARATOR).each do |path| 
 997             exe = "#{path}/#{cmd}#{ext}" 
 998             return exe if File.executable? exe 
1015 require 'forwardable' 
1018   def self.parse(data) new(data).parse 
end 
1021   OBJ 
= /[{\[]/;    HEN 
= /\}/;  AEN 
= /\]/ 
1022   COL 
= /\s*:\s*/;  KEY 
= /\s*,\s*/ 
1023   NUM 
= /-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?/ 
1024   BOL 
= /true|false/;  NUL 
= /null/ 
1028   attr_reader 
:scanner 
1029   alias_method 
:s, :scanner 
1030   def_delegators 
:scanner, :scan, :matched 
1031   private :s, :scan, :matched 
1034     @scanner = StringScanner
.new 
data.to_s
 
1044   def space() scan WSP 
end 
1046   def endkey() scan(KEY
) or space 
end 
1049     matched 
== '{' ? hash 
: array 
if scan(OBJ
) 
1055       scan(BOL
) ? matched
.size 
== 4: 
1056       scan(NUM
) ? eval(matched
) : 
1063     repeat_until(HEN
) { k 
= string
; scan(COL
); obj
[k
] = value
; endkey 
} 
1070     repeat_until(AEN
) { ary 
<< value
; endkey 
} 
1074   SPEC 
= {'b' => "\b", 'f' => "\f", 'n' => "\n", 'r' => "\r", 't' => "\t"} 
1075   UNI 
= 'u'; CODE 
= /[a-fA-F0-9]{4}/ 
1076   STR 
= /"/; STE 
= '"' 
1081       str
, esc 
= '', false 
1084           str 
<< (c 
== UNI 
? (s
.scan(CODE
) || error
).to_i(16).chr 
: SPEC
[c
] || c
) 
1088           when ESC 
then esc 
= true 
1099     raise "parse error at: #{scan(/.{1,10}/m).inspect}" 
1102   def repeat_until reg
 
1106       error 
unless s
.pos 
> pos
 
1112       raise ArgumentError 
unless obj
.is_a
? Array 
or obj
.is_a
? Hash
 
1119     def generate_type(obj
) 
1120       type 
= obj
.is_a
?(Numeric
) ? :Numeric : obj
.class.name
 
1121       begin send(:"generate_#{type}", obj
) 
1122       rescue NoMethodError
; raise ArgumentError
, "can't serialize #{type}" 
1126     ESC_MAP 
= Hash
.new 
{|h
,k
| k 
}.update \
 
1133     def generate_String(str
) 
1134       escaped 
= str
.gsub(/[\r\n\f\t\b"\\]/) { "\\#{ESC_MAP[$&]}"} 
1138     def generate_simple(obj
) obj
.inspect 
end 
1139     alias generate_Numeric generate_simple
 
1140     alias generate_TrueClass generate_simple
 
1141     alias generate_FalseClass generate_simple
 
1143     def generate_Symbol(sym
) generate_String(sym
.to_s
) end 
1145     def generate_NilClass(*) 'null' end 
1147     def generate_Array(ary
) '[%s]' % ary
.map 
{|o
| generate_type(o
) }.join(', ') end 
1149     def generate_Hash(hash
) 
1150       '{%s}' % hash
.map 
{ |key
, value
| 
1151         "#{generate_String(key.to_s)}: #{generate_type(value)}" 
1161     instance_methods
.each 
{ |m
| undef_method(m
) unless m 
=~ 
/(^__|send|to\?$)/ } 
1166     NAME_RE 
= /[\w.][\w.-]*/ 
1167     OWNER_RE 
= /[a-zA-Z0-9-]+/ 
1168     NAME_WITH_OWNER_RE 
= /^(?:#{NAME_RE}|#{OWNER_RE}\/#{NAME_RE})$/ 
1170     CUSTOM_COMMANDS 
= %w
[alias create browse compare fork pull-request
] 
1173       slurp_global_flags(args
) 
1175       args
.unshift 
'help' if args
.empty
? 
1178       if expanded_args 
= expand_alias(cmd
) 
1179         cmd 
= expanded_args
[0] 
1180         expanded_args
.concat args
[1..-1] 
1183       respect_help_flags(expanded_args 
|| args
) if custom_command
? cmd
 
1185       cmd 
= cmd
.gsub(/(\w)-/, '\1_') 
1186       if method_defined
?(cmd
) and cmd !
= 'run' 
1187         args
.replace expanded_args 
if expanded_args
 
1190     rescue Errno
::ENOENT 
1191       if $!
.message
.include? "No such file or directory - git" 
1192         abort 
"Error: `git` command not found" 
1196     rescue Context
::FatalError => err
 
1197       abort 
"fatal: #{err.message}" 
1200     def pull_request(args
) 
1203       force 
= explicit_owner 
= false 
1204       base_project 
= local_repo
.main_project
 
1205       head_project 
= local_repo
.current_project
 
1208         abort 
"Aborted: the origin remote doesn't point to a GitHub repository." 
1211       from_github_ref 
= lambda 
do |ref
, context_project
| 
1213           owner
, ref 
= ref
.split(':', 2) 
1214           project 
= github_project(context_project
.name
, owner
) 
1216         [project 
|| context_project
, ref
] 
1219       while arg 
= args
.shift
 
1224           base_project
, options
[:base] = from_github_ref
.call(args
.shift
, base_project
) 
1227           explicit_owner 
= !!head
.index(':') 
1228           head_project
, options
[:head] = from_github_ref
.call(head
, head_project
) 
1230           options
[:issue] = args
.shift
 
1232           if url 
= resolve_github_url(arg
) and url
.project_path 
=~ 
/^issues\/(\d+
)/ 
1233             options
[:issue] = $1 
1234             base_project 
= url
.project
 
1235           elsif !options
[:title] then options
[:title] = arg
 
1237             abort 
"invalid argument: #{arg}" 
1242       options
[:project] = base_project
 
1243       options
[:base] ||= master_branch
.short_name
 
1245       if tracked_branch 
= options
[:head].nil? && current_branch
.upstream
 
1246         if !tracked_branch
.remote
? 
1247           tracked_branch 
= nil 
1248         elsif base_project 
== head_project 
and tracked_branch
.short_name 
== options
[:base] 
1249           $stderr.puts 
"Aborted: head branch is the same as base (#{options[:base].inspect})" 
1250           warn 
"(use `-h <branch>` to specify an explicit pull request head)" 
1254       options
[:head] ||= (tracked_branch 
|| current_branch
).short_name
 
1256       user 
= github_user(head_project
.host
) 
1257       if head_project
.owner !
= user 
and !tracked_branch 
and !explicit_owner
 
1258         head_project 
= head_project
.owned_by(user
) 
1261       remote_branch 
= "#{head_project.remote}/#{options[:head]}" 
1262       options
[:head] = "#{head_project.owner}:#{options[:head]}" 
1264       if !force 
and tracked_branch 
and local_commits 
= rev_list(remote_branch
, nil) 
1265         $stderr.puts 
"Aborted: #{local_commits.split("\n").size} commits are not yet pushed to #{remote_branch}" 
1266         warn 
"(use `-f` to force submit a pull request anyway)" 
1271         puts 
"Would request a pull to #{base_project.owner}:#{options[:base]} from #{options[:head]}" 
1275       unless options
[:title] or options
[:issue] 
1276         base_branch 
= "#{base_project.remote}/#{options[:base]}" 
1277         commits 
= rev_list(base_branch
, remote_branch
).to_s
.split("\n") 
1281           default_message 
= commit_summary 
= nil 
1283           format 
= '%w(78,0,0)%s%n%+b
' 
1284           default_message = git_command "show -s --format='#{format}' #{commits.first}" 
1285           commit_summary = nil 
1287           format = '%h (%aN
, %ar
)%n
%w(78,3,3)%s
%n
%+b
' 
1288           default_message = nil 
1289           commit_summary = git_command "log --no-color --format='%s
' --cherry %s...%s" % 
1290             [format, base_branch, remote_branch] 
1293         options[:title], options[:body] = pullrequest_editmsg(commit_summary) { |msg| 
1294           msg.puts default_message if default_message 
1296           msg.puts "# Requesting a pull to #{base_project.owner}:#{options[:base]} from #{options[:head]}" 
1298           msg.puts "# Write a message for this pull request. The first block" 
1299           msg.puts "# of text is the title and the rest is description." 
1303       pull = api_client.create_pullrequest(options) 
1305       args.executable = 'echo
' 
1306       args.replace [pull['html_url
']] 
1307     rescue GitHubAPI::Exceptions 
1308       display_api_exception("creating pull request", $!.response
) 
1313       ssh 
= args
.delete('-p') 
1314       has_values 
= /^(--(upload-pack|template|depth|origin|branch|reference)|-[ubo])$/ 
1317       while idx 
< args
.length
 
1319         if arg
.index('-') == 0 
1320           idx +
= 1 if arg 
=~ has_values
 
1322           if arg 
=~ NAME_WITH_OWNER_RE 
and !File
.directory
?(arg
) 
1323             name
, owner 
= arg
, nil 
1324             owner
, name 
= name
.split('/', 2) if name
.index('/') 
1325             project 
= github_project(name
, owner 
|| github_user
) 
1326             ssh 
||= args
[0] !
= 'submodule' && project
.owner 
== github_user(project
.host
) { } 
1327             args
[idx
] = project
.git_url(:private => ssh
, :https => https_protocol
?) 
1336       return unless index 
= args
.index('add') 
1337       args
.delete_at index
 
1339       branch 
= args
.index('-b') || args
.index('--branch') 
1341         args
.delete_at branch
 
1342         branch_name 
= args
.delete_at branch
 
1348         args
.insert branch
, '-b', branch_name
 
1350       args
.insert index
, 'add' 
1354       if %w
[add set-url
].include?(args
[1]) 
1356         if name 
=~ 
/^(#{OWNER_RE})$/ || name 
=~ 
/^(#{OWNER_RE})\/(#{NAME_RE})$/ 
1357           user
, repo 
= $1, $2 || repo_name
 
1360       return unless user 
# do not touch arguments 
1362       ssh 
= args
.delete('-p') 
1364       if args
.words
[2] == 'origin' && args
.words
[3].nil? 
1365         user
, repo 
= github_user
, repo_name
 
1366       elsif args
.words
[-2] == args
.words
[1] 
1367         idx 
= args
.index( args
.words
[-1] ) 
1373       args 
<< git_url(user
, repo
, :private => ssh
) 
1377       if args
.include?('--multiple') 
1378         names 
= args
.words
[1..-1] 
1379       elsif remote_name 
= args
.words
[1] 
1380         if remote_name 
=~ 
/^\w+(,\w+)+$/ 
1381           index 
= args
.index(remote_name
) 
1382           args
.delete(remote_name
) 
1383           names 
= remote_name
.split(',') 
1384           args
.insert(index
, *names
) 
1385           args
.insert(index
, '--multiple') 
1387           names 
= [remote_name
] 
1393       projects 
= names
.map 
{ |name
| 
1394         unless name 
=~ 
/\W/ or remotes
.include?(name
) or remotes_group(name
) 
1395           project 
= github_project(nil, name
) 
1396           repo_info 
= api_client
.repo_info(project
) 
1397           if repo_info
.success
? 
1398             project
.repo_data 
= repo_info
.data 
1405         projects
.each 
do |project
| 
1406           args
.before 
['remote', 'add', project
.owner
, project
.git_url(:https => https_protocol
?)] 
1412       _
, url_arg
, new_branch_name 
= args
.words
 
1413       if url 
= resolve_github_url(url_arg
) and url
.project_path 
=~ 
/^pull\/(\d+
)/ 
1415         pull_data 
= api_client
.pullrequest_info(url
.project
, pull_id
) 
1417         args
.delete new_branch_name
 
1418         user
, branch 
= pull_data
['head']['label'].split(':', 2) 
1419         abort 
"Error: #{user}'s fork is not available anymore" unless pull_data
['head']['repo'] 
1420         new_branch_name 
||= "#{user}-#{branch}" 
1422         if remotes
.include? user
 
1423           args
.before 
['remote', 'set-branches', '--add', user
, branch
] 
1424           args
.before 
['fetch', user
, "+refs
/heads
/#{branch}:refs/remotes
/#{user}/#{branch}"] 
1426           url = github_project(url.project_name, user).git_url(:private => pull_data['head']['repo']['private'], 
1427                                                                :https => https_protocol?) 
1428           args.before ['remote', 'add', '-f', '-t', branch, user, url] 
1430         idx = args.index url_arg 
1432         args.insert idx, '--track', '-B', new_branch_name, "#{user}/#{branch}" 
1437       _, url_arg = args.words 
1438       if url = resolve_github_url(url_arg) and url.project_path =~ /^pull\/(\d+)/ 
1440         pull_data 
= api_client
.pullrequest_info(url
.project
, pull_id
) 
1442         user
, branch 
= pull_data
['head']['label'].split(':', 2) 
1443         abort 
"Error: #{user}'s fork is not available anymore" unless pull_data
['head']['repo'] 
1445         url 
= github_project(url
.project_name
, user
).git_url(:private => pull_data
['head']['repo']['private'], 
1446                                                              :https => https_protocol
?) 
1448         merge_head 
= "#{user}/#{branch}" 
1449         args
.before 
['fetch', url
, "+refs
/heads
/#{branch}:refs/remotes
/#{merge_head}"] 
1451         idx = args.index url_arg 
1453         args.insert idx, merge_head, '--no-ff', '-m', 
1454                     "Merge pull request 
##{pull_id} from #{merge_head}\n\n#{pull_data['title']}" 
1458     def cherry_pick(args
) 
1459       unless args
.include?('-m') or args
.include?('--mainline') 
1460         ref 
= args
.words
.last
 
1461         if url 
= resolve_github_url(ref
) and url
.project_path 
=~ 
/^commit\/([a-f0-9
]{7,40})/ 
1463           project 
= url
.project
 
1464         elsif ref 
=~ 
/^(#{OWNER_RE})@([a-f0-9]{7,40})$/ 
1466           project 
= local_repo
.main_project
.owned_by(owner
) 
1470           args
[args
.index(ref
)] = sha
 
1472           if remote 
= project
.remote 
and remotes
.include? remote
 
1473             args
.before 
['fetch', remote
.to_s
] 
1475             args
.before 
['remote', 'add', '-f', project
.owner
, project
.git_url(:https => https_protocol
?)] 
1482       if url 
= args
.find 
{ |a
| a 
=~ 
%r
{^https
?://(gist\
.)?github\
.com
/} } 
1483         idx 
= args
.index(url
) 
1484         gist 
= $1 == 'gist.' 
1485         url 
= url
.sub(/#.+/, '') 
1486         url 
= url
.sub(%r
{(/pull/\d+
)/\w
*$
}, '\1') unless gist
 
1487         ext 
= gist 
? '.txt' : '.patch' 
1488         url +
= ext 
unless File
.extname(url
) == ext
 
1489         patch_file 
= File
.join(ENV['TMPDIR'] || '/tmp', "#{gist ? 'gist-' : ''}#{File.basename(url)}") 
1490         args
.before 
'curl', ['-#LA', "hub #{Hub::Version}", url
, '-o', patch_file
] 
1491         args
[idx
] = patch_file
 
1495     alias_method 
:apply, :am 
1498       if args
.delete('-g') 
1499         project 
= github_project(File
.basename(current_dir
)) 
1500         url 
= project
.git_url(:private => true, :https => https_protocol
?) 
1501         args
.after 
['remote', 'add', 'origin', url
] 
1506       unless project 
= local_repo
.main_project
 
1507         abort 
"Error: repository under 'origin' remote is not a GitHub project" 
1509       forked_project 
= project
.owned_by(github_user(project
.host
)) 
1511       existing_repo 
= api_client
.repo_info(forked_project
) 
1512       if existing_repo
.success
? 
1513         parent_data 
= existing_repo
.data['parent'] 
1514         parent_url  
= parent_data 
&& resolve_github_url(parent_data
['html_url']) 
1515         if !parent_url 
or parent_url
.project !
= project
 
1516           abort 
"Error creating fork: %s already exists on %s" % 
1517             [ forked_project
.name_with_owner
, forked_project
.host 
] 
1520         api_client
.fork_repo(project
) unless args
.noop
? 
1523       if args
.include?('--no-remote') 
1526         url 
= forked_project
.git_url(:private => true, :https => https_protocol
?) 
1527         args
.replace 
%W
"remote add -f #{forked_project.owner} #{url}" 
1528         args
.after 
'echo', ['new remote:', forked_project
.owner
] 
1530     rescue GitHubAPI
::Exceptions 
1531       display_api_exception("creating fork", $!
.response
) 
1537         abort 
"'create' must be run from inside a git repository" 
1542         options
[:private] = true if args
.delete('-p') 
1546           case arg 
= args
.shift
 
1548             options
[:description] = args
.shift
 
1550             options
[:homepage] = args
.shift
 
1552             if arg 
=~ 
/^[^-]/ and new_repo_name
.nil? 
1554               owner
, new_repo_name 
= new_repo_name
.split('/', 2) if new_repo_name
.index('/') 
1556               abort 
"invalid argument: #{arg}" 
1560         new_repo_name 
||= repo_name
 
1561         new_project 
= github_project(new_repo_name
, owner
) 
1563         if api_client
.repo_exists
?(new_project
) 
1564           warn 
"#{new_project.name_with_owner} already exists on #{new_project.host}" 
1565           action 
= "set remote origin" 
1567           action 
= "created repository" 
1569             repo_data 
= api_client
.create_repo(new_project
, options
) 
1570             new_project 
= github_project(repo_data
['full_name']) 
1574         url 
= new_project
.git_url(:private => true, :https => https_protocol
?) 
1576         if remotes
.first !
= 'origin' 
1577           args
.replace 
%W
"remote add -f origin #{url}" 
1579           args
.replace 
%W
"remote -v" 
1582         args
.after 
'echo', ["#{action}:", new_project
.name_with_owner
] 
1584     rescue GitHubAPI
::Exceptions 
1585       display_api_exception("creating repository", $!
.response
) 
1590       return if args
[1].nil? || !args
[1].index(',') 
1592       refs    
= args
.words
[2..-1] 
1593       remotes 
= args
[1].split(',') 
1594       args
[1] = remotes
.shift
 
1597         refs 
= [current_branch
.short_name
] 
1601       remotes
.each 
do |name
| 
1602         args
.after 
['push', name
, *refs
] 
1608       browse_command(args
) do 
1610         dest 
= nil if dest 
== '--' 
1613           project 
= github_project dest
 
1614           branch 
= master_branch
 
1616           project 
= current_project
 
1617           branch 
= current_branch 
&& current_branch
.upstream 
|| master_branch
 
1620         abort 
"Usage: hub browse [<USER>/]<REPOSITORY>" unless project
 
1622         path 
= case subpage 
= args
.shift
 
1624           "/commits/#{branch.short_name}" 
1625         when 'tree', NilClass
 
1626           "/tree/#{branch.short_name}" if branch 
and !branch
.master
? 
1631         project
.web_url(path
) 
1637       browse_command(args
) do 
1639           branch 
= current_branch
.upstream
 
1640           if branch 
and not branch
.master
? 
1641             range 
= branch
.short_name
 
1642             project 
= current_project
 
1644             abort 
"Usage: hub compare [USER] [<START>...]<END>" 
1647           sha_or_tag 
= /(\w{1,2}|\w[\w.-]+\w)/ 
1648           range 
= args
.pop
.sub(/^#{sha_or_tag}\.\.#{sha_or_tag}$/, '\1...\2') 
1649           project 
= if owner 
= args
.pop 
then github_project(nil, owner
) 
1650                     else current_project
 
1654         project
.web_url 
"/compare/#{range}" 
1659       return help(args
) unless args
[1] == 'standalone' 
1660       require 'hub/standalone' 
1661       Hub
::Standalone.build 
$stdout 
1664       abort 
"hub is already running in standalone mode." 
1666       exit 
# ignore broken pipe 
1670       shells 
= %w
[bash zsh sh ksh csh fish
] 
1672       script 
= !!args
.delete('-s') 
1673       shell 
= args
[1] || ENV['SHELL'] 
1674       abort 
"hub alias: unknown shell" if shell
.nil? or shell
.empty
? 
1675       shell 
= File
.basename shell
 
1677       unless shells
.include? shell
 
1678         $stderr.puts 
"hub alias: unsupported shell" 
1679         warn 
"supported shells: #{shells.join(' ')}" 
1684         puts 
"alias git=hub" 
1686           puts 
"if type compdef >/dev/null; then" 
1687           puts 
"   compdef hub=git" 
1691         profile 
= case shell
 
1692           when 'bash' then '~/.bash_profile' 
1693           when 'zsh'  then '~/.zshrc' 
1694           when 'ksh'  then '~/.profile' 
1699         puts 
"# Wrap git automatically by adding the following to #{profile}:" 
1701         puts 
'eval "$(hub alias -s)"' 
1708       args
.after 
'echo', ['hub version', Version
] 
1710     alias_method 
"--version", :version 
1713       command 
= args
.words
[1] 
1718       elsif command
.nil? && !args
.has_flag
?('-a', '--all') 
1719         ENV['GIT_PAGER'] = '' unless args
.has_flag
?('-p', '--paginate') # Use `cat`. 
1720         puts improved_help_text
 
1724     alias_method 
"--help", :help 
1729       @api_client ||= begin 
1730         config_file 
= ENV['HUB_CONFIG'] || '~/.config/hub' 
1731         file_store 
= GitHubAPI
::FileStore.new File
.expand_path(config_file
) 
1732         file_config 
= GitHubAPI
::Configuration.new file_store
 
1733         GitHubAPI
.new file_config
, :app_url => 'http://defunkt.io/hub/' 
1737     def github_user host 
= nil, &block
 
1738       host 
||= (local_repo(false) || Context
::LocalRepo).default_host
 
1739       api_client
.config
.username(host
, &block
) 
1742     def custom_command
? cmd
 
1743       CUSTOM_COMMANDS
.include? cmd
 
1746     def respect_help_flags args
 
1747       return if args
.size 
> 2 
1750         pattern 
= /(git|hub) #{Regexp.escape args[0].gsub('-', '\-')}/ 
1751         hub_raw_manpage
.each_line 
{ |line
| 
1753             $stderr.print 
"Usage: " 
1754             $stderr.puts line
.gsub(/\\f./, '').gsub('\-', '-') 
1758         abort 
"Error: couldn't find usage help for #{args[0]}" 
1765     def improved_help_text
 
1767 usage: git [--version] [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path] 
1768            [-p|--paginate|--no-pager] [--no-replace-objects] [--bare] 
1769            [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>] 
1770            [-c name=value] [--help] 
1774    init       Create an empty git repository 
or reinitialize an existing one
 
1775    add        Add new 
or modified files to the staging area
 
1776    rm         Remove files from the working directory 
and staging area
 
1777    mv         Move 
or rename a file
, a directory
, or a symlink
 
1778    status     Show the status of the working directory 
and staging area
 
1779    commit     Record changes to the repository
 
1782    log        Show the commit history log
 
1783    diff       Show changes between commits
, commit 
and working tree
, etc
 
1784    show       Show information about commits
, tags 
or files
 
1787    branch     List
, create
, or delete branches
 
1788    checkout   Switch the active branch to another branch
 
1789    merge      Join two 
or more development 
histories (branches
) together
 
1790    tag        Create
, list
, delete
, sign 
or verify a tag object
 
1793    clone      Clone a remote repository into a new directory
 
1794    fetch      Download 
data, tags 
and branches from a remote repository
 
1795    pull       Fetch from 
and merge with another repository 
or a local branch
 
1796    push       Upload 
data, tags 
and branches to a remote repository
 
1797    remote     View 
and manage a set of remote repositories
 
1800    reset      Reset your staging area 
or working directory to another point
 
1801    rebase     Re-apply a series of patches 
in one branch onto another
 
1802    bisect     Find by binary search the change that introduced a bug
 
1803    grep       Print files with lines matching a pattern 
in your codebase
 
1806    pull-request   Open a pull request on GitHub
 
1807    fork           Make a fork of a remote repository on GitHub 
and add as remote
 
1808    create         Create this repository on GitHub 
and add GitHub as origin
 
1809    browse         Open a GitHub page 
in the default browser
 
1810    compare        Open a compare page on GitHub
 
1812 See 
'git help <command>' for more information on a specific command
. 
1816     def slurp_global_flags(args
) 
1817       flags 
= %w
[ --noop 
-c 
-p 
--paginate 
--no-pager 
--no-replace-objects 
--bare 
--version --help 
] 
1818       flags2 
= %w
[ --exec-path
= --git-dir
= --work-tree
= ] 
1823       while args
[0] && (flags
.include?(args
[0]) || flags2
.any
? {|f
| args
[0].index(f
) == 0 }) 
1828         when '--version', '--help' 
1829           args
.unshift flag
.sub('--', '') 
1831           config_pair 
= args
.shift
 
1832           key
, value 
= config_pair
.split('=', 2) 
1833           git_reader
.stub_config_value(key
, value
) 
1835           globals 
<< flag 
<< config_pair
 
1836         when '-p', '--paginate', '--no-pager' 
1843       git_reader
.add_exec_flags(globals
) 
1844       args
.add_exec_flags(globals
) 
1845       args
.add_exec_flags(locals
) 
1848     def browse_command(args
) 
1849       url_only 
= args
.delete('-u') 
1850       warn 
"Warning: the `-p` flag has no effect anymore" if args
.delete('-p') 
1853       args
.executable 
= url_only 
? 'echo' : browser_launcher
 
1858       abort 
"** Can't find groff(1)" unless command
?('groff') 
1862       Open3
.popen3(groff_command
) do |stdin, stdout, _
| 
1863         stdin.puts hub_raw_manpage
 
1865         out 
= stdout.read
.strip
 
1871       "groff -Wall -mtty-char -mandoc -Tascii" 
1875       if File
.exists
? file 
= File
.dirname(__FILE__
) + 
'/../../man/hub.1' 
1888       return if not $stdout.tty
? or windows
? 
1890       read
, write 
= IO
.pipe
 
1897         ENV['LESS'] = 'FSRX' 
1899         Kernel
.select 
[STDIN] 
1901         pager 
= ENV['GIT_PAGER'] || 
1902           `git config --get-all core.pager`.split
.first 
|| ENV['PAGER'] || 
1905         pager 
= 'cat' if pager
.empty
? 
1907         exec pager 
rescue exec 
"/bin/sh", "-c", pager
 
1909         $stdout.reopen(write
) 
1910         $stderr.reopen(write
) if $stderr.tty
? 
1914     rescue NotImplementedError
 
1917     def pullrequest_editmsg(changes
) 
1918       message_file 
= File
.join(git_dir
, 'PULLREQ_EDITMSG') 
1919       File
.open(message_file
, 'w') { |msg
| 
1922           msg
.puts 
"#\n# Changes:\n#" 
1923           msg
.puts changes
.gsub(/^/, '# ').gsub(/ +$/, '') 
1926       edit_cmd 
= Array(git_editor
).dup
 
1927       edit_cmd 
<< '-c' << 'set ft=gitcommit' if edit_cmd
[0] =~ 
/^[mg]?vim$/ 
1928       edit_cmd 
<< message_file
 
1930       abort 
"can't open text editor for pull request message" unless $
?.success
? 
1931       title
, body 
= read_editmsg(message_file
) 
1932       abort 
"Aborting due to empty pull request title" unless title
 
1936     def read_editmsg(file
) 
1937       title
, body 
= '', '' 
1938       File
.open(file
, 'r') { |msg
| 
1939         msg
.each_line 
do |line
| 
1940           next if line
.index('#') == 0 
1941           ((body
.empty
? and line 
=~ 
/\S/) ? title 
: body
) << line
 
1944       title
.tr!
("\n", ' ') 
1948       [title 
=~ 
/\S/ ? title 
: nil, body 
=~ 
/\S/ ? body 
: nil] 
1951     def expand_alias(cmd
) 
1952       if expanded 
= git_alias_for(cmd
) 
1953         if expanded
.index('!') != 0 
1954           require 'shellwords' unless defined?(::Shellwords) 
1955           Shellwords
.shellwords(expanded
) 
1960     def display_api_exception(action
, response
) 
1961       $stderr.puts 
"Error #{action}: #{response.message.strip} (HTTP #{response.status})" 
1962       if 422 == response
.status 
and response
.error_message
? 
1963         msg 
= response
.error_message
 
1964         msg 
= msg
.join("\n") if msg
.respond_to
? :join 
1976     def initialize(*args
) 
1977       @args = Args
.new(args
) 
1981     def self.execute(*args
) 
1994       args
.commands
.map 
do |cmd
| 
1995         if cmd
.respond_to
?(:join) 
1996           cmd
.map 
{ |arg
| arg 
= arg
.to_s
; (arg
.index(' ') || arg
.empty
?) ? "'#{arg}'" : arg 
}.join(' ') 
2006       elsif not args
.skip
? 
2008           execute_command_chain
 
2015     def execute_command_chain
 
2016       commands 
= args
.commands
 
2017       commands
.each_with_index 
do |cmd
, i
| 
2018         if cmd
.respond_to
?(:call) then cmd
.call
 
2019         elsif i 
== commands
.length 
- 1 
2022           exit($
?.exitstatus
) unless system(*cmd
) 
2029 Hub
::Runner.execute(*ARGV) 
2032 .\" generated with Ronn
/v0
.7
.3 
2033 .\" http
://github
.com
/rtomayko
/ronn
/tree/0.7.3 
2035 .TH 
"HUB" "1" "November 2012" "DEFUNKT" "Git Manual" 
2038 \fBhub
\fR \
- git + hub 
= github
 
2041 \fBhub
\fR 
[\fB\
-\
-noop
\fR
] \fICOMMAND
\fR 
\fIOPTIONS
\fR
 
2044 \fBhub 
alias\fR 
[\fB\
-s
\fR
] [\fISHELL
\fR
] 
2046 .SS 
"Expanded git commands:" 
2047 \fBgit init \
-g
\fR 
\fIOPTIONS
\fR
 
2050 \fBgit clone
\fR 
[\fB\
-p
\fR
] \fIOPTIONS
\fR 
[\fIUSER
\fR
/]\fIREPOSITORY
\fR 
\fIDIRECTORY
\fR
 
2053 \fBgit remote add
\fR 
[\fB\
-p
\fR
] \fIOPTIONS
\fR 
\fIUSER
\fR
[/\fIREPOSITORY
\fR
] 
2056 \fBgit remote set\
-url
\fR 
[\fB\
-p
\fR
] \fIOPTIONS
\fR 
\fIREMOTE\
-NAME
\fR 
\fIUSER
\fR
[/\fIREPOSITORY
\fR
] 
2059 \fBgit fetch
\fR 
\fIUSER\
-1\fR
,[\fIUSER\
-2\fR
,\
.\
.\
.] 
2062 \fBgit checkout
\fR 
\fIPULLREQ\
-URL
\fR 
[\fIBRANCH
\fR
] 
2065 \fBgit merge
\fR 
\fIPULLREQ\
-URL
\fR
 
2068 \fBgit cherry\
-pick
\fR 
\fIGITHUB\
-REF
\fR
 
2071 \fBgit am
\fR 
\fIGITHUB\
-URL
\fR
 
2074 \fBgit apply
\fR 
\fIGITHUB\
-URL
\fR
 
2077 \fBgit push
\fR 
\fIREMOTE\
-1\fR
,\fIREMOTE\
-2\fR
,\
.\
.\
.,\fIREMOTE\
-N
\fR 
[\fIREF
\fR
] 
2080 \fBgit submodule add
\fR 
[\fB\
-p
\fR
] \fIOPTIONS
\fR 
[\fIUSER
\fR
/]\fIREPOSITORY
\fR 
\fIDIRECTORY
\fR
 
2082 .SS 
"Custom git commands:" 
2083 \fBgit create
\fR 
[\fINAME
\fR
] [\fB\
-p
\fR
] [\fB\
-d
\fR 
\fIDESCRIPTION
\fR
] [\fB\
-h
\fR 
\fIHOMEPAGE
\fR
] 
2086 \fBgit browse
\fR 
[\fB\
-u
\fR
] [[\fIUSER
\fR
\fB
/\fR
]\fIREPOSITORY
\fR
] [SUBPAGE
] 
2089 \fBgit compare
\fR 
[\fB\
-u
\fR
] [\fIUSER
\fR
] [\fISTART
\fR\
.\
.\
.]\fIEND
\fR
 
2092 \fBgit fork
\fR 
[\fB\
-\
-no\
-remote
\fR
] 
2095 \fBgit pull\
-request
\fR 
[\fB\
-f
\fR
] [\fITITLE
\fR
|\fB\
-i
\fR 
\fIISSUE
\fR
] [\fB\
-b
\fR 
\fIBASE
\fR
] [\fB\
-h
\fR 
\fIHEAD
\fR
] 
2098 hub enhances various git commands to ease most common workflows with GitHub\
. 
2101 \fBhub \
-\
-noop
\fR 
\fICOMMAND
\fR
 
2102 Shows which 
command(s
) would be run as a result of the current command\
. Doesn
\'t perform anything\
. 
2105 \fBhub 
alias\fR 
[\fB\
-s
\fR
] [\fISHELL
\fR
] 
2106 Shows shell instructions 
for wrapping git\
. If given
, \fISHELL
\fR specifies the type of shell
; otherwise defaults to the value of SHELL environment variable\
. With 
\fB\
-s
\fR
, outputs shell script suitable 
for \fBeval
\fR\
. 
2109 \fBgit init
\fR 
\fB\
-g
\fR 
\fIOPTIONS
\fR
 
2110 Create a git repository as with git\
-init(1) and add remote 
\fBorigin
\fR at 
"git@github\.com:\fIUSER\fR/\fIREPOSITORY\fR\.git"; \fIUSER
\fR is your GitHub username 
and \fIREPOSITORY
\fR is the current working directory
\'s basename\
. 
2113 \fBgit clone
\fR 
[\fB\
-p
\fR
] \fIOPTIONS
\fR 
[\fIUSER
\fR
\fB
/\fR
]\fIREPOSITORY
\fR 
\fIDIRECTORY
\fR
 
2114 Clone repository 
"git://github\.com/\fIUSER\fR/\fIREPOSITORY\fR\.git" into 
\fIDIRECTORY
\fR as with git\
-clone(1)\
. When 
\fIUSER
\fR
/ is omitted
, assumes your GitHub login\
. With 
\fB\
-p
\fR
, clone 
private repositories over SSH\
. For repositories under your GitHub login
, \fB\
-p
\fR is implicit\
. 
2117 \fBgit remote add
\fR 
[\fB\
-p
\fR
] \fIOPTIONS
\fR 
\fIUSER
\fR
[\fB
/\fR
\fIREPOSITORY
\fR
] 
2118 Add remote 
"git://github\.com/\fIUSER\fR/\fIREPOSITORY\fR\.git" as with git\
-remote(1)\
. When 
/\fIREPOSITORY\fR is omitted, the basename of the current working directory is used\. With \fB\-p\fR, use private remote "git@github\.com:\fIUSER\fR/\fIREPOSITORY
\fR\
.git
"\. If \fIUSER\fR is "origin
" then uses your GitHub login\. 
2121 \fBgit remote set\-url\fR [\fB\-p\fR] \fIOPTIONS\fR \fIREMOTE\-NAME\fR \fIUSER\fR[/\fIREPOSITORY\fR] 
2122 Sets the url of remote \fIREMOTE\-NAME\fR using the same rules as \fBgit remote add\fR\. 
2125 \fBgit fetch\fR \fIUSER\-1\fR,[\fIUSER\-2\fR,\.\.\.] 
2126 Adds missing remote(s) with \fBgit remote add\fR prior to fetching\. New remotes are only added if they correspond to valid forks on GitHub\. 
2129 \fBgit checkout\fR \fIPULLREQ\-URL\fR [\fIBRANCH\fR] 
2130 Checks out the head of the pull request as a local branch, to allow for reviewing, rebasing and otherwise cleaning up the commits in the pull request before merging\. The name of the local branch can explicitly be set with \fIBRANCH\fR\. 
2133 \fBgit merge\fR \fIPULLREQ\-URL\fR 
2134 Merge the pull request with a commit message that includes the pull request ID and title, similar to the GitHub Merge Button\. 
2137 \fBgit cherry\-pick\fR \fIGITHUB\-REF\fR 
2138 Cherry\-pick a commit from a fork using either full URL to the commit or GitHub\-flavored Markdown notation, which is \fBuser@sha\fR\. If the remote doesn\'t yet exist, it will be added\. A \fBgit fetch <user>\fR is issued prior to the cherry\-pick attempt\. 
2141 \fBgit [am|apply]\fR \fIGITHUB\-URL\fR 
2142 Downloads the patch file for the pull request or commit at the URL and applies that patch from disk with \fBgit am\fR or \fBgit apply\fR\. Similar to \fBcherry\-pick\fR, but doesn\'t add new remotes\. \fBgit am\fR creates commits while preserving authorship info while \fBapply\fR only applies the patch to the working copy\. 
2145 \fBgit push\fR \fIREMOTE\-1\fR,\fIREMOTE\-2\fR,\.\.\.,\fIREMOTE\-N\fR [\fIREF\fR] 
2146 Push \fIREF\fR to each of \fIREMOTE\-1\fR through \fIREMOTE\-N\fR by executing multiple \fBgit push\fR commands\. 
2149 \fBgit submodule add\fR [\fB\-p\fR] \fIOPTIONS\fR [\fIUSER\fR/]\fIREPOSITORY\fR \fIDIRECTORY\fR 
2150 Submodule repository "git
://github\
.com
/\fIUSER
\fR
/\fIREPOSITORY
\fR\
.git
" into \fIDIRECTORY\fR as with git\-submodule(1)\. When \fIUSER\fR/ is omitted, assumes your GitHub login\. With \fB\-p\fR, use private remote "git
@github\
.com
:\fIUSER
\fR
/\fIREPOSITORY
\fR\
.git
"\. 
2154 Display enhanced git\-help(1)\. 
2157 hub also adds some custom commands that are otherwise not present in git: 
2160 \fBgit create\fR [\fINAME\fR] [\fB\-p\fR] [\fB\-d\fR \fIDESCRIPTION\fR] [\fB\-h\fR \fIHOMEPAGE\fR] 
2161 Create a new public GitHub repository from the current git repository and add remote \fBorigin\fR at "git
@github\
.com
:\fIUSER
\fR
/\fIREPOSITORY\fR\.git"; \fIUSER\fR is your GitHub username and \fIREPOSITORY\fR is the current working directory name\. To explicitly name the new repository, pass in \fINAME\fR, optionally in \fIORGANIZATION\fR/\fINAME
\fR form to create under an organization you
\'re a member of\
. With 
\fB\
-p
\fR
, create a 
private repository
, and with 
\fB\
-d
\fR 
and \fB\
-h
\fR set the repository
\'s description 
and homepage URL
, respectively\
. 
2164 \fBgit browse
\fR 
[\fB\
-u
\fR
] [[\fIUSER
\fR
\fB
/\fR
]\fIREPOSITORY
\fR
] [SUBPAGE
] 
2165 Open repository
\'s GitHub page 
in the system
\'s default web browser using 
\fBopen
(1)\fR 
or the 
\fBBROWSER
\fR 
env variable\
. If the repository isn
\'t specified
, \fBbrowse
\fR opens the page of the repository found 
in the current directory\
. If SUBPAGE is specified
, the browser will open on the specified subpage
: one of 
"wiki", "commits", "issues" or other (the default is 
"tree")\
. 
2168 \fBgit compare
\fR 
[\fB\
-u
\fR
] [\fIUSER
\fR
] [\fISTART
\fR\
.\
.\
.]\fIEND
\fR
 
2169 Open a GitHub compare view page 
in the system
\'s default web browser\
. \fISTART
\fR to 
\fIEND
\fR are branch names
, tag names
, or commit SHA1s specifying the range of history to compare\
. If a range with two 
dots (\fBa\
.\
.b
\fR
) is given
, it will be transformed into one with three dots\
. If 
\fISTART
\fR is omitted
, GitHub will compare against the base 
branch (the default is 
"master")\
. 
2172 \fBgit fork
\fR 
[\fB\
-\
-no\
-remote
\fR
] 
2173 Forks the original 
project (referenced by 
"origin" remote
) on GitHub 
and adds a new remote 
for it under your username\
. 
2176 \fBgit pull\
-request
\fR 
[\fB\
-f
\fR
] [\fITITLE
\fR
|\fB\
-i
\fR 
\fIISSUE
\fR
|\fIISSUE\
-URL
\fR
] [\fB\
-b
\fR 
\fIBASE
\fR
] [\fB\
-h
\fR 
\fIHEAD
\fR
] 
2177 Opens a pull request on GitHub 
for the project that the 
"origin" remote points to\
. The default head of the pull request is the current branch\
. Both base 
and head of the pull request can be explicitly given 
in one of the following formats
: "branch", "owner:branch", "owner/repo:branch"\
. This command will abort operation 
if it detects that the current topic branch has local commits that are 
not yet pushed to its upstream branch on the remote\
. To skip this check
, use 
\fB\
-f
\fR\
. 
2180 If 
\fITITLE
\fR is omitted
, a text editor will open 
in which title 
and body of the pull request can be entered 
in the same manner as git commit message\
. 
2183 If instead of normal 
\fITITLE
\fR an issue number is given with 
\fB\
-i
\fR
, the pull request will be attached to an existing GitHub issue\
. Alternatively
, instead of title you can paste a full URL to an issue on GitHub\
. 
2186 Hub will prompt 
for GitHub username 
& password the first time it needs to access the API 
and exchange it 
for an OAuth token
, which it saves 
in "~/\.config/hub"\
. 
2189 To avoid being prompted
, use 
\fIGITHUB_USER
\fR 
and \fIGITHUB_PASSWORD
\fR environment variables\
. 
2192 If you prefer the HTTPS protocol 
for GitHub repositories
, you can set 
"hub\.protocol" to 
"https"\
. This will affect 
\fBclone
\fR
, \fBfork
\fR
, \fBremote add
\fR 
and other operations that expand references to GitHub repositories as full URLs that otherwise use git 
and ssh protocols\
. 
2198 $ git config \
-\
-global hub\
.protocol https
 
2204 .SS 
"GitHub Enterprise" 
2205 By default
, hub will only work with repositories that have remotes which point to github\
.com\
. GitHub Enterprise hosts need to be whitelisted to configure hub to treat such remotes same as github\
.com
: 
2211 $ git config \
-\
-global \
-\
-add hub\
.host my\
.git\
.org
 
2218 The default host 
for commands like 
\fBinit
\fR 
and \fBclone
\fR is still github\
.com
, but this can be affected with the 
\fIGITHUB_HOST
\fR environment variable
: 
2224 $ GITHUB_HOST
=my\
.git\
.org git clone myproject
 
2236 $ git clone schacon
/ticgit
 
2237 > git clone git
://github\
.com
/schacon
/ticgit\
.git
 
2239 $ git clone \
-p schacon
/ticgit
 
2240 > git clone git
@github\
.com
:schacon/ticgit\
.git
 
2243 > git clone git
@github\
.com
/YOUR_USER
/resque\
.git
 
2247 .SS 
"git remote add" 
2251 $ git remote add rtomayko
 
2252 > git remote add rtomayko git
://github\
.com
/rtomayko
/CURRENT_REPO\
.git
 
2254 $ git remote add \
-p rtomayko
 
2255 > git remote add rtomayko git
@github\
.com
:rtomayko/CURRENT_REPO\
.git
 
2257 $ git remote add origin
 
2258 > git remote add origin git
://github\
.com
/YOUR_USER
/CURRENT_REPO\
.git
 
2267 > git remote add mislav git
://github\
.com
/mislav
/REPO\
.git
 
2270 $ git fetch mislav
,xoebus
 
2271 > git remote add mislav \
.\
.\
. 
2272 > git remote add xoebus \
.\
.\
. 
2273 > git fetch \
-\
-multiple mislav xoebus
 
2277 .SS 
"git cherry\-pick" 
2281 $ git cherry\
-pick http
://github\
.com
/mislav
/REPO
/commit/SHA
 
2282 > git remote add \
-f mislav git
://github\
.com
/mislav
/REPO\
.git
 
2283 > git cherry\
-pick SHA
 
2285 $ git cherry\
-pick mislav
@SHA 
2286 > git remote add \
-f mislav git
://github\
.com
/mislav
/CURRENT_REPO\
.git
 
2287 > git cherry\
-pick SHA
 
2289 $ git cherry\
-pick mislav
@SHA 
2291 > git cherry\
-pick SHA
 
2295 .SS 
"git am, git apply" 
2299 $ git am https
://github\
.com
/defunkt
/hub
/pull/55 
2300 > curl https
://github\
.com
/defunkt
/hub
/pull/55\
.patch \
-o 
/tmp/55\
.patch
 
2301 > git am 
/tmp/55\
.patch
 
2303 $ git am \
-\
-ignore\
-whitespace https
://github\
.com
/davidbalbert
/hub
/commit/fdb9921
 
2304 > curl https
://github\
.com
/davidbalbert
/hub
/commit/fdb9921\
.patch \
-o 
/tmp/fdb9921\
.patch
 
2305 > git am \
-\
-ignore\
-whitespace 
/tmp/fdb9921\
.patch
 
2307 $ git apply https
://gist\
.github\
.com
/8da7fb575debd88c54cf
 
2308 > curl https
://gist\
.github\
.com
/8da7fb575debd88c54cf\
.txt \
-o 
/tmp
/gist\
-8da7fb575debd88c54cf\
.txt
 
2309 > git apply 
/tmp/gist\
-8da7fb575debd88c54cf\
.txt
 
2318 [ repo forked on GitHub 
] 
2319 > git remote add \
-f YOUR_USER git
@github\
.com
:YOUR_USER/CURRENT_REPO\
.git
 
2323 .SS 
"git pull\-request" 
2327 # while on a topic branch called "feature": 
2329 [ opens text editor to edit title 
& body 
for the request 
] 
2330 [ opened pull request on GitHub 
for "YOUR_USER:feature" ] 
2332 # explicit title, pull base & head: 
2333 $ git pull\
-request 
"I\'ve implemented feature X" \
-b defunkt
:master \
-h mislav
:feature 
2335 $ git pull\
-request \
-i 
123 
2336 [ attached pull request to issue 
#123 ] 
2344 $ git checkout https
://github\
.com
/defunkt
/hub
/pull/73 
2345 > git remote add \
-f \
-t feature git
://github
:com/mislav
/hub\
.git
 
2346 > git checkout \
-\
-track \
-B mislav\
-feature mislav
/feature
 
2348 $ git checkout https
://github\
.com
/defunkt
/hub
/pull/73 custom\
-branch\
-name
 
2356 $ git merge https
://github\
.com
/defunkt
/hub
/pull/73 
2357 > git fetch git
://github\
.com
/mislav
/hub\
.git +refs
/heads
/feature
:refs/remotes
/mislav/feature
 
2358 > git merge mislav
/feature \-\-no\-ff \-m \'Merge pull request #73 from mislav/feature\
.\
.\
.\' 
2367 [ repo created on GitHub 
] 
2368 > git remote add origin git
@github\
.com
:YOUR_USER/CURRENT_REPO\
.git
 
2371 $ git create \
-d 
\'It shall be mine
, all mine!
\' 
2373 $ git create recipes
 
2374 [ repo created on GitHub 
] 
2375 > git remote add origin git
@github\
.com
:YOUR_USER/recipes\
.git
 
2377 $ git create sinatra
/recipes
 
2378 [ repo created 
in GitHub organization 
] 
2379 > git remote add origin git
@github\
.com
:sinatra/recipes\
.git
 
2389 > git remote add origin git
@github\
.com
:YOUR_USER/REPO\
.git
 
2397 $ git push origin
,staging
,qa bert_timeout
 
2398 > git push origin bert_timeout
 
2399 > git push staging bert_timeout
 
2400 > git push qa bert_timeout
 
2409 > open https
://github\
.com
/YOUR_USER
/CURRENT_REPO
 
2411 $ git browse \
-\
- commit
/SHA
 
2412 > open https
://github\
.com
/YOUR_USER
/CURRENT_REPO
/commit/SHA
 
2414 $ git browse \
-\
- issues
 
2415 > open https
://github\
.com
/YOUR_USER
/CURRENT_REPO
/issues
 
2417 $ git browse schacon
/ticgit
 
2418 > open https
://github\
.com
/schacon
/ticgit
 
2420 $ git browse schacon
/ticgit commit/SHA
 
2421 > open https
://github\
.com
/schacon
/ticgit
/commit/SHA
 
2424 > open https
://github\
.com
/YOUR_USER
/resque
 
2426 $ git browse resque network
 
2427 > open https
://github\
.com
/YOUR_USER
/resque
/network
 
2435 $ git compare refactor
 
2436 > open https
://github\
.com
/CURRENT_REPO
/compare
/refactor
 
2438 $ git compare 
1\
.0\
.\
.1\
.1 
2439 > open https
://github\
.com
/CURRENT_REPO
/compare
/1\
.0\
.\
.\
.1\
.1 
2441 $ git compare \
-u fix
 
2442 > (https
://github\
.com
/CURRENT_REPO
/compare
/fix
) 
2444 $ git compare other\
-user patch
 
2445 > open https
://github\
.com
/other\
-user
/REPO
/compare/patch
 
2453 $ hub submodule add wycats
/bundler vendor/bundler
 
2454 > git submodule add git
://github\
.com
/wycats
/bundler\
.git vendor
/bundler
 
2456 $ hub submodule add \
-p wycats
/bundler vendor/bundler
 
2457 > git submodule add git
@github\
.com
:wycats/bundler\.git vendor/bundler
 
2459 $ hub submodule add \
-b ryppl ryppl
/pip vendor/pip
 
2460 > git submodule add \
-b ryppl git
://github\
.com
/ryppl
/pip\
.git vendor
/pip
 
2469 > (improved git help
) 
2476 \fIhttps
://github\
.com
/defunkt
/hub
/issues
\fR
 
2479 \fIhttps
://github\
.com
/defunkt
/hub
/contributors
\fR
 
2482 git(1), git\
-clone(1), git\
-remote(1), git\
-init(1), \fIhttp
://github\
.com
\fR
, \fIhttps
://github\
.com
/defunkt
/hub
\fR