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/bin/jit
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require_relative "../lib/command"
|
4
|
+
|
5
|
+
begin
|
6
|
+
cmd = Command.execute(Dir.getwd, ENV, ARGV, $stdin, $stdout, $stderr)
|
7
|
+
exit cmd.status
|
8
|
+
|
9
|
+
rescue Command::Unknown => error
|
10
|
+
$stderr.puts "jit: #{ error.message }"
|
11
|
+
exit 1
|
12
|
+
|
13
|
+
rescue => error
|
14
|
+
$stderr.puts "fatal: #{ error.message }"
|
15
|
+
if ENV["DEBUG"]
|
16
|
+
error.backtrace.each do |line|
|
17
|
+
$stderr.puts " from #{ line }"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
exit 1
|
21
|
+
end
|
data/lib/color.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
module Color
|
2
|
+
SGR_CODES = {
|
3
|
+
"normal" => 0,
|
4
|
+
"bold" => 1,
|
5
|
+
"dim" => 2,
|
6
|
+
"italic" => 3,
|
7
|
+
"ul" => 4,
|
8
|
+
"reverse" => 7,
|
9
|
+
"strike" => 9,
|
10
|
+
"black" => 30,
|
11
|
+
"red" => 31,
|
12
|
+
"green" => 32,
|
13
|
+
"yellow" => 33,
|
14
|
+
"blue" => 34,
|
15
|
+
"magenta" => 35,
|
16
|
+
"cyan" => 36,
|
17
|
+
"white" => 37
|
18
|
+
}
|
19
|
+
|
20
|
+
def self.format(style, string)
|
21
|
+
codes = [*style].map { |name| SGR_CODES.fetch(name.to_s) }
|
22
|
+
color = false
|
23
|
+
|
24
|
+
codes.each_with_index do |code, i|
|
25
|
+
next unless code >= 30
|
26
|
+
codes[i] += 10 if color
|
27
|
+
color = true
|
28
|
+
end
|
29
|
+
|
30
|
+
"\e[#{ codes.join(";") }m#{ string }\e[m"
|
31
|
+
end
|
32
|
+
end
|
data/lib/command.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
require_relative "./command/add"
|
2
|
+
require_relative "./command/branch"
|
3
|
+
require_relative "./command/checkout"
|
4
|
+
require_relative "./command/cherry_pick"
|
5
|
+
require_relative "./command/commit"
|
6
|
+
require_relative "./command/config"
|
7
|
+
require_relative "./command/diff"
|
8
|
+
require_relative "./command/fetch"
|
9
|
+
require_relative "./command/init"
|
10
|
+
require_relative "./command/log"
|
11
|
+
require_relative "./command/merge"
|
12
|
+
require_relative "./command/push"
|
13
|
+
require_relative "./command/remote"
|
14
|
+
require_relative "./command/receive_pack"
|
15
|
+
require_relative "./command/reset"
|
16
|
+
require_relative "./command/rev_list"
|
17
|
+
require_relative "./command/revert"
|
18
|
+
require_relative "./command/rm"
|
19
|
+
require_relative "./command/status"
|
20
|
+
require_relative "./command/upload_pack"
|
21
|
+
|
22
|
+
module Command
|
23
|
+
Unknown = Class.new(StandardError)
|
24
|
+
|
25
|
+
COMMANDS = {
|
26
|
+
"init" => Init,
|
27
|
+
"config" => Config,
|
28
|
+
"add" => Add,
|
29
|
+
"rm" => Rm,
|
30
|
+
"commit" => Commit,
|
31
|
+
"status" => Status,
|
32
|
+
"diff" => Diff,
|
33
|
+
"branch" => Branch,
|
34
|
+
"checkout" => Checkout,
|
35
|
+
"reset" => Reset,
|
36
|
+
"rev-list" => RevList,
|
37
|
+
"log" => Log,
|
38
|
+
"merge" => Merge,
|
39
|
+
"cherry-pick" => CherryPick,
|
40
|
+
"revert" => Revert,
|
41
|
+
"remote" => Remote,
|
42
|
+
"fetch" => Fetch,
|
43
|
+
"push" => Push,
|
44
|
+
"upload-pack" => UploadPack,
|
45
|
+
"receive-pack" => ReceivePack
|
46
|
+
}
|
47
|
+
|
48
|
+
def self.execute(dir, env, argv, stdin, stdout, stderr)
|
49
|
+
name = argv.first
|
50
|
+
args = argv.drop(1)
|
51
|
+
|
52
|
+
unless COMMANDS.has_key?(name)
|
53
|
+
raise Unknown, "'#{ name }' is not a jit command."
|
54
|
+
end
|
55
|
+
|
56
|
+
command_class = COMMANDS[name]
|
57
|
+
command = command_class.new(dir, env, args, stdin, stdout, stderr)
|
58
|
+
|
59
|
+
command.execute
|
60
|
+
command
|
61
|
+
end
|
62
|
+
end
|
data/lib/command/add.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require "pathname"
|
2
|
+
require_relative "./base"
|
3
|
+
|
4
|
+
module Command
|
5
|
+
class Add < Base
|
6
|
+
|
7
|
+
LOCKED_INDEX_MESSAGE = <<~MSG
|
8
|
+
Another jit process seems to be running in this repository.
|
9
|
+
Please make sure all processes are terminated then try again.
|
10
|
+
If it still fails, a jit process may have crashed in this
|
11
|
+
repository earlier: remove the file manually to continue.
|
12
|
+
MSG
|
13
|
+
|
14
|
+
def run
|
15
|
+
repo.index.load_for_update
|
16
|
+
expanded_paths.each { |path| add_to_index(path) }
|
17
|
+
repo.index.write_updates
|
18
|
+
exit 0
|
19
|
+
rescue Lockfile::LockDenied => error
|
20
|
+
handle_locked_index(error)
|
21
|
+
rescue Workspace::MissingFile => error
|
22
|
+
handle_missing_file(error)
|
23
|
+
rescue Workspace::NoPermission => error
|
24
|
+
handle_unreadable_file(error)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def expanded_paths
|
30
|
+
@args.flat_map do |path|
|
31
|
+
repo.workspace.list_files(expanded_pathname(path))
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def add_to_index(path)
|
36
|
+
data = repo.workspace.read_file(path)
|
37
|
+
stat = repo.workspace.stat_file(path)
|
38
|
+
|
39
|
+
blob = Database::Blob.new(data)
|
40
|
+
repo.database.store(blob)
|
41
|
+
repo.index.add(path, blob.oid, stat)
|
42
|
+
end
|
43
|
+
|
44
|
+
def handle_locked_index(error)
|
45
|
+
@stderr.puts "fatal: #{ error.message }"
|
46
|
+
@stderr.puts
|
47
|
+
@stderr.puts LOCKED_INDEX_MESSAGE
|
48
|
+
exit 128
|
49
|
+
end
|
50
|
+
|
51
|
+
def handle_missing_file(error)
|
52
|
+
@stderr.puts "fatal: #{ error.message }"
|
53
|
+
repo.index.release_lock
|
54
|
+
exit 128
|
55
|
+
end
|
56
|
+
|
57
|
+
def handle_unreadable_file(error)
|
58
|
+
@stderr.puts "error: #{ error.message }"
|
59
|
+
@stderr.puts "fatal: adding files failed"
|
60
|
+
repo.index.release_lock
|
61
|
+
exit 128
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
data/lib/command/base.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
require "optparse"
|
2
|
+
require "pathname"
|
3
|
+
|
4
|
+
require_relative "../color"
|
5
|
+
require_relative "../editor"
|
6
|
+
require_relative "../pager"
|
7
|
+
require_relative "../repository"
|
8
|
+
|
9
|
+
module Command
|
10
|
+
class Base
|
11
|
+
|
12
|
+
attr_reader :status
|
13
|
+
|
14
|
+
def initialize(dir, env, args, stdin, stdout, stderr)
|
15
|
+
@dir = dir
|
16
|
+
@env = env
|
17
|
+
@args = args
|
18
|
+
@stdin = stdin
|
19
|
+
@stdout = stdout
|
20
|
+
@stderr = stderr
|
21
|
+
|
22
|
+
@isatty = @stdout.isatty
|
23
|
+
end
|
24
|
+
|
25
|
+
def execute
|
26
|
+
parse_options
|
27
|
+
catch(:exit) { run }
|
28
|
+
|
29
|
+
if defined? @pager
|
30
|
+
@stdout.close_write
|
31
|
+
@pager.wait
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def repo
|
38
|
+
@repo ||= Repository.new(Pathname.new(@dir).join(".git"))
|
39
|
+
end
|
40
|
+
|
41
|
+
def expanded_pathname(path)
|
42
|
+
Pathname.new(File.expand_path(path, @dir))
|
43
|
+
end
|
44
|
+
|
45
|
+
def parse_options
|
46
|
+
@options = {}
|
47
|
+
@parser = OptionParser.new
|
48
|
+
|
49
|
+
define_options
|
50
|
+
@parser.parse!(@args)
|
51
|
+
end
|
52
|
+
|
53
|
+
def define_options
|
54
|
+
end
|
55
|
+
|
56
|
+
def setup_pager
|
57
|
+
return if defined? @pager
|
58
|
+
return unless @isatty
|
59
|
+
|
60
|
+
@pager = Pager.new(@env, @stdout, @stderr)
|
61
|
+
@stdout = @pager.input
|
62
|
+
end
|
63
|
+
|
64
|
+
def edit_file(path)
|
65
|
+
Editor.edit(path, editor_command) do |editor|
|
66
|
+
yield editor
|
67
|
+
editor.close unless @isatty
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def editor_command
|
72
|
+
core_editor = repo.config.get(["core", "editor"])
|
73
|
+
@env["GIT_EDITOR"] || core_editor || @env["VISUAL"] || @env["EDITOR"]
|
74
|
+
end
|
75
|
+
|
76
|
+
def fmt(style, string)
|
77
|
+
@isatty ? Color.format(style, string) : string
|
78
|
+
end
|
79
|
+
|
80
|
+
def puts(string)
|
81
|
+
@stdout.puts(string)
|
82
|
+
rescue Errno::EPIPE
|
83
|
+
exit 0
|
84
|
+
end
|
85
|
+
|
86
|
+
def exit(status = 0)
|
87
|
+
@status = status
|
88
|
+
throw :exit
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,199 @@
|
|
1
|
+
require_relative "./base"
|
2
|
+
require_relative "./shared/fast_forward"
|
3
|
+
require_relative "../revision"
|
4
|
+
|
5
|
+
module Command
|
6
|
+
class Branch < Base
|
7
|
+
|
8
|
+
include FastForward
|
9
|
+
|
10
|
+
def define_options
|
11
|
+
@parser.on("-a", "--all") { @options[:all] = true }
|
12
|
+
@parser.on("-r", "--remotes") { @options[:remotes] = true }
|
13
|
+
|
14
|
+
@options[:verbose] = 0
|
15
|
+
@parser.on("-v", "--verbose") { @options[:verbose] += 1 }
|
16
|
+
|
17
|
+
@parser.on("-d", "--delete") { @options[:delete] = true }
|
18
|
+
@parser.on("-f", "--force") { @options[:force] = true }
|
19
|
+
|
20
|
+
@parser.on "-D" do
|
21
|
+
@options[:delete] = @options[:force] = true
|
22
|
+
end
|
23
|
+
|
24
|
+
@parser.on "-u <upstream>", "--set-upstream-to=<upstream>" do |upstream|
|
25
|
+
@options[:upstream] = upstream
|
26
|
+
end
|
27
|
+
|
28
|
+
@parser.on("-t", "--track") { @options[:track] = true }
|
29
|
+
@parser.on("--unset-upstream") { @options[:upstream] = :unset }
|
30
|
+
end
|
31
|
+
|
32
|
+
def run
|
33
|
+
if @options[:upstream]
|
34
|
+
set_upstream_branch
|
35
|
+
elsif @options[:delete]
|
36
|
+
delete_branches
|
37
|
+
elsif @args.empty?
|
38
|
+
list_branches
|
39
|
+
else
|
40
|
+
create_branch
|
41
|
+
end
|
42
|
+
|
43
|
+
exit 0
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def list_branches
|
49
|
+
current = repo.refs.current_ref
|
50
|
+
branches = branch_refs.sort_by(&:path)
|
51
|
+
max_width = branches.map { |b| b.short_name.size }.max
|
52
|
+
|
53
|
+
setup_pager
|
54
|
+
|
55
|
+
branches.each do |ref|
|
56
|
+
info = format_ref(ref, current)
|
57
|
+
info.concat(extended_branch_info(ref, max_width))
|
58
|
+
puts info
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def branch_refs
|
63
|
+
branches = repo.refs.list_branches
|
64
|
+
remotes = repo.refs.list_remotes
|
65
|
+
|
66
|
+
return branches + remotes if @options[:all]
|
67
|
+
return remotes if @options[:remotes]
|
68
|
+
|
69
|
+
branches
|
70
|
+
end
|
71
|
+
|
72
|
+
def format_ref(ref, current)
|
73
|
+
if ref == current
|
74
|
+
"* #{ fmt :green, ref.short_name }"
|
75
|
+
elsif ref.remote?
|
76
|
+
" #{ fmt :red, ref.short_name }"
|
77
|
+
else
|
78
|
+
" #{ ref.short_name }"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def extended_branch_info(ref, max_width)
|
83
|
+
return "" unless @options[:verbose] > 0
|
84
|
+
|
85
|
+
commit = repo.database.load(ref.read_oid)
|
86
|
+
short = repo.database.short_oid(commit.oid)
|
87
|
+
space = " " * (max_width - ref.short_name.size)
|
88
|
+
upstream = upstream_info(ref)
|
89
|
+
|
90
|
+
"#{ space } #{ short }#{ upstream } #{ commit.title_line }"
|
91
|
+
end
|
92
|
+
|
93
|
+
def upstream_info(ref)
|
94
|
+
divergence = repo.divergence(ref)
|
95
|
+
return "" unless divergence.upstream
|
96
|
+
|
97
|
+
ahead = divergence.ahead
|
98
|
+
behind = divergence.behind
|
99
|
+
|
100
|
+
return "" if ahead == 0 and behind == 0
|
101
|
+
|
102
|
+
info = []
|
103
|
+
|
104
|
+
if @options[:verbose] > 1
|
105
|
+
info.push(fmt(:blue, repo.refs.short_name(divergence.upstream)))
|
106
|
+
end
|
107
|
+
info.push("ahead #{ ahead }") if ahead > 0
|
108
|
+
info.push("behind #{ behind }") if behind > 0
|
109
|
+
|
110
|
+
" [#{ info.join(", ") }]"
|
111
|
+
end
|
112
|
+
|
113
|
+
def create_branch
|
114
|
+
branch_name = @args[0]
|
115
|
+
start_point = @args[1]
|
116
|
+
|
117
|
+
if start_point
|
118
|
+
revision = Revision.new(repo, start_point)
|
119
|
+
start_oid = revision.resolve(Revision::COMMIT)
|
120
|
+
else
|
121
|
+
start_oid = repo.refs.read_head
|
122
|
+
end
|
123
|
+
|
124
|
+
repo.refs.create_branch(branch_name, start_oid)
|
125
|
+
set_upstream(branch_name, start_point) if @options[:track]
|
126
|
+
|
127
|
+
rescue Refs::InvalidBranch => error
|
128
|
+
@stderr.puts "fatal: #{ error.message }"
|
129
|
+
exit 128
|
130
|
+
|
131
|
+
rescue Revision::InvalidObject => error
|
132
|
+
revision.errors.each do |err|
|
133
|
+
@stderr.puts "error: #{ err.message }"
|
134
|
+
err.hint.each { |line| @stderr.puts "hint: #{ line }" }
|
135
|
+
end
|
136
|
+
@stderr.puts "fatal: #{ error.message }"
|
137
|
+
exit 128
|
138
|
+
end
|
139
|
+
|
140
|
+
def delete_branches
|
141
|
+
@args.each { |branch_name| delete_branch(branch_name) }
|
142
|
+
end
|
143
|
+
|
144
|
+
def delete_branch(branch_name)
|
145
|
+
check_merge_status(branch_name) unless @options[:force]
|
146
|
+
|
147
|
+
oid = repo.refs.delete_branch(branch_name)
|
148
|
+
short = repo.database.short_oid(oid)
|
149
|
+
|
150
|
+
repo.remotes.unset_upstream(branch_name)
|
151
|
+
|
152
|
+
puts "Deleted branch #{ branch_name } (was #{ short })."
|
153
|
+
|
154
|
+
rescue Refs::InvalidBranch => error
|
155
|
+
@stderr.puts "error: #{ error }"
|
156
|
+
exit 1
|
157
|
+
end
|
158
|
+
|
159
|
+
def check_merge_status(branch_name)
|
160
|
+
upstream = repo.remotes.get_upstream(branch_name)
|
161
|
+
head_oid = upstream ? repo.refs.read_ref(upstream) : repo.refs.read_head
|
162
|
+
branch_oid = repo.refs.read_ref(branch_name)
|
163
|
+
|
164
|
+
if fast_forward_error(branch_oid, head_oid)
|
165
|
+
@stderr.puts "error: The branch '#{ branch_name }' is not fully merged."
|
166
|
+
exit 1
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def set_upstream_branch
|
171
|
+
branch_name = @args.first || repo.refs.current_ref.short_name
|
172
|
+
|
173
|
+
if @options[:upstream] == :unset
|
174
|
+
repo.remotes.unset_upstream(branch_name)
|
175
|
+
else
|
176
|
+
set_upstream(branch_name, @options[:upstream])
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def set_upstream(branch_name, upstream)
|
181
|
+
upstream = repo.refs.long_name(upstream)
|
182
|
+
remote, ref = repo.remotes.set_upstream(branch_name, upstream)
|
183
|
+
|
184
|
+
base = repo.refs.short_name(ref)
|
185
|
+
|
186
|
+
puts "Branch '#{ branch_name }' set up to track remote " +
|
187
|
+
"branch '#{ base }' from '#{ remote }'."
|
188
|
+
|
189
|
+
rescue Refs::InvalidBranch => error
|
190
|
+
@stderr.puts "error: #{ error.message }"
|
191
|
+
exit 1
|
192
|
+
|
193
|
+
rescue Remotes::InvalidBranch => error
|
194
|
+
@stderr.puts "fatal: #{ error.message }"
|
195
|
+
exit 128
|
196
|
+
end
|
197
|
+
|
198
|
+
end
|
199
|
+
end
|