git_helpers 0.1.0 → 0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,347 +1,116 @@
1
1
  #!/usr/bin/env ruby
2
- # Inspired by https://github.com/olivierverdier/zsh-git-prompt
3
- # [commit: 350be32093d0585f395413253536d891c247f538,
4
- # last commit checked: 0a6c8b610e799040b612db8888945f502a2ddd9d (2016-02-14))
5
- #Inspired by the contrib git script
6
2
 
7
- require "open3"
8
- require "pathname"
9
- require "shellwords"
10
- require "optparse"
11
- require "simplecolor"
12
- #require "dr/git" #TODO merge the two implems
13
- SimpleColor.mix_in_string
3
+ require "git_helpers"
4
+ require 'optparse'
14
5
 
15
- module GitStatus
16
- module Run
17
- extend(self)
18
- #if we get interrupted once, we don't want to launch any more commands
19
- @interrupted=false
20
- def runstatus(*args)
21
- if !@interrupted
22
- begin
23
- if Open3.respond_to?(:capture3) then
24
- out, error, status=Open3.capture3(*args)
25
- return out, status.success?
26
- else
27
- out = `#{args} 2>/dev/null`
28
- status=$?
29
- return out, status.success?
30
- end
31
- rescue Interrupt #interruption
32
- @interrupted=true
33
- return "", false
34
- end
35
- else
36
- return "", false
37
- end
38
- end
39
- def run(*args)
40
- msg,_=runstatus(*args)
41
- return msg
42
- end
43
- end
44
-
45
- class Git
46
- include GitStatus::Run
47
- attr_reader :msg
48
-
49
- def git?
50
- if @git.nil?
51
- _,@git=runstatus "git rev-parse"
52
- end
53
- return @git
54
- end
55
- def getgitdir
56
- return Pathname.new((run "git rev-parse --git-dir").chomp)
57
- end
58
- def ingitdir?
59
- return (run "git rev-parse --is-inside-git-dir") == "true\n"
60
- end
61
- def worktree?
62
- return (run "git rev-parse --is-inside-work-tree") == "true\n"
63
- end
64
- def bare?
65
- return (run "git rev-parse --is-bare-repository") == "true\n"
66
- end
67
-
68
- def cd_and_exec(*args)
69
- if @path.nil? then
70
- yield(*args)
71
- else
72
- if File.directory?(@path)
73
- Dir.chdir(@path) do
74
- yield(*args)
75
- end
76
- else
77
- warn "#{@path} is not a directory"
78
- end
79
- end
80
- end
81
-
82
- def initialize(path=nil)
83
- #a nil path means we want information on the current directory
84
- if !path.nil?
85
- @path=Pathname.new(path).expand_path
86
- end
87
- cd_and_exec {git?}
88
- end
89
-
90
- def get_msg
91
- #gitst="git status --porcelain --branch"
92
- #too many git are too old to mix --porcelain with --branch
93
- gitm=git="git"
94
- gitm="#{git} -c color.ui=always" if $opts[:color]
95
- gitm="#{gitm} status --short --branch"
96
- @msg=run(gitm)
97
- end
98
-
99
- def describe_detached_head
100
- case $opts[:describe]
101
- when "sha1"
102
- describe=(run "git rev-parse --short HEAD").chomp
103
- when "describe"
104
- describe=(run "git describe HEAD").chomp
105
- when "contains"
106
- describe=(run "git describe --contains HEAD").chomp
107
- when "branch"
108
- describe=(run "git describe --contains --all HEAD").chomp
109
- when "match"
110
- describe=(run "git describe --tags --exact-match HEAD").chomp
111
- when "all" #try --contains all, then --all
112
- describe=(run "git describe --contains --all HEAD").chomp
113
- describe=(run "git describe --all HEAD").chomp if describe.nil? or describe.empty?
114
- when "magic"
115
- describe1=(run "git describe --contains --all HEAD").chomp
116
- describe2=(run "git describe --all HEAD").chomp
117
- describe= describe1.length < describe2.length ? describe1 : describe2
118
- describe=describe1 if describe2.empty?
119
- describe=describe2 if describe1.empty?
120
- else
121
- describe=(run($opts[:describe])).chomp
122
- end
123
- if describe.empty?
124
- describe=(run "git rev-parse --short HEAD").chomp
125
- end
126
- @branch=":#{describe}"
127
- end
128
-
129
- def parse_head(head)
130
- @ahead=@behind=0
131
- if (head =~ /## Initial commit on (\S*)/) then
132
- @branch=$1
133
- if @branch =~ /(\S*)\.\.\./
134
- @branch=$1
135
- end
136
- @branch+="…"
137
- elsif (head =~ /## (\S*) \(no branch\)/) then
138
- describe_detached_head
139
- elsif (head =~ /## (\S*)(.*)/) then
140
- branchs=$1
141
- rest=$2
142
- if (branchs =~ /(\S*)\.\.\.(\S*)/) then
143
- @branch=$1
144
- remote=$2
145
- else
146
- @branch=branchs
147
- end
148
- if (rest =~ /.*\[ahead\s+(\d*)(.*)/) then
149
- @ahead=$1.to_i
150
- rest=$2
151
- end
152
- if (rest =~ /.*behind\s+(\d*)\]/) then
153
- @behind=$1.to_i
154
- end
155
- end
156
- end
157
-
158
- def parse_msg
159
- msg=@msg
160
- #find the branch name, and if we are behind/ahead of upstream
161
- lines=msg.uncolor.lines.to_a
162
- return if lines.empty?
163
- head=lines.shift
164
- parse_head(head)
165
-
166
- #get status of files
167
- @changed=@staged=@untracked=@conflicts=0
168
- lines.each do |line|
169
- index = line[0];
170
- workdir = line[1];
171
- #puts "index: #{index}, workdir: #{workdir}"
172
- if index=~/[DRAMTC]/ then
173
- @staged+=1
174
- end
175
- if workdir=~ /[DMT]/ then
176
- @changed+=1
177
- end
178
- if workdir=='?' || index=='?' then
179
- @untracked+=1
180
- end
181
- if workdir=='U' || index=='U' then
182
- @conflicts+=1
183
- end
184
- end
185
- @clean=true
186
- @clean=false if @staged != 0 || @changed !=0 ||
187
- @untracked !=0 || @conflicts !=0
188
- end
189
-
190
- def get_status
191
- if worktree?
192
- get_msg
193
- parse_msg
194
- if $opts[:sequencer] and !@msg.empty?
195
- @sequencer=""
196
- gitdir=getgitdir
197
- if (gitdir+"rebase-merge").directory?
198
- if (gitdir+"rebase-merge/interactive").file?
199
- @sequencer<<" rb-i " #REBASE-i
200
- else
201
- @sequencer<<" rb-m " #REBASE-m
202
- end
203
- @sequencer<<(gitdir+"rebase-merge/head-name").read.chomp.sub(/^refs\/heads\//,"")
204
- end
205
- if (gitdir+"rebase-apply").directory?
206
- if (gitdir+"rebase-apply/rebasing").file?
207
- @sequencer<<" rb" #RB
208
- elsif (gitdir+"rebase-apply/applying").file?
209
- @sequencer<<" am" #AM
210
- else
211
- @sequencer<<" am/rb" #AM/REBASE
212
- end
213
- end
214
- if (gitdir+"MERGE_HEAD").file?
215
- @sequencer<<" mg" #MERGING
216
- end
217
- if (gitdir+"CHERRY_PICK_HEAD").file?
218
- @sequencer<<" ch" #CHERRY-PICKING
219
- end
220
- if (gitdir+"BISECT_LOG").file?
221
- @sequencer<<" bi" #BISECTING
222
- end
223
- _,stashstatus=runstatus "git rev-parse --verify refs/stash"
224
- if stashstatus
225
- stashs=run "git rev-list -g refs/stash"
226
- @sequencer<<" $#{stashs.lines.to_a.length}" #Stash
227
- end
228
- end
229
- return !@msg.empty?
230
- else
231
- if $opts[:sequencer]
232
- if ingitdir?
233
- if bare?
234
- @branch="|bare|"
235
- else
236
- @branch="|.git|"
237
- end
238
- end
239
- end
240
- end
241
- return false
242
- end
243
-
244
- def status
245
- cd_and_exec { get_status } if git?
246
- end
247
-
248
- def prompt
249
- if status
250
- return "(" <<
251
- @branch.color(:magenta,:bold) <<
252
- (@ahead==0 ? "" : "↑"<<@ahead.to_s ) <<
253
- (@behind==0 ? "" : "↓"<<@behind.to_s ) <<
254
- "|" <<
255
- (@staged==0 ? "" : ("●"+@staged.to_s).color(:red) ) <<
256
- (@conflicts==0 ? "" : ("✖"+@conflicts.to_s).color(:red) ) <<
257
- (@changed==0 ? "" : ("✚"+@changed.to_s).color(:blue) ) <<
258
- (@untracked==0 ? "" : "…" ) <<
259
- (@clean ? "✔".color(:green,:bold) : "" ) <<
260
- (@sequencer.empty? ? "" : @sequencer.color(:yellow) ) <<
261
- ")"
262
- else
263
- return "(" << @branch.color(:magenta,:bold) << ")" if @branch
264
- end
265
- end
266
-
267
- def porcelain
268
- if git?
269
- return "#{@branch}\n#{@ahead}\n#{@behind}\n#{@staged}\n#{@conflicts}\n#{@changed}\n#{@untracked}\n#{@clean?1:0}\n#{@sequencer}\n"
270
- else
271
- return ""
272
- end
273
- end
274
- end
275
- end
276
-
277
- $opts={:color => true, :indent => nil, :sequencer => true, :describe => "magic"}
6
+ opts={:color => true}
278
7
  optparse = OptionParser.new do |opt|
279
8
  opt.banner= "#{File.basename($0)} [options] git_dirs"
280
9
  opt.on("-p", "--[no-]prompt", "To be used in shell prompt", "This ensure that color ansi sequence are escaped so that they are not counted as text by the shell") do |v|
281
- $opts[:prompt]=v
282
- end
283
- opt.on("--[no-]porcelain", "Don't format the status but output it in a machine convenient format") do |v|
284
- $opts[:porcelain]=v
10
+ opts[:prompt]=v
11
+ opts[:max_length]=40 if v
285
12
  end
286
- opt.on("-s", "--[no-]status", "List file", "Print the output of git status additionally of what this program parse") do |v|
287
- $opts[:status]=v
13
+ opt.on("-s", "--[no-]status[=options]", "List file", "Print the output of git status additionally of what this program parse") do |v|
14
+ opts[:status]=v
288
15
  end
289
16
  opt.on("-c", "--[no-]color", "Color output", "on by default") do |v|
290
- $opts[:color]=v
17
+ opts[:color]=v
291
18
  end
292
19
  opt.on("--[no-]sequencer", "Show sequencer data (and also look for bare directory)", "on by default") do |v|
293
- $opts[:sequencer]=v
20
+ opts[:sequencer]=v
294
21
  end
295
22
  opt.on("--indent spaces", Integer, "Indent to use if showing git status", "2 by default, 0 for empty ARGV") do |v|
296
- $opts[:indent]=v
23
+ opts[:indent]=v
24
+ end
25
+ opt.on("--describe sha1/describe/contains/branch/match/all/magic", "How to describe a detached HEAD", "'branch-fb' by default") do |v|
26
+ opts[:detached_name]=v
27
+ end
28
+ opt.on("--[no-]ignored[=full]", "-i", "Show ignored files") do |v|
29
+ opts[:ignored]=v
30
+ end
31
+ opt.on("--[no-]untracked[=full]", "-u", "Show untracked files") do |v|
32
+ opts[:untracked]=v
33
+ end
34
+ opt.on("--[no-]branch", "Get branch infos (true by default)") do |v|
35
+ opts[:branch]=v
36
+ end
37
+ opt.on("--[no-]files", "Get files infos (true by default)") do |v|
38
+ opts[:files]=v
297
39
  end
298
- opt.on("--describe sha1/describe/contains/branch/match/all/magic", "How to describe a detached HEAD", "'magic' by default") do |v|
299
- $opts[:describe]=v
40
+ opt.on("--use=branch_name", "Show a different branch than HEAD") do |v|
41
+ opts[:use]=v
42
+ end
43
+ opt.on("--[no-]raw", "Show raw status infos") do |v|
44
+ opts[:raw]=v
300
45
  end
301
46
  opt.on("--sm", "Recurse on each submodules") do |v|
302
- $opts[:submodules]=v
47
+ opts[:submodules]=v
48
+ end
49
+ opt.on("--max-length=length", "Maximum status length", Integer) do |v|
50
+ opts[:max_length]=v
51
+ end
52
+ opt.on("--[no-]debug", "Debug git calls") do |v|
53
+ opts[:debug]=v
303
54
  end
304
55
  end
305
56
  optparse.parse!
306
57
 
307
- if !$opts[:color]
58
+ if !opts[:color]
308
59
  SimpleColor.enabled=false
309
60
  end
61
+ if opts[:debug]
62
+ SH.debug
63
+ end
310
64
 
311
65
  def prettify_dir(dir)
312
- return dir.sub(/^#{ENV['HOME']}/,"~")
66
+ return '' if dir.nil?
67
+ return (dir.sub(/^#{ENV['HOME']}/,"~"))+": "
313
68
  end
314
69
 
315
- def gs_output(dir)
316
- g=GitStatus::Git.new(dir)
317
- puts "#{prettify_dir(dir)+": " if dir}#{g.prompt}"
318
- if $opts[:status] and g.git?
319
- g.msg.lines.each do |line|
320
- print " "*$opts[:indent] + line
70
+ def gs_output(dir=".", **opts)
71
+ g=GitHelpers::GitDir.new(dir || ".")
72
+ status={}
73
+ arg=opts.delete(:use)
74
+ args= arg.nil? ? [] : [arg]
75
+ if opts[:raw]
76
+ puts "#{prettify_dir(dir)}#{g.status(*args,**opts)}"
77
+ else
78
+ puts "#{prettify_dir(dir)}#{g.format_status(*args,**opts) {|s| status=s}}"
79
+ end
80
+ if opts[:status] and g.worktree?
81
+ g.with_dir do
82
+ options=opts[:status]
83
+ if options.is_a?(String)
84
+ options=options.split(',')
85
+ else
86
+ options=[]
87
+ end
88
+ out=SH.run_simple("git #{opts[:color] ? "-c color.ui=always" : ""} status --short #{(status[:status_options]+options).shelljoin}")
89
+ out.each_line.each do |line|
90
+ print " "*(opts[:indent]||0) + line
91
+ end
321
92
  end
322
93
  end
323
94
  end
324
95
 
325
- if $opts[:porcelain]
326
- puts GitStatus::Git.new.porcelain
327
- elsif $opts[:prompt]
96
+ if opts[:prompt]
328
97
  SimpleColor.enabled=:shell
329
- prompt=GitStatus::Git.new.prompt
98
+ prompt=GitHelpers.create.format_status(**opts)
330
99
  puts prompt if prompt #in ruby1.8, puts nil output nil...
331
100
  else
332
101
  args=ARGV
333
102
  if args.empty?
334
- $opts[:indent]=0 unless $opts[:indent]
103
+ opts[:indent]=0 unless opts[:indent]
335
104
  args=[nil]
336
105
  else
337
- $opts[:indent]=2 unless $opts[:indent]
106
+ opts[:indent]=2 unless opts[:indent]
338
107
  end
339
108
  args.each do |dir|
340
- gs_output(dir)
341
- if $opts[:submodules]
342
- Dir.chdir(dir||".") do
343
- %x/git submodule status/.each_line.map { |l| l.split[1] }.each do |dir|
344
- gs_output(dir)
109
+ gs_output(dir,**opts)
110
+ if opts[:submodules]
111
+ g.with_dir do
112
+ %x/git submodule status/.each_line.map { |l| l.split[1] }.each do |sdir|
113
+ gs_output(sdir, **opts)
345
114
  end
346
115
  end
347
116
  end
@@ -1,344 +1,38 @@
1
1
  require 'git_helpers/version'
2
- require 'git_helpers/extra_helpers'
2
+ require 'simplecolor/mixin'
3
+ require 'shell_helpers'
3
4
  require 'dr/base/bool'
4
- require 'pathname'
5
+ require 'git_helpers/git_dir'
6
+ require 'git_helpers/branch'
5
7
 
8
+ #git functions helper
9
+ #small library wrapping git; use rugged for more interesting things
6
10
  module GitHelpers
7
- #git functions helper
8
-
9
- #small library wrapping git; use rugged for more interesting things
10
- class GitDir
11
- attr_accessor :dir
12
- def initialize(dir=".")
13
- @dir=Pathname.new(dir.to_s).realpath
14
- end
15
-
16
- def to_s
17
- @dir.to_s
18
- end
19
-
20
-
21
- #we could also use 'git -C #{@dir}' for each git invocation
22
- def with_dir
23
- Dir.chdir(@dir) { yield }
24
- end
25
-
26
- def all_files
27
- with_dir do
28
- %x/git ls-files -z/.split("\0")
29
- end
30
- end
31
-
32
- #are we in a git folder?
33
- def git?(quiet: false)
34
- launch="git rev-parse"
35
- launch=launch + " 2>/dev/null" if quiet
36
- with_dir do
37
- system launch
38
- return Bool.to_bool($?)
39
- end
40
- end
41
-
42
- #are we in .git/?
43
- def gitdir?
44
- with_dir do
45
- return Bool.to_bool(%x/git rev-parse --is-inside-git-dir/)
46
- end
47
- end
48
- #are we in the worktree?
49
- def worktree?
50
- with_dir do
51
- return Bool.to_bool(%x/git rev-parse --is-inside-work-tree/)
52
- end
53
- end
54
- #are we in a bare repo?
55
- def bare?
56
- with_dir do
57
- return Bool.to_bool(%x/git rev-parse --is-bare-repository/)
58
- end
59
- end
60
-
61
- #return the absolute path of the toplevel
62
- def toplevel
63
- with_dir do
64
- return Pathname.new(%x/git rev-parse --show-toplevel/.chomp)
65
- end
66
- end
67
- #relative path from toplevel to @dir
68
- def prefix
69
- with_dir do
70
- return Pathname.new(%x/git rev-parse --show-prefix/.chomp)
71
- end
72
- end
73
- #return the relative path from @dir to the toplevel
74
- def relative_toplevel
75
- with_dir do
76
- return Pathname.new(%x/git rev-parse --show-cdup/.chomp)
77
- end
78
- end
79
- #get path to .git directory (can be relative or absolute)
80
- def gitdir
81
- with_dir do
82
- return Pathname.new(%x/git rev-parse --git-dir/.chomp)
83
- end
84
- end
85
-
86
- def with_toplevel(&b)
87
- with_dir do
88
- dir=relative_toplevel
89
- if !dir.to_s.empty?
90
- Dir.chdir(dir,&b)
91
- else
92
- warn "No toplevel found, executing inside dir #{@dir}"
93
- with_dir(&b)
94
- end
95
- end
96
- end
97
-
98
- #return a list of submodules
99
- def submodules
100
- with_dir do
101
- return %x/git submodule status/.each_line.map { |l| l.split[1] }
102
- end
103
- end
104
-
105
- def get_config(*args)
106
- with_dir do
107
- return %x/git config #{args.shelljoin}/.chomp
108
- end
109
- end
110
-
111
- def current_branch(always: true)
112
- with_dir do
113
- branchname= %x/git symbolic-ref -q --short HEAD/.chomp!
114
- branchname||= %x/git rev-parse --verify HEAD/.chomp! if always
115
- return branch(branchname)
116
- end
117
- end
118
-
119
- def head
120
- return branch('HEAD')
121
- end
122
-
123
- #return all branches that have an upstream
124
- #if branches=:all look through all branches
125
- def all_upstream_branches(branches)
126
- #TODO
127
- upstreams=%x!git for-each-ref --format='%(upstream:short)' refs/heads/branch/!
128
- end
129
-
130
- def get_topic_branches(*branches, complete: :local)
131
- if branches.length >= 2
132
- return branch(branches[0]), branch(branches[1])
133
- elsif branches.length == 1
134
- b=branch(branches[0])
135
- if complete == :local
136
- return current_branch, b
137
- elsif complete == :remote
138
- return b, b.upstream
139
- else
140
- fail "complete keyword should be :local or :remote"
141
- end
142
- else
143
- c=current_branch
144
- return c, c.upstream
145
- end
146
- end
147
-
148
- def branch(branch="HEAD")
149
- GitBranch.new(branch, dir: @self)
150
- end
151
-
152
- def branch_infos(*branches, local: false, remote: false, tags: false)
153
- query=branches.map {|b| name_branch(b, method: 'full_name')}
154
- query << 'refs/heads' if local
155
- query << 'refs/remotes' if remote
156
- query << 'refs/tags' if tags
157
- r={}
158
- format=%w(refname refname:short objecttype objectsize objectname upstream upstream:short upstream:track upstream:remotename upstream:remoteref push push:short push:remotename push:remoteref HEAD symref)
159
- out=SH::Run.run_simple("git for-each-ref --format '#{format.map {|f| "%(#{f})"}.join(',')}, ' #{query.shelljoin}", chomp: :lines)
160
- out.each do |l|
161
- infos=l.split(',')
162
- full_name=infos[0]
163
- r[full_name]=Hash[format.zip(infos)]
164
- type=if full_name.start_with?("refs/heads/")
165
- :local
166
- elsif full_name.start_with?("refs/remotes/")
167
- :remote
168
- elsif full_name.start_with?("refs/tags/")
169
- :tags
170
- end
171
- name = case type
172
- when :local
173
- full_name.delete_prefix("refs/heads/")
174
- when :remote
175
- full_name.delete_prefix("refs/remotes/")
176
- when :tags
177
- full_name.delete_prefix("refs/tags/")
178
- end
179
- r[full_name][:type]=type
180
- r[full_name][:name]=name
181
- end
182
- r
183
- end
184
-
185
- def name_branch(branch,*args)
186
- self.branch(branch).name(*args)
187
- end
188
- end
11
+ DefaultLogOptions=["-M", "-C", "--no-color"].shelljoin
12
+ # we only call git to get status updates, we never modify the git dir
13
+ # so locks are not required, pass that information through the env
14
+ # variabole:
15
+ ENV['GIT_OPTIONAL_LOCKS']="0"
16
+ # another solution would be to invoke git via git --no-optional-locks
17
+ # each time. For now the env variable is easier to use.
18
+ # Note that the only optional lock is for git status currently.
19
+ # There is the following trade-off: If git-status will not take locks, it
20
+ # cannot update the index to save refresh information and reuse the next
21
+ # time. So do we want to use this?
189
22
 
190
23
  extend self
191
24
  add_instance_methods = lambda do |klass|
192
25
  klass.instance_methods(false).each do |m|
193
- define_method(m) do |*args,&b|
194
- GitDir.new.public_send(m,*args,&b)
26
+ define_method(m) do |*args,**kws,&b|
27
+ GitDir.new.public_send(m,*args,**kws,&b)
195
28
  end
196
29
  end
197
30
  end
198
- add_instance_methods.call(GitDir)
199
- add_instance_methods.call(GitStats)
200
- add_instance_methods.call(GitExtraInfos)
201
-
202
- class GitBranch
203
- attr_accessor :gitdir
204
- attr_accessor :branch
205
- attr_writer :infos
206
-
207
- def initialize(branch="HEAD", dir: ".")
208
- @gitdir=dir.is_a?(GitDir) ? dir : GitDir.new(dir)
209
- @branch=branch
210
- end
211
-
212
- def new_branch(name)
213
- self.class.new(name, @gitdir)
214
- end
215
-
216
- def to_s
217
- @branch.to_s
218
- end
219
-
220
- def nil?
221
- @branch.nil?
222
- end
223
-
224
- def shellescape
225
- @branch.shellescape
226
- end
227
-
228
- def infos
229
- return @infos if @infos
230
- infos=branch_infos
231
- type=infos[:type]
232
- if type == :local
233
- rebase=gitdir.get_config("branch.#{name}.rebase")
234
- rebase = false if rebase.empty?
235
- rebase = true if rebase == "true"
236
- infos[:rebase]=rebase
237
- end
238
- @infos=infos
239
- end
240
-
241
- def name(method: "name", always: true)
242
- @gitdir.with_dir do
243
- case method
244
- when "sha1"
245
- describe=%x"git rev-parse --short #{@branch.shellescape}".chomp!
246
- when "describe"
247
- describe=%x"git describe #{@branch.shellescape}".chomp!
248
- when "contains"
249
- describe=%x"git describe --contains #{@branch.shellescape}".chomp!
250
- when "match"
251
- describe=%x"git describe --tags --exact-match #{@branch.shellescape}".chomp!
252
- when "topic"
253
- describe=%x"git describe --all #{@branch.shellescape}".chomp!
254
- when "branch"
255
- describe=%x"git describe --contains --all #{@branch.shellescape}".chomp!
256
- when "topic-fb" #try --all, then --contains all
257
- describe=%x"git describe --all #{@branch.shellescape}".chomp!
258
- describe=%x"git describe --contains --all #{@branch.shellescape}".chomp! if describe.nil? or describe.empty?
259
- when "branch-fb" #try --contains all, then --all
260
- describe=%x"git describe --contains --all #{@branch.shellescape}".chomp!
261
- describe=%x"git describe --all #{@branch.shellescape}".chomp! if describe.nil? or describe.empty?
262
- when "magic"
263
- describe1=%x"git describe --contains --all #{@branch.shellescape}".chomp!
264
- describe2=%x"git describe --all #{@branch.shellescape}".chomp!
265
- describe= describe1.length < describe2.length ? describe1 : describe2
266
- describe=describe1 if describe2.empty?
267
- describe=describe2 if describe1.empty?
268
- when "name"
269
- describe=%x"git rev-parse --abbrev-ref --symbolic-full-name #{@branch.shellescape}".chomp!
270
- when "full_name"
271
- describe=%x"git rev-parse --symbolic-full-name #{@branch.shellescape}".chomp!
272
- when "symbolic"
273
- describe=%x"git rev-parse --symbolic #{@branch.shellescape}".chomp!
274
- else
275
- describe=%x/#{method}/.chomp! unless method.nil? or method.empty?
276
- end
277
- if (describe.nil? or describe.empty?) and always
278
- describe=%x/git rev-parse --short #{@branch.shellescape}/.chomp!
279
- end
280
- return describe
281
- end
282
- end
283
-
284
- def rebase?
285
- @gitdir.with_dir do
286
- rb=%x/git config --bool branch.#{@branch.shellescape}.rebase/.chomp!
287
- rb||=%x/git config --bool pull.rebase/.chomp!
288
- return rb=="true"
289
- end
290
- end
291
-
292
- def remote
293
- @gitdir.with_dir do
294
- rm=%x/git config --get branch.#{@branch.shellescape}.remote/.chomp!
295
- rm||="origin"
296
- return rm
297
- end
298
- end
299
-
300
- def push_remote
301
- @gitdir.with_dir do
302
- rm= %x/git config --get branch.#{@branch.shellescape}.pushRemote/.chomp! ||
303
- %x/git config --get remote.pushDefault/.chomp! ||
304
- remote
305
- return rm
306
- end
307
- end
308
-
309
- def upstream
310
- @gitdir.with_dir do
311
- up=%x/git rev-parse --abbrev-ref #{@branch.shellescape}@{u}/.chomp!
312
- return new_branch(up)
313
- end
314
- end
315
-
316
- def push
317
- @gitdir.with_dir do
318
- pu=%x/git rev-parse --abbrev-ref #{@branch.shellescape}@{push}/.chomp!
319
- return new_branch(pu)
320
- end
321
- end
322
-
323
- def hash
324
- @hash||=`git rev-parse #{@branch.shellescape}`.chomp!
325
- end
326
-
327
- def ==(other)
328
- @branch == other.branch && @gitdir=other.gitdir
329
- end
330
-
331
- #return upstream + push if push !=upstream
332
- def related
333
- up=upstream
334
- pu=push
335
- pu=new_branch(nil) if up==pu
336
- return up, pu
337
- end
338
-
339
- def branch_infos
340
- @gitdir.branch_infos(@branch).values.first
341
- end
31
+ GitDir.ancestors.each do |mod|
32
+ add_instance_methods.call(mod) if mod.to_s =~ /^GitHelpers::/
342
33
  end
343
34
 
35
+ def self.create(dir='.')
36
+ GitDir.new(dir)
37
+ end
344
38
  end