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,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
@@ -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
@@ -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
@@ -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
@@ -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