stg 0.1.5 → 0.1.6
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 +4 -4
- data/README.md +52 -40
- data/lib/stg/actions.rb +57 -19
- data/lib/stg/differencing.rb +2 -1
- data/lib/stg/help.rb +8 -8
- data/lib/stg/utils.rb +30 -0
- data/lib/stg/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1eb93a1f37a9ec874a195189c9047b322ef7eb823f2c4af4219dad4aba1bdcb0
|
|
4
|
+
data.tar.gz: 7795502739c3503dcc0fa241cecc65093c711eed608d633ef32813c96c0f4d80
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 60c435caaec0c696b269a1cd014a96539fa646eb6c204a9b53d67cb55dda4f2de16813202e3e1c6e5a3a12d774acf1c43cb26eb418c1817b03cca7d242b2aded
|
|
7
|
+
data.tar.gz: e1b69a714e519862c46d4264648504f3699b94fc7046f9900dbe780e36f3db8fa255cc9dfe40323b201bcb6f18ea7a8a0f01409b23724eedda67d7fa665e8d5e
|
data/README.md
CHANGED
|
@@ -12,17 +12,22 @@ Stolen git is well... you get it. I'm building a mini git clone to learn version
|
|
|
12
12
|
|
|
13
13
|
## Usage
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
|
18
|
-
|
|
|
19
|
-
|
|
|
20
|
-
|
|
|
21
|
-
|
|
|
22
|
-
|
|
23
|
-
|
|
|
24
|
-
|
|
|
25
|
-
|
|
|
15
|
+
Run `stg init` once in a project before using the other commands. Stolen Git stores its data in `.stolen-git/` and tracks files through its own index.
|
|
16
|
+
|
|
17
|
+
| Command | Description | Options |
|
|
18
|
+
| ------------------------- | ---------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
|
|
19
|
+
| `init` | Initialize `.stolen-git/` in the current directory. | N/A |
|
|
20
|
+
| `stage <file...>` | Add files or directories to the Stolen Git index. Directories are staged recursively. | N/A |
|
|
21
|
+
| `commit` | Save the current indexed state as a commit. | `-n, --name NAME` <br> `-d, --description DESCRIPTION` |
|
|
22
|
+
| `diff` | Show differences between the working directory and the last commit. | N/A |
|
|
23
|
+
| `log [limit]` | Print commit history. Pass a limit to show only the latest entries. | N/A |
|
|
24
|
+
| `reset [commit_id]` | With no id, restore working files from the index. With an id, restore that commit and move the current branch pointer. | N/A |
|
|
25
|
+
| `checkout <name>` | Check out a branch by name. | N/A |
|
|
26
|
+
| `checkout -c <commit_id>` | Check out a commit without moving the current branch pointer. | `-c, --commit` |
|
|
27
|
+
| `branch [name]` | List all branches, or create a branch when a name is provided. | N/A |
|
|
28
|
+
| `help` | Print the command list. | N/A |
|
|
29
|
+
|
|
30
|
+
For more detail on staging, committing, and reset behavior, see [COMMANDS.md](COMMANDS.md).
|
|
26
31
|
|
|
27
32
|
## Installation
|
|
28
33
|
|
|
@@ -39,6 +44,9 @@ Stolen git is well... you get it. I'm building a mini git clone to learn version
|
|
|
39
44
|
|
|
40
45
|
```
|
|
41
46
|
gem install stg
|
|
47
|
+
|
|
48
|
+
# you may need administrative permission, in this case
|
|
49
|
+
sudo gem install stg
|
|
42
50
|
```
|
|
43
51
|
|
|
44
52
|
Run `stg` to verify your installation
|
|
@@ -48,47 +56,51 @@ Run `stg` to verify your installation
|
|
|
48
56
|
> [!NOTE]
|
|
49
57
|
> You have to initialize with `stg init` for any of the other commands to work
|
|
50
58
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
```
|
|
54
|
-
stg init
|
|
55
|
-
```
|
|
59
|
+
### Start a new project
|
|
56
60
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
61
|
+
```sh
|
|
62
|
+
stg init
|
|
63
|
+
stg stage .
|
|
64
|
+
stg commit -n "Initial commit"
|
|
65
|
+
```
|
|
62
66
|
|
|
63
|
-
|
|
67
|
+
### Save a file change
|
|
64
68
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
69
|
+
```sh
|
|
70
|
+
stg stage lib/stg/actions.rb
|
|
71
|
+
stg commit -n "Improve reset validation"
|
|
72
|
+
```
|
|
68
73
|
|
|
69
|
-
|
|
74
|
+
### Inspect history
|
|
70
75
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
76
|
+
```sh
|
|
77
|
+
stg log # Show 5 logs and waits for user confirmation to continue
|
|
78
|
+
stg log 3 # Shows last 3 commits in the branch and closes
|
|
79
|
+
```
|
|
74
80
|
|
|
75
|
-
|
|
81
|
+
### Discard unstaged working changes
|
|
76
82
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
83
|
+
```sh
|
|
84
|
+
stg stage README.md
|
|
85
|
+
# edit README.md again
|
|
86
|
+
stg reset
|
|
87
|
+
```
|
|
80
88
|
|
|
81
|
-
|
|
89
|
+
`README.md` is restored to the version stored in the index (a.k.a last version of the file you staged).
|
|
82
90
|
|
|
83
|
-
|
|
84
|
-
stg
|
|
85
|
-
or
|
|
86
|
-
stg help
|
|
87
|
-
```
|
|
91
|
+
### Reset to a previous commit
|
|
88
92
|
|
|
89
|
-
|
|
93
|
+
> [!WARNING]
|
|
94
|
+
> `stg reset <commit_id>` is destructive. It moves the branch pointer back and can make later Stolen Git commits unreachable. Use `stg checkout -c <commit_id>` if you only want to inspect an older commit.
|
|
90
95
|
|
|
96
|
+
```sh
|
|
97
|
+
stg log # shows all commits with commit_id next to the word commit in green
|
|
98
|
+
stg reset <commit_id>
|
|
91
99
|
```
|
|
92
100
|
|
|
101
|
+
### Help
|
|
102
|
+
|
|
103
|
+
```sh
|
|
93
104
|
stg
|
|
105
|
+
stg help
|
|
94
106
|
```
|
data/lib/stg/actions.rb
CHANGED
|
@@ -96,11 +96,27 @@ module Actions
|
|
|
96
96
|
|
|
97
97
|
index = read_json('.stolen-git/index.json')
|
|
98
98
|
ignore = read_json('.stg-ignore')
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
99
|
+
index.reject! { |key, _value| ignored_path?(key, ignore) }
|
|
100
|
+
|
|
101
|
+
path_in_directory = lambda do |path, dir_path|
|
|
102
|
+
dir_path == '.' || path == dir_path || path.start_with?("#{dir_path}/")
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
stage_deleted = lambda do |path|
|
|
106
|
+
path = clean_path(path)
|
|
107
|
+
|
|
108
|
+
index.keys.each do |indexed_path|
|
|
109
|
+
next unless indexed_path == path || path_in_directory.call(indexed_path, path)
|
|
110
|
+
next if File.exist?(indexed_path)
|
|
111
|
+
|
|
112
|
+
index.delete(indexed_path)
|
|
102
113
|
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
stage_file = lambda do |file_path|
|
|
103
117
|
file_path = clean_path(file_path)
|
|
118
|
+
return if ignored_path?(file_path, ignore)
|
|
119
|
+
|
|
104
120
|
file_hash = get_file_hash(file_path)
|
|
105
121
|
file_content = File.read(file_path)
|
|
106
122
|
|
|
@@ -117,6 +133,10 @@ module Actions
|
|
|
117
133
|
|
|
118
134
|
stage_directory = lambda do |dir_path|
|
|
119
135
|
dir_path = clean_path(dir_path)
|
|
136
|
+
return if ignored_path?(dir_path, ignore)
|
|
137
|
+
|
|
138
|
+
stage_deleted.call(dir_path)
|
|
139
|
+
|
|
120
140
|
Dir.children(dir_path).each do |entry|
|
|
121
141
|
next if entry == '.stolen-git'
|
|
122
142
|
|
|
@@ -132,7 +152,11 @@ module Actions
|
|
|
132
152
|
inp.each do |inp_path|
|
|
133
153
|
inp_path = clean_path(inp_path)
|
|
134
154
|
unless File.exist? inp_path
|
|
135
|
-
|
|
155
|
+
if index.key?(inp_path) || index.keys.any? { |key| path_in_directory.call(key, inp_path) }
|
|
156
|
+
stage_deleted.call(inp_path)
|
|
157
|
+
else
|
|
158
|
+
puts "#{inp_path} doesn't exist"
|
|
159
|
+
end
|
|
136
160
|
next
|
|
137
161
|
end
|
|
138
162
|
|
|
@@ -182,6 +206,11 @@ module Actions
|
|
|
182
206
|
|
|
183
207
|
# Get the index
|
|
184
208
|
index = JSON.parse(File.read('.stolen-git/index.json'))
|
|
209
|
+
ignore = read_json('.stg-ignore')
|
|
210
|
+
original_index_size = index.length
|
|
211
|
+
index.reject! { |key, _value| ignored_path?(key, ignore) }
|
|
212
|
+
File.write('.stolen-git/index.json', JSON.pretty_generate(index)) if index.length != original_index_size
|
|
213
|
+
|
|
185
214
|
tree_content = {
|
|
186
215
|
entries: []
|
|
187
216
|
}
|
|
@@ -213,7 +242,9 @@ module Actions
|
|
|
213
242
|
commit_diff[key] = diff
|
|
214
243
|
end
|
|
215
244
|
else
|
|
216
|
-
parent_map = entries
|
|
245
|
+
parent_map = entries
|
|
246
|
+
.reject { |entry| ignored_path?(entry['path'], ignore) }
|
|
247
|
+
.to_h { |e| [e['path'], e['hash']] }
|
|
217
248
|
|
|
218
249
|
index.each do |key, value|
|
|
219
250
|
key = clean_path(key)
|
|
@@ -321,9 +352,14 @@ module Actions
|
|
|
321
352
|
end
|
|
322
353
|
|
|
323
354
|
def reset
|
|
355
|
+
reset_usage = lambda do
|
|
356
|
+
puts 'Usage: stg reset <commit_id>'
|
|
357
|
+
puts "You can find commit_id by running 'stg log'"
|
|
358
|
+
end
|
|
359
|
+
|
|
324
360
|
begin
|
|
325
361
|
OptionParser.new do |opts|
|
|
326
|
-
opts.banner = 'Usage: stg reset
|
|
362
|
+
opts.banner = 'Usage: stg reset <commit_id>'
|
|
327
363
|
|
|
328
364
|
opts.on_tail('-h', '--help', 'Show this help') do
|
|
329
365
|
puts opts
|
|
@@ -332,28 +368,30 @@ module Actions
|
|
|
332
368
|
end.parse!
|
|
333
369
|
rescue OptionParser::ParseError => e
|
|
334
370
|
puts e.message
|
|
335
|
-
|
|
371
|
+
reset_usage.call
|
|
336
372
|
puts ' -h, --help Show this help'
|
|
337
373
|
exit 1
|
|
338
374
|
end
|
|
339
375
|
|
|
376
|
+
if ARGV.length > 1
|
|
377
|
+
reset_usage.call
|
|
378
|
+
return
|
|
379
|
+
end
|
|
380
|
+
|
|
340
381
|
commit_id = ARGV.first
|
|
341
382
|
commit_history = read_json('.stolen-git/commits.json')
|
|
342
383
|
pointer = read_json('.stolen-git/pointer.json')
|
|
343
384
|
branch_id = pointer['point_to']
|
|
344
385
|
branch_content = read_json(".stolen-git/branches/#{branch_id}.json")
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
if new_commit.empty?
|
|
356
|
-
puts "This commit doesn't exit"
|
|
386
|
+
if commit_id.nil? || commit_id.empty?
|
|
387
|
+
revert_to_index
|
|
388
|
+
return
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
commit = commit_history['commits'].find { |x| x['id'] == commit_id }
|
|
392
|
+
new_commit = commit && commit['hash']
|
|
393
|
+
if new_commit.nil? || new_commit.empty?
|
|
394
|
+
reset_usage.call
|
|
357
395
|
return
|
|
358
396
|
end
|
|
359
397
|
|
data/lib/stg/differencing.rb
CHANGED
|
@@ -83,7 +83,8 @@ module DiffCalc
|
|
|
83
83
|
deletion_seq[i2].push({ old_index: i1, ma_type: 'bs' })
|
|
84
84
|
i1 += 1
|
|
85
85
|
when :insert
|
|
86
|
-
insertion_seq[i2] =
|
|
86
|
+
insertion_seq[i2] =
|
|
87
|
+
{ value: @new_s[i2].encode('UTF-8', invalid: :replace, undef: :replace, replace: ''), old_index: i1 }
|
|
87
88
|
i2 += 1
|
|
88
89
|
end
|
|
89
90
|
end
|
data/lib/stg/help.rb
CHANGED
|
@@ -5,14 +5,14 @@ module Help
|
|
|
5
5
|
Commands:\n"
|
|
6
6
|
commands_docs = {
|
|
7
7
|
init: 'Initialize the project',
|
|
8
|
-
stage: '
|
|
9
|
-
commit: 'Save the current
|
|
10
|
-
diff: '
|
|
11
|
-
log: '
|
|
12
|
-
reset: '
|
|
13
|
-
checkout: '
|
|
14
|
-
branch: 'List
|
|
15
|
-
help: '
|
|
8
|
+
stage: 'Add files or directories to the index',
|
|
9
|
+
commit: 'Save the current indexed state',
|
|
10
|
+
diff: 'Show differences between the working directory and the last commit',
|
|
11
|
+
log: 'Print commit history',
|
|
12
|
+
reset: 'Restore from the index, or restore a commit when an id is provided',
|
|
13
|
+
checkout: 'Check out a branch, or a commit with -c',
|
|
14
|
+
branch: 'List branches, or create a branch when a name is provided',
|
|
15
|
+
help: 'Show this list'
|
|
16
16
|
}
|
|
17
17
|
max_len = 0
|
|
18
18
|
commands_docs.each_key do |command|
|
data/lib/stg/utils.rb
CHANGED
|
@@ -50,22 +50,52 @@ module Utils
|
|
|
50
50
|
def revert_to_commit(commit_hash)
|
|
51
51
|
commit_content = read_json(".stolen-git/commits/#{commit_hash}.json")
|
|
52
52
|
commit_tree = read_json(".stolen-git/storage/trees/#{commit_content['tree_hash']}.json")
|
|
53
|
+
current_index = read_json('.stolen-git/index.json') || {}
|
|
53
54
|
index = {}
|
|
55
|
+
|
|
54
56
|
commit_tree['entries'].each do |entry|
|
|
55
57
|
blob = File.read(".stolen-git/storage/blobs/#{entry['hash']}")
|
|
56
58
|
# TODO: Figure out what to do when path changes
|
|
59
|
+
dir = File.dirname(entry['path'])
|
|
60
|
+
FileUtils.mkdir_p(dir) unless dir == '.'
|
|
57
61
|
File.write(entry['path'], blob)
|
|
58
62
|
index[entry['path']] ||= {}
|
|
59
63
|
index[entry['path']]['hash'] = entry['hash']
|
|
60
64
|
end
|
|
61
65
|
|
|
66
|
+
(current_index.keys - index.keys).each do |path|
|
|
67
|
+
FileUtils.rm_f(path)
|
|
68
|
+
end
|
|
69
|
+
|
|
62
70
|
File.write('.stolen-git/index.json', JSON.pretty_generate(index))
|
|
63
71
|
end
|
|
64
72
|
|
|
73
|
+
def revert_to_index
|
|
74
|
+
index = read_json('.stolen-git/index.json') || {}
|
|
75
|
+
|
|
76
|
+
index.each do |path, entry|
|
|
77
|
+
blob = File.read(".stolen-git/storage/blobs/#{entry['hash']}")
|
|
78
|
+
File.write(path, blob)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
65
82
|
def clean_path(path)
|
|
66
83
|
Pathname.new(path).cleanpath.to_s
|
|
67
84
|
end
|
|
68
85
|
|
|
86
|
+
def ignored_path?(path, ignore_patterns)
|
|
87
|
+
path = clean_path(path)
|
|
88
|
+
return false if path == '.'
|
|
89
|
+
|
|
90
|
+
path_as_dir = path.end_with?('/') ? path : "#{path}/"
|
|
91
|
+
|
|
92
|
+
ignore_patterns&.any? do |pattern|
|
|
93
|
+
File.fnmatch(pattern, path) ||
|
|
94
|
+
File.fnmatch(pattern, path_as_dir) ||
|
|
95
|
+
(pattern.end_with?('/') && File.fnmatch("#{pattern}**", path))
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
69
99
|
def check_program_exists
|
|
70
100
|
return true if File.exist? '.stolen-git'
|
|
71
101
|
|
data/lib/stg/version.rb
CHANGED