git-improved 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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