jit 0.0.0 → 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.
Files changed (95) hide show
  1. checksums.yaml +5 -5
  2. data/LICENSE.txt +674 -0
  3. data/bin/jit +21 -0
  4. data/lib/color.rb +32 -0
  5. data/lib/command.rb +62 -0
  6. data/lib/command/add.rb +65 -0
  7. data/lib/command/base.rb +92 -0
  8. data/lib/command/branch.rb +199 -0
  9. data/lib/command/checkout.rb +104 -0
  10. data/lib/command/cherry_pick.rb +51 -0
  11. data/lib/command/commit.rb +86 -0
  12. data/lib/command/config.rb +126 -0
  13. data/lib/command/diff.rb +114 -0
  14. data/lib/command/fetch.rb +116 -0
  15. data/lib/command/init.rb +41 -0
  16. data/lib/command/log.rb +188 -0
  17. data/lib/command/merge.rb +148 -0
  18. data/lib/command/push.rb +172 -0
  19. data/lib/command/receive_pack.rb +92 -0
  20. data/lib/command/remote.rb +55 -0
  21. data/lib/command/reset.rb +64 -0
  22. data/lib/command/rev_list.rb +33 -0
  23. data/lib/command/revert.rb +69 -0
  24. data/lib/command/rm.rb +105 -0
  25. data/lib/command/shared/fast_forward.rb +19 -0
  26. data/lib/command/shared/print_diff.rb +116 -0
  27. data/lib/command/shared/receive_objects.rb +37 -0
  28. data/lib/command/shared/remote_agent.rb +44 -0
  29. data/lib/command/shared/remote_client.rb +82 -0
  30. data/lib/command/shared/send_objects.rb +24 -0
  31. data/lib/command/shared/sequencing.rb +146 -0
  32. data/lib/command/shared/write_commit.rb +167 -0
  33. data/lib/command/status.rb +210 -0
  34. data/lib/command/upload_pack.rb +54 -0
  35. data/lib/config.rb +240 -0
  36. data/lib/config/stack.rb +42 -0
  37. data/lib/database.rb +112 -0
  38. data/lib/database/author.rb +27 -0
  39. data/lib/database/backends.rb +57 -0
  40. data/lib/database/blob.rb +24 -0
  41. data/lib/database/commit.rb +70 -0
  42. data/lib/database/entry.rb +7 -0
  43. data/lib/database/loose.rb +70 -0
  44. data/lib/database/packed.rb +75 -0
  45. data/lib/database/tree.rb +77 -0
  46. data/lib/database/tree_diff.rb +88 -0
  47. data/lib/diff.rb +46 -0
  48. data/lib/diff/combined.rb +72 -0
  49. data/lib/diff/hunk.rb +64 -0
  50. data/lib/diff/myers.rb +90 -0
  51. data/lib/editor.rb +59 -0
  52. data/lib/index.rb +212 -0
  53. data/lib/index/checksum.rb +44 -0
  54. data/lib/index/entry.rb +91 -0
  55. data/lib/lockfile.rb +55 -0
  56. data/lib/merge/bases.rb +38 -0
  57. data/lib/merge/common_ancestors.rb +77 -0
  58. data/lib/merge/diff3.rb +156 -0
  59. data/lib/merge/inputs.rb +42 -0
  60. data/lib/merge/resolve.rb +178 -0
  61. data/lib/pack.rb +45 -0
  62. data/lib/pack/compressor.rb +83 -0
  63. data/lib/pack/delta.rb +58 -0
  64. data/lib/pack/entry.rb +54 -0
  65. data/lib/pack/expander.rb +54 -0
  66. data/lib/pack/index.rb +100 -0
  67. data/lib/pack/indexer.rb +200 -0
  68. data/lib/pack/numbers.rb +79 -0
  69. data/lib/pack/reader.rb +98 -0
  70. data/lib/pack/stream.rb +80 -0
  71. data/lib/pack/unpacker.rb +62 -0
  72. data/lib/pack/window.rb +47 -0
  73. data/lib/pack/writer.rb +92 -0
  74. data/lib/pack/xdelta.rb +118 -0
  75. data/lib/pager.rb +24 -0
  76. data/lib/progress.rb +78 -0
  77. data/lib/refs.rb +260 -0
  78. data/lib/remotes.rb +82 -0
  79. data/lib/remotes/protocol.rb +82 -0
  80. data/lib/remotes/refspec.rb +70 -0
  81. data/lib/remotes/remote.rb +57 -0
  82. data/lib/repository.rb +64 -0
  83. data/lib/repository/divergence.rb +21 -0
  84. data/lib/repository/hard_reset.rb +35 -0
  85. data/lib/repository/inspector.rb +49 -0
  86. data/lib/repository/migration.rb +168 -0
  87. data/lib/repository/pending_commit.rb +60 -0
  88. data/lib/repository/sequencer.rb +118 -0
  89. data/lib/repository/status.rb +98 -0
  90. data/lib/rev_list.rb +244 -0
  91. data/lib/revision.rb +155 -0
  92. data/lib/sorted_hash.rb +17 -0
  93. data/lib/temp_file.rb +34 -0
  94. data/lib/workspace.rb +107 -0
  95. metadata +103 -9
@@ -0,0 +1,118 @@
1
+ module Pack
2
+ class XDelta
3
+
4
+ BLOCK_SIZE = 16
5
+
6
+ def self.create_index(source)
7
+ blocks = source.bytesize / BLOCK_SIZE
8
+ index = {}
9
+
10
+ (0 ... blocks).each do |i|
11
+ offset = i * BLOCK_SIZE
12
+ slice = source.byteslice(offset, BLOCK_SIZE)
13
+
14
+ index[slice] ||= []
15
+ index[slice].push(offset)
16
+ end
17
+
18
+ new(source, index)
19
+ end
20
+
21
+ def initialize(source, index)
22
+ @source = source
23
+ @index = index
24
+ end
25
+
26
+ def compress(target)
27
+ @target = target
28
+ @offset = 0
29
+ @insert = []
30
+ @ops = []
31
+
32
+ generate_ops while @offset < @target.bytesize
33
+ flush_insert
34
+
35
+ @ops
36
+ end
37
+
38
+ private
39
+
40
+ def generate_ops
41
+ m_offset, m_size = longest_match
42
+ return push_insert if m_size == 0
43
+
44
+ m_offset, m_size = expand_match(m_offset, m_size)
45
+
46
+ flush_insert
47
+ @ops.push(Delta::Copy.new(m_offset, m_size))
48
+ end
49
+
50
+ def longest_match
51
+ slice = @target.byteslice(@offset, BLOCK_SIZE)
52
+ return [0, 0] unless @index.has_key?(slice)
53
+
54
+ m_offset = m_size = 0
55
+
56
+ @index[slice].each do |pos|
57
+ remaining = remaining_bytes(pos)
58
+ break if remaining <= m_size
59
+
60
+ s = match_from(pos, remaining)
61
+ next if m_size >= s - pos
62
+
63
+ m_offset = pos
64
+ m_size = s - pos
65
+ end
66
+
67
+ [m_offset, m_size]
68
+ end
69
+
70
+ def remaining_bytes(pos)
71
+ source_remaining = @source.bytesize - pos
72
+ target_remaining = @target.bytesize - @offset
73
+
74
+ [source_remaining, target_remaining, MAX_COPY_SIZE].min
75
+ end
76
+
77
+ def match_from(pos, remaining)
78
+ s, t = pos, @offset
79
+
80
+ while remaining > 0 and @source.getbyte(s) == @target.getbyte(t)
81
+ s, t = s + 1, t + 1
82
+ remaining -= 1
83
+ end
84
+
85
+ s
86
+ end
87
+
88
+ def expand_match(m_offset, m_size)
89
+ while m_offset > 0 and @source.getbyte(m_offset - 1) == @insert.last
90
+ break if m_size == MAX_COPY_SIZE
91
+
92
+ @offset -= 1
93
+ m_offset -= 1
94
+ m_size += 1
95
+
96
+ @insert.pop
97
+ end
98
+
99
+ @offset += m_size
100
+ [m_offset, m_size]
101
+ end
102
+
103
+ def push_insert
104
+ @insert.push(@target.getbyte(@offset))
105
+ @offset += 1
106
+ flush_insert(MAX_INSERT_SIZE)
107
+ end
108
+
109
+ def flush_insert(size = nil)
110
+ return if size and @insert.size < size
111
+ return if @insert.empty?
112
+
113
+ @ops.push(Delta::Insert.new(@insert.pack("C*")))
114
+ @insert = []
115
+ end
116
+
117
+ end
118
+ end
@@ -0,0 +1,24 @@
1
+ class Pager
2
+ PAGER_CMD = "less"
3
+ PAGER_ENV = { "LESS" => "FRX", "LV" => "-c" }
4
+
5
+ attr_reader :input
6
+
7
+ def initialize(env = {}, stdout = $stdout, stderr = $stderr)
8
+ env = PAGER_ENV.merge(env)
9
+ cmd = env["GIT_PAGER"] || env["PAGER"] || PAGER_CMD
10
+
11
+ reader, writer = IO.pipe
12
+ options = { :in => reader, :out => stdout, :err => stderr }
13
+
14
+ @pid = Process.spawn(env, cmd, options)
15
+ @input = writer
16
+
17
+ reader.close
18
+ end
19
+
20
+ def wait
21
+ Process.waitpid(@pid) if @pid
22
+ @pid = nil
23
+ end
24
+ end
@@ -0,0 +1,78 @@
1
+ class Progress
2
+ UNITS = ["B", "KiB", "MiB", "GiB"]
3
+ SCALE = 1024.0
4
+
5
+ def initialize(output)
6
+ @output = output
7
+ @message = nil
8
+ end
9
+
10
+ def start(message, total = nil)
11
+ return if ENV["NO_PROGRESS"] or not @output.isatty
12
+
13
+ @message = message
14
+ @total = total
15
+ @count = 0
16
+ @bytes = 0
17
+ @write_at = get_time
18
+ end
19
+
20
+ def tick(bytes = 0)
21
+ return unless @message
22
+
23
+ @count += 1
24
+ @bytes = bytes
25
+
26
+ current_time = get_time
27
+ return if current_time < @write_at + 0.05
28
+ @write_at = current_time
29
+
30
+ clear_line
31
+ @output.write(status_line)
32
+ end
33
+
34
+ def stop
35
+ return unless @message
36
+
37
+ @total = @count
38
+
39
+ clear_line
40
+ @output.puts(status_line)
41
+ @message = nil
42
+ end
43
+
44
+ private
45
+
46
+ def get_time
47
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
48
+ end
49
+
50
+ def clear_line
51
+ @output.write("\e[G\e[K")
52
+ end
53
+
54
+ def status_line
55
+ line = "#{ @message }: #{ format_count }"
56
+
57
+ line.concat(", #{ format_bytes }") if @bytes > 0
58
+ line.concat(", done.") if @count == @total
59
+
60
+ line
61
+ end
62
+
63
+ def format_count
64
+ if @total
65
+ percent = (@total == 0) ? 100 : 100 * @count / @total
66
+ "#{ percent }% (#{ @count }/#{ @total })"
67
+ else
68
+ "(#{ @count })"
69
+ end
70
+ end
71
+
72
+ def format_bytes
73
+ power = Math.log(@bytes, SCALE).floor
74
+ scaled = @bytes / (SCALE ** power)
75
+
76
+ format("%.2f #{ UNITS[power] }", scaled)
77
+ end
78
+ end
@@ -0,0 +1,260 @@
1
+ require "fileutils"
2
+ require "pathname"
3
+
4
+ require_relative "./lockfile"
5
+ require_relative "./revision"
6
+
7
+ class Refs
8
+ InvalidBranch = Class.new(StandardError)
9
+ StaleValue = Class.new(StandardError)
10
+
11
+ SymRef = Struct.new(:refs, :path) do
12
+ def read_oid
13
+ refs.read_ref(path)
14
+ end
15
+
16
+ def head?
17
+ path == HEAD
18
+ end
19
+
20
+ def branch?
21
+ path.start_with?("refs/heads/")
22
+ end
23
+
24
+ def remote?
25
+ path.start_with?("refs/remotes/")
26
+ end
27
+
28
+ def short_name
29
+ refs.short_name(path)
30
+ end
31
+ end
32
+
33
+ Ref = Struct.new(:oid) do
34
+ def read_oid
35
+ oid
36
+ end
37
+ end
38
+
39
+ HEAD = "HEAD"
40
+ ORIG_HEAD = "ORIG_HEAD"
41
+ SYMREF = /^ref: (.+)$/
42
+
43
+ REFS_DIR = Pathname.new("refs")
44
+ HEADS_DIR = REFS_DIR.join("heads")
45
+ REMOTES_DIR = REFS_DIR.join("remotes")
46
+
47
+ def initialize(pathname)
48
+ @pathname = pathname
49
+ @refs_path = @pathname.join(REFS_DIR)
50
+ @heads_path = @pathname.join(HEADS_DIR)
51
+ @remotes_path = @pathname.join(REMOTES_DIR)
52
+ end
53
+
54
+ def read_head
55
+ read_symref(@pathname.join(HEAD))
56
+ end
57
+
58
+ def update_head(oid)
59
+ update_symref(@pathname.join(HEAD), oid)
60
+ end
61
+
62
+ def set_head(revision, oid)
63
+ head = @pathname.join(HEAD)
64
+ path = @heads_path.join(revision)
65
+
66
+ if File.file?(path)
67
+ relative = path.relative_path_from(@pathname)
68
+ update_ref_file(head, "ref: #{ relative }")
69
+ else
70
+ update_ref_file(head, oid)
71
+ end
72
+ end
73
+
74
+ def read_ref(name)
75
+ path = path_for_name(name)
76
+ path ? read_symref(path) : nil
77
+ end
78
+
79
+ def update_ref(name, oid)
80
+ update_ref_file(@pathname.join(name), oid)
81
+ end
82
+
83
+ def compare_and_swap(name, old_oid, new_oid)
84
+ path = @pathname.join(name)
85
+
86
+ update_ref_file(path, new_oid) do
87
+ unless old_oid == read_symref(path)
88
+ raise StaleValue, "value of #{ name } changed since last read"
89
+ end
90
+ end
91
+ end
92
+
93
+ def create_branch(branch_name, start_oid)
94
+ path = @heads_path.join(branch_name)
95
+
96
+ unless Revision.valid_ref?(branch_name)
97
+ raise InvalidBranch, "'#{ branch_name }' is not a valid branch name."
98
+ end
99
+
100
+ if File.file?(path)
101
+ raise InvalidBranch, "A branch named '#{ branch_name }' already exists."
102
+ end
103
+
104
+ FileUtils.mkdir_p(path.dirname)
105
+ update_ref_file(path, start_oid)
106
+ end
107
+
108
+ def delete_branch(branch_name)
109
+ path = @heads_path.join(branch_name)
110
+
111
+ lockfile = Lockfile.new(path)
112
+ lockfile.hold_for_update
113
+
114
+ oid = read_symref(path)
115
+ raise InvalidBranch, "branch '#{ branch_name }' not found." unless oid
116
+
117
+ File.unlink(path)
118
+ oid
119
+ ensure
120
+ lockfile.rollback
121
+ end
122
+
123
+ def current_ref(source = HEAD)
124
+ ref = read_oid_or_symref(@pathname.join(source))
125
+
126
+ case ref
127
+ when SymRef then current_ref(ref.path)
128
+ when Ref, nil then SymRef.new(self, source)
129
+ end
130
+ end
131
+
132
+ def list_all_refs
133
+ [SymRef.new(self, HEAD)] + list_refs(@refs_path)
134
+ end
135
+
136
+ def list_branches
137
+ list_refs(@heads_path)
138
+ end
139
+
140
+ def list_remotes
141
+ list_refs(@remotes_path)
142
+ end
143
+
144
+ def reverse_refs
145
+ table = Hash.new { |hash, key| hash[key] = [] }
146
+
147
+ list_all_refs.each do |ref|
148
+ oid = ref.read_oid
149
+ table[oid].push(ref) if oid
150
+ end
151
+
152
+ table
153
+ end
154
+
155
+ def short_name(path)
156
+ path = @pathname.join(path)
157
+
158
+ prefix = [@remotes_path, @heads_path, @pathname].find do |dir|
159
+ path.dirname.ascend.any? { |parent| parent == dir }
160
+ end
161
+
162
+ path.relative_path_from(prefix).to_s
163
+ end
164
+
165
+ def long_name(ref)
166
+ path = path_for_name(ref)
167
+ return path.relative_path_from(@pathname).to_s if path
168
+
169
+ raise InvalidBranch,
170
+ "the requested upstream branch '#{ ref }' does not exist"
171
+ end
172
+
173
+ private
174
+
175
+ def list_refs(dirname)
176
+ names = Dir.entries(dirname) - [".", ".."]
177
+
178
+ names.map { |name| dirname.join(name) }.flat_map do |path|
179
+ if File.directory?(path)
180
+ list_refs(path)
181
+ else
182
+ path = path.relative_path_from(@pathname)
183
+ SymRef.new(self, path.to_s)
184
+ end
185
+ end
186
+
187
+ rescue Errno::ENOENT
188
+ []
189
+ end
190
+
191
+ def path_for_name(name)
192
+ prefixes = [@pathname, @refs_path, @heads_path, @remotes_path]
193
+ prefix = prefixes.find { |path| File.file? path.join(name) }
194
+
195
+ prefix ? prefix.join(name) : nil
196
+ end
197
+
198
+ def read_oid_or_symref(path)
199
+ data = File.read(path).strip
200
+ match = SYMREF.match(data)
201
+
202
+ match ? SymRef.new(self, match[1]) : Ref.new(data)
203
+ rescue Errno::ENOENT
204
+ nil
205
+ end
206
+
207
+ def read_symref(path)
208
+ ref = read_oid_or_symref(path)
209
+
210
+ case ref
211
+ when SymRef then read_symref(@pathname.join(ref.path))
212
+ when Ref then ref.oid
213
+ end
214
+ end
215
+
216
+ def update_ref_file(path, oid)
217
+ lockfile = Lockfile.new(path)
218
+
219
+ lockfile.hold_for_update
220
+ yield if block_given?
221
+
222
+ if oid
223
+ write_lockfile(lockfile, oid)
224
+ else
225
+ File.unlink(path) rescue Errno::ENOENT
226
+ lockfile.rollback
227
+ end
228
+
229
+ rescue Lockfile::MissingParent
230
+ FileUtils.mkdir_p(path.dirname)
231
+ retry
232
+ rescue => error
233
+ lockfile.rollback
234
+ raise error
235
+ end
236
+
237
+ def update_symref(path, oid)
238
+ lockfile = Lockfile.new(path)
239
+ lockfile.hold_for_update
240
+
241
+ ref = read_oid_or_symref(path)
242
+
243
+ unless ref.is_a?(SymRef)
244
+ write_lockfile(lockfile, oid)
245
+ return ref&.oid
246
+ end
247
+
248
+ begin
249
+ update_symref(@pathname.join(ref.path), oid)
250
+ ensure
251
+ lockfile.rollback
252
+ end
253
+ end
254
+
255
+ def write_lockfile(lockfile, oid)
256
+ lockfile.write(oid)
257
+ lockfile.write("\n")
258
+ lockfile.commit
259
+ end
260
+ end