gitloop 0.0.3

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.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in gitloop.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,61 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ gitloop (0.0.3)
5
+ methadone
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ aruba (0.4.11)
11
+ childprocess (>= 0.2.3)
12
+ cucumber (>= 1.1.1)
13
+ ffi (>= 1.0.11)
14
+ rspec (>= 2.7.0)
15
+ builder (3.0.0)
16
+ childprocess (0.3.1)
17
+ ffi (~> 1.0.6)
18
+ cucumber (1.1.4)
19
+ builder (>= 2.1.2)
20
+ diff-lcs (>= 1.1.2)
21
+ gherkin (~> 2.7.1)
22
+ json (>= 1.4.6)
23
+ term-ansicolor (>= 1.0.6)
24
+ diff-lcs (1.1.3)
25
+ ffi (1.0.11)
26
+ gherkin (2.7.7)
27
+ json (>= 1.4.6)
28
+ guard (1.0.0)
29
+ ffi (>= 0.5.0)
30
+ thor (~> 0.14.6)
31
+ guard-cucumber (0.7.5)
32
+ cucumber (>= 0.10)
33
+ guard (>= 0.8.3)
34
+ json (1.6.5)
35
+ methadone (0.5.1)
36
+ bundler
37
+ rake (0.9.2.2)
38
+ rdoc (3.12)
39
+ json (~> 1.4)
40
+ rspec (2.8.0)
41
+ rspec-core (~> 2.8.0)
42
+ rspec-expectations (~> 2.8.0)
43
+ rspec-mocks (~> 2.8.0)
44
+ rspec-core (2.8.0)
45
+ rspec-expectations (2.8.0)
46
+ diff-lcs (~> 1.1.2)
47
+ rspec-mocks (2.8.0)
48
+ ruby_gntp (0.3.4)
49
+ term-ansicolor (1.0.7)
50
+ thor (0.14.6)
51
+
52
+ PLATFORMS
53
+ ruby
54
+
55
+ DEPENDENCIES
56
+ aruba
57
+ gitloop!
58
+ guard-cucumber
59
+ rake (~> 0.9.2)
60
+ rdoc
61
+ ruby_gntp
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Alain Ravet
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,49 @@
1
+ [gitloop](http://rubygems.org/gems/gitloop)
2
+ =======
3
+
4
+
5
+ <table>
6
+ <tr style="line-height:5em">
7
+ <td colspan="3" style="text-align:center;">
8
+ <code style="font-size:1.6em;padding:20px 40px;background:lightyellow">
9
+ git <b>loop</b>&nbsp;&nbsp;master~4&nbsp;&nbsp;master~2&nbsp;&nbsp;&nbsp;<b>-m</b> "let's group them"
10
+ </code>
11
+ </td>
12
+ </tr>
13
+ <tr>
14
+ <td width="42%" style="text-align:center"> <img src="https://github.com/alainravet/gitloop/raw/master/doc/BEFORE.png"/></td>
15
+ <td width="6%" style="text-align:center;font-size:4em;">&rarr;</td>
16
+ <td width="42%" style="text-align:center"> <img src="https://github.com/alainravet/gitloop/raw/master/doc/AFTER.png" /></td>
17
+ </tr>
18
+ </table>
19
+
20
+
21
+ The same results would be obtained by any of :
22
+
23
+ $ git loop 7355c79 6ffd9 -m "a logical group"
24
+ $ git loop second c4 -m "a logical group"
25
+ $ git loop c2 6ffd9 -m "a logical group"
26
+
27
+
28
+ Installation :
29
+ -------------
30
+ $ gem install gitloop
31
+
32
+ #### Report bugs to <https://github.com/alainravet/alainravet/>
33
+
34
+ --------------------------------------------------------------------------------
35
+
36
+ == Note on Patches/Pull Requests
37
+
38
+ * Fork the project.
39
+ * Make your feature addition or bug fix.
40
+ * Add tests for it. This is important so I don't break it in a
41
+ future version unintentionally.
42
+ * Commit, do not mess with rakefile, version, or history.
43
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
44
+ * Send me a pull request. Bonus points for topic branches.
45
+
46
+ == Copyright
47
+
48
+ Copyright (c) 2012 Alain Ravet. See LICENSE for details.
49
+ ·
data/bin/git-loop ADDED
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require 'methadone'
5
+ require File.dirname(__FILE__) + '/../lib/gitloop'
6
+
7
+ include Methadone::Main
8
+
9
+ main do |from_ref, to_ref|
10
+ all_parameters_provided = from_ref && to_ref && options[:message]
11
+ if all_parameters_provided
12
+ begin
13
+ Gitloop::Looper.make_loop_for_references_or_messages(from_ref, to_ref, options[:message])
14
+ rescue Gitloop::GitError => e
15
+ puts "*** ERROR : #{e}"
16
+ end
17
+ else
18
+ puts @banner
19
+ end
20
+ end
21
+
22
+ on("-m MESSAGE", "--message", "commit message for the loop") do |m|
23
+ options[:message] = m
24
+ end
25
+
26
+ @banner = <<-DOC
27
+ Usage: git loop <from_ref> <to_ref> -m "<message>"
28
+ where <*_ref> is either
29
+ - a commit reference (SHA, branch name, etc..) or
30
+ - a commit message part
31
+
32
+
33
+ example:
34
+
35
+ +-----------------------------------------------------------------+
36
+ | $ git loop "c2" "the third" -m "a logical group" |
37
+ | or $ git loop 7355c79 bab916a -m "a logical group" |
38
+ +-----------------------------------------------------------------+
39
+ BEFORE AFTER
40
+ -------------------------------------------------------------------
41
+ * 69fd256 c6
42
+ * 377c650 c5 five - fifth commit
43
+ * 9f31be9 c4 not the third commit
44
+ * edadbb7 c6 ----------> * 845c17e *** a logical group
45
+ * da55377 c5 five - fifth commit |\\
46
+ * 6fddd9c c4 not the third commit [ | * bab916a c3 the third commit ]
47
+ [ * bab916a c3 the third commit ] [ | * 7355c79 c2 the second commit ]
48
+ [ * 7355c79 c2 the second commit ] |/
49
+ * 91182df c1 * 91182df c1
50
+
51
+ DOC
52
+ description " combine `git merge --no--ff ..` and `git rebase ..` to regroup commits sequences in \"loops\"" +
53
+ "\n\n" +
54
+ @banner
55
+
56
+
57
+ version Gitloop::VERSION
58
+
59
+ go!
data/bin/gitloop ADDED
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require 'methadone'
5
+ require File.dirname(__FILE__) + '/../lib/gitloop'
6
+
7
+ include Methadone::Main
8
+
9
+ main do |from_ref, to_ref|
10
+ all_parameters_provided = from_ref && to_ref && options[:message]
11
+ if all_parameters_provided
12
+ begin
13
+ Gitloop::Looper.make_loop_for_references_or_messages(from_ref, to_ref, options[:message])
14
+ rescue Gitloop::GitError => e
15
+ puts "*** ERROR : #{e}"
16
+ end
17
+ else
18
+ puts @banner
19
+ end
20
+ end
21
+
22
+ on("-m MESSAGE", "--message", "commit message for the loop") do |m|
23
+ options[:message] = m
24
+ end
25
+
26
+ @banner = <<-DOC
27
+ Usage: git loop <from_ref> <to_ref> -m "<message>"
28
+ where <*_ref> is either
29
+ - a commit reference (SHA, branch name, etc..) or
30
+ - a commit message part
31
+
32
+
33
+ example:
34
+
35
+ +-----------------------------------------------------------------+
36
+ | $ git loop "c2" "the third" -m "a logical group" |
37
+ | or $ git loop 7355c79 bab916a -m "a logical group" |
38
+ +-----------------------------------------------------------------+
39
+ BEFORE AFTER
40
+ -------------------------------------------------------------------
41
+ * 69fd256 c6
42
+ * 377c650 c5 five - fifth commit
43
+ * 9f31be9 c4 not the third commit
44
+ * edadbb7 c6 ----------> * 845c17e *** a logical group
45
+ * da55377 c5 five - fifth commit |\\
46
+ * 6fddd9c c4 not the third commit [ | * bab916a c3 the third commit ]
47
+ [ * bab916a c3 the third commit ] [ | * 7355c79 c2 the second commit ]
48
+ [ * 7355c79 c2 the second commit ] |/
49
+ * 91182df c1 * 91182df c1
50
+
51
+ DOC
52
+ description " combine `git merge --no--ff ..` and `git rebase ..` to regroup commits sequences in \"loops\"" +
53
+ "\n\n" +
54
+ @banner
55
+
56
+
57
+ version Gitloop::VERSION
58
+
59
+ go!
data/doc/AFTER.png ADDED
Binary file
data/doc/BEFORE.png ADDED
Binary file
data/doc/TODO.txt ADDED
@@ -0,0 +1,31 @@
1
+ TESTS FOR ERROR CASES
2
+
3
+ error result
4
+ - exception
5
+ - error message in the output
6
+ ------------------------------------------------------------------------
7
+
8
+
9
+ -f -t : allow using SHA for 1/2 of the args
10
+
11
+ ABORT if
12
+ - unstaged changes
13
+ - not on a branch (current_branch.nil?)
14
+ - <from> == very 1st commit
15
+ - missing parameters
16
+ - `git` not found
17
+ - not in a git directory
18
+
19
+ after ABORT,
20
+ * reset --hard to original situation + clean if anything fails
21
+ * explain
22
+
23
+
24
+ edge case :
25
+ - empty repository
26
+
27
+ def current_SHA
28
+ `git rev-parse HEAD`
29
+ end
30
+
31
+
data/doc/dev_notes.txt ADDED
@@ -0,0 +1,6 @@
1
+
2
+ - After bootstraping the app, launch the binary skeleton
3
+
4
+ $ cd <..>/gitloop
5
+ $ bundle exec rake install
6
+ $ ./bin/gitloop --help
@@ -0,0 +1,29 @@
1
+ Feature: Errors detection and handling
2
+
3
+ As a developer
4
+ In order to improve my git history structure
5
+ I want to create a few loops via git merge and git rebase
6
+
7
+
8
+ Background:
9
+ Given the sandbox is setup
10
+ Given I cd to "sandbox"
11
+
12
+
13
+ Scenario Outline: in Ruby, create a loop from the exact SHAs
14
+
15
+
16
+ When I run `git-loop <from_ref> <to_ref> -m "fail"`
17
+
18
+ Then the repo is in its original state
19
+ And there are no unstaged nor staged changes
20
+ And the current branch is "master"
21
+
22
+ Scenarios: invalid or unknown SHAs
23
+ | from_ref | to_ref |
24
+ | 91182df | a059392 |
25
+ | 1111111 | a059392 |
26
+
27
+ Scenarios: wrong order
28
+ | from_ref | to_ref |
29
+ | a059392 | 8aab2de |
@@ -0,0 +1,58 @@
1
+ Feature: Happy path (no problems, no edge case)
2
+
3
+ As a developer
4
+ In order to improve my git history structure
5
+ I want to create a few loops via git merge and git rebase
6
+
7
+
8
+ Background:
9
+ Given the sandbox is setup
10
+ Given I cd to "sandbox"
11
+
12
+ #--------------------------------------------------------------------------------
13
+
14
+ Scenario Outline: the many ways to create the same loop
15
+
16
+
17
+ When I run `<command>`
18
+
19
+ Then the git log graph matches:
20
+ """
21
+ * <a_sha> c6
22
+ * <a_sha> c5 five - fifth commit
23
+ * <a_sha> *** hellboy was here
24
+ |\
25
+ | * 6fddd9c c4 not the third commit
26
+ | * bab916a c3 the third commit
27
+ | * 7355c79 c2 the second commit
28
+ |/
29
+ * 91182df c1
30
+ """
31
+ And the current branch is "master"
32
+
33
+ Scenarios: pure SHAs or pure messages snippets
34
+ | command |
35
+ | git-loop 7355c79 6fddd9c -m "hellboy was here" |
36
+ | git-loop master~4 master~2 -m "hellboy was here" |
37
+ | git-loop "c2" "c4" -m "hellboy was here" |
38
+ | git-loop "second commit" 6fddd9c -m "hellboy was here" |
39
+
40
+
41
+ #--------------------------------------------------------------------------------
42
+
43
+ Scenario: comment can contain quote
44
+ When I run `git-loop 7355c79 6fddd9c -m "let's do it"`
45
+
46
+ Then the current branch is "master"
47
+ And the git log graph matches:
48
+ """
49
+ * <a_sha> c6
50
+ * <a_sha> c5 five - fifth commit
51
+ * <a_sha> *** let's do it
52
+ |\
53
+ | * 6fddd9c c4 not the third commit
54
+ | * bab916a c3 the third commit
55
+ | * 7355c79 c2 the second commit
56
+ |/
57
+ * 91182df c1
58
+ """
@@ -0,0 +1,98 @@
1
+ Feature: playing in the sanbox
2
+ As a developer
3
+ In order to test `gitloop` thoroughly
4
+ I want to Install in tmp/sandbox different prepared git repositories
5
+ that cover all the possible combinations of staged/unstanged
6
+ files
7
+
8
+
9
+ Background:
10
+ * I cleared the sandbox directory
11
+ * a directory named "sandbox" should not exist
12
+
13
+
14
+ #############################
15
+ # Test the git status output :
16
+ #############################
17
+
18
+ Scenario: checking the clean sandbox
19
+
20
+ Given I unzip the clean git repo in the sandbox
21
+ * I cd to "sandbox"
22
+ Then the git status is empty
23
+
24
+
25
+ Scenario: checking the sandbox with some unstaged changes
26
+
27
+ Given I unzip the git repo with unstaged changes in the sandbox
28
+ * I cd to "sandbox"
29
+ Then the git status is:
30
+ """
31
+ M f1
32
+ ?? unstaged-new-file
33
+ """
34
+
35
+ Scenario: checking the sandbox with some staged changes
36
+
37
+ Given I unzip the git repo with staged changes in the sandbox
38
+ * I cd to "sandbox"
39
+ Then the git status is:
40
+ """
41
+ M f1
42
+ A unstaged-new-file
43
+ """
44
+
45
+
46
+
47
+ #############################
48
+ # Test the git log graph output :
49
+ #############################
50
+
51
+ Scenario Outline: the sandbox is initialized by unzipping a model git repository
52
+
53
+ Given I unzip the <repository> in the sandbox
54
+ * I cd to "sandbox"
55
+
56
+ Then the repo is in its original state
57
+ Then HEAD starts with edadbb7
58
+ * the current branch is "master"
59
+ * there are <outcome>
60
+
61
+ Examples:
62
+ | repository | outcome |
63
+ | clean git repo | no unstaged nor staged changes |
64
+
65
+
66
+
67
+ Scenario Outline: the sandbox is initialized by unzipping a model git repository
68
+
69
+ Given I unzip the <repository> in the sandbox
70
+ * I cd to "sandbox"
71
+
72
+ Then the git log graph is:
73
+ """
74
+ * a059392 c6
75
+ * e917b56 c5
76
+ * 933c4d1 c4
77
+ * 4d72f8a c3
78
+ * 8aab2de c2
79
+ * 91182df c1
80
+ """
81
+ Then the git log graph matches:
82
+ """
83
+ * a059392 c6
84
+ * <a_sha> c5
85
+ * 933c4d1 c4
86
+ * <a_sha> c3
87
+ * 8aab2de c2
88
+ * <a_sha> c1
89
+ """
90
+ Then HEAD starts with a059392
91
+ * the current branch is "master"
92
+ * there are <outcome>
93
+
94
+ Examples:
95
+ | repository | outcome |
96
+ | git repo with unstaged changes | untracked or uncommited changes|
97
+ | git repo with staged changes | untracked or uncommited changes|
98
+
@@ -0,0 +1,14 @@
1
+ Feature: My bootstrapped app kinda works
2
+ In order to get going on coding my awesome app
3
+ I want to have aruba and cucumber setup
4
+ So I don't have to do it myself
5
+
6
+ Scenario: App just runs
7
+ When I get help for "git-loop"
8
+ Then the exit status should be 0
9
+ And the banner should document that this app's arguments are:
10
+ |message|which is not optional|
11
+ And the output should contain:
12
+ """
13
+ Usage: git loop <from_ref> <to_ref> -m "<message>"
14
+ """
@@ -0,0 +1,21 @@
1
+
2
+ # Setup :
3
+ #########
4
+
5
+
6
+
7
+ # Test :
8
+ #########
9
+
10
+ Then 'the git status is empty' do
11
+ untracked_or_uncommited_changes.chomp.should be_empty
12
+ end
13
+
14
+ Then 'the git status is:' do |text|
15
+ untracked_or_uncommited_changes.chomp.should == text
16
+ end
17
+
18
+
19
+ Then 'the current branch is "$branch"' do |branch|
20
+ the_current_branch.should == "* #{branch}"
21
+ end
@@ -0,0 +1,49 @@
1
+ # -----------
2
+ # Setup :
3
+ # -----------
4
+
5
+
6
+ # -----------
7
+ # Tests :
8
+ # -----------
9
+
10
+
11
+ # Usage :
12
+ # Then HEAD starts with a059392
13
+
14
+ Then 'HEAD starts with $sha_start' do |sha_start|
15
+ in_current_dir do
16
+ `git rev-parse HEAD`.should match(/^#{sha_start}/)
17
+ end
18
+ end
19
+
20
+
21
+ # Usage :
22
+ # Then the git log graph is:
23
+ # """
24
+ # * 4d72f8a c3
25
+ # * 8aab2de c2
26
+ # * 91182df c1
27
+ # """
28
+
29
+ Then 'the git log graph is:' do |expected_output|
30
+ record_time_taken("git-log-graph-IS") do
31
+ the_git_log_graph.should == expected_output
32
+ end
33
+
34
+ end
35
+
36
+
37
+ # Usage :
38
+ # Then the git log graph matches:
39
+ # """
40
+ # * <a_sha> c3
41
+ # * 8aab2de c2
42
+ # * 91182df c1
43
+ # """
44
+
45
+ Then 'the git log graph matches:' do |raw_expected_output|
46
+ record_time_taken("git-log-graph-matches") do
47
+ the_git_log_graph.should match(make_smart_regexp(raw_expected_output))
48
+ end
49
+ end
@@ -0,0 +1,63 @@
1
+
2
+ # Setup :
3
+ #########
4
+
5
+ Given /^I cleared the sandbox directory$/ do
6
+ in_current_dir do
7
+ FileUtils.rm_rf("sandbox")
8
+ end
9
+ end
10
+
11
+ SANDBOX_PATH = {
12
+ :default => FIXTURES_PATH + '/sandbox.zip',
13
+ :staged => FIXTURES_PATH + '/sandbox-with-staged-changes.zip',
14
+ :unstaged => FIXTURES_PATH + '/sandbox-with-unstaged-changes.zip'
15
+ }
16
+
17
+ Given /^the sandbox is setup$/ do
18
+ step %Q{I cleared the sandbox directory}
19
+ step %Q{I unzip the clean git repo in the sandbox}
20
+ end
21
+
22
+
23
+ Given /^I unzip the (.*) in the sandbox$/ do |repository|
24
+ path = case repository
25
+ when 'clean git repo' then SANDBOX_PATH[:default ]
26
+ when 'git repo with staged changes' then SANDBOX_PATH[:staged ]
27
+ when 'git repo with unstaged changes' then SANDBOX_PATH[:unstaged]
28
+ else raise "NOT SUPPORTED repository : #{repository.inspect}"
29
+ end
30
+ record_time_taken("unzip") do
31
+ in_current_dir do `unzip #{path}` end # 0.5 seconds
32
+ #step %(I successfully run `unzip #{path}`) # 2.3 seconds
33
+ end
34
+ end
35
+
36
+
37
+ # Test :
38
+ #########
39
+
40
+ Then /^there are (.*)$/ do |outcome|
41
+ case outcome
42
+ when 'no unstaged nor staged changes'
43
+ untracked_or_uncommited_changes.should be_empty
44
+ when 'untracked or uncommited changes'
45
+ untracked_or_uncommited_changes.should_not be_empty
46
+ else
47
+ raise "BUG : unsupported outcome #{outcome}"
48
+ end
49
+ end
50
+
51
+
52
+ CLEAN_REPO_LOG =<<TEXT.chomp
53
+ * edadbb7 c6
54
+ * da55377 c5 five - fifth commit
55
+ * 6fddd9c c4 not the third commit
56
+ * bab916a c3 the third commit
57
+ * 7355c79 c2 the second commit
58
+ * 91182df c1
59
+ TEXT
60
+
61
+ Then /^the (?:clean repo|repo) is in its original state$/ do
62
+ the_git_log_graph.should == CLEAN_REPO_LOG
63
+ end
@@ -0,0 +1,24 @@
1
+ $timers={}
2
+
3
+
4
+ def record_time_taken(category)
5
+ category = category.to_sym
6
+ $timers[category] ||= [0,0]
7
+ start = Time.now
8
+ res = yield
9
+ time, count = $timers[category]
10
+ $timers[category] = [time + (Time.now - start), count+1]
11
+ res
12
+ end
13
+
14
+ at_exit do
15
+ puts "-"*80
16
+ keylength = $timers.keys.collect(&:length).max
17
+ puts "**** total || secs/run || runs"
18
+ puts "-"*66
19
+ $timers.keys.each do |key|
20
+ time, count = $timers[key]
21
+ #puts "**** %{key} : total = %{time} sec. || %{count} secs/run || %{loop_time} runs" % {:key => key, :time => time, :count => count, :loop_time => (time/count)}
22
+ puts "**** %#{keylength+1}s : %#7.2f sec. || %7.3f sec. || %3d runs" % [key, time, (time/count), count]
23
+ end
24
+ end
@@ -0,0 +1,20 @@
1
+ require 'aruba/cucumber'
2
+ require 'methadone/cucumber'
3
+
4
+ ENV['PATH'] = "#{File.expand_path(File.dirname(__FILE__) + '/../../bin')}#{File::PATH_SEPARATOR}#{ENV['PATH']}"
5
+ LIB_DIR = File.join(File.expand_path(File.dirname(__FILE__)),'..','..','lib')
6
+ require LIB_DIR + '/gitloop'
7
+
8
+ FIXTURES_PATH = File.join(File.expand_path(File.dirname(__FILE__)),'fixtures')
9
+
10
+ Before do
11
+ # Using "announce" causes massive warnings on 1.9.2
12
+ @puts = true
13
+ @original_rubylib = ENV['RUBYLIB']
14
+ ENV['RUBYLIB'] = LIB_DIR + File::PATH_SEPARATOR + ENV['RUBYLIB'].to_s
15
+ end
16
+
17
+ After do
18
+ ENV['RUBYLIB'] = @original_rubylib
19
+ FileUtils.rm_rf File.join(File.dirname(__FILE__), '../../tmp/aruba')
20
+ end
@@ -0,0 +1,21 @@
1
+ def the_current_branch
2
+ in_current_dir do
3
+ `git branch | grep "*"`.chomp
4
+ end
5
+ end
6
+
7
+
8
+ GIT_LOG_GRAPH_COMMAND = "git log --oneline --graph"
9
+
10
+ def the_git_log_graph
11
+ step %Q{I run `#{GIT_LOG_GRAPH_COMMAND}`} # runs the actual process
12
+ output_from(GIT_LOG_GRAPH_COMMAND).chomp # only accesses the previous processes outputs
13
+ end
14
+
15
+
16
+ def untracked_or_uncommited_changes
17
+ in_current_dir do
18
+ `git status -s`
19
+ end
20
+ end
21
+
@@ -0,0 +1,23 @@
1
+
2
+ # turn the feature multiline "enhanced" text into a regexp
3
+
4
+ def make_smart_regexp(raw_expected_output)
5
+ Regexp.compile escape_xxl(raw_expected_output),
6
+ Regexp::MULTILINE
7
+ end
8
+
9
+
10
+ # turn the feature multiline "enhanced" text into a valid regexp-ready string.
11
+ # It
12
+ # - escapes the string
13
+ # - translate <a_sha> -> (\S+)
14
+ # - replace \n by \s+ because of a problem with multiline strings in Cucumber
15
+
16
+ def escape_xxl(raw_text)
17
+ Regexp.escape(raw_text).tap do |text|
18
+ text.gsub!('\n', "\\s*") # necessary (? due to Cucumber ??)
19
+ text.gsub!(/<a_sha>/, '(\S+)')
20
+ end
21
+ end
22
+
23
+
data/lib/gitloop.rb ADDED
@@ -0,0 +1,8 @@
1
+ module Gitloop
2
+
3
+ class GitError < Exception; end
4
+
5
+ end
6
+
7
+ require File.dirname(__FILE__) + "/gitloop/version"
8
+ require File.dirname(__FILE__) + "/gitloop/looper"
@@ -0,0 +1,33 @@
1
+ module Gitloop
2
+
3
+ module GitUtils
4
+
5
+ def current_branch
6
+ branch = `git branch | grep "*"`
7
+ branch.empty? ?
8
+ nil :
9
+ branch[2..-2] # remove the current branch marker : '* '
10
+ end
11
+
12
+
13
+ def invalid_commits_sequence?(first_sha, second_sha)
14
+ output = (first_sha == second_sha) ?
15
+ call_git("show #{first_sha}") :
16
+ call_git("show #{first_sha}..#{second_sha}")
17
+ error = !output.start_with?('commit')
18
+ end
19
+
20
+ def valid_commits_reference?(reference)
21
+ call_git("show #{reference}").start_with?('commit')
22
+ rescue Gitloop::GitError
23
+ false
24
+ end
25
+
26
+
27
+ def shas_for_messages_that_match(from_grep)
28
+ onelines = (`git log --oneline --grep "#{from_grep}"`).split("\n")
29
+ shas = onelines.collect { |l| l[/\w+/] }
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,59 @@
1
+ require 'open3'
2
+ require File.dirname(__FILE__) + '/git_utils'
3
+
4
+ module Gitloop
5
+
6
+ class Looper
7
+ extend GitUtils
8
+
9
+ def self.make_loop_for_references_or_messages(from, to, message=nil)
10
+ from_ref, to_ref = convert_messages_to_git_refs(from, to)
11
+ validate_commits_refs_sequence! from_ref, to_ref
12
+
13
+ build_the_loop(from_ref, message, to_ref)
14
+
15
+ loop_starts_at_very_first_commit = !valid_commits_reference?("#{from_ref}^^")
16
+ puts loop_starts_at_very_first_commit ?
17
+ call_git("log --oneline --graph --color --decorate") :
18
+ call_git("log --oneline --graph --color --decorate #{from_ref}^^..HEAD")
19
+ end
20
+
21
+ private
22
+
23
+ def self.build_the_loop(from_ref, message, to_ref)
24
+ curr_branch = current_branch()
25
+
26
+ call_git "co #{from_ref}^ --quiet"
27
+
28
+ msg = message || "loop #{from_ref}..#{to_ref}"
29
+ call_git "merge --no-ff #{to_ref} -m \"*** #{msg}\""
30
+
31
+ merge_top = call_git "rev-parse HEAD"
32
+ call_git "co --quiet #{curr_branch}"
33
+ call_git "rebase #{merge_top}"
34
+ end
35
+
36
+ def self.convert_messages_to_git_refs(from, to)
37
+ from_ref = valid_commits_reference?(from) ? from : shas_for_messages_that_match(from).last
38
+ to_ref = valid_commits_reference?(to ) ? to : shas_for_messages_that_match(to ).last
39
+ [from_ref, to_ref]
40
+ end
41
+
42
+ def self.call_git(command, error_message_prefix=nil)
43
+ output, error, status = Open3.capture3("git #{command}")
44
+ if error.empty?
45
+ output
46
+ else
47
+ raise Gitloop::GitError.new [error_message_prefix,error].compact.join("\n")
48
+ end
49
+ end
50
+
51
+ def self.validate_commits_refs_sequence!(first_sha, second_sha)
52
+ if invalid_commits_sequence?(first_sha, second_sha)
53
+ error_msg = "#{first_sha}..#{second_sha} is an invalid SHAs sequence"
54
+ raise Gitloop::GitError.new(error_msg)
55
+ end
56
+ end
57
+
58
+ end
59
+ end
@@ -0,0 +1,3 @@
1
+ module Gitloop
2
+ VERSION = "0.0.3"
3
+ end
metadata ADDED
@@ -0,0 +1,161 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gitloop
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Alain Ravet
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-02-21 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: methadone
16
+ requirement: &70328618475780 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70328618475780
25
+ - !ruby/object:Gem::Dependency
26
+ name: rdoc
27
+ requirement: &70328618473840 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70328618473840
36
+ - !ruby/object:Gem::Dependency
37
+ name: aruba
38
+ requirement: &70328618471420 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70328618471420
47
+ - !ruby/object:Gem::Dependency
48
+ name: rake
49
+ requirement: &70328618469200 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 0.9.2
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70328618469200
58
+ - !ruby/object:Gem::Dependency
59
+ name: guard-cucumber
60
+ requirement: &70328618466840 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *70328618466840
69
+ - !ruby/object:Gem::Dependency
70
+ name: ruby_gntp
71
+ requirement: &70328618453460 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *70328618453460
80
+ description: easily merge and rebase flat git history
81
+ email:
82
+ - alainravet@gmail.com
83
+ executables:
84
+ - git-loop
85
+ - gitloop
86
+ extensions: []
87
+ extra_rdoc_files: []
88
+ files:
89
+ - bin/git-loop
90
+ - bin/gitloop
91
+ - lib/gitloop/git_utils.rb
92
+ - lib/gitloop/looper.rb
93
+ - lib/gitloop/version.rb
94
+ - lib/gitloop.rb
95
+ - doc/AFTER.png
96
+ - doc/BEFORE.png
97
+ - doc/dev_notes.txt
98
+ - doc/TODO.txt
99
+ - LICENSE
100
+ - README.markdown
101
+ - Gemfile
102
+ - Gemfile.lock
103
+ - features/errors.feature
104
+ - features/happy_path.feature
105
+ - features/sandbox.feature
106
+ - features/shell_command.feature
107
+ - features/step_definitions/git_steps.rb
108
+ - features/step_definitions/gitloop_steps.rb
109
+ - features/step_definitions/sandbox_steps.rb
110
+ - features/support/benchmarking.rb
111
+ - features/support/env.rb
112
+ - features/support/fixtures/sandbox-with-staged-changes.zip
113
+ - features/support/fixtures/sandbox-with-unstaged-changes.zip
114
+ - features/support/fixtures/sandbox.zip
115
+ - features/support/git.rb
116
+ - features/support/regexp.rb
117
+ homepage: ''
118
+ licenses: []
119
+ post_install_message:
120
+ rdoc_options: []
121
+ require_paths:
122
+ - lib
123
+ required_ruby_version: !ruby/object:Gem::Requirement
124
+ none: false
125
+ requirements:
126
+ - - ! '>='
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ segments:
130
+ - 0
131
+ hash: -412658776607306167
132
+ required_rubygems_version: !ruby/object:Gem::Requirement
133
+ none: false
134
+ requirements:
135
+ - - ! '>='
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ segments:
139
+ - 0
140
+ hash: -412658776607306167
141
+ requirements: []
142
+ rubyforge_project: gitloop
143
+ rubygems_version: 1.8.15
144
+ signing_key:
145
+ specification_version: 3
146
+ summary: easily merge and rebase flat git history
147
+ test_files:
148
+ - features/errors.feature
149
+ - features/happy_path.feature
150
+ - features/sandbox.feature
151
+ - features/shell_command.feature
152
+ - features/step_definitions/git_steps.rb
153
+ - features/step_definitions/gitloop_steps.rb
154
+ - features/step_definitions/sandbox_steps.rb
155
+ - features/support/benchmarking.rb
156
+ - features/support/env.rb
157
+ - features/support/fixtures/sandbox-with-staged-changes.zip
158
+ - features/support/fixtures/sandbox-with-unstaged-changes.zip
159
+ - features/support/fixtures/sandbox.zip
160
+ - features/support/git.rb
161
+ - features/support/regexp.rb