git-smart 0.1.3 → 0.1.4

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 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>