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 +1 -0
- data/Gemfile.lock +6 -0
- data/README.md +10 -20
- data/Rakefile +7 -0
- data/VERSION +1 -1
- data/docs/images/git-smart.png +0 -0
- data/docs/smart-merge.html +211 -0
- data/docs/smart-pull.html +274 -0
- data/git-smart.gemspec +13 -2
- data/lib/commands/smart-merge.rb +63 -0
- data/lib/commands/smart-pull.rb +38 -10
- data/lib/git-smart/git_repo.rb +27 -10
- data/spec/smart-merge_failures_spec.rb +46 -0
- data/spec/smart-merge_spec.rb +101 -0
- data/spec/smart-pull_spec.rb +2 -5
- data/spec/spec_helper.rb +2 -1
- metadata +52 -23
data/Gemfile
CHANGED
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
|
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
|
-
|
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
|
-
|
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
|
-
|
45
|
-
|
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.
|
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 …
|
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’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">'smart-merge'</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’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">"Starting: smart-merge on branch '</span><span class="si">#{</span><span class="n">current_branch</span><span class="si">}</span><span class="s2">'"</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">"Usage: git smart-merge ref"</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">"Branch to merge '</span><span class="si">#{</span><span class="n">merge_target</span><span class="si">}</span><span class="s2">' not recognised by git!"</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’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">'HEAD'</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">"Branch '</span><span class="si">#{</span><span class="n">merge_target</span><span class="si">}</span><span class="s2">' has no new commits. Nothing to merge in."</span>
|
89
|
+
<span class="n">success</span> <span class="s1">'Already up-to-date.'</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’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">"Branch '</span><span class="si">#{</span><span class="n">merge_target</span><span class="si">}</span><span class="s2">' 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">'s'</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."</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’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">"Branch '</span><span class="si">#{</span><span class="n">current_branch</span><span class="si">}</span><span class="s2">' has not moved on since '</span><span class="si">#{</span><span class="n">merge_target</span><span class="si">}</span><span class="s2">' diverged. Running with --no-ff anyway, since a fast-forward is unexpected behaviour."</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">"Branch '</span><span class="si">#{</span><span class="n">current_branch</span><span class="si">}</span><span class="s2">' 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">'s'</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 '</span><span class="si">#{</span><span class="n">merge_target</span><span class="si">}</span><span class="s2">' diverged."</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">"Working directory dirty. Stashing..."</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 —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">"Reapplying local changes..."</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">"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">'HEAD'</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">."</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 …
|
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’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">'smart-pull'</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’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">"Starting: smart-pull on branch '</span><span class="si">#{</span><span class="n">branch</span><span class="si">}</span><span class="s2">'"</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’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">"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">"</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’t exist,
|
75
|
+
notify the user and default to ‘origin’</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">"No tracking remote configured, assuming 'origin'"</span><span class="p">)</span> <span class="o">||</span>
|
80
|
+
<span class="s1">'origin'</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’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’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">"No tracking branch configured, assuming '</span><span class="si">#{</span><span class="n">branch</span><span class="si">}</span><span class="s2">'"</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’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">"</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">"</span>
|
118
|
+
<span class="n">failure</span><span class="p">(</span><span class="s2">"Upstream branch '</span><span class="si">#{</span><span class="n">upstream_branch</span><span class="si">}</span><span class="s2">' doesn't exist!"</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’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">'HEAD'</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’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">"Neither your local branch '</span><span class="si">#{</span><span class="n">branch</span><span class="si">}</span><span class="s2">', nor the remote branch '</span><span class="si">#{</span><span class="n">upstream_branch</span><span class="si">}</span><span class="s2">' have moved on."</span>
|
143
|
+
<span class="n">success</span> <span class="s2">"Already up-to-date"</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’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’t changed, we’re already up to date, so there’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">"Remote branch '</span><span class="si">#{</span><span class="n">upstream_branch</span><span class="si">}</span><span class="s2">' has not moved on."</span>
|
172
|
+
<span class="n">success</span> <span class="s2">"Already up-to-date"</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’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">'is'</span><span class="p">,</span> <span class="s1">''</span><span class="o">]</span> <span class="p">:</span> <span class="o">[</span><span class="s1">'are'</span><span class="p">,</span> <span class="s1">'s'</span><span class="o">]</span>
|
188
|
+
<span class="n">note</span> <span class="s2">"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 '</span><span class="si">#{</span><span class="n">upstream_branch</span><span class="si">}</span><span class="s2">'."</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">"Working directory dirty. Stashing..."</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’t moved on, that’s easy – 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">"Local branch '</span><span class="si">#{</span><span class="n">branch</span><span class="si">}</span><span class="s2">' has not moved on. Fast-forwarding..."</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"><<</span> <span class="s2">"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">"</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">"Both local and remote branches have moved on. Branch 'master' needs to be rebased onto 'origin/master'"</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"><<</span> <span class="s2">"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">'HEAD'</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">."</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">"Reapplying local changes..."</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">"All good."</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">" "</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>
|