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,172 @@
1
+ require_relative "./base"
2
+ require_relative "./shared/fast_forward"
3
+ require_relative "./shared/remote_client"
4
+ require_relative "./shared/send_objects"
5
+ require_relative "../remotes"
6
+ require_relative "../revision"
7
+
8
+ module Command
9
+ class Push < Base
10
+
11
+ include FastForward
12
+ include RemoteClient
13
+ include SendObjects
14
+
15
+ CAPABILITIES = ["report-status"]
16
+ RECEIVE_PACK = "git-receive-pack"
17
+
18
+ UNPACK_LINE = /^unpack (.+)$/
19
+ UPDATE_LINE = /^(ok|ng) (\S+)(.*)$/
20
+
21
+ def define_options
22
+ @parser.on("-f", "--force") { @options[:force] = true }
23
+
24
+ @parser.on "--receive-pack=<receive-pack>" do |receiver|
25
+ @options[:receiver] = receiver
26
+ end
27
+ end
28
+
29
+ def run
30
+ configure
31
+ start_agent("push", @receiver, @push_url, CAPABILITIES)
32
+
33
+ recv_references
34
+ send_update_requests
35
+ send_objects
36
+ print_summary
37
+ recv_report_status
38
+
39
+ exit (@errors.empty? ? 0 : 1)
40
+ end
41
+
42
+ private
43
+
44
+ def configure
45
+ current_branch = repo.refs.current_ref.short_name
46
+ branch_remote = repo.config.get(["branch", current_branch, "remote"])
47
+ branch_merge = repo.config.get(["branch", current_branch, "merge"])
48
+
49
+ name = @args.fetch(0, branch_remote || Remotes::DEFAULT_REMOTE)
50
+ remote = repo.remotes.get(name)
51
+
52
+ @push_url = remote&.push_url || @args[0]
53
+ @fetch_specs = remote&.fetch_specs || []
54
+ @receiver = @options[:receiver] || remote&.receiver || RECEIVE_PACK
55
+
56
+ if @args.size > 1
57
+ @push_specs = @args.drop(1)
58
+ elsif branch_merge
59
+ spec = Remotes::Refspec.new(current_branch, branch_merge, false)
60
+ @push_specs = [spec.to_s]
61
+ else
62
+ @push_specs = remote&.push_specs
63
+ end
64
+ end
65
+
66
+ def send_update_requests
67
+ @updates = {}
68
+ @errors = []
69
+
70
+ local_refs = repo.refs.list_all_refs.map(&:path).sort
71
+ targets = Remotes::Refspec.expand(@push_specs, local_refs)
72
+
73
+ targets.each do |target, (source, forced)|
74
+ select_update(target, source, forced)
75
+ end
76
+
77
+ @updates.each { |ref, (*, old, new)| send_update(ref, old, new) }
78
+ @conn.send_packet(nil)
79
+ end
80
+
81
+ def select_update(target, source, forced)
82
+ return select_deletion(target) unless source
83
+
84
+ old_oid = @remote_refs[target]
85
+ new_oid = Revision.new(repo, source).resolve
86
+
87
+ return if old_oid == new_oid
88
+
89
+ ff_error = fast_forward_error(old_oid, new_oid)
90
+
91
+ if @options[:force] or forced or ff_error == nil
92
+ @updates[target] = [source, ff_error, old_oid, new_oid]
93
+ else
94
+ @errors.push([[source, target], ff_error])
95
+ end
96
+ end
97
+
98
+ def select_deletion(target)
99
+ if @conn.capable?("delete-refs")
100
+ @updates[target] = [nil, nil, @remote_refs[target], nil]
101
+ else
102
+ @errors.push([[nil, target], "remote does not support deleting refs"])
103
+ end
104
+ end
105
+
106
+ def send_update(ref, old_oid, new_oid)
107
+ old_oid = nil_to_zero(old_oid)
108
+ new_oid = nil_to_zero(new_oid)
109
+
110
+ @conn.send_packet("#{ old_oid } #{ new_oid } #{ ref }")
111
+ end
112
+
113
+ def nil_to_zero(oid)
114
+ oid == nil ? ZERO_OID : oid
115
+ end
116
+
117
+ def send_objects
118
+ revs = @updates.values.map(&:last).compact
119
+ return if revs.empty?
120
+
121
+ revs += @remote_refs.values.map { |oid| "^#{ oid }" }
122
+
123
+ send_packed_objects(revs)
124
+ end
125
+
126
+ def print_summary
127
+ if @updates.empty? and @errors.empty?
128
+ @stderr.puts "Everything up-to-date"
129
+ else
130
+ @stderr.puts "To #{ @push_url }"
131
+ @errors.each { |ref_names, error| report_ref_update(ref_names, error) }
132
+ end
133
+ end
134
+
135
+ def recv_report_status
136
+ return unless @conn.capable?("report-status") and not @updates.empty?
137
+
138
+ unpack_result = UNPACK_LINE.match(@conn.recv_packet)[1]
139
+
140
+ unless unpack_result == "ok"
141
+ @stderr.puts "error: remote unpack failed: #{ unpack_result }"
142
+ end
143
+
144
+ @conn.recv_until(nil) { |line| handle_status(line) }
145
+ end
146
+
147
+ def handle_status(line)
148
+ return unless match = UPDATE_LINE.match(line)
149
+
150
+ status = match[1]
151
+ ref = match[2]
152
+ error = (status == "ok") ? nil : match[3].strip
153
+
154
+ @errors.push([ref, error]) if error
155
+ report_update(ref, error)
156
+
157
+ targets = Remotes::Refspec.expand(@fetch_specs, [ref])
158
+
159
+ targets.each do |local_ref, (remote_ref, _)|
160
+ new_oid = @updates[remote_ref].last
161
+ repo.refs.update_ref(local_ref, new_oid) unless error
162
+ end
163
+ end
164
+
165
+ def report_update(target, error)
166
+ source, ff_error, old_oid, new_oid = @updates[target]
167
+ ref_names = [source, target]
168
+ report_ref_update(ref_names, error, old_oid, new_oid, ff_error == nil)
169
+ end
170
+
171
+ end
172
+ end
@@ -0,0 +1,92 @@
1
+ require_relative "./base"
2
+ require_relative "./shared/fast_forward"
3
+ require_relative "./shared/receive_objects"
4
+ require_relative "./shared/remote_agent"
5
+
6
+ module Command
7
+ class ReceivePack < Base
8
+
9
+ include FastForward
10
+ include ReceiveObjects
11
+ include RemoteAgent
12
+
13
+ CAPABILITIES = ["no-thin", "report-status", "delete-refs", "ofs-delta"]
14
+
15
+ def run
16
+ accept_client("receive-pack", CAPABILITIES)
17
+
18
+ send_references
19
+ recv_update_requests
20
+ recv_objects
21
+ update_refs
22
+
23
+ exit 0
24
+ end
25
+
26
+ private
27
+
28
+ def recv_update_requests
29
+ @requests = {}
30
+
31
+ @conn.recv_until(nil) do |line|
32
+ old_oid, new_oid, ref = line.split(/ +/)
33
+ @requests[ref] = [old_oid, new_oid].map { |oid| zero_to_nil(oid) }
34
+ end
35
+ end
36
+
37
+ def zero_to_nil(oid)
38
+ oid == ZERO_OID ? nil : oid
39
+ end
40
+
41
+ def recv_objects
42
+ @unpack_error = nil
43
+ unpack_limit = repo.config.get(["receive", "unpackLimit"])
44
+ recv_packed_objects(unpack_limit) if @requests.values.any?(&:last)
45
+ report_status("unpack ok")
46
+ rescue => error
47
+ @unpack_error = error
48
+ report_status("unpack #{ error.message }")
49
+ end
50
+
51
+ def update_refs
52
+ @requests.each { |ref, (old, new)| update_ref(ref, old, new) }
53
+ report_status(nil)
54
+ end
55
+
56
+ def update_ref(ref, old_oid, new_oid)
57
+ return report_status("ng #{ ref } unpacker error") if @unpack_error
58
+
59
+ validate_update(ref, old_oid, new_oid)
60
+ repo.refs.compare_and_swap(ref, old_oid, new_oid)
61
+ report_status("ok #{ ref }")
62
+ rescue => error
63
+ report_status("ng #{ ref } #{ error.message }")
64
+ end
65
+
66
+ def validate_update(ref, old_oid, new_oid)
67
+ if repo.config.get(["receive", "denyDeletes"])
68
+ raise "deletion prohibited" unless new_oid
69
+ end
70
+
71
+ if repo.config.get(["receive", "denyNonFastForwards"])
72
+ raise "non-fast-forward" if fast_forward_error(old_oid, new_oid)
73
+ end
74
+
75
+ return unless repo.config.get(["core", "bare"]) == false and
76
+ repo.refs.current_ref.path == ref
77
+
78
+ unless repo.config.get(["receive", "denyCurrentBranch"]) == false
79
+ raise "branch is currently checked out" if new_oid
80
+ end
81
+
82
+ unless repo.config.get(["receive", "denyDeleteCurrent"]) == false
83
+ raise "deletion of the current branch prohibited" unless new_oid
84
+ end
85
+ end
86
+
87
+ def report_status(line)
88
+ @conn.send_packet(line) if @conn.capable?("report-status")
89
+ end
90
+
91
+ end
92
+ end
@@ -0,0 +1,55 @@
1
+ require_relative "./base"
2
+
3
+ module Command
4
+ class Remote < Base
5
+
6
+ def define_options
7
+ @parser.on("-v", "--verbose") { @options[:verbose] = true }
8
+
9
+ @options[:tracked] = []
10
+ @parser.on("-t <branch>") { |branch| @options[:tracked].push(branch) }
11
+ end
12
+
13
+ def run
14
+ case @args.shift
15
+ when "add" then add_remote
16
+ when "remove" then remove_remote
17
+ else list_remotes
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def add_remote
24
+ name, url = @args[0], @args[1]
25
+ repo.remotes.add(name, url, @options[:tracked])
26
+ exit 0
27
+ rescue Remotes::InvalidRemote => error
28
+ @stderr.puts "fatal: #{ error.message }"
29
+ exit 128
30
+ end
31
+
32
+ def remove_remote
33
+ repo.remotes.remove(@args[0])
34
+ exit 0
35
+ rescue Remotes::InvalidRemote => error
36
+ @stderr.puts "fatal: #{ error.message }"
37
+ exit 128
38
+ end
39
+
40
+ def list_remotes
41
+ repo.remotes.list_remotes.each { |name| list_remote(name) }
42
+ exit 0
43
+ end
44
+
45
+ def list_remote(name)
46
+ return puts name unless @options[:verbose]
47
+
48
+ remote = repo.remotes.get(name)
49
+
50
+ puts "#{ name }\t#{ remote.fetch_url } (fetch)"
51
+ puts "#{ name }\t#{ remote.push_url } (push)"
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,64 @@
1
+ require "pathname"
2
+
3
+ require_relative "./base"
4
+ require_relative "../revision"
5
+
6
+ module Command
7
+ class Reset < Base
8
+
9
+ def define_options
10
+ @options[:mode] = :mixed
11
+
12
+ @parser.on("--soft") { @options[:mode] = :soft }
13
+ @parser.on("--mixed") { @options[:mode] = :mixed }
14
+ @parser.on("--hard") { @options[:mode] = :hard }
15
+ end
16
+
17
+ def run
18
+ select_commit_oid
19
+
20
+ repo.index.load_for_update
21
+ reset_files
22
+ repo.index.write_updates
23
+
24
+ if @args.empty?
25
+ head_oid = repo.refs.update_head(@commit_oid)
26
+ repo.refs.update_ref(Refs::ORIG_HEAD, head_oid)
27
+ end
28
+
29
+ exit 0
30
+ end
31
+
32
+ private
33
+
34
+ def select_commit_oid
35
+ revision = @args.fetch(0, Revision::HEAD)
36
+ @commit_oid = Revision.new(repo, revision).resolve
37
+ @args.shift
38
+ rescue Revision::InvalidObject
39
+ @commit_oid = repo.refs.read_head
40
+ end
41
+
42
+ def reset_files
43
+ return if @options[:mode] == :soft
44
+ return repo.hard_reset(@commit_oid) if @options[:mode] == :hard
45
+
46
+ if @args.empty?
47
+ repo.index.clear!
48
+ reset_path(nil)
49
+ else
50
+ @args.each { |path| reset_path(Pathname.new(path)) }
51
+ end
52
+ end
53
+
54
+ def reset_path(pathname)
55
+ listing = repo.database.load_tree_list(@commit_oid, pathname)
56
+ repo.index.remove(pathname) if pathname
57
+
58
+ listing.each do |path, entry|
59
+ repo.index.add_from_db(path, entry)
60
+ end
61
+ end
62
+
63
+ end
64
+ end
@@ -0,0 +1,33 @@
1
+ require_relative "./base"
2
+ require_relative "../rev_list"
3
+
4
+ module Command
5
+ class RevList < Base
6
+
7
+ def define_options
8
+ @parser.on("--all") { @options[:all] = true }
9
+ @parser.on("--branches") { @options[:branches] = true }
10
+ @parser.on("--remotes") { @options[:remotes] = true }
11
+
12
+ @parser.on("--ignore-missing") { @options[:missing] = true }
13
+ @parser.on("--objects") { @options[:objects] = true }
14
+ @parser.on("--reverse") { @options[:reverse] = true }
15
+
16
+ @options[:walk] = true
17
+ @parser.on("--do-walk") { @options[:walk] = true }
18
+ @parser.on("--no-walk") { @options[:walk] = false }
19
+ end
20
+
21
+ def run
22
+ rev_list = ::RevList.new(repo, @args, @options)
23
+ iterator = @options[:reverse] ? :reverse_each : :each
24
+
25
+ rev_list.__send__(iterator) do |object, path|
26
+ puts "#{ object.oid } #{ path }".strip
27
+ end
28
+
29
+ exit 0
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,69 @@
1
+ require_relative "./base"
2
+ require_relative "./shared/sequencing"
3
+ require_relative "./shared/write_commit"
4
+ require_relative "../merge/inputs"
5
+ require_relative "../rev_list"
6
+
7
+ module Command
8
+ class Revert < Base
9
+
10
+ include Sequencing
11
+ include WriteCommit
12
+
13
+ private
14
+
15
+ def merge_type
16
+ :revert
17
+ end
18
+
19
+ def store_commit_sequence
20
+ commits = ::RevList.new(repo, @args, :walk => false)
21
+ commits.each { |commit| sequencer.revert(commit) }
22
+ end
23
+
24
+ def revert(commit)
25
+ inputs = revert_merge_inputs(commit)
26
+ message = revert_commit_message(commit)
27
+
28
+ resolve_merge(inputs)
29
+ fail_on_conflict(inputs, message) if repo.index.conflict?
30
+
31
+ author = current_author
32
+ message = edit_revert_message(message)
33
+ picked = Database::Commit.new([inputs.left_oid], write_tree.oid,
34
+ author, author, message)
35
+
36
+ finish_commit(picked)
37
+ end
38
+
39
+ def revert_merge_inputs(commit)
40
+ short = repo.database.short_oid(commit.oid)
41
+
42
+ left_name = Refs::HEAD
43
+ left_oid = repo.refs.read_head
44
+ right_name = "parent of #{ short }... #{ commit.title_line.strip }"
45
+ right_oid = select_parent(commit)
46
+
47
+ ::Merge::CherryPick.new(left_name, right_name,
48
+ left_oid, right_oid,
49
+ [commit.oid])
50
+ end
51
+
52
+ def revert_commit_message(commit)
53
+ <<~MESSAGE
54
+ Revert "#{ commit.title_line.strip }"
55
+
56
+ This reverts commit #{ commit.oid }.
57
+ MESSAGE
58
+ end
59
+
60
+ def edit_revert_message(message)
61
+ edit_file(commit_message_path) do |editor|
62
+ editor.puts(message)
63
+ editor.puts("")
64
+ editor.note(Commit::COMMIT_NOTES)
65
+ end
66
+ end
67
+
68
+ end
69
+ end