gx 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,23 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'autotest/restart'
4
+
5
+ # Autotest.add_hook :initialize do |at|
6
+ # at.extra_files << "../some/external/dependency.rb"
7
+ #
8
+ # at.libs << ":../some/external"
9
+ #
10
+ # at.add_exception 'vendor'
11
+ #
12
+ # at.add_mapping(/dependency.rb/) do |f, _|
13
+ # at.files_matching(/test_.*rb$/)
14
+ # end
15
+ #
16
+ # %w(TestA TestB).each do |klass|
17
+ # at.extra_class_map[klass] = "test/test_misc.rb"
18
+ # end
19
+ # end
20
+
21
+ # Autotest.add_hook :run_command do |at|
22
+ # system "rake build"
23
+ # end
File without changes
@@ -0,0 +1,6 @@
1
+ === 1.0.0 / 2011-03-22
2
+
3
+ * 1 major enhancement
4
+
5
+ * Birthday!
6
+
@@ -0,0 +1,10 @@
1
+ .autotest
2
+ History.txt
3
+ Manifest.txt
4
+ README.txt
5
+ Rakefile
6
+ bin/gx-publish
7
+ bin/gx-update
8
+ lib/gx.rb
9
+ lib/gx/enhance.rb
10
+ test/test_gx.rb
@@ -0,0 +1,66 @@
1
+ = gx
2
+
3
+ * http://github.com/evanphx/gx
4
+
5
+ == DESCRIPTION:
6
+
7
+ Gx is 2 git related tools: gx-update and gx-publish.
8
+
9
+ gx-update is a replacement for 'git pull' that includes an integrated
10
+ conflict resolver.
11
+
12
+ == FEATURES/PROBLEMS:
13
+
14
+ * Birthday!
15
+
16
+ == SYNOPSIS:
17
+
18
+ gx-update
19
+
20
+ == REQUIREMENTS:
21
+
22
+ * git
23
+ * grit
24
+ * ruby
25
+
26
+ == INSTALL:
27
+
28
+ * Edit your ~/.gitconfig and add:
29
+ update = !gx-update
30
+
31
+ to your [alias] section.
32
+
33
+
34
+ == DEVELOPERS:
35
+
36
+ After checking out the source, run:
37
+
38
+ $ rake newb
39
+
40
+ This task will install any missing dependencies, run the tests/specs,
41
+ and generate the RDoc.
42
+
43
+ == LICENSE:
44
+
45
+ (The MIT License)
46
+
47
+ Copyright (c) 2011 FIX
48
+
49
+ Permission is hereby granted, free of charge, to any person obtaining
50
+ a copy of this software and associated documentation files (the
51
+ 'Software'), to deal in the Software without restriction, including
52
+ without limitation the rights to use, copy, modify, merge, publish,
53
+ distribute, sublicense, and/or sell copies of the Software, and to
54
+ permit persons to whom the Software is furnished to do so, subject to
55
+ the following conditions:
56
+
57
+ The above copyright notice and this permission notice shall be
58
+ included in all copies or substantial portions of the Software.
59
+
60
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
61
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
62
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
63
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
64
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
65
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
66
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,23 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+
6
+ # Hoe.plugin :compiler
7
+ # Hoe.plugin :gem_prelude_sucks
8
+ # Hoe.plugin :inline
9
+ # Hoe.plugin :inline
10
+ # Hoe.plugin :racc
11
+ # Hoe.plugin :rubyforge
12
+
13
+ Hoe.spec "gx" do
14
+ # HEY! If you fill these out in ~/.hoe_template/Rakefile.erb then
15
+ # you'll never have to touch them again!
16
+ # (delete this comment too, of course)
17
+
18
+ developer "Evan Phoenix", "evan@fallingsnow.net"
19
+
20
+ # self.rubyforge_name = 'gxx' # if different than 'gx'
21
+ end
22
+
23
+ # vim: syntax=ruby
@@ -0,0 +1,94 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pathname'
4
+
5
+ require 'gx/enhance'
6
+ require 'optparse'
7
+ require 'ostruct'
8
+ require 'fileutils'
9
+ require 'readline'
10
+
11
+ opts = OpenStruct.new
12
+
13
+ op = OptionParser.new do |o|
14
+ o.on "-z", "--analyze", "Output information on what update would do" do
15
+ opts.analyze = true
16
+ end
17
+
18
+ o.on "-v", "--verbose", "Be verbose" do
19
+ opts.verbose = true
20
+ end
21
+
22
+ o.on "--debug", "Show all git commands run" do
23
+ Grit.debug = true
24
+ end
25
+
26
+ o.on "-q", "--quiet", "Show the minimal output" do
27
+ opts.quiet = true
28
+ end
29
+ end
30
+
31
+ op.parse!(ARGV)
32
+
33
+ STDOUT.sync = true
34
+
35
+ repo = Grit::Repo.current
36
+
37
+ # Boost the timeout
38
+ Grit::Git.git_timeout = 120
39
+
40
+ current = repo.resolve_rev "HEAD"
41
+ branch = repo.git.symbolic_ref({:q => true}, "HEAD").strip
42
+
43
+ branch_name = branch.gsub %r!^refs/heads/!, ""
44
+
45
+ origin_ref = repo.merge_ref branch_name
46
+
47
+ unless origin_ref
48
+ puts "Sorry, it appears your current branch is not setup with merge info."
49
+ puts "Please set 'branch.#{branch_name}.remote' and 'branch.#{branch_name}.merge'"
50
+ puts "and try again."
51
+ exit 1
52
+ end
53
+
54
+ origin = repo.resolve_rev origin_ref
55
+
56
+ # See if there are actually any commits to publish first.
57
+
58
+ if current == origin
59
+ puts "Already up to date, no commits to publish."
60
+ exit 0
61
+ end
62
+
63
+ # ok, there are commits, now make sure our origin and
64
+ # everything is update to date.
65
+
66
+ common = repo.find_ancestor(origin, current)
67
+
68
+ url = repo.merge_url branch_name
69
+
70
+ push_repo, push_branch = repo.merge_info branch_name
71
+ remote_hash = repo.remote_info push_repo, push_branch
72
+
73
+
74
+ if common != origin or remote_hash != origin
75
+ puts "The upstream contains unmerged commits. Please update/pull first."
76
+ if opts.verbose
77
+ puts "Local branch: #{current}"
78
+ puts "Local origin: #{origin}"
79
+ puts "Remote origin: #{remote_hash}"
80
+ end
81
+ exit 1
82
+ end
83
+
84
+ print "Publishing local commits to #{url}... "
85
+
86
+ out = repo.git.push({:v => true}, push_repo, "#{branch_name}:#{push_branch}")
87
+ if $?.exitstatus != 0
88
+ puts "error!"
89
+ puts "Sorry, I'm not sure what happened. Here is what git said:"
90
+ puts out
91
+ end
92
+
93
+ puts "done!"
94
+
@@ -0,0 +1,370 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # TODO:
4
+ # * Handle a conflict in a remote commit that is in a renamed file.
5
+
6
+ require 'pathname'
7
+ require 'gx/enhance'
8
+ require 'optparse'
9
+ require 'ostruct'
10
+ require 'fileutils'
11
+ require 'readline'
12
+
13
+ opts = OpenStruct.new
14
+
15
+ op = OptionParser.new do |o|
16
+ o.on "-z", "--analyze", "Output information on what update would do" do
17
+ opts.analyze = true
18
+ end
19
+
20
+ o.on "-v", "--verbose", "Be verbose" do
21
+ opts.verbose = true
22
+ end
23
+
24
+ o.on "--debug", "Show all git commands run" do
25
+ Grit.debug = true
26
+ end
27
+
28
+ o.on "-q", "--quiet", "Show the minimal output" do
29
+ opts.quiet = true
30
+ end
31
+ end
32
+
33
+ op.parse!(ARGV)
34
+
35
+ STDOUT.sync = true
36
+
37
+ # Boost the timeout
38
+ Grit::Git.git_timeout = 240
39
+
40
+ class Update
41
+ HELP = <<-TXT
42
+ You're currently inside the conflict resolver. The following commands
43
+ are available to help you.
44
+
45
+ When the conflict resolver is first started, the contents of the file
46
+ will contain the file populated with conflict markers for you to edit.
47
+
48
+ [D]iff View the diffs between the (original version and local version)
49
+ and (original version and remote version).
50
+ [E]dit Launch your editor to edit the file.
51
+ [T]ool Run git-mergetool on the file.
52
+ [O]riginal Set the contents of the file to the original version. This is
53
+ version from the common ancestor of your commit and the remote
54
+ commit.
55
+ [M]ine Set the contents of the file to be your version.
56
+ [R]emote Set the contents of the file to be the remote version.
57
+ co[N]flict Set the contents of the file to contain the merged between the
58
+ local version and remote version, with conflict markers.
59
+ [P]rompt Launch a subshell to deal with the conflict. Simply exit
60
+ from the shell to continue with conflict resolution.
61
+ [I]nfo View information about the commit and the current file.
62
+ [A]bort Cancel the update altogether, restore everything to before
63
+ the update was started.
64
+ [C]ontinue You're done dealing with this conflict, move on to the next one.
65
+ [H]elp Detail all available options, you're looking at it now.
66
+ TXT
67
+
68
+
69
+ def initialize(opts)
70
+ @opts = opts
71
+ @repo = Grit::Repo.current
72
+
73
+ @current = @repo.resolve_rev "HEAD"
74
+ @branch = @repo.git.symbolic_ref({:q => true}, "HEAD").strip
75
+
76
+ @branch_name = @branch.gsub %r!^refs/heads/!, ""
77
+
78
+ @origin_ref = @repo.merge_ref @branch_name
79
+
80
+ unless @origin_ref
81
+ puts "Sorry, it appears your current branch is not setup with merge info."
82
+ puts "Please set 'branch.#{@branch_name}.remote' and 'branch.#{@branch_name}.merge'"
83
+ puts "and try again."
84
+ exit 1
85
+ end
86
+ end
87
+
88
+ def fetch
89
+ print "Fetching new commits: "
90
+ out = @repo.git.fetch :timeout => false
91
+ puts "done."
92
+
93
+ # TODO parse +out+ for details to show the user.
94
+ end
95
+
96
+ def includes_conflict_markers?(path)
97
+ /^<<<<<<< HEAD/.match(File.read(path))
98
+ end
99
+
100
+ def cat_file(ref, file)
101
+ File.open(file, "w") do |f|
102
+ f << @repo.git.cat_file({}, ref)
103
+ end
104
+ end
105
+
106
+ def handle_unmerged(patch_info, files)
107
+ files.each do |name, info|
108
+ system "cp #{name} .git/with_markers"
109
+
110
+ puts
111
+ puts "Conflict discovered in '#{name}'"
112
+
113
+ loop do
114
+
115
+ # If there are conflict markers, default is edit.
116
+ if includes_conflict_markers?(name)
117
+ default = "E"
118
+
119
+ # otherwise it's continue.
120
+ else
121
+ default = "C"
122
+ end
123
+
124
+ ans = Readline.readline "Select: [D]iff, [E]dit, [C]ontinue, [H]elp: [#{default}] "
125
+ ans = default if ans.empty?
126
+ want = ans.downcase[0]
127
+ case want
128
+ when ?d
129
+ orig = ".git/diff/original/#{name}"
130
+ FileUtils.mkdir_p File.dirname(orig)
131
+ cat_file info.original, orig
132
+
133
+ mine = ".git/diff/mine/#{name}"
134
+ FileUtils.mkdir_p File.dirname(mine)
135
+ cat_file info.mine, mine
136
+
137
+ remote = ".git/diff/remote/#{name}"
138
+ FileUtils.mkdir_p File.dirname(remote)
139
+ cat_file info.yours, remote
140
+
141
+ system "cd .git/diff; diff -u original/#{name} mine/#{name}"
142
+ system "cd .git/diff; diff -u original/#{name} remote/#{name}"
143
+ system "rm -rf .git/diff"
144
+ when ?e
145
+ system "#{ENV['EDITOR']} #{name}"
146
+ when ?t
147
+ system "git mergetool #{name}"
148
+ when ?o
149
+ cat_file info.original, name
150
+ when ?m
151
+ cat_file info.mine, name
152
+ when ?r
153
+ cat_file info.yours, name
154
+ when ?n
155
+ system "cp .git/with_markers #{name}"
156
+ when ?p
157
+ puts "Starting a sub-shell to handle conflicts for #{name}."
158
+ puts "Exit the shell to continue resolution."
159
+ system "$SHELL"
160
+ when ?i
161
+ puts "Current file: #{name}"
162
+ puts "Current commit:"
163
+ puts " Subject: #{patch_info[:subject]}"
164
+ puts " Date: #{patch_info[:date]}"
165
+ puts " Author: #{patch_info[:author]} (#{patch_info[:email]})"
166
+ when ?a
167
+ raise "abort!"
168
+ when ?h
169
+ puts HELP
170
+ when ?c
171
+ if includes_conflict_markers?(name)
172
+ puts
173
+ puts "It looks like this file still contains conflict markers."
174
+ a = Readline.readline "Are you sure that you want to commit it? [Y/N]: "
175
+ break if a.downcase[0] == ?y
176
+ else
177
+ break
178
+ end
179
+ else
180
+ puts "Unknown option. Try again."
181
+ end
182
+ end
183
+
184
+ File.unlink ".git/with_markers" rescue nil
185
+ @repo.git.add({}, name)
186
+ end
187
+ end
188
+
189
+ def analyze
190
+ puts "Automatically merging in refs from: #{@origin_ref} / #{@origin[0,7]}"
191
+ puts "Closest ancestor between HEAD and origin: #{@common[0,7]}"
192
+ puts
193
+
194
+ if @to_receive.empty?
195
+ puts "Current history is up to date."
196
+ exit 0
197
+ end
198
+
199
+ puts "#{@to_receive.size} new commits."
200
+ if @opts.verbose
201
+ system "git log --pretty=oneline #{@common}..#{@origin_ref}"
202
+ puts
203
+ end
204
+
205
+ puts "#{@to_replay.size} commits to adapt."
206
+ if @opts.verbose
207
+ system "git log --pretty=oneline #{@common}..HEAD"
208
+ puts
209
+ end
210
+ end
211
+
212
+ def run
213
+
214
+ fetch
215
+
216
+ @origin = @repo.resolve_rev @origin_ref
217
+
218
+ @common = @repo.find_ancestor(@origin, @current)
219
+
220
+ @to_replay = @repo.revs_between(@common, @current)
221
+ @to_receive = @repo.revs_between(@common, @origin)
222
+
223
+ if @opts.analyze
224
+ analyze
225
+ exit 0
226
+ end
227
+
228
+ if @to_receive.empty?
229
+ puts "Up to date."
230
+ exit 0
231
+ end
232
+
233
+ if @opts.verbose
234
+ puts "Extracting commits between #{@common[0,7]} and HEAD..."
235
+ end
236
+
237
+ # DANGER. Before here, we can abort anytime, after here, we're making
238
+ # changes, so we need to be able to recover.
239
+ #
240
+ begin
241
+ port_changes
242
+ rescue Exception => e
243
+ puts "Error detected, aborting update: #{e.message} (#{e.class})"
244
+ puts e.backtrace
245
+ recover
246
+ exit 1
247
+ end
248
+ end
249
+
250
+ def recover
251
+ @repo.git.reset({:hard => true}, @current)
252
+ @repo.git.checkout({}, @branch.gsub(%r!^refs/heads/!, ""))
253
+
254
+ if @used_wip
255
+ @repo.git.reset({:mixed => true}, "HEAD^")
256
+ end
257
+
258
+ system "rm -rf #{Grit.rebase_dir}" rescue nil
259
+ end
260
+
261
+ def sh(cmd)
262
+ Grit.log cmd if Grit.debug
263
+ out = `#{cmd}`
264
+ Grit.log out if Grit.debug
265
+ return out
266
+ end
267
+
268
+ def port_changes
269
+ # Switch back in time so we can re-apply commits. checkout
270
+ # will return non-zero if there it can't be done. In that case
271
+ # we perform a WIP commit, and unwind that WIP commit later,
272
+ # leaving the working copy the same way it was.
273
+
274
+ @used_wip = false
275
+
276
+ list = @repo.git.ls_files(:m => true).split("\n")
277
+ if list.size > 0
278
+ @repo.git.commit({:m => "++WIP++", :a => true})
279
+ @used_wip = true
280
+
281
+ # Because we've introduced a new commit, we need to repoint current.
282
+ @current = @repo.resolve_rev "HEAD"
283
+
284
+ # And the list of commits to replay.
285
+ @to_replay = @repo.revs_between(@common, @current)
286
+
287
+ # Ok, try again.
288
+ # Use sh, since the git proxy seems to fuck up $?
289
+ error = sh "git checkout -q #{@origin} 2>&1"
290
+ if $?.exitstatus != 0
291
+ # Ok, give up.
292
+ recover
293
+
294
+ # Now tell the user what happened.
295
+ puts "ERROR: Sorry, 'git checkout' can't figure out how to properly switch"
296
+ puts "the working copy. Please fix this and run 'git update' again."
297
+ puts "Here is the error that 'git checkout' reported:"
298
+ puts
299
+ puts error
300
+ puts
301
+ exit 1
302
+ end
303
+ else
304
+ error = sh "git checkout -q #{@origin} 2>&1"
305
+
306
+ if $?.exitstatus != 0
307
+ # Ok, give up.
308
+ recover
309
+
310
+ # Now tell the user what happened.
311
+ puts "ERROR: Sorry, 'git checkout' can't figure out how to properly switch"
312
+ puts "the working copy. Please fix this and run 'git update' again."
313
+ puts "Here is the error that 'git checkout' reported:"
314
+ puts
315
+ puts error
316
+ puts
317
+ exit 1
318
+ end
319
+ end
320
+
321
+ sh "git format-patch --full-index --stdout #{@common}..#{@current} > .git/update-patch"
322
+ out = sh "git am --rebasing < .git/update-patch 2> /dev/null"
323
+ while $?.exitstatus != 0
324
+ info = @repo.am_info
325
+ if @opts.verbose
326
+ if info[:subject] == "++WIP++"
327
+ puts "Conflict detected in working copy."
328
+ else
329
+ puts "Conflict detected applying: #{info[:subject]}"
330
+ end
331
+ end
332
+
333
+ unmerged = @repo.unmerged_files
334
+ handle_unmerged info, unmerged
335
+
336
+ if @repo.to_be_committed.empty?
337
+ out = @repo.git.am({:skip => true, "3" => true})
338
+ else
339
+ out = @repo.git.am({:resolved => true, "3" => true})
340
+ end
341
+ end
342
+
343
+ # Remove the patch we created contain all the rebased commits
344
+ File.unlink ".git/update-patch" rescue nil
345
+
346
+ rev = @repo.resolve_rev "HEAD"
347
+
348
+ # Update the branch ref to point to our new commit
349
+
350
+ @repo.git.update_ref({:m => "updated"}, @branch, rev, @current)
351
+ @repo.git.symbolic_ref({}, "HEAD", @branch)
352
+
353
+ # If we inserted a WIP commit on the top, remove the commit, but leave
354
+ # the work.
355
+ if @used_wip
356
+ @repo.git.reset({:mixed => true}, "HEAD^")
357
+ end
358
+
359
+ puts
360
+ puts "Updated. Imported #{@to_receive.size} commits, HEAD now pointed to #{rev[0,7]}."
361
+ puts
362
+
363
+ unless @opts.quiet
364
+ system "git diff --stat #{@common}..#{@origin}"
365
+ end
366
+
367
+ end
368
+ end
369
+
370
+ Update.new(opts).run
@@ -0,0 +1,3 @@
1
+ class Gx
2
+ VERSION = '1.0.0'
3
+ end
@@ -0,0 +1,144 @@
1
+ require 'rubygems'
2
+ require 'grit'
3
+
4
+ module Grit
5
+ class Repo
6
+
7
+ def self.current(goto=true)
8
+ # cd to the top of this git tree. If run via git's alias
9
+ # infrastructure, this is done for us. We do it again, just
10
+ # to be sure.
11
+
12
+ top = `git rev-parse --show-cdup 2>&1`.strip
13
+ if goto
14
+ Dir.chdir top unless top.empty?
15
+ return Grit::Repo.new(".")
16
+ else
17
+ return Grit::Repo.new(top)
18
+ end
19
+ end
20
+
21
+ # Given +hashish+, parse it and return the hash
22
+ # it refers to.
23
+ #
24
+ def resolve_rev(hashish)
25
+ hash = @git.rev_parse({:verify => true}, hashish)
26
+ return nil if $?.exitstatus != 0
27
+ return hash.strip
28
+ end
29
+
30
+ # Given +left+ and +right+, detect and return their
31
+ # closest common ancestor. Used to find the point to perform
32
+ # merges from.
33
+ #
34
+ # +right+ defaults to the current HEAD.
35
+ #
36
+ def find_ancestor(left, right=nil)
37
+ right ||= resolve_rev "HEAD"
38
+ hash = @git.merge_base({}, left, right)
39
+ return nil if $?.exitstatus != 0
40
+ return hash.strip
41
+ end
42
+
43
+ def revs_between(left, right)
44
+ @git.rev_list({}, "#{left}..#{right}").split("\n")
45
+ end
46
+
47
+ class UnmergedFile
48
+ def initialize(name)
49
+ @name = name
50
+ end
51
+
52
+ attr_accessor :original, :mine, :yours
53
+ end
54
+
55
+ def unmerged_files
56
+ files = Hash.new { |h,k| h[k] = UnmergedFile.new(k) }
57
+ @git.ls_files({:u => true}).split("\n").each do |line|
58
+ mode, hash, stage, name = line.split(/\s+/, 4)
59
+ case stage
60
+ when "1"
61
+ files[name].original = hash
62
+ when "2"
63
+ files[name].yours = hash
64
+ when "3"
65
+ files[name].mine = hash
66
+ end
67
+ end
68
+
69
+ return files
70
+ end
71
+
72
+ def Grit.rebase_dir
73
+ if File.directory? ".dotest"
74
+ return ".dotest"
75
+ elsif File.directory? ".git/rebase"
76
+ return ".git/rebase"
77
+ elsif File.directory? ".git/rebase-apply"
78
+ return ".git/rebase-apply"
79
+ else
80
+ raise "No rebase info found."
81
+ end
82
+ end
83
+
84
+ def am_info
85
+ info = {}
86
+ File.open("#{Grit.rebase_dir}/info") do |f|
87
+ f.readlines.each do |line|
88
+ line.strip!
89
+ break if line.empty?
90
+ key, val = line.split(": ")
91
+ info[key.downcase.to_sym] = val
92
+ end
93
+ end
94
+
95
+ if subject = info[:subject]
96
+ subject.gsub!(/^\[PATCH\] /,"")
97
+ end
98
+
99
+ return info
100
+ end
101
+
102
+ def to_be_committed
103
+ @git.diff_index({:cached => true, :name_only => true}, "HEAD").split("\n")
104
+ end
105
+
106
+ def path2ref(name)
107
+ name.gsub %r!^refs/heads/!, ""
108
+ end
109
+
110
+ def merge_info(branch)
111
+ repo = @git.config({}, "branch.#{branch}.remote").strip
112
+ ref = @git.config({}, "branch.#{branch}.merge").strip
113
+ return [repo, ref]
114
+ end
115
+
116
+ def merge_ref(branch)
117
+ repo, ref = merge_info(branch)
118
+ return nil if repo.empty?
119
+ path = "#{repo}/#{path2ref(ref)}"
120
+ return path
121
+ end
122
+
123
+ def merge_url(branch)
124
+ repo = @git.config({}, "branch.#{branch}.remote").strip
125
+ return "local" if repo == "."
126
+
127
+ @git.config({}, "remote.#{repo}.url").strip
128
+ end
129
+
130
+ def remote_info(who, which=nil)
131
+ if which
132
+ hash, name = @git.ls_remote({:timeout => false}, who, which).split(/\s+/, 2)
133
+ return hash
134
+ else
135
+ ret = {}
136
+ @git.ls_remote({:timeout => false}, who).split("\n").each do |line|
137
+ hash, name = line.split(/\s+/, 2)
138
+ ret[name] = hash
139
+ end
140
+ return ret
141
+ end
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,8 @@
1
+ require "test/unit"
2
+ require "gx"
3
+
4
+ class TestGx < Test::Unit::TestCase
5
+ def test_sanity
6
+ flunk "write tests or I will kneecap you"
7
+ end
8
+ end
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gx
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease:
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 0
10
+ version: 1.0.0
11
+ platform: ruby
12
+ authors:
13
+ - Evan Phoenix
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-03-22 00:00:00 -07:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: hoe
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 41
30
+ segments:
31
+ - 2
32
+ - 9
33
+ - 1
34
+ version: 2.9.1
35
+ type: :development
36
+ version_requirements: *id001
37
+ description: |-
38
+ Gx is 2 git related tools: gx-update and gx-publish.
39
+
40
+ gx-update is a replacement for 'git pull' that includes an integrated
41
+ conflict resolver.
42
+ email:
43
+ - evan@fallingsnow.net
44
+ executables:
45
+ - gx-publish
46
+ - gx-update
47
+ extensions: []
48
+
49
+ extra_rdoc_files:
50
+ - History.txt
51
+ - Manifest.txt
52
+ - README.txt
53
+ files:
54
+ - .autotest
55
+ - History.txt
56
+ - Manifest.txt
57
+ - README.txt
58
+ - Rakefile
59
+ - bin/gx-publish
60
+ - bin/gx-update
61
+ - lib/gx.rb
62
+ - lib/gx/enhance.rb
63
+ - test/test_gx.rb
64
+ - .gemtest
65
+ has_rdoc: true
66
+ homepage: http://github.com/evanphx/gx
67
+ licenses: []
68
+
69
+ post_install_message:
70
+ rdoc_options:
71
+ - --main
72
+ - README.txt
73
+ require_paths:
74
+ - lib
75
+ required_ruby_version: !ruby/object:Gem::Requirement
76
+ none: false
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ hash: 3
81
+ segments:
82
+ - 0
83
+ version: "0"
84
+ required_rubygems_version: !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ hash: 3
90
+ segments:
91
+ - 0
92
+ version: "0"
93
+ requirements: []
94
+
95
+ rubyforge_project: gx
96
+ rubygems_version: 1.6.2
97
+ signing_key:
98
+ specification_version: 3
99
+ summary: "Gx is 2 git related tools: gx-update and gx-publish"
100
+ test_files:
101
+ - test/test_gx.rb