jit 0.0.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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/config/stack.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require "pathname"
|
2
|
+
require_relative "../config"
|
3
|
+
|
4
|
+
class Config
|
5
|
+
class Stack
|
6
|
+
|
7
|
+
GLOBAL_CONFIG = File.expand_path("~/.gitconfig")
|
8
|
+
SYSTEM_CONFIG = "/etc/gitconfig"
|
9
|
+
|
10
|
+
def initialize(git_path)
|
11
|
+
@configs = {
|
12
|
+
:local => Config.new(git_path.join("config")),
|
13
|
+
:global => Config.new(Pathname.new(GLOBAL_CONFIG)),
|
14
|
+
:system => Config.new(Pathname.new(SYSTEM_CONFIG))
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
def file(name)
|
19
|
+
if @configs.has_key?(name)
|
20
|
+
@configs[name]
|
21
|
+
else
|
22
|
+
Config.new(Pathname.new(name))
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def open
|
27
|
+
@configs.each_value(&:open)
|
28
|
+
end
|
29
|
+
|
30
|
+
def get(key)
|
31
|
+
get_all(key).last
|
32
|
+
end
|
33
|
+
|
34
|
+
def get_all(key)
|
35
|
+
[:system, :global, :local].flat_map do |name|
|
36
|
+
@configs[name].open
|
37
|
+
@configs[name].get_all(key)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
data/lib/database.rb
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
require "digest/sha1"
|
2
|
+
require "forwardable"
|
3
|
+
require "pathname"
|
4
|
+
require "strscan"
|
5
|
+
|
6
|
+
require_relative "./database/author"
|
7
|
+
require_relative "./database/blob"
|
8
|
+
require_relative "./database/commit"
|
9
|
+
require_relative "./database/entry"
|
10
|
+
require_relative "./database/tree"
|
11
|
+
require_relative "./database/tree_diff"
|
12
|
+
|
13
|
+
require_relative "./database/backends"
|
14
|
+
|
15
|
+
class Database
|
16
|
+
TYPES = {
|
17
|
+
"blob" => Blob,
|
18
|
+
"tree" => Tree,
|
19
|
+
"commit" => Commit
|
20
|
+
}
|
21
|
+
|
22
|
+
Raw = Struct.new(:type, :size, :data)
|
23
|
+
|
24
|
+
extend Forwardable
|
25
|
+
def_delegators :@backend, :has?, :load_info, :load_raw,
|
26
|
+
:prefix_match, :pack_path
|
27
|
+
|
28
|
+
def initialize(pathname)
|
29
|
+
@objects = {}
|
30
|
+
@backend = Backends.new(pathname)
|
31
|
+
end
|
32
|
+
|
33
|
+
def store(object)
|
34
|
+
content = serialize_object(object)
|
35
|
+
object.oid = hash_content(content)
|
36
|
+
|
37
|
+
@backend.write_object(object.oid, content)
|
38
|
+
end
|
39
|
+
|
40
|
+
def hash_object(object)
|
41
|
+
hash_content(serialize_object(object))
|
42
|
+
end
|
43
|
+
|
44
|
+
def load(oid)
|
45
|
+
@objects[oid] ||= read_object(oid)
|
46
|
+
end
|
47
|
+
|
48
|
+
def load_tree_entry(oid, pathname)
|
49
|
+
commit = load(oid)
|
50
|
+
root = Database::Entry.new(commit.tree, Tree::TREE_MODE)
|
51
|
+
|
52
|
+
return root unless pathname
|
53
|
+
|
54
|
+
pathname.each_filename.reduce(root) do |entry, name|
|
55
|
+
entry ? load(entry.oid).entries[name] : nil
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def load_tree_list(oid, pathname = nil)
|
60
|
+
return {} unless oid
|
61
|
+
|
62
|
+
entry = load_tree_entry(oid, pathname)
|
63
|
+
list = {}
|
64
|
+
|
65
|
+
build_list(list, entry, pathname || Pathname.new(""))
|
66
|
+
list
|
67
|
+
end
|
68
|
+
|
69
|
+
def build_list(list, entry, prefix)
|
70
|
+
return unless entry
|
71
|
+
return list[prefix.to_s] = entry unless entry.tree?
|
72
|
+
|
73
|
+
load(entry.oid).each_entry do |name, item|
|
74
|
+
build_list(list, item, prefix.join(name))
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def tree_entry(oid)
|
79
|
+
Entry.new(oid, Tree::TREE_MODE)
|
80
|
+
end
|
81
|
+
|
82
|
+
def short_oid(oid)
|
83
|
+
oid[0..6]
|
84
|
+
end
|
85
|
+
|
86
|
+
def tree_diff(a, b, prune = [])
|
87
|
+
diff = TreeDiff.new(self, prune)
|
88
|
+
diff.compare_oids(a, b)
|
89
|
+
diff.changes
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def serialize_object(object)
|
95
|
+
string = object.to_s.force_encoding(Encoding::ASCII_8BIT)
|
96
|
+
"#{ object.type } #{ string.bytesize }\0#{ string }"
|
97
|
+
end
|
98
|
+
|
99
|
+
def hash_content(string)
|
100
|
+
Digest::SHA1.hexdigest(string)
|
101
|
+
end
|
102
|
+
|
103
|
+
def read_object(oid)
|
104
|
+
raw = load_raw(oid)
|
105
|
+
scanner = StringScanner.new(raw.data)
|
106
|
+
|
107
|
+
object = TYPES[raw.type].parse(scanner)
|
108
|
+
object.oid = oid
|
109
|
+
|
110
|
+
object
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "time"
|
2
|
+
|
3
|
+
class Database
|
4
|
+
TIME_FORMAT = "%s %z"
|
5
|
+
|
6
|
+
Author = Struct.new(:name, :email, :time) do
|
7
|
+
def self.parse(string)
|
8
|
+
name, email, time = string.split(/<|>/).map(&:strip)
|
9
|
+
time = Time.strptime(time, TIME_FORMAT)
|
10
|
+
|
11
|
+
Author.new(name, email, time)
|
12
|
+
end
|
13
|
+
|
14
|
+
def short_date
|
15
|
+
time.strftime("%Y-%m-%d")
|
16
|
+
end
|
17
|
+
|
18
|
+
def readable_time
|
19
|
+
time.strftime("%a %b %-d %H:%M:%S %Y %z")
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_s
|
23
|
+
timestamp = time.strftime(TIME_FORMAT)
|
24
|
+
"#{ name } <#{ email }> #{ timestamp }"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
|
3
|
+
require_relative "./loose"
|
4
|
+
require_relative "./packed"
|
5
|
+
|
6
|
+
class Database
|
7
|
+
class Backends
|
8
|
+
|
9
|
+
extend Forwardable
|
10
|
+
def_delegators :@loose, :write_object
|
11
|
+
|
12
|
+
def initialize(pathname)
|
13
|
+
@pathname = pathname
|
14
|
+
@loose = Loose.new(pathname)
|
15
|
+
@stores = [@loose] + packed
|
16
|
+
end
|
17
|
+
|
18
|
+
def pack_path
|
19
|
+
@pathname.join("pack")
|
20
|
+
end
|
21
|
+
|
22
|
+
def has?(oid)
|
23
|
+
@stores.any? { |store| store.has?(oid) }
|
24
|
+
end
|
25
|
+
|
26
|
+
def load_info(oid)
|
27
|
+
@stores.reduce(nil) { |info, store| info || store.load_info(oid) }
|
28
|
+
end
|
29
|
+
|
30
|
+
def load_raw(oid)
|
31
|
+
@stores.reduce(nil) { |raw, store| raw || store.load_raw(oid) }
|
32
|
+
end
|
33
|
+
|
34
|
+
def prefix_match(name)
|
35
|
+
oids = @stores.reduce([]) do |list, store|
|
36
|
+
list + store.prefix_match(name)
|
37
|
+
end
|
38
|
+
|
39
|
+
oids.uniq
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def packed
|
45
|
+
packs = Dir.entries(pack_path).grep(/\.pack$/)
|
46
|
+
.map { |name| pack_path.join(name) }
|
47
|
+
.sort_by { |path| File.mtime(path) }
|
48
|
+
.reverse
|
49
|
+
|
50
|
+
packs.map { |path| Packed.new(path) }
|
51
|
+
|
52
|
+
rescue Errno::ENOENT
|
53
|
+
[]
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class Database
|
2
|
+
class Blob
|
3
|
+
|
4
|
+
attr_accessor :oid
|
5
|
+
attr_reader :data
|
6
|
+
|
7
|
+
def self.parse(scanner)
|
8
|
+
Blob.new(scanner.rest)
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(data)
|
12
|
+
@data = data
|
13
|
+
end
|
14
|
+
|
15
|
+
def type
|
16
|
+
"blob"
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_s
|
20
|
+
@data
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require_relative "./author"
|
2
|
+
|
3
|
+
class Database
|
4
|
+
class Commit
|
5
|
+
|
6
|
+
attr_accessor :oid
|
7
|
+
attr_reader :parents, :tree, :author, :committer, :message
|
8
|
+
|
9
|
+
def self.parse(scanner)
|
10
|
+
headers = Hash.new { |hash, key| hash[key] = [] }
|
11
|
+
|
12
|
+
loop do
|
13
|
+
line = scanner.scan_until(/\n/).strip
|
14
|
+
break if line == ""
|
15
|
+
|
16
|
+
key, value = line.split(/ +/, 2)
|
17
|
+
headers[key].push(value)
|
18
|
+
end
|
19
|
+
|
20
|
+
Commit.new(
|
21
|
+
headers["parent"],
|
22
|
+
headers["tree"].first,
|
23
|
+
Author.parse(headers["author"].first),
|
24
|
+
Author.parse(headers["committer"].first),
|
25
|
+
scanner.rest)
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(parents, tree, author, committer, message)
|
29
|
+
@parents = parents
|
30
|
+
@tree = tree
|
31
|
+
@author = author
|
32
|
+
@committer = committer
|
33
|
+
@message = message
|
34
|
+
end
|
35
|
+
|
36
|
+
def merge?
|
37
|
+
@parents.size > 1
|
38
|
+
end
|
39
|
+
|
40
|
+
def parent
|
41
|
+
@parents.first
|
42
|
+
end
|
43
|
+
|
44
|
+
def date
|
45
|
+
@committer.time
|
46
|
+
end
|
47
|
+
|
48
|
+
def title_line
|
49
|
+
@message.lines.first
|
50
|
+
end
|
51
|
+
|
52
|
+
def type
|
53
|
+
"commit"
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_s
|
57
|
+
lines = []
|
58
|
+
|
59
|
+
lines.push("tree #{ @tree }")
|
60
|
+
lines.concat(@parents.map { |oid| "parent #{ oid }" })
|
61
|
+
lines.push("author #{ @author }")
|
62
|
+
lines.push("committer #{ @committer }")
|
63
|
+
lines.push("")
|
64
|
+
lines.push(@message)
|
65
|
+
|
66
|
+
lines.join("\n")
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require "strscan"
|
2
|
+
require "zlib"
|
3
|
+
|
4
|
+
require_relative "../temp_file"
|
5
|
+
|
6
|
+
class Database
|
7
|
+
class Loose
|
8
|
+
|
9
|
+
def initialize(pathname)
|
10
|
+
@pathname = pathname
|
11
|
+
end
|
12
|
+
|
13
|
+
def has?(oid)
|
14
|
+
File.file?(object_path(oid))
|
15
|
+
end
|
16
|
+
|
17
|
+
def load_info(oid)
|
18
|
+
type, size, _ = read_object_header(oid, 128)
|
19
|
+
Raw.new(type, size)
|
20
|
+
rescue Errno::ENOENT
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def load_raw(oid)
|
25
|
+
type, size, scanner = read_object_header(oid)
|
26
|
+
Raw.new(type, size, scanner.rest)
|
27
|
+
rescue Errno::ENOENT
|
28
|
+
nil
|
29
|
+
end
|
30
|
+
|
31
|
+
def prefix_match(name)
|
32
|
+
dirname = object_path(name).dirname
|
33
|
+
|
34
|
+
oids = Dir.entries(dirname).map do |filename|
|
35
|
+
"#{ dirname.basename }#{ filename }"
|
36
|
+
end
|
37
|
+
|
38
|
+
oids.select { |oid| oid.start_with?(name) }
|
39
|
+
rescue Errno::ENOENT
|
40
|
+
[]
|
41
|
+
end
|
42
|
+
|
43
|
+
def write_object(oid, content)
|
44
|
+
path = object_path(oid)
|
45
|
+
return if File.exist?(path)
|
46
|
+
|
47
|
+
file = TempFile.new(path.dirname, "tmp_obj")
|
48
|
+
file.write(Zlib::Deflate.deflate(content, Zlib::BEST_SPEED))
|
49
|
+
file.move(path.basename)
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def object_path(oid)
|
55
|
+
@pathname.join(oid[0..1], oid[2..-1])
|
56
|
+
end
|
57
|
+
|
58
|
+
def read_object_header(oid, read_bytes = nil)
|
59
|
+
path = object_path(oid)
|
60
|
+
data = Zlib::Inflate.new.inflate(File.read(path, read_bytes))
|
61
|
+
scanner = StringScanner.new(data)
|
62
|
+
|
63
|
+
type = scanner.scan_until(/ /).strip
|
64
|
+
size = scanner.scan_until(/\0/)[0..-2].to_i
|
65
|
+
|
66
|
+
[type, size, scanner]
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
|
3
|
+
require_relative "../pack/expander"
|
4
|
+
require_relative "../pack/index"
|
5
|
+
require_relative "../pack/reader"
|
6
|
+
|
7
|
+
class Database
|
8
|
+
class Packed
|
9
|
+
|
10
|
+
extend Forwardable
|
11
|
+
def_delegators :@index, :prefix_match
|
12
|
+
|
13
|
+
def initialize(pathname)
|
14
|
+
@pack_file = File.open(pathname, File::RDONLY)
|
15
|
+
@reader = Pack::Reader.new(@pack_file)
|
16
|
+
|
17
|
+
@index_file = File.open(pathname.sub_ext(".idx"), File::RDONLY)
|
18
|
+
@index = Pack::Index.new(@index_file)
|
19
|
+
end
|
20
|
+
|
21
|
+
def has?(oid)
|
22
|
+
@index.oid_offset(oid) != nil
|
23
|
+
end
|
24
|
+
|
25
|
+
def load_info(oid)
|
26
|
+
offset = @index.oid_offset(oid)
|
27
|
+
offset ? load_info_at(offset) : nil
|
28
|
+
end
|
29
|
+
|
30
|
+
def load_raw(oid)
|
31
|
+
offset = @index.oid_offset(oid)
|
32
|
+
offset ? load_raw_at(offset) : nil
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def load_info_at(offset)
|
38
|
+
@pack_file.seek(offset)
|
39
|
+
record = @reader.read_info
|
40
|
+
|
41
|
+
case record
|
42
|
+
when Pack::Record
|
43
|
+
Raw.new(record.type, record.data)
|
44
|
+
when Pack::OfsDelta
|
45
|
+
base = load_info_at(offset - record.base_ofs)
|
46
|
+
Raw.new(base.type, record.delta_data)
|
47
|
+
when Pack::RefDelta
|
48
|
+
base = load_info(record.base_oid)
|
49
|
+
Raw.new(base.type, record.delta_data)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def load_raw_at(offset)
|
54
|
+
@pack_file.seek(offset)
|
55
|
+
record = @reader.read_record
|
56
|
+
|
57
|
+
case record
|
58
|
+
when Pack::Record
|
59
|
+
record
|
60
|
+
when Pack::OfsDelta
|
61
|
+
base = load_raw_at(offset - record.base_ofs)
|
62
|
+
expand_delta(base, record)
|
63
|
+
when Pack::RefDelta
|
64
|
+
base = load_raw(record.base_oid)
|
65
|
+
expand_delta(base, record)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def expand_delta(base, record)
|
70
|
+
data = Pack::Expander.expand(base.data, record.delta_data)
|
71
|
+
Pack::Record.new(base.type, data)
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|