git-improved 0.1.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e11e5f761930d6144256491b8a70969fc476a3f69a46279b5cd3bc202d5a5fb0
4
- data.tar.gz: d921d52ba6e620b61c1c0e8d2258dd386025b865a1c97a854c672aeb9df3a2af
3
+ metadata.gz: 2617ea60b8914d34c0b4781f2f81ddbc0daeb9db2400dfb5c55238a93a34d006
4
+ data.tar.gz: 95d621dde81968cc258c21e9caf33318a83ba61235af844bd774258e815d6e38
5
5
  SHA512:
6
- metadata.gz: 9ac92a732673c69a58c50c2d5036b3f9e0ca76bcf0e47af8d2d1324386e88ffc1c58a28a7e14c89297babd26823c5eeff16a69174d2f1b9b85dc5f2620e1713b
7
- data.tar.gz: e86c62fcf12164acbc3b3fc97ffd16965f851217a28a3c9a9e5f7d265c524a79a1f827f25d61df19c306967e98e816571e0a7d0689c2a9d4a638a4c775fa5352
6
+ metadata.gz: c51a5861bd3f6b02aac5528ee029a603bccafeee258044a109b9ceb5aac711c4195fdf3c8dec49ca5b767de7d8f479484abe75dfd963cf3e8fcd2811797c3e19
7
+ data.tar.gz: 633c0228ba23a7e9cb42e76201d596a84d90056637686d43c12971f54e28a6fa6febc37864c6e8ad8331463d25e1c1dc5ab809b681940c85b16abe6907be1b63
data/CHANGES.md CHANGED
@@ -2,6 +2,19 @@ ChangeLog
2
2
  =========
3
3
 
4
4
 
5
+ Release 0.2.0 (2024-09-30)
6
+ --------------------------
7
+
8
+
9
+ * [enhance] New action `file:rename:all` added.
10
+ * [enhance] New action `commit:unmerge` added.
11
+ * [enhance] Action `file:track` supports `-s, --autoskip` option.
12
+ * [enhance] Action `file:list` supports `-F changed` option.
13
+ * [enhance] Action `file:delete` supports `-f, --force` option.
14
+ * [enhance] Action `file:rename` supports `-f, --force` option.
15
+
16
+
17
+
5
18
  Release 0.1.0 (2023-11-26)
6
19
  --------------------------
7
20
 
data/README.md CHANGED
@@ -8,13 +8,45 @@ It provides a much better interface than Git.
8
8
 
9
9
  * Intuitive
10
10
  * Easy to understand
11
- * Fewer commands
11
+ * Categorized commands
12
+
13
+ Command comparison:
14
+
15
+ | Git Improved | Git |
16
+ | --------------------- | ------------------------------------- |
17
+ | `gi` | `git status -sb .` |
18
+ | `gi sw <branch>` | `git checkout <branch>` |
19
+ | `gi fork <branch>` | `git checkout -b <branch>` |
20
+ | `gi join` | `git checkout -; git merge <branch>` |
21
+ | `gi pick .` | `git add -i .` |
22
+ | `gi track <newfile>` | `git add <newfile>` |
23
+ | `gi stage <file>` | `git add <file>` |
24
+ | `gi staged` | `git diff --cached` |
25
+ | `gi unstage` | `git reset HEAD` |
26
+ | `gi commit:rollback` | `git reset HEAD^` |
27
+ | `gi file:restore` | `git reset --hard` |
28
+ | `gi cc "<comment>"` | `git commit -m "<comment>"` |
29
+ | `gi correct` | `git commit --ammend` |
30
+ | `gi fixup <commit>` | `git commit --fixup=<commit>` |
31
+ | `gi changes` | `git diff` |
32
+ | `gi branches` | `git branch -a` |
33
+ | `gi commits` | `git log -p` |
34
+ | `gi tags` | `git tag -l` |
35
+ | `gi tag:upload` | `git push --tags` |
36
+ | `gi hist` | `git git log --oneline --graph ...` |
37
+ | `gi histedit` | `git rebase -i` |
38
+ | `gi histedit:resume` | `git rebase --continue` |
39
+ | `gi histedit:cancel` | `git rebase --abort` |
40
+ | ...(and more)... | .... |
41
+
42
+ GitImproved is also an example program of [Benry-CmdApp](https://kwatch.github.io/benry-ruby/benry-cmdapp.html) framework.
43
+ Benry-CmdApp is a framework for commad-line applications which take sub-commands (like `git`, `docker`, `npm`, etc).
12
44
 
13
45
  Links:
14
46
 
15
47
  * Document: <https://kwatch.github.io/git-improved/>
16
48
  * GitHub: <https://github.com/kwatch/git-improved>
17
- * Changes: <https://github.com/kwatch/git-improved/CHANGES.md>
49
+ * Changes: <https://github.com/kwatch/git-improved/blob/main/CHANGES.md>
18
50
 
19
51
 
20
52
  ### Table of Contents
@@ -38,7 +70,7 @@ Links:
38
70
  * [Status](#status)
39
71
  * [Sync](#sync)
40
72
  * [Tag](#tag)
41
- * [Aliases](#aliases)
73
+ * [Customizing Configurations](#customizing-configurations)
42
74
  * [License and Copyright](#license-and-copyright)
43
75
 
44
76
  <!-- /TOC -->
@@ -51,7 +83,7 @@ GitImproved requires Ruby >= 2.3.
51
83
  ```console
52
84
  $ gem install git-improved
53
85
  $ gi --version
54
- 1.0.0
86
+ 0.2.0
55
87
  ```
56
88
 
57
89
 
@@ -61,6 +93,8 @@ $ gi --version
61
93
  ## help
62
94
  $ gi -h | less # help message
63
95
  $ gi -l | less # list actions
96
+ $ gi : # list top-level categories of actions
97
+ $ gi commit: # list actions under 'commit' category
64
98
  $ gi -h commit:create # help of an action
65
99
 
66
100
  ## create a repo
@@ -83,7 +117,7 @@ $ gi cc "update README file" # commit changes
83
117
 
84
118
  ## upload changes
85
119
  $ gi repo:remote:seturl github:yourname/mysample
86
- $ gi push # upload local commits to remote repo
120
+ $ gi upload # upload local commits to remote repo
87
121
  ```
88
122
 
89
123
 
@@ -93,215 +127,245 @@ $ gi push # upload local commits to remote repo
93
127
  ### Branch
94
128
 
95
129
  ```
96
- branch:checkout : create a new local branch from a remote branch
97
- branch:create : create a new branch, not switch to it
98
- (alias: branch)
99
- branch:current : show current branch name
100
- branch:delete : delete a branch
101
- branch:echo : print CURR/PREV/PARENT branch name
102
- branch:fork : create a new branch and switch to it
103
- (alias: fork)
104
- branch:join : merge current branch into previous or other branch
105
- (alias: join)
106
- branch:list : list branches
107
- (alias: branches)
108
- branch:merge : merge previous or other branch into current branch
109
- (alias: merge)
110
- branch:parent : show parent branch name (EXPERIMENTAL)
111
- branch:previous : show previous branch name
112
- branch:rebase : rebase (move) current branch on top of other branch
113
- branch:rename : rename the current branch to other name
114
- branch:reset : change commit-id of current HEAD
115
- branch:switch : switch to previous or other branch
116
- (alias: sw, switch)
117
- branch:update : git pull && git stash && git rebase && git stash pop
118
- (alias: update)
119
- branch:upstream : print upstream repo name of current branch
130
+ $ gi branch:
131
+ Actions:
132
+ branch:checkout : create a new local branch from a remote branch
133
+ branch:create : create a new branch, not switch to it
134
+ branch:current : show current branch name
135
+ branch:delete : delete a branch
136
+ branch:echo : print CURR/PREV/PARENT branch name
137
+ branch:fork : create a new branch and switch to it
138
+ branch:join : merge current branch into previous or other branch
139
+ branch:list : list branches
140
+ branch:merge : merge previous or other branch into current branch
141
+ branch:parent : show parent branch name (EXPERIMENTAL)
142
+ branch:previous : show previous branch name
143
+ branch:rebase : rebase (move) current branch on top of other branch
144
+ branch:rename : rename the current branch to other name
145
+ branch:reset : change commit-id of current HEAD
146
+ branch:switch : switch to previous or other branch
147
+ branch:update : git pull && git stash && git rebase && git stash pop
148
+ branch:upstream : print upstream repo name of current branch
149
+
150
+ Aliases:
151
+ branch : alias for 'branch:create'
152
+ fork : alias for 'branch:fork'
153
+ join : alias for 'branch:join'
154
+ branches : alias for 'branch:list'
155
+ merge : alias for 'branch:merge'
156
+ sw : alias for 'branch:switch'
157
+ switch : alias for 'branch:switch'
158
+ update : alias for 'branch:update'
120
159
  ```
121
160
 
122
161
 
123
162
  ### Commit
124
163
 
125
164
  ```
126
- commit:apply : apply a commit to curr branch (known as 'cherry-pick')
127
- commit:correct : correct the last commit
128
- (alias: correct)
129
- commit:create : create a new commit
130
- (alias: cc, commit)
131
- commit:fixup : correct the previous commit
132
- (alias: fixup)
133
- commit:revert : create a new commit which reverts the target commit
134
- commit:rollback : cancel recent commits up to the target commit-id
135
- commit:show : show commits in current branch
136
- (alias: commits)
165
+ $ gi commit:
166
+ Actions:
167
+ commit:apply : apply a commit to curr branch (known as 'cherry-pick')
168
+ commit:correct : correct the last commit
169
+ commit:create : create a new commit
170
+ commit:fixup : correct the previous commit
171
+ commit:revert : create a new commit which reverts the target commit
172
+ commit:rollback : cancel recent commits up to the target commit-id
173
+ commit:show : show commits in current branch
174
+ commit:unmerge : rollback merge commit
175
+
176
+ Aliases:
177
+ correct : alias for 'commit:correct'
178
+ cc : alias for 'commit:create'
179
+ commit : alias for 'commit:create'
180
+ fixup : alias for 'commit:fixup'
181
+ commits : alias for 'commit:show'
182
+ unmerge : alias for 'commit:unmerge'
137
183
  ```
138
184
 
139
185
 
140
186
  ### Config
141
187
 
142
188
  ```
143
- config : list/get/set/delete config values
144
- config:alias : list/get/set/delete aliases of 'git' (not of 'gi')
145
- config:setuser : set user name and email
189
+ $ gi config:
190
+ Actions:
191
+ config : list/get/set/delete config values
192
+ config:alias : list/get/set/delete aliases of 'git' (not of 'gi')
193
+ config:setuser : set user name and email
146
194
  ```
147
195
 
148
196
 
149
197
  ### File
150
198
 
151
199
  ```
152
- file:blame : print commit-id, author, and timestap of each line
153
- file:changes : show changes of files
154
- (alias: changes)
155
- file:delete : delete files or directories
156
- file:egrep : find by pattern
157
- file:list : list (un)tracked/ignored/missing files
158
- (alias: files)
159
- file:move : move files into a directory
160
- file:rename : rename a file or directory to new name
161
- file:restore : restore files (= clear changes)
162
- file:track : register files into the repository
163
- (alias: register, track)
200
+ $ gi file:
201
+ Actions:
202
+ file:blame : print commit-id, author, and timestap of each line
203
+ file:changes : show changes of files
204
+ file:delete : delete files or directories
205
+ file:egrep : find by pattern
206
+ file:list : list (un)tracked/changed/ignored/missing files
207
+ file:move : move files into a directory
208
+ file:rename : rename a file or directory to new name
209
+ file:rename:all : rename multi files by pattern
210
+ file:restore : restore files (= clear changes)
211
+ file:track : register files into the repository
212
+
213
+ Aliases:
214
+ changes : alias for 'file:changes'
215
+ files : alias for 'file:list'
216
+ register : alias for 'file:track'
217
+ track : alias for 'file:track'
164
218
  ```
165
219
 
166
220
 
167
221
  ### Help
168
222
 
169
223
  ```
170
- help : print help message (of action if specified)
224
+ $ gi help:
225
+ Actions:
226
+ help : print help message (of action if specified)
171
227
  ```
172
228
 
173
229
 
174
230
  ### History
175
231
 
176
232
  ```
177
- history : show commit history in various format
178
- (alias: hist (with '-F graph'))
179
- history:edit:cancel : cancel (or abort) `git rebase -i`
180
- history:edit:resume : resume (= conitnue) suspended `git rebase -i`
181
- history:edit:skip : skip current commit and resume
182
- history:edit:start : start `git rebase -i` to edit commit history
183
- (alias: histedit)
184
- history:notuploaded : show commits not uploaded yet
233
+ $ gi history:
234
+ Actions:
235
+ history : show commit history in various format
236
+ history:edit:cancel : cancel (or abort) `git rebase -i`
237
+ history:edit:resume : resume (= conitnue) suspended `git rebase -i`
238
+ history:edit:skip : skip current commit and resume
239
+ history:edit:start : start `git rebase -i` to edit commit history
240
+ history:notuploaded : show commits not uploaded yet
241
+
242
+ Aliases:
243
+ hist : alias for 'history -F graph'
244
+ histedit : alias for 'history:edit:start'
185
245
  ```
186
246
 
187
247
 
188
248
  ### Misc
189
249
 
190
250
  ```
191
- misc:initfile : generate a init file, or print to stdout if no args
251
+ $ gi misc:
252
+ Actions:
253
+ misc:initfile : generate a init file, or print to stdout if no args
192
254
  ```
193
255
 
194
256
 
195
257
  ### Repo
196
258
 
197
259
  ```
198
- repo:clone : copy a repository ('github:<user>/<repo>' is available)
199
- repo:create : create a new directory and initialize it as a git repo
200
- repo:init : initialize git repository with empty initial commit
201
- repo:remote : list/get/set/delete remote repository
202
- repo:remote:origin : get/set/delete origin (= default remote repository)
260
+ $ gi repo:
261
+ Actions:
262
+ repo:clone : copy a repository ('github:<user>/<repo>' is available)
263
+ repo:create : create a new directory and initialize it as a git repo
264
+ repo:init : initialize git repository with empty initial commit
265
+ repo:remote : list/get/set/delete remote repository
266
+ repo:remote:origin : get/set/delete origin (= default remote repository)
203
267
  ```
204
268
 
205
269
 
206
270
  ### Staging
207
271
 
208
272
  ```
209
- staging:add : add changes of files into staging area
210
- (alias: pick (with '-p'), stage)
211
- staging:clear : delete all changes in staging area
212
- (alias: unstage)
213
- staging:edit : edit changes in staging area
214
- staging:show : show changes in staging area
215
- (alias: staged)
273
+ $ gi staging:
274
+ Actions:
275
+ staging:add : add changes of files into staging area
276
+ staging:clear : delete all changes in staging area
277
+ staging:edit : edit changes in staging area
278
+ staging:show : show changes in staging area
279
+
280
+ Aliases:
281
+ stage : alias for 'staging:add'
282
+ pick : alias for 'staging:add -p'
283
+ unstage : alias for 'staging:clear'
284
+ staged : alias for 'staging:show'
216
285
  ```
217
286
 
218
287
 
219
288
  ### Stash
220
289
 
221
290
  ```
222
- stash:drop : delete latest changes from stash
223
- stash:list : list stash history
224
- stash:pop : restore latest changes from stash
225
- stash:put : save current changes into stash
226
- stash:show : show changes on stash
291
+ $ gi stash:
292
+ Actions:
293
+ stash:drop : delete latest changes from stash
294
+ stash:list : list stash history
295
+ stash:pop : restore latest changes from stash
296
+ stash:put : save current changes into stash
297
+ stash:show : show changes on stash
227
298
  ```
228
299
 
229
300
 
230
301
  ### Status
231
302
 
232
303
  ```
233
- status:compact : show status in compact format
234
- (alias: status)
235
- status:default : show status in default format
236
- status:here : same as 'stats:compact .'
237
- status:info : show various infomation of current status
304
+ $ gi status:
305
+ Actions:
306
+ status:compact : show status in compact format
307
+ status:default : show status in default format
308
+ status:here : same as 'stats:compact .'
309
+ status:info : show various infomation of current status
310
+
311
+ Aliases:
312
+ status : alias for 'status:compact'
238
313
  ```
239
314
 
240
315
 
241
316
  ### Sync
242
317
 
243
318
  ```
244
- sync:both : download and upload commits
245
- (alias: sync)
246
- sync:pull : download commits from remote and apply them to local
247
- (alias: dl, download, pull)
248
- sync:push : upload commits to remote
249
- (alias: push, up, upload)
319
+ $ gi sync
320
+ Actions:
321
+ sync:both : download and upload commits
322
+ sync:pull : download commits from remote and apply them to local
323
+ sync:push : upload commits to remote
324
+
325
+ Aliases:
326
+ sync : alias for 'sync:both'
327
+ dl : alias for 'sync:pull'
328
+ download : alias for 'sync:pull'
329
+ pull : alias for 'sync:pull'
330
+ push : alias for 'sync:push'
331
+ up : alias for 'sync:push'
332
+ upload : alias for 'sync:push'
250
333
  ```
251
334
 
252
335
 
253
336
  ### Tag
254
337
 
255
338
  ```
256
- tag : list/show/create/delete tags
257
- tag:create : create a new tag
258
- tag:delete : delete a tag
259
- tag:download : download tags
260
- tag:list : list tags
261
- (alias: tags)
262
- tag:upload : upload tags
339
+ $ gi tag:
340
+ Actions:
341
+ tag : list/show/create/delete tags
342
+ tag:create : create a new tag
343
+ tag:delete : delete a tag
344
+ tag:download : download tags
345
+ tag:list : list tags
346
+ tag:upload : upload tags
347
+
348
+ Aliases:
349
+ tags : alias for 'tag:list'
263
350
  ```
264
351
 
265
352
 
266
- ## Aliases
353
+
354
+ ## Customizing Configurations
267
355
 
268
356
  ```
269
- branch : alias for 'branch:create'
270
- fork : alias for 'branch:fork'
271
- join : alias for 'branch:join'
272
- branches : alias for 'branch:list'
273
- merge : alias for 'branch:merge'
274
- sw : alias for 'branch:switch'
275
- switch : alias for 'branch:switch'
276
- update : alias for 'branch:update'
277
- correct : alias for 'commit:correct'
278
- cc : alias for 'commit:create'
279
- commit : alias for 'commit:create'
280
- fixup : alias for 'commit:fixup'
281
- commits : alias for 'commit:show'
282
- changes : alias for 'file:changes'
283
- files : alias for 'file:list'
284
- register : alias for 'file:track'
285
- track : alias for 'file:track'
286
- hist : alias for 'history -F graph'
287
- histedit : alias for 'history:edit:start'
288
- pick : alias for 'staging:add -p'
289
- stage : alias for 'staging:add'
290
- unstage : alias for 'staging:clear'
291
- staged : alias for 'staging:show'
292
- status : alias for 'status:compact'
293
- sync : alias for 'sync:both'
294
- dl : alias for 'sync:pull'
295
- download : alias for 'sync:pull'
296
- pull : alias for 'sync:pull'
297
- push : alias for 'sync:push'
298
- up : alias for 'sync:push'
299
- upload : alias for 'sync:push'
300
- tags : alias for 'tag:list'
357
+ ## create an init file
358
+ $ gi misc:initfile > ~/.gi_init.rb
359
+
360
+ ## set an environment variable
361
+ $ export GI_INITFILE=~/.gi_init.rb
301
362
  ```
302
363
 
364
+ For details, see the output of `gi misc:initfile`.
365
+
366
+
303
367
 
304
368
  ## License and Copyright
305
369
 
306
370
  * $License: MIT License $
307
- * $Copyright: copyright(c) 2023 kwatch@gmail.com $
371
+ * $Copyright: copyright(c) 2023-2024 kwatch@gmail.com $
data/git-improved.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = "git-improved"
5
- spec.version = "$Release: 0.1.0 $".split()[1]
5
+ spec.version = "$Release: 0.2.0 $".split()[1]
6
6
  spec.author = "kwatch"
7
7
  spec.email = "kwatch@gmail.com"
8
8
  spec.platform = Gem::Platform::RUBY
@@ -28,7 +28,7 @@ END
28
28
  #spec.extra_rdoc_files = ["README.md", "CHANGES.md"]
29
29
 
30
30
  spec.required_ruby_version = ">= 2.3"
31
- spec.add_runtime_dependency "benry-cmdapp" , "~> 1"
31
+ spec.add_runtime_dependency "benry-cmdapp" , "~> 1.1", ">= 1.1.2"
32
32
  spec.add_runtime_dependency "benry-unixcommand" , "~> 1"
33
33
  spec.add_development_dependency "oktest" , "~> 1"
34
34
  end
data/lib/git-improved.rb CHANGED
@@ -3,8 +3,8 @@
3
3
  # frozen_string_literal: true
4
4
 
5
5
  ###
6
- ### $Release: 0.1.0 $
7
- ### $Copyright: copyright(c) 2023 kwatch@gmail.com $
6
+ ### $Release: 0.2.0 $
7
+ ### $Copyright: copyright(c) 2023-2024 kwatch@gmail.com $
8
8
  ### $License: MIT License $
9
9
  ###
10
10
 
@@ -207,6 +207,21 @@ END
207
207
  return remote
208
208
  end
209
209
 
210
+ def merge_commit?(commit)
211
+ ## ref: https://stackoverflow.com/questions/3824050/
212
+ #output = `git cat-file -p #{commit}`
213
+ #header = output.split(/\n\n/)[0]
214
+ #parent_commits = header.scan(/^parent (.*)/).flatten()
215
+ #return parent_commits.length > 1
216
+ output = `git show -s --format=%p #{commit}`
217
+ return output.split().length > 1
218
+ end
219
+
220
+ def changes_exist?()
221
+ output = `git status -s -uno`
222
+ return ! output.strip().empty?
223
+ end
224
+
210
225
  def color_mode?
211
226
  return $stdout.tty?
212
227
  end
@@ -629,10 +644,11 @@ END
629
644
  ##
630
645
  category "file:" do
631
646
 
632
- @action.("list (un)tracked/ignored/missing files")
647
+ @action.("list (un)tracked/changed/ignored/missing files")
633
648
  @option.(:filtertype, "-F <filtertype>", "one of:", detail: <<~END)
634
- - tracked : only tracked files (default)
635
- - untracked : only not-tracked files
649
+ - tracked : tracked files only (default)
650
+ - untracked : not-tracked files only
651
+ - changed : changed files only
636
652
  - ignored : ignored files by '.gitignore'
637
653
  - missing : tracked but missing files
638
654
  END
@@ -660,6 +676,11 @@ END
660
676
  puts output.each_line().grep(/^\?\? /)
661
677
  end
662
678
 
679
+ def __file__list__changed(path, full)
680
+ paths = path ? [path] : []
681
+ git "status", "-s", "-uno", *paths
682
+ end
683
+
663
684
  def __file__list__ignored(path, full)
664
685
  opt = full ? "--ignored=matching" : "--ignored"
665
686
  echoback "git status -s #{opt} #{path} | grep '^!! '"
@@ -678,16 +699,26 @@ END
678
699
  @action.("register files into the repository", important: true)
679
700
  @option.(:force, "-f, --force", "allow to track ignored files")
680
701
  @option.(:recursive, "-r, --recursive", "track files under directories")
702
+ @option.(:autoskip, "-s, --autoskip", "skip already tracked files")
681
703
  #@option.(:allow_empty_dir, "-e, --allow-empty-dir", "create '.gitkeep' to track empty directory")
682
- def track(file, *file2, force: false, recursive: false)
704
+ def track(file, *file2, force: false, recursive: false, autoskip: false)
683
705
  files = [file] + file2
684
- files.each do |x|
706
+ tracked_files, untracked_files = files.partition {|x|
685
707
  output = `git ls-files -- #{x}`
686
- output.empty? or
687
- raise action_error("#{x}: Already tracked.")
708
+ ! output.empty?
709
+ }
710
+ if autoskip
711
+ ! untracked_files.empty? or
712
+ raise action_error("Missing untracked files.")
713
+ files = untracked_files
714
+ else
715
+ tracked_files.empty? or
716
+ raise action_error("#{tracked_files[0]}: Already tracked.")
688
717
  end
689
718
  files.each do |x|
690
- if File.directory?(x)
719
+ if File.symlink?(x)
720
+ # ok
721
+ elsif File.directory?(x)
691
722
  recursive or
692
723
  raise action_error("#{x}: File expected, but is a directory (specify `-r` or `--recursive` otpion to track files under the directory).")
693
724
  end
@@ -716,17 +747,71 @@ END
716
747
  end
717
748
 
718
749
  @action.("rename a file or directory to new name")
719
- def rename(old_file, new_file)
720
- ! File.exist?(new_file) or
721
- raise action_failed("#{new_file}: Already exist.")
722
- git "mv", old_file, new_file
750
+ @option.(:force, "-f, --force", "rename even if new file or dir exists")
751
+ def rename(old_file, new_file, force: false)
752
+ opts = []
753
+ if force
754
+ opts << "-f"
755
+ else
756
+ ! File.exist?(new_file) or
757
+ raise action_error("#{new_file}: Already exist.")
758
+ end
759
+ git "mv", *opts, old_file, new_file
760
+ end
761
+
762
+ @action.("rename multiple files by pattern")
763
+ @option.(:force, "-f, --force", "rename even if new file or dir exists")
764
+ def rename__all(old_pattern, new_pattern, file, *file_, force: false)
765
+ opts = []
766
+ if opts
767
+ opts << "-f"
768
+ end
769
+ files = [file, *file_]
770
+ ! files.empty? or
771
+ raise action_error("No files nor directories.")
772
+ #
773
+ begin
774
+ old_rexp = Regexp.compile(old_pattern)
775
+ rescue => exc
776
+ raise action_error("#{old_pattern}: Invalid regular expression.")
777
+ end
778
+ #
779
+ pairs = []
780
+ files.each do |old_file|
781
+ new_file = old_file.gsub(old_rexp, new_pattern)
782
+ pairs << [old_file, new_file]
783
+ puts "#{old_file} => #{new_file}"
784
+ new_file != old_file or
785
+ raise action_error("#{new_file}: New name is same as old name.")
786
+ force || ! File.exist?(new_file) or
787
+ raise action_error("#{new_file}: Already exist.")
788
+ end
789
+ #
790
+ puts ""
791
+ print "Are you sure to rename above files? [Y/n]: "
792
+ answer_yes = (
793
+ case $stdin.gets.strip()
794
+ when "" ; true
795
+ when /\Ay/i ; true
796
+ when /\An/i ; false
797
+ else ; false
798
+ end
799
+ )
800
+ return unless answer_yes
801
+ #
802
+ pairs.each do |old_file, new_file|
803
+ git "mv", *opts, old_file, new_file
804
+ end
723
805
  end
724
806
 
725
807
  @action.("delete files or directories")
726
808
  @option.(:recursive, "-r, --recursive", "delete files recursively.")
727
- def delete(file, *file2, recursive: false)
809
+ @option.(:force , "-f, --force" , "delete files forcedly.")
810
+ def delete(file, *file2, recursive: false, force: false)
728
811
  files = [file] + file2
729
- opts = recursive ? ["-r"] : []
812
+ opts = []
813
+ opts << "-r" if recursive
814
+ opts << "-f" if force
730
815
  git "rm", *opts, *files
731
816
  end
732
817
 
@@ -909,6 +994,19 @@ END
909
994
  end
910
995
  end
911
996
 
997
+ @action.("rollback merge commit")
998
+ def unmerge()
999
+ #; [!8aa2p] fails if HEAD is not a merge commit.
1000
+ merge_commit?("HEAD") or
1001
+ raise action_error("HEAD is not a merge commit.")
1002
+ #; [!qfo66] fails if any changed files exist.
1003
+ ! changes_exist?() or
1004
+ raise action_error("There are changes not committed yet."\
1005
+ " Put them into stash before unmerging.")
1006
+ #; [!mtaem] rollback merge commit
1007
+ run_once "commit:rollback", restore: true
1008
+ end
1009
+
912
1010
  end
913
1011
 
914
1012
  define_alias("commit" , "commit:create")
@@ -917,6 +1015,7 @@ END
917
1015
  define_alias("fixup" , "commit:fixup")
918
1016
  define_alias("commits" , "commit:show")
919
1017
  #define_alias("rollback", "commit:rollback")
1018
+ define_alias("unmerge" , "commit:unmerge")
920
1019
 
921
1020
 
922
1021
  ##
data/test/action_test.rb CHANGED
@@ -747,6 +747,55 @@ Oktest.scope do
747
747
  end
748
748
  end
749
749
 
750
+ topic 'commit:unmerge' do
751
+ def _prepare(n)
752
+ file = "file#{n}.tmp"
753
+ writefile(file, "A\n")
754
+ system! "git stage ."
755
+ system! "git commit -qm 'commit A'"
756
+ cid1 = get_commit_id("HEAD")
757
+ system! "git checkout -q -b b#{n}"
758
+ writefile(file, "AA\n")
759
+ system! "git stage ."
760
+ system! "git commit -qm 'commit B'"
761
+ system! "git checkout -q -"
762
+ system! "git merge -q -m 'ok' --no-ff b#{n}"
763
+ cid2 = get_commit_id("HEAD")
764
+ ok {cid2} != cid1
765
+ return cid1, cid2
766
+ end
767
+ spec "[!mtaem] rollback merge commit" do
768
+ cid1, cid2 = _prepare("4963")
769
+ output, sout = main "commit:unmerge"
770
+ cid3 = get_commit_id("HEAD")
771
+ ok {cid3} != cid2
772
+ ok {cid3} == cid1
773
+ ok {sout} == "[gi]$ git reset --hard HEAD^\n"
774
+ ok {output} == "HEAD is now at #{cid1} commit A\n"
775
+ end
776
+ spec "[!8aa2p] fails if HEAD is not a merge commit." do
777
+ _prepare("6033")
778
+ main "commit:unmerge"
779
+ output, sout, serr, status = main! "commit:unmerge"
780
+ ok {output} == ""
781
+ ok {sout} == ""
782
+ ok {status} == 1
783
+ ok {serr} != ""
784
+ ok {serr.split("\n").first} == "[ERROR] HEAD is not a merge commit."
785
+ end
786
+ spec "[!qfo66] fails if any changed files exist." do
787
+ _prepare("5014")
788
+ file = "file5014.tmp"
789
+ writefile(file, "B\n")
790
+ output, sout, serr, status = main! "commit:unmerge"
791
+ ok {output} == ""
792
+ ok {sout} == ""
793
+ ok {status} == 1
794
+ ok {serr} != ""
795
+ ok {serr.split("\n").first} == "[ERROR] There are changes not committed yet. Put them into stash before unmerging."
796
+ end
797
+ end
798
+
750
799
  }
751
800
 
752
801
 
@@ -926,7 +975,7 @@ Oktest.scope do
926
975
  before do
927
976
  _reset_all_commits()
928
977
  end
929
- spec "list (un)tracked/ignored/missing files" do
978
+ spec "list (un)tracked/changed/ignored/missing files" do
930
979
  file1 = "file1154.txt"
931
980
  file2 = "file1154.css"
932
981
  file3 = "file1154.json"
@@ -938,6 +987,7 @@ Oktest.scope do
938
987
  system! "git add #{file1}"
939
988
  system! "git add #{file2}"
940
989
  system! "git commit -q -m 'add #{file1} and #{file2}'"
990
+ writefile(file2, "BB\n")
941
991
  writefile(".gitignore", "*~\n")
942
992
  at_end { rm_rf ".gitignore" }
943
993
  ## tracked
@@ -955,6 +1005,12 @@ Oktest.scope do
955
1005
  ?? file1154.json
956
1006
  END
957
1007
  ok {output} == ""
1008
+ ## changed
1009
+ output, sout = main "file:list", "-F", "changed"
1010
+ ok {sout} == <<~'END'
1011
+ [gi]$ git status -s -uno .
1012
+ END
1013
+ ok {output} == " M file1154.css\n"
958
1014
  ## ignored
959
1015
  output, sout = main "file:list", "-F", "ignored"
960
1016
  ok {sout} == <<~'END'
@@ -1026,6 +1082,34 @@ Oktest.scope do
1026
1082
  end
1027
1083
  end
1028
1084
 
1085
+ topic 'file:rename:all' do
1086
+ spec "rename multiple files by pattern" do
1087
+ file = "file5190"
1088
+ dummy_file(file+"a.tmp", "A\n")
1089
+ dummy_file(file+"b.tmp", "B\n")
1090
+ at_end { Dir.glob(file+"*.*").each {|x| File.unlink(x) } }
1091
+ system! "git add #{file}a.tmp #{file}b.tmp"
1092
+ system! "git commit -q -m 'add files'"
1093
+ #
1094
+ ok {file+"a.tmp"}.file_exist?
1095
+ ok {file+"b.tmp"}.file_exist?
1096
+ ok {file+"a.txt"}.not_exist?
1097
+ ok {file+"b.txt"}.not_exist?
1098
+ output, sout = main "file:rename:all", '\.tmp$', '.txt', file+"a.tmp", file+"b.tmp", stdin: "y"
1099
+ ok {file+"a.tmp"}.not_exist?
1100
+ ok {file+"b.tmp"}.not_exist?
1101
+ ok {file+"a.txt"}.file_exist?
1102
+ ok {file+"b.txt"}.file_exist?
1103
+ ok {sout} == "file5190a.tmp => file5190a.txt\n"\
1104
+ "file5190b.tmp => file5190b.txt\n"\
1105
+ "\n"\
1106
+ "Are you sure to rename above files? [Y/n]: "\
1107
+ "[gi]$ git mv -f file5190a.tmp file5190a.txt\n"\
1108
+ "[gi]$ git mv -f file5190b.tmp file5190b.txt\n"
1109
+ ok {output} == ""
1110
+ end
1111
+ end
1112
+
1029
1113
  topic 'file:restore' do
1030
1114
  before do
1031
1115
  system! "git reset -q --hard HEAD"
data/test/shared.rb CHANGED
@@ -84,6 +84,11 @@ Oktest.global_scope do
84
84
  return `git branch --show-current`.strip()
85
85
  end
86
86
 
87
+ def get_commit_id(name="HEAD", width: 7)
88
+ commit_id = `git rev-parse #{name}`.strip()
89
+ return commit_id[0...width]
90
+ end
91
+
87
92
  def _reset_all_commits()
88
93
  system! "git reset -q --hard #{$initial_commit_id}"
89
94
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: git-improved
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - kwatch
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-11-25 00:00:00.000000000 Z
11
+ date: 2024-09-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: benry-cmdapp
@@ -16,14 +16,20 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1'
19
+ version: '1.1'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.1.2
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
27
  - - "~>"
25
28
  - !ruby/object:Gem::Version
26
- version: '1'
29
+ version: '1.1'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 1.1.2
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: benry-unixcommand
29
35
  requirement: !ruby/object:Gem::Requirement
@@ -90,7 +96,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
90
96
  - !ruby/object:Gem::Version
91
97
  version: '0'
92
98
  requirements: []
93
- rubygems_version: 3.4.10
99
+ rubygems_version: 3.4.19
94
100
  signing_key:
95
101
  specification_version: 4
96
102
  summary: Improved interface for Git command