git-smart 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -7,4 +7,5 @@ group :development do
7
7
  gem "rcov", ">= 0"
8
8
  gem "bundler", "~> 1.0.0"
9
9
  gem "jeweler", "~> 1.5.2"
10
+ gem "rocco"
10
11
  end
data/Gemfile.lock CHANGED
@@ -8,8 +8,13 @@ GEM
8
8
  bundler (~> 1.0.0)
9
9
  git (>= 1.2.5)
10
10
  rake
11
+ mustache (0.12.0)
11
12
  rake (0.8.7)
12
13
  rcov (0.9.8)
14
+ rdiscount (1.6.5)
15
+ rocco (0.5)
16
+ mustache
17
+ rdiscount
13
18
  rspec (2.3.0)
14
19
  rspec-core (~> 2.3.0)
15
20
  rspec-expectations (~> 2.3.0)
@@ -27,4 +32,5 @@ DEPENDENCIES
27
32
  colorize
28
33
  jeweler (~> 1.5.2)
29
34
  rcov
35
+ rocco
30
36
  rspec (~> 2.3.0)
data/README.md CHANGED
@@ -1,11 +1,13 @@
1
1
  # git-smart
2
2
 
3
+ ![git-smart logo](https://github.com/geelen/git-smart/raw/master/docs/images/git-smart.png)
4
+
3
5
  Adds some additional git commands to add some smarts to your workflow. These commands follow a few guidelines:
4
6
 
5
7
  0. It should do the 'right thing' in all situations - an inexperienced git user should be guided away from making simple mistakes.
6
8
  0. It should make every attempt to explain to the user what decisions it has made, and why.
7
9
  0. All git commands that modify the repository should be shown to the user - hopefully this helps the user eventually learn the underlying git commands, and when they're relevant.
8
- 0. All git commands, destructive or not, and their output should be shown to the user with the -v/--verbose flag.
10
+ 0. All git commands, destructive or not, and their output should be shown to the user with the -v/--verbose flag. (not implemented yet)
9
11
 
10
12
  # Installing
11
13
 
@@ -20,7 +22,7 @@ List the commands you can install (currently only the one):
20
22
  Install away!
21
23
 
22
24
  git-smart install smart-pull
23
-
25
+
24
26
  OR
25
27
 
26
28
  git-smart install --all
@@ -29,29 +31,17 @@ That'll put an executable file for each command in your ~/bin directory if that
29
31
 
30
32
  # Using
31
33
 
32
- Git allows custom commands with a simple convention - `git xyz` tries to find an executable `git-xyz` on the path. So, to run the smart-pull command, simply run:
34
+ Git allows custom commands with a simple convention - `git xyz` tries to find an executable `git-xyz` on the path. So, to run the commands, simply type
33
35
 
34
36
  git smart-pull
37
+ git smart-merge <branchname>
35
38
 
36
- ## git-smart-pull
37
-
38
- Calling 'git smart-pull' will fetch remote tracked changes and reapply your work on top of it. It's like a much, much smarter version of 'git pull --rebase'.
39
-
40
- For some background as to why this is needed, see [my blog post about the perils of rebasing merge commits](https://gist.github.com/591209)
39
+ # Documentation
41
40
 
42
- This is how it works:
41
+ The code for each of these commands has been annotated with comments and rendered with [Rocco](https://github.com/rtomayko/rocco):
43
42
 
44
- 0. First, determine which remote branch to update from. Use branch tracking config if present, otherwise default to a remote of 'origin' and the same branch name. E.g. 'branchX', by default, tracks 'origin/branchX'.
45
- 0. Fetch the remote.
46
- 0. Determine what needs to be done:
47
- - If the remote is a parent of HEAD, there's nothing to do.
48
- - If HEAD is a parent of the remote, you simply need to reapply any working changes to the new HEAD. Stash, fast-forward, stash pop.
49
- - If HEAD and the remote have diverged:
50
- 0. stash
51
- 0. rebase -p onto the remote
52
- 0. stash pop
53
- 0. update ORIG\_HEAD to be the previous local HEAD, as expected (rebase -p doesn't set ORIG\_HEAD correctly)
54
- 0. Output a big green or red message so, at a glance, you know if things worked or not.
43
+ - [smart-pull](http://github-displayer.heroku.com/geelen/git-smart/raw/master/docs/smart-pull.html)
44
+ - [smart-merge](http://github-displayer.heroku.com/geelen/git-smart/raw/master/docs/smart-merge.html)
55
45
 
56
46
  # Contributing to git-smart
57
47
 
data/Rakefile CHANGED
@@ -44,3 +44,10 @@ Rake::RDocTask.new do |rdoc|
44
44
  rdoc.rdoc_files.include('README*')
45
45
  rdoc.rdoc_files.include('lib/**/*.rb')
46
46
  end
47
+
48
+ desc "Generate the rocco docs"
49
+ task :rocco do
50
+ %x[cd lib/commands && rocco *.rb -o ../../docs]
51
+ end
52
+
53
+ task :release => :rocco
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.3
1
+ 0.1.4
Binary file
@@ -0,0 +1,211 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta http-equiv="content-type" content="text/html;charset=utf-8">
5
+ <title>smart-merge.rb</title>
6
+ <link rel="stylesheet" href="http://jashkenas.github.com/docco/resources/docco.css">
7
+ </head>
8
+ <body>
9
+ <div id='container'>
10
+ <div id="background"></div>
11
+ <div id="jump_to">
12
+ Jump To &hellip;
13
+ <div id="jump_wrapper">
14
+ <div id="jump_page">
15
+ <a class="source" href="smart-merge.html">smart-merge.rb</a>
16
+ <a class="source" href="smart-pull.html">smart-pull.rb</a>
17
+ </div>
18
+ </div>
19
+ </div>
20
+ <table cellspacing=0 cellpadding=0>
21
+ <thead>
22
+ <tr>
23
+ <th class=docs><h1>smart-merge.rb</h1></th>
24
+ <th class=code></th>
25
+ </tr>
26
+ </thead>
27
+ <tbody>
28
+ <tr id='section-1'>
29
+ <td class=docs>
30
+ <div class="octowrap">
31
+ <a class="octothorpe" href="#section-1">#</a>
32
+ </div>
33
+ <p>Calling <code>git smart-merge branchname</code> will, quite simply, perform a
34
+ non-fast-forward merge wrapped in a stash push/pop, if that&rsquo;s required.
35
+ With some helpful extra output.</p>
36
+ </td>
37
+ <td class=code>
38
+ <div class='highlight'><pre><span class="no">GitSmart</span><span class="o">.</span><span class="n">register</span> <span class="s1">&#39;smart-merge&#39;</span> <span class="k">do</span> <span class="o">|</span><span class="n">repo</span><span class="p">,</span> <span class="n">args</span><span class="o">|</span></pre></div>
39
+ </td>
40
+ </tr>
41
+ <tr id='section-2'>
42
+ <td class=docs>
43
+ <div class="octowrap">
44
+ <a class="octothorpe" href="#section-2">#</a>
45
+ </div>
46
+ <p>Let&rsquo;s begin!</p>
47
+ </td>
48
+ <td class=code>
49
+ <div class='highlight'><pre> <span class="n">current_branch</span> <span class="o">=</span> <span class="n">repo</span><span class="o">.</span><span class="n">current_branch</span>
50
+ <span class="n">start</span> <span class="s2">&quot;Starting: smart-merge on branch &#39;</span><span class="si">#{</span><span class="n">current_branch</span><span class="si">}</span><span class="s2">&#39;&quot;</span></pre></div>
51
+ </td>
52
+ </tr>
53
+ <tr id='section-3'>
54
+ <td class=docs>
55
+ <div class="octowrap">
56
+ <a class="octothorpe" href="#section-3">#</a>
57
+ </div>
58
+ <p>Grab the merge_target the user specified</p>
59
+ </td>
60
+ <td class=code>
61
+ <div class='highlight'><pre> <span class="n">merge_target</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">shift</span>
62
+ <span class="n">failure</span> <span class="s2">&quot;Usage: git smart-merge ref&quot;</span> <span class="k">if</span> <span class="o">!</span><span class="n">merge_target</span></pre></div>
63
+ </td>
64
+ </tr>
65
+ <tr id='section-4'>
66
+ <td class=docs>
67
+ <div class="octowrap">
68
+ <a class="octothorpe" href="#section-4">#</a>
69
+ </div>
70
+ <p>Make sure git can resolve the reference to the merge_target</p>
71
+ </td>
72
+ <td class=code>
73
+ <div class='highlight'><pre> <span class="n">merge_sha</span> <span class="o">=</span> <span class="n">repo</span><span class="o">.</span><span class="n">sha</span><span class="p">(</span><span class="n">merge_target</span><span class="p">)</span>
74
+ <span class="n">failure</span> <span class="s2">&quot;Branch to merge &#39;</span><span class="si">#{</span><span class="n">merge_target</span><span class="si">}</span><span class="s2">&#39; not recognised by git!&quot;</span> <span class="k">if</span> <span class="o">!</span><span class="n">merge_sha</span></pre></div>
75
+ </td>
76
+ </tr>
77
+ <tr id='section-5'>
78
+ <td class=docs>
79
+ <div class="octowrap">
80
+ <a class="octothorpe" href="#section-5">#</a>
81
+ </div>
82
+ <p>If the SHA of HEAD and the merge_target are the same, we&rsquo;re trying to merge
83
+ the same commit with itself. Which is madness!</p>
84
+ </td>
85
+ <td class=code>
86
+ <div class='highlight'><pre> <span class="n">head</span> <span class="o">=</span> <span class="n">repo</span><span class="o">.</span><span class="n">sha</span><span class="p">(</span><span class="s1">&#39;HEAD&#39;</span><span class="p">)</span>
87
+ <span class="k">if</span> <span class="n">merge_sha</span> <span class="o">==</span> <span class="n">head</span>
88
+ <span class="n">note</span> <span class="s2">&quot;Branch &#39;</span><span class="si">#{</span><span class="n">merge_target</span><span class="si">}</span><span class="s2">&#39; has no new commits. Nothing to merge in.&quot;</span>
89
+ <span class="n">success</span> <span class="s1">&#39;Already up-to-date.&#39;</span>
90
+ <span class="k">else</span></pre></div>
91
+ </td>
92
+ </tr>
93
+ <tr id='section-6'>
94
+ <td class=docs>
95
+ <div class="octowrap">
96
+ <a class="octothorpe" href="#section-6">#</a>
97
+ </div>
98
+ <p>Determine the merge-base of the two commits, so we can report some useful output
99
+ about how many new commits have been added.</p>
100
+ </td>
101
+ <td class=code>
102
+ <div class='highlight'><pre> <span class="n">merge_base</span> <span class="o">=</span> <span class="n">repo</span><span class="o">.</span><span class="n">merge_base</span><span class="p">(</span><span class="n">head</span><span class="p">,</span> <span class="n">merge_sha</span><span class="p">)</span></pre></div>
103
+ </td>
104
+ </tr>
105
+ <tr id='section-7'>
106
+ <td class=docs>
107
+ <div class="octowrap">
108
+ <a class="octothorpe" href="#section-7">#</a>
109
+ </div>
110
+ <p>Report the number of commits on merge_target we&rsquo;re about to merge in.</p>
111
+ </td>
112
+ <td class=code>
113
+ <div class='highlight'><pre> <span class="n">new_commits_on_merge_target</span> <span class="o">=</span> <span class="n">repo</span><span class="o">.</span><span class="n">rev_list</span><span class="p">(</span><span class="n">merge_base</span><span class="p">,</span> <span class="n">merge_target</span><span class="p">)</span>
114
+ <span class="nb">puts</span> <span class="s2">&quot;Branch &#39;</span><span class="si">#{</span><span class="n">merge_target</span><span class="si">}</span><span class="s2">&#39; has diverged by </span><span class="si">#{</span><span class="n">new_commits_on_merge_target</span><span class="o">.</span><span class="n">length</span><span class="si">}</span><span class="s2"> commit</span><span class="si">#{</span><span class="s1">&#39;s&#39;</span> <span class="k">if</span> <span class="n">new_commits_on_merge_target</span><span class="o">.</span><span class="n">length</span> <span class="o">!=</span> <span class="mi">1</span><span class="si">}</span><span class="s2">. Merging in.&quot;</span></pre></div>
115
+ </td>
116
+ </tr>
117
+ <tr id='section-8'>
118
+ <td class=docs>
119
+ <div class="octowrap">
120
+ <a class="octothorpe" href="#section-8">#</a>
121
+ </div>
122
+ <p>Determine if our branch has moved on.</p>
123
+ </td>
124
+ <td class=code>
125
+ <div class='highlight'><pre> <span class="k">if</span> <span class="n">head</span> <span class="o">==</span> <span class="n">merge_base</span></pre></div>
126
+ </td>
127
+ </tr>
128
+ <tr id='section-9'>
129
+ <td class=docs>
130
+ <div class="octowrap">
131
+ <a class="octothorpe" href="#section-9">#</a>
132
+ </div>
133
+ <p>Note: Even though we <em>can</em> fast-forward here, it&rsquo;s a really bad idea since
134
+ it results in the disappearance of the branch in history. For a good discussion
135
+ on this topic, see this <a href="http://stackoverflow.com/questions/2850369/why-uses-git-fast-forward-merging-per-default">StackOverflow question</a>.</p>
136
+ </td>
137
+ <td class=code>
138
+ <div class='highlight'><pre> <span class="n">note</span> <span class="s2">&quot;Branch &#39;</span><span class="si">#{</span><span class="n">current_branch</span><span class="si">}</span><span class="s2">&#39; has not moved on since &#39;</span><span class="si">#{</span><span class="n">merge_target</span><span class="si">}</span><span class="s2">&#39; diverged. Running with --no-ff anyway, since a fast-forward is unexpected behaviour.&quot;</span>
139
+ <span class="k">else</span></pre></div>
140
+ </td>
141
+ </tr>
142
+ <tr id='section-10'>
143
+ <td class=docs>
144
+ <div class="octowrap">
145
+ <a class="octothorpe" href="#section-10">#</a>
146
+ </div>
147
+ <p>Report how many commits on our branch since merge_target diverged.</p>
148
+ </td>
149
+ <td class=code>
150
+ <div class='highlight'><pre> <span class="n">new_commits_on_branch</span> <span class="o">=</span> <span class="n">repo</span><span class="o">.</span><span class="n">rev_list</span><span class="p">(</span><span class="n">merge_base</span><span class="p">,</span> <span class="n">head</span><span class="p">)</span>
151
+ <span class="nb">puts</span> <span class="s2">&quot;Branch &#39;</span><span class="si">#{</span><span class="n">current_branch</span><span class="si">}</span><span class="s2">&#39; has </span><span class="si">#{</span><span class="n">new_commits_on_branch</span><span class="o">.</span><span class="n">length</span><span class="si">}</span><span class="s2"> new commit</span><span class="si">#{</span><span class="s1">&#39;s&#39;</span> <span class="k">if</span> <span class="n">new_commits_on_merge_target</span><span class="o">.</span><span class="n">length</span> <span class="o">!=</span> <span class="mi">1</span><span class="si">}</span><span class="s2"> since &#39;</span><span class="si">#{</span><span class="n">merge_target</span><span class="si">}</span><span class="s2">&#39; diverged.&quot;</span>
152
+ <span class="k">end</span></pre></div>
153
+ </td>
154
+ </tr>
155
+ <tr id='section-11'>
156
+ <td class=docs>
157
+ <div class="octowrap">
158
+ <a class="octothorpe" href="#section-11">#</a>
159
+ </div>
160
+ <p>Before we merge, detect if there are local changes and stash them.</p>
161
+ </td>
162
+ <td class=code>
163
+ <div class='highlight'><pre> <span class="n">stash_required</span> <span class="o">=</span> <span class="n">repo</span><span class="o">.</span><span class="n">dirty?</span>
164
+ <span class="k">if</span> <span class="n">stash_required</span>
165
+ <span class="n">note</span> <span class="s2">&quot;Working directory dirty. Stashing...&quot;</span>
166
+ <span class="n">repo</span><span class="o">.</span><span class="n">stash!</span>
167
+ <span class="k">end</span></pre></div>
168
+ </td>
169
+ </tr>
170
+ <tr id='section-12'>
171
+ <td class=docs>
172
+ <div class="octowrap">
173
+ <a class="octothorpe" href="#section-12">#</a>
174
+ </div>
175
+ <p>Perform the merge, using &mdash;no-ff.</p>
176
+ </td>
177
+ <td class=code>
178
+ <div class='highlight'><pre> <span class="n">repo</span><span class="o">.</span><span class="n">merge_no_ff!</span><span class="p">(</span><span class="n">merge_target</span><span class="p">)</span></pre></div>
179
+ </td>
180
+ </tr>
181
+ <tr id='section-13'>
182
+ <td class=docs>
183
+ <div class="octowrap">
184
+ <a class="octothorpe" href="#section-13">#</a>
185
+ </div>
186
+ <p>If we stashed before, pop now.</p>
187
+ </td>
188
+ <td class=code>
189
+ <div class='highlight'><pre> <span class="k">if</span> <span class="n">stash_required</span>
190
+ <span class="n">note</span> <span class="s2">&quot;Reapplying local changes...&quot;</span>
191
+ <span class="n">repo</span><span class="o">.</span><span class="n">stash_pop!</span>
192
+ <span class="k">end</span></pre></div>
193
+ </td>
194
+ </tr>
195
+ <tr id='section-14'>
196
+ <td class=docs>
197
+ <div class="octowrap">
198
+ <a class="octothorpe" href="#section-14">#</a>
199
+ </div>
200
+ <p>Display a nice completion message in large, friendly letters.</p>
201
+
202
+ </td>
203
+ <td class=code>
204
+ <div class='highlight'><pre> <span class="n">success</span> <span class="s2">&quot;All good. Created merge commit </span><span class="si">#{</span><span class="n">repo</span><span class="o">.</span><span class="n">sha</span><span class="p">(</span><span class="s1">&#39;HEAD&#39;</span><span class="p">)</span><span class="o">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">7</span><span class="o">]</span><span class="si">}</span><span class="s2">.&quot;</span>
205
+ <span class="k">end</span>
206
+ <span class="k">end</span></pre></div>
207
+ </td>
208
+ </tr>
209
+ </table>
210
+ </div>
211
+ </body>
@@ -0,0 +1,274 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta http-equiv="content-type" content="text/html;charset=utf-8">
5
+ <title>smart-pull.rb</title>
6
+ <link rel="stylesheet" href="http://jashkenas.github.com/docco/resources/docco.css">
7
+ </head>
8
+ <body>
9
+ <div id='container'>
10
+ <div id="background"></div>
11
+ <div id="jump_to">
12
+ Jump To &hellip;
13
+ <div id="jump_wrapper">
14
+ <div id="jump_page">
15
+ <a class="source" href="smart-merge.html">smart-merge.rb</a>
16
+ <a class="source" href="smart-pull.html">smart-pull.rb</a>
17
+ </div>
18
+ </div>
19
+ </div>
20
+ <table cellspacing=0 cellpadding=0>
21
+ <thead>
22
+ <tr>
23
+ <th class=docs><h1>smart-pull.rb</h1></th>
24
+ <th class=code></th>
25
+ </tr>
26
+ </thead>
27
+ <tbody>
28
+ <tr id='section-1'>
29
+ <td class=docs>
30
+ <div class="octowrap">
31
+ <a class="octothorpe" href="#section-1">#</a>
32
+ </div>
33
+ <p>Calling <code>git smart-pull</code> will fetch remote tracked changes
34
+ and reapply your work on top of it. It&rsquo;s like a much, much
35
+ smarter version of <code>git pull --rebase</code>.</p>
36
+
37
+ <p>For some background as to why this is needed, see <a href="https://gist.github.com/591209">my blog
38
+ post about the perils of rebasing merge commits</a></p>
39
+
40
+ <p>This is how it works:</p>
41
+ </td>
42
+ <td class=code>
43
+ <div class='highlight'><pre><span class="no">GitSmart</span><span class="o">.</span><span class="n">register</span> <span class="s1">&#39;smart-pull&#39;</span> <span class="k">do</span> <span class="o">|</span><span class="n">repo</span><span class="p">,</span> <span class="n">args</span><span class="o">|</span></pre></div>
44
+ </td>
45
+ </tr>
46
+ <tr id='section-2'>
47
+ <td class=docs>
48
+ <div class="octowrap">
49
+ <a class="octothorpe" href="#section-2">#</a>
50
+ </div>
51
+ <p>Let&rsquo;s begin!</p>
52
+ </td>
53
+ <td class=code>
54
+ <div class='highlight'><pre> <span class="n">branch</span> <span class="o">=</span> <span class="n">repo</span><span class="o">.</span><span class="n">current_branch</span>
55
+ <span class="n">start</span> <span class="s2">&quot;Starting: smart-pull on branch &#39;</span><span class="si">#{</span><span class="n">branch</span><span class="si">}</span><span class="s2">&#39;&quot;</span></pre></div>
56
+ </td>
57
+ </tr>
58
+ <tr id='section-3'>
59
+ <td class=docs>
60
+ <div class="octowrap">
61
+ <a class="octothorpe" href="#section-3">#</a>
62
+ </div>
63
+ <p>Let&rsquo;s not have any arguments, fellas.</p>
64
+ </td>
65
+ <td class=code>
66
+ <div class='highlight'><pre> <span class="nb">warn</span> <span class="s2">&quot;Ignoring arguments: </span><span class="si">#{</span><span class="n">args</span><span class="o">.</span><span class="n">inspect</span><span class="si">}</span><span class="s2">&quot;</span> <span class="k">if</span> <span class="o">!</span><span class="n">args</span><span class="o">.</span><span class="n">empty?</span></pre></div>
67
+ </td>
68
+ </tr>
69
+ <tr id='section-4'>
70
+ <td class=docs>
71
+ <div class="octowrap">
72
+ <a class="octothorpe" href="#section-4">#</a>
73
+ </div>
74
+ <p>Try grabbing the tracking remote from the config. If it doesn&rsquo;t exist,
75
+ notify the user and default to &lsquo;origin&rsquo;</p>
76
+ </td>
77
+ <td class=code>
78
+ <div class='highlight'><pre> <span class="n">tracking_remote</span> <span class="o">=</span> <span class="n">repo</span><span class="o">.</span><span class="n">tracking_remote</span> <span class="o">||</span>
79
+ <span class="n">note</span><span class="p">(</span><span class="s2">&quot;No tracking remote configured, assuming &#39;origin&#39;&quot;</span><span class="p">)</span> <span class="o">||</span>
80
+ <span class="s1">&#39;origin&#39;</span></pre></div>
81
+ </td>
82
+ </tr>
83
+ <tr id='section-5'>
84
+ <td class=docs>
85
+ <div class="octowrap">
86
+ <a class="octothorpe" href="#section-5">#</a>
87
+ </div>
88
+ <p> Fetch the remote. This pulls down all new commits from the server, not just our branch,
89
+ but generally that&rsquo;s a good thing. This is the only communication we need to do with the server.</p>
90
+ </td>
91
+ <td class=code>
92
+ <div class='highlight'><pre> <span class="n">repo</span><span class="o">.</span><span class="n">fetch!</span><span class="p">(</span><span class="n">tracking_remote</span><span class="p">)</span></pre></div>
93
+ </td>
94
+ </tr>
95
+ <tr id='section-6'>
96
+ <td class=docs>
97
+ <div class="octowrap">
98
+ <a class="octothorpe" href="#section-6">#</a>
99
+ </div>
100
+ <p>Try grabbing the tracking branch from the config. If it doesn&rsquo;t exist,
101
+ notify the user and choose the branch of the same name</p>
102
+ </td>
103
+ <td class=code>
104
+ <div class='highlight'><pre> <span class="n">tracking_branch</span> <span class="o">=</span> <span class="n">repo</span><span class="o">.</span><span class="n">tracking_branch</span> <span class="o">||</span>
105
+ <span class="n">note</span><span class="p">(</span><span class="s2">&quot;No tracking branch configured, assuming &#39;</span><span class="si">#{</span><span class="n">branch</span><span class="si">}</span><span class="s2">&#39;&quot;</span><span class="p">)</span> <span class="o">||</span>
106
+ <span class="n">branch</span></pre></div>
107
+ </td>
108
+ </tr>
109
+ <tr id='section-7'>
110
+ <td class=docs>
111
+ <div class="octowrap">
112
+ <a class="octothorpe" href="#section-7">#</a>
113
+ </div>
114
+ <p>Check the specified upstream branch exists. Fail if it doesn&rsquo;t.</p>
115
+ </td>
116
+ <td class=code>
117
+ <div class='highlight'><pre> <span class="n">upstream_branch</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">#{</span><span class="n">tracking_remote</span><span class="si">}</span><span class="s2">/</span><span class="si">#{</span><span class="n">tracking_branch</span><span class="si">}</span><span class="s2">&quot;</span>
118
+ <span class="n">failure</span><span class="p">(</span><span class="s2">&quot;Upstream branch &#39;</span><span class="si">#{</span><span class="n">upstream_branch</span><span class="si">}</span><span class="s2">&#39; doesn&#39;t exist!&quot;</span><span class="p">)</span> <span class="k">if</span> <span class="o">!</span><span class="n">repo</span><span class="o">.</span><span class="n">exists?</span><span class="p">(</span><span class="n">upstream_branch</span><span class="p">)</span></pre></div>
119
+ </td>
120
+ </tr>
121
+ <tr id='section-8'>
122
+ <td class=docs>
123
+ <div class="octowrap">
124
+ <a class="octothorpe" href="#section-8">#</a>
125
+ </div>
126
+ <p>Grab the SHAs of the commits we&rsquo;ll be working with.</p>
127
+ </td>
128
+ <td class=code>
129
+ <div class='highlight'><pre> <span class="n">head</span> <span class="o">=</span> <span class="n">repo</span><span class="o">.</span><span class="n">sha</span><span class="p">(</span><span class="s1">&#39;HEAD&#39;</span><span class="p">)</span>
130
+ <span class="n">remote</span> <span class="o">=</span> <span class="n">repo</span><span class="o">.</span><span class="n">sha</span><span class="p">(</span><span class="n">upstream_branch</span><span class="p">)</span></pre></div>
131
+ </td>
132
+ </tr>
133
+ <tr id='section-9'>
134
+ <td class=docs>
135
+ <div class="octowrap">
136
+ <a class="octothorpe" href="#section-9">#</a>
137
+ </div>
138
+ <p>If both HEAD and our upstream_branch resolve to the same SHA, there&rsquo;s nothing to do!</p>
139
+ </td>
140
+ <td class=code>
141
+ <div class='highlight'><pre> <span class="k">if</span> <span class="n">head</span> <span class="o">==</span> <span class="n">remote</span>
142
+ <span class="nb">puts</span> <span class="s2">&quot;Neither your local branch &#39;</span><span class="si">#{</span><span class="n">branch</span><span class="si">}</span><span class="s2">&#39;, nor the remote branch &#39;</span><span class="si">#{</span><span class="n">upstream_branch</span><span class="si">}</span><span class="s2">&#39; have moved on.&quot;</span>
143
+ <span class="n">success</span> <span class="s2">&quot;Already up-to-date&quot;</span>
144
+ <span class="k">else</span></pre></div>
145
+ </td>
146
+ </tr>
147
+ <tr id='section-10'>
148
+ <td class=docs>
149
+ <div class="octowrap">
150
+ <a class="octothorpe" href="#section-10">#</a>
151
+ </div>
152
+ <p>Find out where the two branches diverged using merge-base. It&rsquo;s what git
153
+ uses internally.</p>
154
+ </td>
155
+ <td class=code>
156
+ <div class='highlight'><pre> <span class="n">merge_base</span> <span class="o">=</span> <span class="n">repo</span><span class="o">.</span><span class="n">merge_base</span><span class="p">(</span><span class="n">head</span><span class="p">,</span> <span class="n">remote</span><span class="p">)</span></pre></div>
157
+ </td>
158
+ </tr>
159
+ <tr id='section-11'>
160
+ <td class=docs>
161
+ <div class="octowrap">
162
+ <a class="octothorpe" href="#section-11">#</a>
163
+ </div>
164
+ <p>By comparing the merge_base to both HEAD and the remote, we can
165
+ determine whether both or only one have moved on.
166
+ If the remote hasn&rsquo;t changed, we&rsquo;re already up to date, so there&rsquo;s nothing
167
+ to pull.</p>
168
+ </td>
169
+ <td class=code>
170
+ <div class='highlight'><pre> <span class="k">if</span> <span class="n">merge_base</span> <span class="o">==</span> <span class="n">remote</span>
171
+ <span class="nb">puts</span> <span class="s2">&quot;Remote branch &#39;</span><span class="si">#{</span><span class="n">upstream_branch</span><span class="si">}</span><span class="s2">&#39; has not moved on.&quot;</span>
172
+ <span class="n">success</span> <span class="s2">&quot;Already up-to-date&quot;</span>
173
+ <span class="k">else</span></pre></div>
174
+ </td>
175
+ </tr>
176
+ <tr id='section-12'>
177
+ <td class=docs>
178
+ <div class="octowrap">
179
+ <a class="octothorpe" href="#section-12">#</a>
180
+ </div>
181
+ <p>If the remote <em>has</em> moved on, we actually have some work to do:</p>
182
+
183
+ <p>First, report how many commits are new on remote. Because that&rsquo;s useful information.</p>
184
+ </td>
185
+ <td class=code>
186
+ <div class='highlight'><pre> <span class="n">new_commits_on_remote</span> <span class="o">=</span> <span class="n">repo</span><span class="o">.</span><span class="n">rev_list</span><span class="p">(</span><span class="n">merge_base</span><span class="p">,</span> <span class="n">remote</span><span class="p">)</span>
187
+ <span class="n">is_are</span><span class="p">,</span> <span class="n">s_or_not</span> <span class="o">=</span> <span class="p">(</span><span class="n">new_commits_on_remote</span><span class="o">.</span><span class="n">length</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span> <span class="p">?</span> <span class="o">[</span><span class="s1">&#39;is&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="o">]</span> <span class="p">:</span> <span class="o">[</span><span class="s1">&#39;are&#39;</span><span class="p">,</span> <span class="s1">&#39;s&#39;</span><span class="o">]</span>
188
+ <span class="n">note</span> <span class="s2">&quot;There </span><span class="si">#{</span><span class="n">is_are</span><span class="si">}</span><span class="s2"> </span><span class="si">#{</span><span class="n">new_commits_on_remote</span><span class="o">.</span><span class="n">length</span><span class="si">}</span><span class="s2"> new commit</span><span class="si">#{</span><span class="n">s_or_not</span><span class="si">}</span><span class="s2"> on &#39;</span><span class="si">#{</span><span class="n">upstream_branch</span><span class="si">}</span><span class="s2">&#39;.&quot;</span></pre></div>
189
+ </td>
190
+ </tr>
191
+ <tr id='section-13'>
192
+ <td class=docs>
193
+ <div class="octowrap">
194
+ <a class="octothorpe" href="#section-13">#</a>
195
+ </div>
196
+ <p>Next, detect if there are local changes and stash them.</p>
197
+ </td>
198
+ <td class=code>
199
+ <div class='highlight'><pre> <span class="n">stash_required</span> <span class="o">=</span> <span class="n">repo</span><span class="o">.</span><span class="n">dirty?</span>
200
+ <span class="k">if</span> <span class="n">stash_required</span>
201
+ <span class="n">note</span> <span class="s2">&quot;Working directory dirty. Stashing...&quot;</span>
202
+ <span class="n">repo</span><span class="o">.</span><span class="n">stash!</span>
203
+ <span class="k">end</span>
204
+
205
+ <span class="n">success_messages</span> <span class="o">=</span> <span class="o">[]</span></pre></div>
206
+ </td>
207
+ </tr>
208
+ <tr id='section-14'>
209
+ <td class=docs>
210
+ <div class="octowrap">
211
+ <a class="octothorpe" href="#section-14">#</a>
212
+ </div>
213
+ <p>Then, bring the local branch up to date.</p>
214
+
215
+ <p>If our local branch hasn&rsquo;t moved on, that&rsquo;s easy &ndash; we just need to fast-forward.</p>
216
+ </td>
217
+ <td class=code>
218
+ <div class='highlight'><pre> <span class="k">if</span> <span class="n">merge_base</span> <span class="o">==</span> <span class="n">head</span>
219
+ <span class="nb">puts</span> <span class="s2">&quot;Local branch &#39;</span><span class="si">#{</span><span class="n">branch</span><span class="si">}</span><span class="s2">&#39; has not moved on. Fast-forwarding...&quot;</span>
220
+ <span class="n">repo</span><span class="o">.</span><span class="n">fast_forward!</span><span class="p">(</span><span class="n">upstream_branch</span><span class="p">)</span>
221
+ <span class="n">success_messages</span> <span class="o">&lt;&lt;</span> <span class="s2">&quot;Fast forwarded from </span><span class="si">#{</span><span class="n">head</span><span class="o">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">7</span><span class="o">]</span><span class="si">}</span><span class="s2"> to </span><span class="si">#{</span><span class="n">remote</span><span class="o">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">7</span><span class="o">]</span><span class="si">}</span><span class="s2">&quot;</span>
222
+ <span class="k">else</span></pre></div>
223
+ </td>
224
+ </tr>
225
+ <tr id='section-15'>
226
+ <td class=docs>
227
+ <div class="octowrap">
228
+ <a class="octothorpe" href="#section-15">#</a>
229
+ </div>
230
+ <p>If our local branch has new commits, we need to rebase them on top of master.</p>
231
+
232
+ <p>When we rebase, we use <code>git rebase -p</code>, which attempts to recreate merges
233
+ instead of ignoring them. For a description as to why, see my <a href="(https://gist.github.com/591209">blog post</a>.</p>
234
+ </td>
235
+ <td class=code>
236
+ <div class='highlight'><pre> <span class="n">note</span> <span class="s2">&quot;Both local and remote branches have moved on. Branch &#39;master&#39; needs to be rebased onto &#39;origin/master&#39;&quot;</span>
237
+ <span class="n">repo</span><span class="o">.</span><span class="n">rebase_preserving_merges!</span><span class="p">(</span><span class="n">upstream_branch</span><span class="p">)</span>
238
+ <span class="n">success_messages</span> <span class="o">&lt;&lt;</span> <span class="s2">&quot;HEAD moved from </span><span class="si">#{</span><span class="n">head</span><span class="o">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">7</span><span class="o">]</span><span class="si">}</span><span class="s2"> to </span><span class="si">#{</span><span class="n">repo</span><span class="o">.</span><span class="n">sha</span><span class="p">(</span><span class="s1">&#39;HEAD&#39;</span><span class="p">)</span><span class="o">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">7</span><span class="o">]</span><span class="si">}</span><span class="s2">.&quot;</span>
239
+ <span class="k">end</span></pre></div>
240
+ </td>
241
+ </tr>
242
+ <tr id='section-16'>
243
+ <td class=docs>
244
+ <div class="octowrap">
245
+ <a class="octothorpe" href="#section-16">#</a>
246
+ </div>
247
+ <p>If we stashed before, pop now.</p>
248
+ </td>
249
+ <td class=code>
250
+ <div class='highlight'><pre> <span class="k">if</span> <span class="n">stash_required</span>
251
+ <span class="n">note</span> <span class="s2">&quot;Reapplying local changes...&quot;</span>
252
+ <span class="n">repo</span><span class="o">.</span><span class="n">stash_pop!</span>
253
+ <span class="k">end</span></pre></div>
254
+ </td>
255
+ </tr>
256
+ <tr id='section-17'>
257
+ <td class=docs>
258
+ <div class="octowrap">
259
+ <a class="octothorpe" href="#section-17">#</a>
260
+ </div>
261
+ <p>Display a nice completion message in large, friendly letters.</p>
262
+
263
+ </td>
264
+ <td class=code>
265
+ <div class='highlight'><pre> <span class="n">success</span> <span class="o">[</span><span class="s2">&quot;All good.&quot;</span><span class="p">,</span> <span class="o">*</span><span class="n">success_messages</span><span class="o">].</span><span class="n">join</span><span class="p">(</span><span class="s2">&quot; &quot;</span><span class="p">)</span>
266
+ <span class="k">end</span>
267
+
268
+ <span class="k">end</span>
269
+ <span class="k">end</span></pre></div>
270
+ </td>
271
+ </tr>
272
+ </table>
273
+ </div>
274
+ </body>