git-stash-commit 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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e343c2e5d62e8bc807ccc0db3784c1ade1719ac7
4
+ data.tar.gz: 9eec3df1ac935fdacc50c6d07a31cc5b1341db0d
5
+ SHA512:
6
+ metadata.gz: 45d04be095fab1b66912e26d42b333868c95970cfafb89b8bd28b5253d02fe6a607b584b50e18dafe3e0c9f2d259316abc8d2ffe43b81cb64658d9fb8fb9f97c
7
+ data.tar.gz: 98594ecedeed9e16ea4ea5dd5fc06cdfccde8dde5427f450a3ac645c1486fab748f62d258b1f768f8ae5f55e5b43f187ac1c3663f2784d39d62f8794b736e746
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at wordijp@gmail.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in git-stash-commit.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 wordi
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,128 @@
1
+ # git-stash-commit
2
+ ==================
3
+
4
+ git sub command made in ruby, stash change files as commit of branch.
5
+ when have the change files, commit to 'stash-commit' branch, and restore it. this command is instead of the 'git stash'
6
+
7
+
8
+ ## Installation
9
+
10
+ $ gem install git-stash-commit
11
+
12
+
13
+ ## stash-commit branches
14
+
15
+ when run 'git stash-commit --to NAME', change files commit to prefixed with 'stash-commit/' and postfixed with '@NAME' branch('stash-commit/from_branch@NAME').
16
+ commit, and make a new stash-commit/*topic*@NAME branch point to it.
17
+
18
+ --- * --- * --- * <-- topic
19
+ \
20
+ * <-- stash-commit/topic@NAME
21
+
22
+ the second time, if when run 'git stash-commit', --to is serial number(default, start is 0).
23
+
24
+ --- * --- * --- * <-- topic
25
+ |\
26
+ | * <-- stash-commit/topic@NAME
27
+ \
28
+ * <-- stash-commit/topic@0
29
+
30
+
31
+ the third time, when run 'git stash-commit', next serial number is '1'.
32
+
33
+ --- * --- * --- * <-- topic
34
+ |\
35
+ | * <-- stash-commit/topic@NAME
36
+ |\
37
+ | * <-- stash-commit/topic@0
38
+ \
39
+ * <-- stash-commit/topic@1
40
+
41
+ the fourth time, when run 'git stash-commit --to 0', growth commit to 'stash-commit/topic@0'.
42
+
43
+ --- * --- * --- * <-- topic
44
+ |\
45
+ | * <-- stash-commit/topic@NAME
46
+ |\
47
+ | * --- * <-- stash-commit/topic@0
48
+ \
49
+ * <-- stash-commit/topic@1
50
+
51
+
52
+ unstash branch, if when run 'git stash-commit --from NAME', apply 'stash-commit/topic@NAME' branch on top of the current working tree state.
53
+
54
+ --- * --- * --- * <-- topic
55
+ |\
56
+ | * --- * <-- stash-commit/topic@0
57
+ \
58
+ * <-- stash-commit/topic@1
59
+
60
+ if use the '--patch' option, only patch is commit.
61
+
62
+
63
+ ## git-stash-commit commands
64
+
65
+ show command help
66
+
67
+ $ git stash-commit help
68
+
69
+ ```
70
+ usage)
71
+ git stash-commit [--to (index | name)] [-m <commit message>] [-a | -p]
72
+ options : --to default: unused index
73
+ -m | --message default: "WIP on <branch>: <hash> <title>"
74
+ -a | --all default
75
+ -p | --patch
76
+ NOTE : --all equal 'git commit --all'
77
+ --patch equal 'git commit --patch'
78
+ git stash-commit --from (index | name) [--no-reset]
79
+ NOTE : --no-reset rebase only
80
+ git stash-commit --continue
81
+ git stash-commit --skip
82
+ git stash-commit --abort
83
+ git stash-commit --rename <oldname> <newname>
84
+ NOTE : stash-commit/<oldname>@to stash-commit/<newname>@to
85
+ git stash-commit -l [-a]
86
+ options : -l | --list listup stash-commit branch, in this group
87
+ -a | --all listup stash-commit branch all
88
+ git stash-commit help
89
+ git stash-commit <any args> [-d]
90
+ options : -d | --debug debug mode, show backtrace
91
+ ```
92
+
93
+ ## if CONFLICT
94
+
95
+ if conflict of 'stash-commit [--to N] [-p]' command, working branch remains.
96
+
97
+ * stash-commit/*topic*@backup
98
+ - backup branch of this time, contains commit all change files
99
+ - delete on complete
100
+ * stash-commit/*topic*@*to*-progresstmp
101
+ - growth commit branch, contains change files of 'commit --patch', it add to '--to' target branch
102
+ - delete on add finish
103
+ * stash-commit/*topic*@*to*-progresstmp-patch-remain
104
+ - commit remain branch, contains remain change files of 'commit --patch', it apply the current orking tree state
105
+
106
+ if fixed CONFLICT, add to it and run 'git stash-commit --continue'
107
+ if cancel this time, run 'git stash-commit --abort'
108
+ if skip this time, run 'git stash-commit --skip'
109
+
110
+ these options behave like rebase.
111
+
112
+ the conflict of '--from' is also the same.
113
+
114
+
115
+ ## if renamed branch name
116
+
117
+ if renamed branch 'topic' to 'renamed_topic', please run 'git stash-commit --rename topic renamed_topic'.
118
+
119
+
120
+ ## Contributing
121
+
122
+ Bug reports and pull requests are welcome on GitHub at https://github.com/wordijp/git-stash-commit.
123
+
124
+
125
+ ## License
126
+
127
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
128
+
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "git/stash/commit"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+ #
4
+ # This file was generated by Bundler.
5
+ #
6
+ # The application 'git-stash-commit' is installed as part of a gem, and
7
+ # this file is here to facilitate running it.
8
+ #
9
+
10
+ require "pathname"
11
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
12
+ Pathname.new(__FILE__).realpath)
13
+
14
+ require "rubygems"
15
+ require "bundler/setup"
16
+
17
+ load Gem.bin_path("git-stash-commit", "git-stash-commit")
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+ #
4
+ # This file was generated by Bundler.
5
+ #
6
+ # The application 'rake' is installed as part of a gem, and
7
+ # this file is here to facilitate running it.
8
+ #
9
+
10
+ require "pathname"
11
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
12
+ Pathname.new(__FILE__).realpath)
13
+
14
+ require "rubygems"
15
+ require "bundler/setup"
16
+
17
+ load Gem.bin_path("rake", "rake")
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "git/stash/commit"
@@ -0,0 +1,35 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'git/stash/commit/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "git-stash-commit"
8
+ spec.version = Git::Stash::Commit::VERSION
9
+ spec.authors = ["wordi"]
10
+ spec.email = ["wordijp@gmail.com"]
11
+
12
+ spec.summary = %q{git sub command, stash change files as commit of branch}
13
+ spec.description = %q{when have the change files, commit to 'stash-commit' branch, and restore it. this command is instead of the 'git stash'}
14
+ spec.homepage = "https://github.com/wordijp/git-stash-commit"
15
+ spec.license = "MIT"
16
+
17
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
19
+ # if spec.respond_to?(:metadata)
20
+ # spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
21
+ # else
22
+ # raise "RubyGems 2.0 or newer is required to protect against " \
23
+ # "public gem pushes."
24
+ # end
25
+
26
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
27
+ f.match(%r{^(test|spec|features)/})
28
+ end
29
+ spec.bindir = "exe"
30
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
31
+ spec.require_paths = ["lib"]
32
+
33
+ spec.add_development_dependency "bundler", "~> 1.13"
34
+ spec.add_development_dependency "rake", "~> 10.0"
35
+ end
@@ -0,0 +1,726 @@
1
+ require "git/stash/commit/version"
2
+
3
+ $:.unshift File.dirname(__FILE__)
4
+ require 'sclib/branch.rb'
5
+ require 'sclib/command.rb'
6
+ require 'sclib/define.rb'
7
+
8
+ if !Cmd::gitdirExist?
9
+ puts 'git dir is not found'
10
+ Kernel.exit false
11
+ end
12
+
13
+ MAX = 5
14
+
15
+ G = Struct.new(:tmp, :patch, :backup)
16
+ $g = G.new(
17
+ BranchFactory::find(Cmd::getTmp),
18
+ BranchFactory::find(Cmd::getPatchRemain),
19
+ BranchFactory::find(Cmd::getBackup))
20
+
21
+ # --------------------------------------------------
22
+
23
+ def validateRebase
24
+ return true if $g.tmp
25
+ return true if Cmd::rebaseInProgress?
26
+ return true if $g.patch
27
+
28
+ puts 'stash-commit (--continue | --skip | --abort) is not need'
29
+ return false
30
+ end
31
+
32
+ def validateFromTo(fromto)
33
+ # 数値 or ブランチ名
34
+ if fromto == ''
35
+ puts 'target name is empty'
36
+ return false
37
+ end
38
+ if fromto.match(/^#{PREFIX}/)
39
+ puts "/^#{PREFIX}/ is reserved words"
40
+ return false
41
+ end
42
+ if fromto.match(/#{TMP_SUFFIX}$/)
43
+ puts "/#{TMP_SUFFIX}$/ is reserved words"
44
+ return false
45
+ end
46
+ if fromto.match(/#{PATCH_REMAIN_SUFFIX}$/)
47
+ puts "/#{PATCH_REMAIN_SUFFIX}$/ is reserved words"
48
+ return false
49
+ end
50
+ if fromto.match(/#{BACKUP_SUFFIX}$/)
51
+ puts "/#{BACKUP_SUFFIX}$/ is reserved words"
52
+ return false
53
+ end
54
+ if fromto.match(/@/)
55
+ puts '@ is used in delimiter'
56
+ return false
57
+ end
58
+
59
+ return true
60
+ end
61
+
62
+ def validateStashCommitFromTo(branch)
63
+ if Cmd::rebaseInProgress?
64
+ puts 'now rebase in progress, please fix it'
65
+ return false
66
+ end
67
+ if $g.tmp
68
+ puts 'find tmp branch, please fix it'
69
+ return false
70
+ end
71
+ if $g.patch
72
+ puts 'find patch branch, please fix it'
73
+ return false
74
+ end
75
+ if $g.backup
76
+ puts'find backup branch, please fix it'
77
+ return false
78
+ end
79
+
80
+ if branch.match(/^#{PREFIX}/)
81
+ puts "can't work in stash-commit branch" # ネストはややこしい
82
+ return false
83
+ end
84
+
85
+ return true
86
+ end
87
+
88
+ def validateRename(branch, renameOld, renameNew)
89
+ return false if !validateStashCommitFromTo branch # 同じ
90
+ return false if !validateFromTo renameOld
91
+ return false if !validateFromTo renameNew
92
+ if renameOld == renameNew
93
+ puts "old:\"#{renameOld}\" new:\"#{renameNew}\" is same"
94
+ return false
95
+ end
96
+
97
+ return true
98
+ end
99
+
100
+ def validateStashCommitFrom(branch)
101
+ if Cmd::changesCount != '0'
102
+ puts 'find editing files, please fix it'
103
+ return false
104
+ end
105
+ return false if !validateStashCommitFromTo branch
106
+
107
+ return true
108
+ end
109
+
110
+ def validateStashCommitTo(branch)
111
+ if Cmd::changesCount == '0'
112
+ puts 'not need'
113
+ return false
114
+ end
115
+ return false if !validateStashCommitFromTo branch
116
+
117
+ return true
118
+ end
119
+
120
+ # --------------------------------------------------
121
+
122
+ def createBackup(_branch)
123
+ retBackup = DetachBranch.new Cmd::stashName(_branch, BACKUP_SUFFIX), _branch
124
+ branch = BranchFactory::find _branch
125
+ retBackup.commit Branch::CommitMode::ALL, <<-EOS
126
+ backup from #{_branch}: #{Cmd::revision _branch}
127
+
128
+ *** backup commit ***
129
+ 'stash-commit --to' working backup commit
130
+ EOS
131
+ branch.cherryPickNoCommit retBackup.name
132
+ branch.reset # cancel 'git add'
133
+
134
+ retBackup
135
+ end
136
+
137
+ def _tryCommit(stash, mode, commitMessage, &onFail)
138
+ root = BranchFactory::find stash.name.match(/^#{PREFIX}\/(.+)@.+$/)[1]
139
+ stash.commit(mode, commitMessage){
140
+ # commit --patchのキャンセル時ここに来る
141
+ root.checkout
142
+ $g.backup.delete
143
+ onFail.call
144
+ }
145
+
146
+ if Cmd::changesCount != '0'
147
+ remain = DetachBranch.new "#{stash.name}-#{PATCH_REMAIN_SUFFIX}", stash.name
148
+ remain.commit Branch::CommitMode::ALL, <<-EOS
149
+ patch-remain from #{Cmd::revision stash.name}: #{hash}
150
+
151
+ *** patch remain ***
152
+ 'stash-commit --patch' working patch remain commit.
153
+
154
+ please fix conflicts without '#{stash.name}' contents
155
+ EOS
156
+ $g.patch = remain
157
+ end
158
+
159
+ return true
160
+ end
161
+ def tryCommitAll(stash, commitMessage, &onFail)
162
+ _tryCommit(stash, Branch::CommitMode::ALL, commitMessage){onFail.call}
163
+ end
164
+ def tryCommitPatch(stash, commitMessage, &onFail)
165
+ _tryCommit(stash, Branch::CommitMode::PATCH, commitMessage){onFail.call}
166
+ end
167
+
168
+ def tryStashCommitToInternal(stash, commitMessage, commit, reset=true, backup=true)
169
+ root = BranchFactory::find stash.name.match(/^#{PREFIX}\/(.+)@.+$/)[1]
170
+
171
+ $g.backup = createBackup root.name if backup
172
+
173
+ case commit
174
+ when Commit::ALL
175
+ return false if !tryCommitAll(stash, commitMessage){stash.delete}
176
+ root.checkout
177
+ when Commit::PATCH
178
+ return false if !tryCommitPatch(stash, commitMessage){stash.delete}
179
+
180
+ if $g.patch
181
+ $g.patch.rebaseOnto root.name, "#{$g.patch.name}~"
182
+
183
+ if reset
184
+ revision = Cmd::revision root.name
185
+ root.rebase $g.patch.name
186
+ $g.patch.delete
187
+ root.reset revision
188
+ else
189
+ root.checkout
190
+ end
191
+ else
192
+ root.checkout
193
+ end
194
+ end
195
+
196
+ $g.backup.delete if backup
197
+
198
+ return true
199
+ end
200
+
201
+ def tryStashCommitTo(stashBranch, commitMessage, commit, reset=true, backup=true)
202
+ rootBranch = stashBranch.match(/^#{PREFIX}\/(.+)@.+$/)[1]
203
+ stash = Branch::new stashBranch, rootBranch
204
+ tryStashCommitToInternal stash, commitMessage, commit, reset, backup
205
+ end
206
+
207
+ def tryStashCommitToGrow(branch, to, commitMessage, commit)
208
+ stashBranch = Cmd::stashName branch, to
209
+ root = BranchFactory::find stashBranch.match(/^#{PREFIX}\/(.+)@.+$/)[1]
210
+
211
+ $g.backup = createBackup root.name
212
+
213
+ if !Cmd::branchExist? stashBranch
214
+ # 新規作成
215
+ stash = Branch.new stashBranch, root.name
216
+ return false if !tryStashCommitToInternal stash, commitMessage, commit, true, false
217
+ else
218
+ # 存在してるので、そのブランチへ追加する
219
+ # 一端新規作成し
220
+ tmp = DetachBranch.new "#{stashBranch}-#{TMP_SUFFIX}", root.name
221
+ return false if !tryStashCommitToInternal tmp, commitMessage, commit, false, false
222
+
223
+ stash = BranchFactory::find stashBranch
224
+
225
+ # rebaseで追加
226
+ tmp.rebase stash.name
227
+ stash.rebase tmp.name
228
+ tmp.delete
229
+
230
+ root.checkout
231
+
232
+ case commit
233
+ when Commit::ALL
234
+ # no-op
235
+ when Commit::PATCH
236
+ if $g.patch
237
+ revision = Cmd::revision root.name
238
+ root.rebase $g.patch.name
239
+ $g.patch.delete
240
+ root.reset revision
241
+ end
242
+ end
243
+ end
244
+
245
+ $g.backup.delete
246
+
247
+ return true
248
+ end
249
+
250
+ # --------------------------------------------------
251
+
252
+ def tryStashCommitFrom(_branch, from)
253
+ stash = BranchFactory::find (Cmd::stashName _branch, from)
254
+ branch = BranchFactory::find _branch
255
+
256
+ baseHash = Cmd::mergeBaseHash branch.name, stash.name
257
+ stash.rebaseOnto branch.name, baseHash
258
+
259
+ # ここまでくれば安心
260
+ revision = Cmd::revision branch.name
261
+ branch.rebase stash.name
262
+ stash.delete
263
+ branch.reset revision
264
+
265
+ return true
266
+ end
267
+
268
+ # --------------------------------------------------
269
+
270
+ def tryStashCommitContinueTo(tmp, patch)
271
+ # rebase --continue前かもしれない
272
+ Cmd::exec('git rebase --continue') if Cmd::rebaseInProgress?
273
+
274
+ if patch
275
+ root = BranchFactory::find patch.name.match(/^#{PREFIX}\/(.+)@.+-#{PATCH_REMAIN_SUFFIX}$/)[1]
276
+ # rebase --skip後かもしれない
277
+ if Cmd::sameBranch? patch.name, root.name
278
+ puts "stop, '#{PATCH_REMAIN_SUFFIX}' rebase --skip found, from starting stash-commit --patch"
279
+ raise
280
+ end
281
+ # rebase --abort後かもしれない
282
+ if !Cmd::parentChildBranch? patch.name, root.name
283
+ patch.rebaseOnto root.name, "#{patch.name}~"
284
+ end
285
+ end
286
+ if tmp
287
+ stash = BranchFactory::find tmp.name.match(/^(#{PREFIX}\/.+)-#{TMP_SUFFIX}$/)[1]
288
+ # rebase --skip後かもしれない
289
+ if Cmd::sameBranch? tmp.name, stash.name
290
+ puts "stop, '#{TMP_SUFFIX}' rebase --skip found, from starting stash-commit --to"
291
+ raise
292
+ end
293
+ # rebase --abort後かもしれない
294
+ if !Cmd::parentChildBranch? tmp.name, stash.name
295
+ tmp.rebaseOnto stash.name, "#{tmp.name}~"
296
+ end
297
+ end
298
+
299
+ # ここまでくれば安心
300
+ if tmp
301
+ root = BranchFactory::find tmp.name.match(/^#{PREFIX}\/(.+)@.+-#{TMP_SUFFIX}$/)[1]
302
+ stash = BranchFactory::find tmp.name.match(/^(#{PREFIX}\/.+)-#{TMP_SUFFIX}$/)[1]
303
+
304
+ tmp.rebase stash.name
305
+ stash.rebase tmp.name
306
+ tmp.delete
307
+ root.checkout
308
+ end
309
+ if patch
310
+ root = BranchFactory::find patch.name.match(/^#{PREFIX}\/(.+)@.+-#{PATCH_REMAIN_SUFFIX}$/)[1]
311
+ revision = Cmd::revision root.name
312
+
313
+ root.rebase patch.name
314
+ patch.delete
315
+ root.reset revision
316
+ end
317
+
318
+ return true
319
+ end
320
+
321
+ def tryStashCommitContinueFrom(branch)
322
+ # tmpが無いので、rebase中の時のみ継続
323
+ return false if !Cmd::rebaseInProgress?
324
+
325
+ stashMatch = branch.match(/.+rebasing (#{PREFIX}\/.+)\)$/)
326
+ rootMatch = branch.match(/.+rebasing #{PREFIX}\/(.+)@.+\)$/)
327
+ return false if !stashMatch
328
+ return false if !Cmd::execRet 'git rebase --continue'
329
+
330
+ # ここまでくれば安心
331
+ stash = BranchFactory::find stashMatch[1]
332
+ root = BranchFactory::find rootMatch[1]
333
+ revision = Cmd::revision root.name
334
+ root.rebase stash.name
335
+ stash.delete
336
+ root.reset revision
337
+
338
+ return true
339
+ end
340
+
341
+ def tryStashCommitContinue(branch)
342
+ if $g.tmp or $g.patch
343
+ return false if !tryStashCommitContinueTo $g.tmp, $g.patch
344
+ $g.backup.delete if $g.backup
345
+ else
346
+ return false if !tryStashCommitContinueFrom branch
347
+ end
348
+
349
+ return true
350
+ end
351
+
352
+ # --------------------------------------------------
353
+
354
+ def tryStashCommitSkipTo(tmp, patch)
355
+ # rebase --skip前かもしれない
356
+ Cmd::exec('git rebase --skip') if Cmd::rebaseInProgress?
357
+
358
+ if patch
359
+ root = BranchFactory::find patch.name.match(/^#{PREFIX}\/(.+)@.+-#{PATCH_REMAIN_SUFFIX}$/)[1]
360
+ # rebase --continue後かもしれない
361
+ if Cmd::parentChildBranch? patch.name, root.name
362
+ puts "stop, '#{PATCH_REMAIN_SUFFIX}' rebase --continue found, from starting stash-commit --patch"
363
+ raise
364
+ end
365
+ # rebase --abort後はスルー
366
+ end
367
+ if tmp
368
+ stash = BranchFactory::find tmp.name.match(/^(#{PREFIX}\/.+)-#{TMP_SUFFIX}$/)[1]
369
+ # rebase --continue後かもしれない
370
+ if Cmd::parentChildBranch? tmp.name, stash.name
371
+ puts "stop, '#{TMP_SUFFIX}' rebase --continue found, from starting stash-commit --to"
372
+ raise
373
+ end
374
+ # rebase --abort後はスルー
375
+ end
376
+
377
+ # ここまでくれば安心
378
+ if tmp
379
+ root = BranchFactory::find tmp.name.match(/^#{PREFIX}\/(.+)@.+-#{TMP_SUFFIX}$/)[1]
380
+ root.checkout
381
+ tmp.delete # skipなので捨てる
382
+ end
383
+ if patch
384
+ root = BranchFactory::find patch.name.match(/^#{PREFIX}\/(.+)@.+-#{PATCH_REMAIN_SUFFIX}$/)[1]
385
+ root.checkout
386
+ patch.delete # skipなので捨てる
387
+
388
+ # もしかしたらtmpとして削除済み
389
+ patchParent = BranchFactory::find patch.name.match(/^(#{PREFIX}\/.+)-#{PATCH_REMAIN_SUFFIX}$/)[1]
390
+ if patchParent
391
+ patchParent.delete
392
+ end
393
+ end
394
+
395
+ return true
396
+ end
397
+
398
+ def tryStashCommitSkipFrom(branch)
399
+ # tmpが無いので、rebase中の時のみ継続
400
+ return false if !Cmd::rebaseInProgress?
401
+
402
+ stashMatch = branch.match(/.+rebasing (#{PREFIX}\/.+)\)$/)
403
+ rootMatch = branch.match(/.+rebasing #{PREFIX}\/(.+)@.+\)$/)
404
+ return false if !stashMatch
405
+ return false if !Cmd::execRet 'git rebase --skip'
406
+
407
+ # ここまでくれば安心
408
+ stash = BranchFactory::find stashMatch[1]
409
+ root = BranchFactory::find rootMatch[1]
410
+ root.rebase stash.name
411
+ stash.delete
412
+
413
+ return true
414
+ end
415
+
416
+ def tryStashCommitSkip(branch)
417
+ if $g.tmp or $g.patch
418
+ return false if !tryStashCommitSkipTo $g.tmp, $g.patch
419
+ $g.backup.delete if $g.backup
420
+ else
421
+ return false if !tryStashCommitSkipFrom branch
422
+ end
423
+
424
+ return true
425
+ end
426
+
427
+ # --------------------------------------------------
428
+
429
+ def tryStashCommitAbortTo(tmp, patch)
430
+ if !$g.backup
431
+ puts "stop, '#{BACKUP_SUFFIX}' is not found, from starting stash-commit --to"
432
+ return false
433
+ end
434
+
435
+ # rebase --abort前かもしれない
436
+ Cmd::exec 'git rebase --abort' if Cmd::rebaseInProgress?
437
+
438
+ if tmp
439
+ root = BranchFactory::find tmp.name.match(/^#{PREFIX}\/(.+)@.+-#{TMP_SUFFIX}$/)[1]
440
+ root.checkout
441
+ tmp.delete
442
+ end
443
+ if patch
444
+ root = BranchFactory::find patch.name.match(/^#{PREFIX}\/(.+)@.+-#{PATCH_REMAIN_SUFFIX}$/)[1]
445
+ root.checkout
446
+ patch.delete
447
+
448
+ # もしかしたらtmpとして削除済み
449
+ patchParent = BranchFactory::find patch.name.match(/^(#{PREFIX}\/.+)-#{PATCH_REMAIN_SUFFIX}$/)[1]
450
+ if patchParent
451
+ patchParent.delete
452
+ end
453
+ end
454
+
455
+ # ここまでくれば安心
456
+ root = BranchFactory::find $g.backup.name.match(/^#{PREFIX}\/(.+)@#{BACKUP_SUFFIX}$/)[1]
457
+ root.checkout
458
+ root.cherryPickNoCommit $g.backup.name
459
+ root.reset # cancel 'git add'
460
+
461
+ return true
462
+ end
463
+
464
+ def tryStashCommitAbortFrom(branch)
465
+ # tmpが無いので、rebase中の時のみ継続
466
+ return false if !Cmd::rebaseInProgress?
467
+
468
+ rootMatch = branch.match(/.+rebasing #{PREFIX}\/(.+)@.+\)$/)
469
+ return false if !rootMatch
470
+ return false if !Cmd::execRet 'git rebase --abort'
471
+
472
+ # ここまでくれば安心
473
+ root = BranchFactory::find rootMatch[1]
474
+ root.checkout
475
+
476
+ return true
477
+ end
478
+
479
+ def tryStashCommitAbort(branch)
480
+ if $g.tmp or $g.patch
481
+ return false if !tryStashCommitAbortTo $g.tmp, $g.patch
482
+ $g.backup.delete if $g.backup
483
+ else
484
+ return false if !tryStashCommitAbortFrom branch
485
+ end
486
+
487
+ return true
488
+ end
489
+
490
+ # --------------------------------------------------
491
+
492
+ def tryStashCommitRename(branch, renameOld, renameNew)
493
+ Cmd::stashCommitRename renameOld, renameNew
494
+ end
495
+
496
+ # --------------------------------------------------
497
+
498
+ def usage
499
+ print <<-EOS
500
+ usage)
501
+ git stash-commit [--to (index | name)] [-m <commit message>] [-a | -p]
502
+ options : --to default: unused index
503
+ -m | --message default: "WIP on <branch>: <hash> <title>"
504
+ -a | --all default
505
+ -p | --patch
506
+ NOTE : --all equal 'git commit --all'
507
+ --patch equal 'git commit --patch'
508
+ git stash-commit --from (index | name) [--no-reset]
509
+ NOTE : --no-reset rebase only
510
+ git stash-commit --continue
511
+ git stash-commit --skip
512
+ git stash-commit --abort
513
+ git stash-commit --rename <oldname> <newname>
514
+ NOTE : #{PREFIX}/<oldname>@to #{PREFIX}/<newname>@to
515
+ git stash-commit -l [-a]
516
+ options : -l | --list listup stash-commit branch, in this group
517
+ -a | --all listup stash-commit branch all
518
+ git stash-commit help
519
+ git stash-commit <any args> [-d]
520
+ options : -d | --debug debug mode, show backtrace
521
+ EOS
522
+ end
523
+
524
+ # --------------------------------------------------
525
+
526
+ class ArgvIterator
527
+ def initialize(argv)
528
+ @argv = argv
529
+ @index = 0
530
+ end
531
+
532
+ def next?
533
+ @index < @argv.length
534
+ end
535
+
536
+ def next
537
+ if @index < @argv.length
538
+ ret = @argv[@index]
539
+ @index += 1
540
+ return ret
541
+ else
542
+ puts '* error: argument is not enoufh'
543
+ usage
544
+ raise
545
+ end
546
+ end
547
+ end
548
+
549
+ module Rebase
550
+ CONTINUE = '--continue'
551
+ SKIP = '--skip'
552
+ ABORT = '--abort'
553
+ end
554
+
555
+ module Commit
556
+ ALL = '--all'
557
+ PATCH = '--patch'
558
+ end
559
+
560
+ $debugMode = false
561
+
562
+ def main(argv)
563
+ hash = Cmd::revision
564
+ branch = Cmd::branchName
565
+ title = Cmd::title
566
+
567
+ commitMessage = "WIP on #{branch}: #{hash} #{title}" # default
568
+ to = nil
569
+ from = nil
570
+ rebase = nil
571
+ commit = Commit::ALL
572
+ renameOld = nil
573
+ renameNew = nil
574
+
575
+ listup = false
576
+ listupAll = false
577
+
578
+ # parse argv
579
+ # ----------
580
+ itArgv = ArgvIterator.new(argv)
581
+ while itArgv.next? do
582
+ arg = itArgv.next
583
+ case arg
584
+ when '-m', '--message'
585
+ commitMessage = itArgv.next
586
+ when '--to'
587
+ to = itArgv.next
588
+ when '--from'
589
+ from = itArgv.next
590
+ when '-a', '--all'
591
+ commit = Commit::ALL
592
+ listupAll = true
593
+ when '-p', '--patch'
594
+ commit = Commit::PATCH
595
+ when '--continue'
596
+ rebase = Rebase::CONTINUE
597
+ when '--skip'
598
+ rebase = Rebase::SKIP
599
+ when '--abort'
600
+ rebase = Rebase::ABORT
601
+ when '--rename'
602
+ renameOld = itArgv.next
603
+ renameNew = itArgv.next
604
+ when '-l', '--list'
605
+ listup = true
606
+ when 'help'
607
+ usage
608
+ Kernel.exit true
609
+ when '-d', '--debug'
610
+ $debugMode = true
611
+ else
612
+ puts "* error: unknown option:#{arg}"
613
+ usage
614
+ raise
615
+ end
616
+ end
617
+
618
+ # --list [--all]
619
+ if listup
620
+ Cmd::listup branch, listupAll
621
+ Kernel.exit true
622
+ end
623
+
624
+ # --continue | --skip | --abort
625
+ # -----------------------------
626
+ if rebase != nil
627
+ begin
628
+ raise if !validateRebase
629
+ case rebase
630
+ when Rebase::CONTINUE
631
+ raise if !tryStashCommitContinue branch
632
+ when Rebase::SKIP
633
+ raise if !tryStashCommitSkip branch
634
+ when Rebase::ABORT
635
+ raise if !tryStashCommitAbort branch
636
+ end
637
+ return true
638
+ rescue => e
639
+ puts "* failed: stash-commit #{rebase}"
640
+ raise e
641
+ end
642
+ end
643
+
644
+ # --rename
645
+ # --------
646
+ if renameOld != nil
647
+ begin
648
+ raise if !validateRename branch, renameOld, renameNew
649
+ raise if !tryStashCommitRename branch, renameOld, renameNew
650
+ return true
651
+ rescue => e
652
+ puts '* failed: stash-commit --rename'
653
+ raise e
654
+ end
655
+ end
656
+
657
+ # --from | --to
658
+ # -------------
659
+ if from != nil
660
+ begin
661
+ raise if !validateFromTo from or !validateStashCommitFrom branch
662
+ raise if !tryStashCommitFrom branch, from
663
+ return true
664
+ rescue => e
665
+ puts '* failed: stash-commit --from (index | name)'
666
+ raise e
667
+ end
668
+ elsif to != nil
669
+ # --to 指定がある時
670
+ begin
671
+ raise if !validateFromTo to or !validateStashCommitTo branch
672
+ raise if !tryStashCommitToGrow branch, to, commitMessage, commit
673
+ return true
674
+ rescue => e
675
+ puts '* failed: stash-commit --to (index | name)'
676
+ raise e
677
+ end
678
+ else
679
+ # --to 指定がない時
680
+ begin
681
+ raise if !validateStashCommitTo branch
682
+ (MAX+1).times do |i|
683
+ if i == MAX
684
+ puts '* error: branch is too many'
685
+ raise
686
+ end
687
+
688
+ stashBranch = Cmd::stashName branch, i
689
+ if Cmd::branchExist? stashBranch
690
+ puts "\"#{stashBranch}\" is already exist"
691
+ next
692
+ end
693
+
694
+ raise if !tryStashCommitTo stashBranch, commitMessage, commit
695
+ return true
696
+ end
697
+ rescue => e
698
+ puts '* failed: stash-commit'
699
+ raise e
700
+ end
701
+ end
702
+
703
+ raise 'logic error' # ここには来ないはず
704
+ end
705
+
706
+ # -----------------------------------------------
707
+
708
+ module Git
709
+ module Stash
710
+ module Commit
711
+
712
+ begin
713
+ raise if !main ARGV
714
+ puts 'done!'
715
+ rescue => e
716
+ if $debugMode
717
+ puts "* error: #{e}" if !e.message.empty?
718
+ puts e.backtrace
719
+ end
720
+ puts 'failed'
721
+ Kernel.exit false
722
+ end
723
+
724
+ end
725
+ end
726
+ end