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.
- checksums.yaml +5 -5
- data/LICENSE.txt +674 -0
- data/bin/jit +21 -0
- data/lib/color.rb +32 -0
- data/lib/command.rb +62 -0
- data/lib/command/add.rb +65 -0
- data/lib/command/base.rb +92 -0
- data/lib/command/branch.rb +199 -0
- data/lib/command/checkout.rb +104 -0
- data/lib/command/cherry_pick.rb +51 -0
- data/lib/command/commit.rb +86 -0
- data/lib/command/config.rb +126 -0
- data/lib/command/diff.rb +114 -0
- data/lib/command/fetch.rb +116 -0
- data/lib/command/init.rb +41 -0
- data/lib/command/log.rb +188 -0
- data/lib/command/merge.rb +148 -0
- data/lib/command/push.rb +172 -0
- data/lib/command/receive_pack.rb +92 -0
- data/lib/command/remote.rb +55 -0
- data/lib/command/reset.rb +64 -0
- data/lib/command/rev_list.rb +33 -0
- data/lib/command/revert.rb +69 -0
- data/lib/command/rm.rb +105 -0
- data/lib/command/shared/fast_forward.rb +19 -0
- data/lib/command/shared/print_diff.rb +116 -0
- data/lib/command/shared/receive_objects.rb +37 -0
- data/lib/command/shared/remote_agent.rb +44 -0
- data/lib/command/shared/remote_client.rb +82 -0
- data/lib/command/shared/send_objects.rb +24 -0
- data/lib/command/shared/sequencing.rb +146 -0
- data/lib/command/shared/write_commit.rb +167 -0
- data/lib/command/status.rb +210 -0
- data/lib/command/upload_pack.rb +54 -0
- data/lib/config.rb +240 -0
- data/lib/config/stack.rb +42 -0
- data/lib/database.rb +112 -0
- data/lib/database/author.rb +27 -0
- data/lib/database/backends.rb +57 -0
- data/lib/database/blob.rb +24 -0
- data/lib/database/commit.rb +70 -0
- data/lib/database/entry.rb +7 -0
- data/lib/database/loose.rb +70 -0
- data/lib/database/packed.rb +75 -0
- data/lib/database/tree.rb +77 -0
- data/lib/database/tree_diff.rb +88 -0
- data/lib/diff.rb +46 -0
- data/lib/diff/combined.rb +72 -0
- data/lib/diff/hunk.rb +64 -0
- data/lib/diff/myers.rb +90 -0
- data/lib/editor.rb +59 -0
- data/lib/index.rb +212 -0
- data/lib/index/checksum.rb +44 -0
- data/lib/index/entry.rb +91 -0
- data/lib/lockfile.rb +55 -0
- data/lib/merge/bases.rb +38 -0
- data/lib/merge/common_ancestors.rb +77 -0
- data/lib/merge/diff3.rb +156 -0
- data/lib/merge/inputs.rb +42 -0
- data/lib/merge/resolve.rb +178 -0
- data/lib/pack.rb +45 -0
- data/lib/pack/compressor.rb +83 -0
- data/lib/pack/delta.rb +58 -0
- data/lib/pack/entry.rb +54 -0
- data/lib/pack/expander.rb +54 -0
- data/lib/pack/index.rb +100 -0
- data/lib/pack/indexer.rb +200 -0
- data/lib/pack/numbers.rb +79 -0
- data/lib/pack/reader.rb +98 -0
- data/lib/pack/stream.rb +80 -0
- data/lib/pack/unpacker.rb +62 -0
- data/lib/pack/window.rb +47 -0
- data/lib/pack/writer.rb +92 -0
- data/lib/pack/xdelta.rb +118 -0
- data/lib/pager.rb +24 -0
- data/lib/progress.rb +78 -0
- data/lib/refs.rb +260 -0
- data/lib/remotes.rb +82 -0
- data/lib/remotes/protocol.rb +82 -0
- data/lib/remotes/refspec.rb +70 -0
- data/lib/remotes/remote.rb +57 -0
- data/lib/repository.rb +64 -0
- data/lib/repository/divergence.rb +21 -0
- data/lib/repository/hard_reset.rb +35 -0
- data/lib/repository/inspector.rb +49 -0
- data/lib/repository/migration.rb +168 -0
- data/lib/repository/pending_commit.rb +60 -0
- data/lib/repository/sequencer.rb +118 -0
- data/lib/repository/status.rb +98 -0
- data/lib/rev_list.rb +244 -0
- data/lib/revision.rb +155 -0
- data/lib/sorted_hash.rb +17 -0
- data/lib/temp_file.rb +34 -0
- data/lib/workspace.rb +107 -0
- metadata +103 -9
@@ -0,0 +1,77 @@
|
|
1
|
+
class Database
|
2
|
+
class Tree
|
3
|
+
|
4
|
+
ENTRY_FORMAT = "Z*H40"
|
5
|
+
TREE_MODE = 040000
|
6
|
+
|
7
|
+
attr_accessor :oid, :entries
|
8
|
+
|
9
|
+
def self.parse(scanner)
|
10
|
+
entries = {}
|
11
|
+
|
12
|
+
until scanner.eos?
|
13
|
+
mode = scanner.scan_until(/ /).strip.to_i(8)
|
14
|
+
name = scanner.scan_until(/\0/)[0..-2]
|
15
|
+
|
16
|
+
oid = scanner.peek(20).unpack("H40").first
|
17
|
+
scanner.pos += 20
|
18
|
+
|
19
|
+
entries[name] = Entry.new(oid, mode)
|
20
|
+
end
|
21
|
+
|
22
|
+
Tree.new(entries)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.build(entries)
|
26
|
+
root = Tree.new
|
27
|
+
|
28
|
+
entries.each do |entry|
|
29
|
+
root.add_entry(entry.parent_directories, entry)
|
30
|
+
end
|
31
|
+
|
32
|
+
root
|
33
|
+
end
|
34
|
+
|
35
|
+
def initialize(entries = {})
|
36
|
+
@entries = entries
|
37
|
+
end
|
38
|
+
|
39
|
+
def each_entry(&block)
|
40
|
+
@entries.each(&block)
|
41
|
+
end
|
42
|
+
|
43
|
+
def add_entry(parents, entry)
|
44
|
+
if parents.empty?
|
45
|
+
@entries[entry.basename] = entry
|
46
|
+
else
|
47
|
+
tree = @entries[parents.first.basename] ||= Tree.new
|
48
|
+
tree.add_entry(parents.drop(1), entry)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def traverse(&block)
|
53
|
+
@entries.each do |name, entry|
|
54
|
+
entry.traverse(&block) if entry.is_a?(Tree)
|
55
|
+
end
|
56
|
+
block.call(self)
|
57
|
+
end
|
58
|
+
|
59
|
+
def mode
|
60
|
+
TREE_MODE
|
61
|
+
end
|
62
|
+
|
63
|
+
def type
|
64
|
+
"tree"
|
65
|
+
end
|
66
|
+
|
67
|
+
def to_s
|
68
|
+
entries = @entries.map do |name, entry|
|
69
|
+
mode = entry.mode.to_s(8)
|
70
|
+
["#{ mode } #{ name }", entry.oid].pack(ENTRY_FORMAT)
|
71
|
+
end
|
72
|
+
|
73
|
+
entries.join("")
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require "pathname"
|
2
|
+
|
3
|
+
class Database
|
4
|
+
class TreeDiff
|
5
|
+
|
6
|
+
attr_reader :changes
|
7
|
+
|
8
|
+
def initialize(database, prune = [])
|
9
|
+
@database = database
|
10
|
+
@changes = {}
|
11
|
+
|
12
|
+
build_routing_table(prune)
|
13
|
+
end
|
14
|
+
|
15
|
+
def compare_oids(a, b, prefix = Pathname.new(""))
|
16
|
+
return if a == b
|
17
|
+
|
18
|
+
a_entries = a ? oid_to_tree(a).entries : {}
|
19
|
+
b_entries = b ? oid_to_tree(b).entries : {}
|
20
|
+
|
21
|
+
detect_deletions(a_entries, b_entries, prefix)
|
22
|
+
detect_additions(a_entries, b_entries, prefix)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def build_routing_table(prune)
|
28
|
+
@routes = {}
|
29
|
+
|
30
|
+
prune.each do |path|
|
31
|
+
table = @routes
|
32
|
+
path.each_filename { |name| table = table[name] ||= {} }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def routes_for_prefix(prefix)
|
37
|
+
prefix.each_filename.reduce(@routes) { |table, name| table[name] || {} }
|
38
|
+
end
|
39
|
+
|
40
|
+
def oid_to_tree(oid)
|
41
|
+
object = @database.load(oid)
|
42
|
+
|
43
|
+
case object
|
44
|
+
when Commit then @database.load(object.tree)
|
45
|
+
when Tree then object
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def detect_deletions(a, b, prefix)
|
50
|
+
routes = routes_for_prefix(prefix)
|
51
|
+
|
52
|
+
a.each do |name, entry|
|
53
|
+
next unless routes.empty? or routes.has_key?(name)
|
54
|
+
|
55
|
+
path = prefix.join(name)
|
56
|
+
other = b[name]
|
57
|
+
|
58
|
+
next if entry == other
|
59
|
+
|
60
|
+
tree_a, tree_b = [entry, other].map { |e| e&.tree? ? e.oid : nil }
|
61
|
+
compare_oids(tree_a, tree_b, path)
|
62
|
+
|
63
|
+
blobs = [entry, other].map { |e| e&.tree? ? nil : e }
|
64
|
+
@changes[path] = blobs if blobs.any?
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def detect_additions(a, b, prefix)
|
69
|
+
routes = routes_for_prefix(prefix)
|
70
|
+
|
71
|
+
b.each do |name, entry|
|
72
|
+
next unless routes.empty? or routes.has_key?(name)
|
73
|
+
|
74
|
+
path = prefix.join(name)
|
75
|
+
other = a[name]
|
76
|
+
|
77
|
+
next if other
|
78
|
+
|
79
|
+
if entry.tree?
|
80
|
+
compare_oids(nil, entry.oid, path)
|
81
|
+
else
|
82
|
+
@changes[path] = [nil, entry]
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
data/lib/diff.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require_relative "./diff/combined"
|
2
|
+
require_relative "./diff/hunk"
|
3
|
+
require_relative "./diff/myers"
|
4
|
+
|
5
|
+
module Diff
|
6
|
+
SYMBOLS = {
|
7
|
+
:eql => " ",
|
8
|
+
:ins => "+",
|
9
|
+
:del => "-"
|
10
|
+
}
|
11
|
+
|
12
|
+
Line = Struct.new(:number, :text)
|
13
|
+
|
14
|
+
Edit = Struct.new(:type, :a_line, :b_line) do
|
15
|
+
def a_lines
|
16
|
+
[a_line]
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_s
|
20
|
+
line = a_line || b_line
|
21
|
+
SYMBOLS.fetch(type) + line.text
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.lines(document)
|
26
|
+
document = document.lines if document.is_a?(String)
|
27
|
+
document.map.with_index { |text, i| Line.new(i + 1, text) }
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.diff(a, b)
|
31
|
+
Myers.diff(lines(a), lines(b))
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.diff_hunks(a, b)
|
35
|
+
Hunk.filter(diff(a, b))
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.combined(as, b)
|
39
|
+
diffs = as.map { |a| diff(a, b) }
|
40
|
+
Combined.new(diffs).to_a
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.combined_hunks(as, b)
|
44
|
+
Hunk.filter(combined(as, b))
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Diff
|
2
|
+
class Combined
|
3
|
+
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
Row = Struct.new(:edits) do
|
7
|
+
def type
|
8
|
+
types = edits.compact.map(&:type)
|
9
|
+
types.include?(:ins) ? :ins : types.first
|
10
|
+
end
|
11
|
+
|
12
|
+
def a_lines
|
13
|
+
edits.map { |edit| edit&.a_line }
|
14
|
+
end
|
15
|
+
|
16
|
+
def b_line
|
17
|
+
edits.first&.b_line
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_s
|
21
|
+
symbols = edits.map { |edit| SYMBOLS.fetch(edit&.type, " ") }
|
22
|
+
|
23
|
+
del = edits.find { |edit| edit&.type == :del }
|
24
|
+
line = del ? del.a_line : edits.first.b_line
|
25
|
+
|
26
|
+
symbols.join("") + line.text
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize(diffs)
|
31
|
+
@diffs = diffs
|
32
|
+
end
|
33
|
+
|
34
|
+
def each
|
35
|
+
@offsets = @diffs.map { 0 }
|
36
|
+
|
37
|
+
loop do
|
38
|
+
@diffs.each_with_index do |diff, i|
|
39
|
+
consume_deletions(diff, i) { |row| yield row }
|
40
|
+
end
|
41
|
+
|
42
|
+
return if complete?
|
43
|
+
|
44
|
+
edits = offset_diffs.map { |offset, diff| diff[offset] }
|
45
|
+
@offsets.map! { |offset| offset + 1 }
|
46
|
+
|
47
|
+
yield Row.new(edits)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def complete?
|
54
|
+
offset_diffs.all? { |offset, diff| offset == diff.size }
|
55
|
+
end
|
56
|
+
|
57
|
+
def offset_diffs
|
58
|
+
@offsets.zip(@diffs)
|
59
|
+
end
|
60
|
+
|
61
|
+
def consume_deletions(diff, i)
|
62
|
+
while @offsets[i] < diff.size and diff[@offsets[i]].type == :del
|
63
|
+
edits = Array.new(@diffs.size)
|
64
|
+
edits[i] = diff[@offsets[i]]
|
65
|
+
@offsets[i] += 1
|
66
|
+
|
67
|
+
yield Row.new(edits)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
data/lib/diff/hunk.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
module Diff
|
2
|
+
|
3
|
+
HUNK_CONTEXT = 3
|
4
|
+
|
5
|
+
Hunk = Struct.new(:a_starts, :b_start, :edits) do
|
6
|
+
def self.filter(edits)
|
7
|
+
hunks = []
|
8
|
+
offset = 0
|
9
|
+
|
10
|
+
loop do
|
11
|
+
offset += 1 while edits[offset]&.type == :eql
|
12
|
+
return hunks if offset >= edits.size
|
13
|
+
|
14
|
+
offset -= HUNK_CONTEXT + 1
|
15
|
+
|
16
|
+
a_starts = (offset < 0) ? [] : edits[offset].a_lines.map(&:number)
|
17
|
+
b_start = (offset < 0) ? nil : edits[offset].b_line.number
|
18
|
+
|
19
|
+
hunks.push(Hunk.new(a_starts, b_start, []))
|
20
|
+
offset = build_hunk(hunks.last, edits, offset)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.build_hunk(hunk, edits, offset)
|
25
|
+
counter = -1
|
26
|
+
|
27
|
+
until counter == 0
|
28
|
+
hunk.edits.push(edits[offset]) if offset >= 0 and counter > 0
|
29
|
+
|
30
|
+
offset += 1
|
31
|
+
break if offset >= edits.size
|
32
|
+
|
33
|
+
case edits[offset + HUNK_CONTEXT]&.type
|
34
|
+
when :ins, :del
|
35
|
+
counter = 2 * HUNK_CONTEXT + 1
|
36
|
+
else
|
37
|
+
counter -= 1
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
offset
|
42
|
+
end
|
43
|
+
|
44
|
+
def header
|
45
|
+
a_lines = edits.map(&:a_lines).transpose
|
46
|
+
offsets = a_lines.map.with_index { |lines, i| format("-", lines, a_starts[i]) }
|
47
|
+
|
48
|
+
offsets.push(format("+", edits.map(&:b_line), b_start))
|
49
|
+
sep = "@" * offsets.size
|
50
|
+
|
51
|
+
[sep, *offsets, sep].join(" ")
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def format(sign, lines, start)
|
57
|
+
lines = lines.compact
|
58
|
+
start = lines.first&.number || start || 0
|
59
|
+
|
60
|
+
"#{ sign }#{ start },#{ lines.size }"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
data/lib/diff/myers.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
module Diff
|
2
|
+
class Myers
|
3
|
+
|
4
|
+
def self.diff(a, b)
|
5
|
+
new(a, b).diff
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize(a, b)
|
9
|
+
@a, @b = a, b
|
10
|
+
end
|
11
|
+
|
12
|
+
def diff
|
13
|
+
diff = []
|
14
|
+
|
15
|
+
backtrack do |prev_x, prev_y, x, y|
|
16
|
+
a_line, b_line = @a[prev_x], @b[prev_y]
|
17
|
+
|
18
|
+
if x == prev_x
|
19
|
+
diff.push(Edit.new(:ins, nil, b_line))
|
20
|
+
elsif y == prev_y
|
21
|
+
diff.push(Edit.new(:del, a_line, nil))
|
22
|
+
else
|
23
|
+
diff.push(Edit.new(:eql, a_line, b_line))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
diff.reverse
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def backtrack
|
33
|
+
x, y = @a.size, @b.size
|
34
|
+
|
35
|
+
shortest_edit.each_with_index.reverse_each do |v, d|
|
36
|
+
k = x - y
|
37
|
+
|
38
|
+
if k == -d or (k != d and v[k - 1] < v[k + 1])
|
39
|
+
prev_k = k + 1
|
40
|
+
else
|
41
|
+
prev_k = k - 1
|
42
|
+
end
|
43
|
+
|
44
|
+
prev_x = v[prev_k]
|
45
|
+
prev_y = prev_x - prev_k
|
46
|
+
|
47
|
+
while x > prev_x and y > prev_y
|
48
|
+
yield x - 1, y - 1, x, y
|
49
|
+
x, y = x - 1, y - 1
|
50
|
+
end
|
51
|
+
|
52
|
+
yield prev_x, prev_y, x, y if d > 0
|
53
|
+
|
54
|
+
x, y = prev_x, prev_y
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def shortest_edit
|
59
|
+
n, m = @a.size, @b.size
|
60
|
+
max = n + m
|
61
|
+
|
62
|
+
v = Array.new(2 * max + 1)
|
63
|
+
v[1] = 0
|
64
|
+
trace = []
|
65
|
+
|
66
|
+
(0 .. max).step do |d|
|
67
|
+
trace.push(v.clone)
|
68
|
+
|
69
|
+
(-d .. d).step(2) do |k|
|
70
|
+
if k == -d or (k != d and v[k - 1] < v[k + 1])
|
71
|
+
x = v[k + 1]
|
72
|
+
else
|
73
|
+
x = v[k - 1] + 1
|
74
|
+
end
|
75
|
+
|
76
|
+
y = x - k
|
77
|
+
|
78
|
+
while x < n and y < m and @a[x].text == @b[y].text
|
79
|
+
x, y = x + 1, y + 1
|
80
|
+
end
|
81
|
+
|
82
|
+
v[k] = x
|
83
|
+
|
84
|
+
return trace if x >= n and y >= m
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
data/lib/editor.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require "shellwords"
|
2
|
+
|
3
|
+
class Editor
|
4
|
+
DEFAULT_EDITOR = "vi"
|
5
|
+
|
6
|
+
def self.edit(path, command)
|
7
|
+
editor = new(path, command)
|
8
|
+
yield editor
|
9
|
+
editor.edit_file
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(path, command)
|
13
|
+
@path = path
|
14
|
+
@command = command || DEFAULT_EDITOR
|
15
|
+
@closed = false
|
16
|
+
end
|
17
|
+
|
18
|
+
def puts(string)
|
19
|
+
return if @closed
|
20
|
+
file.puts(string)
|
21
|
+
end
|
22
|
+
|
23
|
+
def note(string)
|
24
|
+
return if @closed
|
25
|
+
string.each_line { |line| file.puts("# #{ line }") }
|
26
|
+
end
|
27
|
+
|
28
|
+
def close
|
29
|
+
@closed = true
|
30
|
+
end
|
31
|
+
|
32
|
+
def edit_file
|
33
|
+
file.close
|
34
|
+
editor_argv = Shellwords.shellsplit(@command) + [@path.to_s]
|
35
|
+
|
36
|
+
unless @closed or system(*editor_argv)
|
37
|
+
raise "There was a problem with the editor '#{ @command }'."
|
38
|
+
end
|
39
|
+
|
40
|
+
remove_notes(File.read(@path))
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def remove_notes(string)
|
46
|
+
lines = string.lines.reject { |line| line.start_with?("#") }
|
47
|
+
|
48
|
+
if lines.all? { |line| /^\s*$/ =~ line }
|
49
|
+
nil
|
50
|
+
else
|
51
|
+
"#{ lines.join("").strip }\n"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def file
|
56
|
+
flags = File::WRONLY | File::CREAT | File::TRUNC
|
57
|
+
@file ||= File.open(@path, flags)
|
58
|
+
end
|
59
|
+
end
|