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
data/lib/remotes.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
require_relative "./refs"
|
2
|
+
require_relative "./remotes/refspec"
|
3
|
+
require_relative "./remotes/remote"
|
4
|
+
|
5
|
+
class Remotes
|
6
|
+
DEFAULT_REMOTE = "origin"
|
7
|
+
|
8
|
+
InvalidBranch = Class.new(StandardError)
|
9
|
+
InvalidRemote = Class.new(StandardError)
|
10
|
+
|
11
|
+
def initialize(config)
|
12
|
+
@config = config
|
13
|
+
end
|
14
|
+
|
15
|
+
def add(name, url, branches = [])
|
16
|
+
branches = ["*"] if branches.empty?
|
17
|
+
@config.open_for_update
|
18
|
+
|
19
|
+
if @config.get(["remote", name, "url"])
|
20
|
+
@config.save
|
21
|
+
raise InvalidRemote, "remote #{ name } already exists."
|
22
|
+
end
|
23
|
+
|
24
|
+
@config.set(["remote", name, "url"], url)
|
25
|
+
|
26
|
+
branches.each do |branch|
|
27
|
+
source = Refs::HEADS_DIR.join(branch)
|
28
|
+
target = Refs::REMOTES_DIR.join(name, branch)
|
29
|
+
refspec = Refspec.new(source, target, true)
|
30
|
+
|
31
|
+
@config.add(["remote", name, "fetch"], refspec.to_s)
|
32
|
+
end
|
33
|
+
|
34
|
+
@config.save
|
35
|
+
end
|
36
|
+
|
37
|
+
def remove(name)
|
38
|
+
@config.open_for_update
|
39
|
+
|
40
|
+
unless @config.remove_section(["remote", name])
|
41
|
+
raise InvalidRemote, "No such remote: #{ name }"
|
42
|
+
end
|
43
|
+
ensure
|
44
|
+
@config.save
|
45
|
+
end
|
46
|
+
|
47
|
+
def list_remotes
|
48
|
+
@config.open
|
49
|
+
@config.subsections("remote")
|
50
|
+
end
|
51
|
+
|
52
|
+
def get(name)
|
53
|
+
@config.open
|
54
|
+
return nil unless @config.section?(["remote", name])
|
55
|
+
|
56
|
+
Remote.new(@config, name)
|
57
|
+
end
|
58
|
+
|
59
|
+
def get_upstream(branch)
|
60
|
+
@config.open
|
61
|
+
name = @config.get(["branch", branch, "remote"])
|
62
|
+
get(name)&.get_upstream(branch)
|
63
|
+
end
|
64
|
+
|
65
|
+
def set_upstream(branch, upstream)
|
66
|
+
list_remotes.each do |name|
|
67
|
+
ref = get(name).set_upstream(branch, upstream)
|
68
|
+
return [name, ref] if ref
|
69
|
+
end
|
70
|
+
|
71
|
+
raise InvalidBranch,
|
72
|
+
"Cannot setup tracking information; " +
|
73
|
+
"starting point '#{ upstream }' is not a branch"
|
74
|
+
end
|
75
|
+
|
76
|
+
def unset_upstream(branch)
|
77
|
+
@config.open_for_update
|
78
|
+
@config.unset(["branch", branch, "remote"])
|
79
|
+
@config.unset(["branch", branch, "merge"])
|
80
|
+
@config.save
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
class Remotes
|
2
|
+
class Protocol
|
3
|
+
|
4
|
+
attr_reader :input, :output
|
5
|
+
|
6
|
+
def initialize(command, input, output, capabilities = [])
|
7
|
+
@command = command
|
8
|
+
@input = input
|
9
|
+
@output = output
|
10
|
+
|
11
|
+
@input.sync = @output.sync = true
|
12
|
+
|
13
|
+
@caps_local = capabilities
|
14
|
+
@caps_remote = nil
|
15
|
+
@caps_sent = false
|
16
|
+
end
|
17
|
+
|
18
|
+
def capable?(ability)
|
19
|
+
@caps_remote&.include?(ability)
|
20
|
+
end
|
21
|
+
|
22
|
+
def send_packet(line)
|
23
|
+
return @output.write("0000") if line == nil
|
24
|
+
|
25
|
+
line = append_caps(line)
|
26
|
+
|
27
|
+
size = line.bytesize + 5
|
28
|
+
@output.write(size.to_s(16).rjust(4, "0"))
|
29
|
+
@output.write(line)
|
30
|
+
@output.write("\n")
|
31
|
+
end
|
32
|
+
|
33
|
+
def recv_packet
|
34
|
+
head = @input.read(4)
|
35
|
+
return head unless /[0-9a-f]{4}/ =~ head
|
36
|
+
|
37
|
+
size = head.to_i(16)
|
38
|
+
return nil if size == 0
|
39
|
+
|
40
|
+
line = @input.read(size - 4).sub(/\n$/, "")
|
41
|
+
detect_caps(line)
|
42
|
+
end
|
43
|
+
|
44
|
+
def recv_until(terminator)
|
45
|
+
loop do
|
46
|
+
line = recv_packet
|
47
|
+
break if line == terminator
|
48
|
+
yield line
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def append_caps(line)
|
55
|
+
return line if @caps_sent
|
56
|
+
@caps_sent = true
|
57
|
+
|
58
|
+
sep = (@command == "fetch") ? " " : "\0"
|
59
|
+
caps = @caps_local
|
60
|
+
caps &= @caps_remote if @caps_remote
|
61
|
+
|
62
|
+
line + sep + caps.join(" ")
|
63
|
+
end
|
64
|
+
|
65
|
+
def detect_caps(line)
|
66
|
+
return line if @caps_remote
|
67
|
+
|
68
|
+
if @command == "upload-pack"
|
69
|
+
sep, n = " ", 3
|
70
|
+
else
|
71
|
+
sep, n = "\0", 2
|
72
|
+
end
|
73
|
+
|
74
|
+
parts = line.split(sep, n)
|
75
|
+
caps = (parts.size == n) ? parts.pop : ""
|
76
|
+
|
77
|
+
@caps_remote = caps.split(/ +/)
|
78
|
+
parts.join(" ")
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require "pathname"
|
2
|
+
|
3
|
+
require_relative "../refs"
|
4
|
+
require_relative "../revision"
|
5
|
+
|
6
|
+
class Remotes
|
7
|
+
|
8
|
+
REFSPEC_FORMAT = /^(\+?)([^:]*)(:([^:]*))?$/
|
9
|
+
|
10
|
+
Refspec = Struct.new(:source, :target, :forced) do
|
11
|
+
def self.parse(spec)
|
12
|
+
match = REFSPEC_FORMAT.match(spec)
|
13
|
+
source = canonical(match[2])
|
14
|
+
target = canonical(match[4]) || source
|
15
|
+
|
16
|
+
Refspec.new(source, target, match[1] == "+")
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.canonical(name)
|
20
|
+
return nil if name.to_s == ""
|
21
|
+
return name unless Revision.valid_ref?(name)
|
22
|
+
|
23
|
+
first = Pathname.new(name).each_filename.first
|
24
|
+
dirs = [Refs::REFS_DIR, Refs::HEADS_DIR, Refs::REMOTES_DIR]
|
25
|
+
prefix = dirs.find { |dir| first == dir.basename.to_s }
|
26
|
+
|
27
|
+
(prefix&.dirname || Refs::HEADS_DIR).join(name).to_s
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.expand(specs, refs)
|
31
|
+
specs = specs.map { |spec| parse(spec) }
|
32
|
+
|
33
|
+
specs.reduce({}) do |mappings, spec|
|
34
|
+
mappings.merge(spec.match_refs(refs))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.invert(specs, ref)
|
39
|
+
specs = specs.map { |spec| parse(spec) }
|
40
|
+
|
41
|
+
map = specs.reduce({}) do |mappings, spec|
|
42
|
+
spec.source, spec.target = spec.target, spec.source
|
43
|
+
mappings.merge(spec.match_refs([ref]))
|
44
|
+
end
|
45
|
+
|
46
|
+
map.keys.first
|
47
|
+
end
|
48
|
+
|
49
|
+
def match_refs(refs)
|
50
|
+
return { target => [source, forced] } unless source.to_s.include?("*")
|
51
|
+
|
52
|
+
pattern = /^#{ source.sub("*", "(.*)") }$/
|
53
|
+
mappings = {}
|
54
|
+
|
55
|
+
refs.each do |ref|
|
56
|
+
next unless match = pattern.match(ref)
|
57
|
+
dst = match[1] ? target.sub("*", match[1]) : target
|
58
|
+
mappings[dst] = [ref, forced]
|
59
|
+
end
|
60
|
+
|
61
|
+
mappings
|
62
|
+
end
|
63
|
+
|
64
|
+
def to_s
|
65
|
+
spec = forced ? "+" : ""
|
66
|
+
spec + [source, target].join(":")
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require_relative "./refspec"
|
2
|
+
|
3
|
+
class Remotes
|
4
|
+
class Remote
|
5
|
+
|
6
|
+
def initialize(config, name)
|
7
|
+
@config = config
|
8
|
+
@name = name
|
9
|
+
|
10
|
+
@config.open
|
11
|
+
end
|
12
|
+
|
13
|
+
def fetch_url
|
14
|
+
@config.get(["remote", @name, "url"])
|
15
|
+
end
|
16
|
+
|
17
|
+
def fetch_specs
|
18
|
+
@config.get_all(["remote", @name, "fetch"])
|
19
|
+
end
|
20
|
+
|
21
|
+
def push_url
|
22
|
+
@config.get(["remote", @name, "pushurl"]) || fetch_url
|
23
|
+
end
|
24
|
+
|
25
|
+
def push_specs
|
26
|
+
@config.get_all(["remote", @name, "push"])
|
27
|
+
end
|
28
|
+
|
29
|
+
def uploader
|
30
|
+
@config.get(["remote", @name, "uploadpack"])
|
31
|
+
end
|
32
|
+
|
33
|
+
def receiver
|
34
|
+
@config.get(["remote", @name, "receivepack"])
|
35
|
+
end
|
36
|
+
|
37
|
+
def get_upstream(branch)
|
38
|
+
merge = @config.get(["branch", branch, "merge"])
|
39
|
+
targets = Refspec.expand(fetch_specs, [merge])
|
40
|
+
|
41
|
+
targets.keys.first
|
42
|
+
end
|
43
|
+
|
44
|
+
def set_upstream(branch, upstream)
|
45
|
+
ref_name = Refspec.invert(fetch_specs, upstream)
|
46
|
+
return nil unless ref_name
|
47
|
+
|
48
|
+
@config.open_for_update
|
49
|
+
@config.set(["branch", branch, "remote"], @name)
|
50
|
+
@config.set(["branch", branch, "merge"], ref_name)
|
51
|
+
@config.save
|
52
|
+
|
53
|
+
ref_name
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
data/lib/repository.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
require_relative "./config/stack"
|
2
|
+
require_relative "./database"
|
3
|
+
require_relative "./index"
|
4
|
+
require_relative "./refs"
|
5
|
+
require_relative "./remotes"
|
6
|
+
require_relative "./workspace"
|
7
|
+
|
8
|
+
require_relative "./repository/divergence"
|
9
|
+
require_relative "./repository/hard_reset"
|
10
|
+
require_relative "./repository/migration"
|
11
|
+
require_relative "./repository/pending_commit"
|
12
|
+
require_relative "./repository/status"
|
13
|
+
|
14
|
+
class Repository
|
15
|
+
attr_reader :git_path
|
16
|
+
|
17
|
+
def initialize(git_path)
|
18
|
+
@git_path = git_path
|
19
|
+
end
|
20
|
+
|
21
|
+
def config
|
22
|
+
@config ||= Config::Stack.new(@git_path)
|
23
|
+
end
|
24
|
+
|
25
|
+
def database
|
26
|
+
@database ||= Database.new(@git_path.join("objects"))
|
27
|
+
end
|
28
|
+
|
29
|
+
def divergence(ref)
|
30
|
+
Divergence.new(self, ref)
|
31
|
+
end
|
32
|
+
|
33
|
+
def hard_reset(oid)
|
34
|
+
HardReset.new(self, oid).execute
|
35
|
+
end
|
36
|
+
|
37
|
+
def index
|
38
|
+
@index ||= Index.new(@git_path.join("index"))
|
39
|
+
end
|
40
|
+
|
41
|
+
def migration(tree_diff)
|
42
|
+
Migration.new(self, tree_diff)
|
43
|
+
end
|
44
|
+
|
45
|
+
def pending_commit
|
46
|
+
PendingCommit.new(@git_path)
|
47
|
+
end
|
48
|
+
|
49
|
+
def refs
|
50
|
+
@refs ||= Refs.new(@git_path)
|
51
|
+
end
|
52
|
+
|
53
|
+
def remotes
|
54
|
+
@remotes ||= Remotes.new(config.file(:local))
|
55
|
+
end
|
56
|
+
|
57
|
+
def status(commit_oid = nil)
|
58
|
+
Status.new(self, commit_oid)
|
59
|
+
end
|
60
|
+
|
61
|
+
def workspace
|
62
|
+
@workspace ||= Workspace.new(@git_path.dirname)
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require_relative "../merge/common_ancestors"
|
2
|
+
|
3
|
+
class Repository
|
4
|
+
class Divergence
|
5
|
+
|
6
|
+
attr_reader :upstream, :ahead, :behind
|
7
|
+
|
8
|
+
def initialize(repo, ref)
|
9
|
+
@upstream = repo.remotes.get_upstream(ref.short_name)
|
10
|
+
return unless @upstream
|
11
|
+
|
12
|
+
left = ref.read_oid
|
13
|
+
right = repo.refs.read_ref(@upstream)
|
14
|
+
common = Merge::CommonAncestors.new(repo.database, left, [right])
|
15
|
+
|
16
|
+
common.find
|
17
|
+
@ahead, @behind = common.counts
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require "pathname"
|
2
|
+
|
3
|
+
class Repository
|
4
|
+
class HardReset
|
5
|
+
|
6
|
+
def initialize(repo, oid)
|
7
|
+
@repo = repo
|
8
|
+
@oid = oid
|
9
|
+
end
|
10
|
+
|
11
|
+
def execute
|
12
|
+
@status = @repo.status(@oid)
|
13
|
+
changed = @status.changed.map { |path| Pathname.new(path) }
|
14
|
+
|
15
|
+
changed.each { |path| reset_path(path) }
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def reset_path(path)
|
21
|
+
@repo.index.remove(path)
|
22
|
+
@repo.workspace.remove(path)
|
23
|
+
|
24
|
+
entry = @status.head_tree[path.to_s]
|
25
|
+
return unless entry
|
26
|
+
|
27
|
+
blob = @repo.database.load(entry.oid)
|
28
|
+
@repo.workspace.write_file(path, blob.data, entry.mode, true)
|
29
|
+
|
30
|
+
stat = @repo.workspace.stat_file(path)
|
31
|
+
@repo.index.add(path, entry.oid, stat)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
class Repository
|
2
|
+
class Inspector
|
3
|
+
|
4
|
+
def initialize(repository)
|
5
|
+
@repo = repository
|
6
|
+
end
|
7
|
+
|
8
|
+
def trackable_file?(path, stat)
|
9
|
+
return false unless stat
|
10
|
+
|
11
|
+
return !@repo.index.tracked_file?(path) if stat.file?
|
12
|
+
return false unless stat.directory?
|
13
|
+
|
14
|
+
items = @repo.workspace.list_dir(path)
|
15
|
+
files = items.select { |_, item_stat| item_stat.file? }
|
16
|
+
dirs = items.select { |_, item_stat| item_stat.directory? }
|
17
|
+
|
18
|
+
[files, dirs].any? do |list|
|
19
|
+
list.any? { |item_path, item_stat| trackable_file?(item_path, item_stat) }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def compare_index_to_workspace(entry, stat)
|
24
|
+
return :untracked unless entry
|
25
|
+
return :deleted unless stat
|
26
|
+
return :modified unless entry.stat_match?(stat)
|
27
|
+
return nil if entry.times_match?(stat)
|
28
|
+
|
29
|
+
data = @repo.workspace.read_file(entry.path)
|
30
|
+
blob = Database::Blob.new(data)
|
31
|
+
oid = @repo.database.hash_object(blob)
|
32
|
+
|
33
|
+
unless entry.oid == oid
|
34
|
+
:modified
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def compare_tree_to_index(item, entry)
|
39
|
+
return nil unless item or entry
|
40
|
+
return :added unless item
|
41
|
+
return :deleted unless entry
|
42
|
+
|
43
|
+
unless entry.mode == item.mode and entry.oid == item.oid
|
44
|
+
:modified
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|