/
chap8-4.html
335 lines (329 loc) · 23.5 KB
/
chap8-4.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Git In The Trenches</title>
<link href="stylesheet.css" rel="stylesheet" type="text/css">
<link type="text/css" href="menu.css" rel="stylesheet" />
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-228354-4']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</head>
<body>
<table width="1000" border="0" align="center" cellpadding="0" cellspacing="0">
<tr>
<td><table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr>
<td><table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr>
<td class="logo"><a href="index.html"><img src="images/git_logo_new.png" alt="Git In The Trenches" height="61" border="0"></a></td>
<td class="nav">
<a href="index.html">Home</a> |
<a href="download.html">Download Now</a> |
<a href="intro.html">Read Now</a> |
<a href="http://github.com/cbx33/gitt">Source</a> |
<a href="feedback.html">Feeback</a>
</td>
</tr>
</table></td>
</tr>
<tr>
<td> </td>
</tr>
<tr>
<td class="main_content_pad"><table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr>
<td width="309"><table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr>
<td class="subnav">
<strong>Introduction</strong><br>
• <a href="intro.html">How this book works</a><br>
<div class="divider"></div>
<strong>Setting up</strong><br>
• <a href="setup.html">Making sure you have everything</a><br>
<div class="divider"></div>
<strong>Week 1</strong><br>
<span>• Day 1 </span> - <a href="chap1-1.html"> "Things need to change"</a><br>
<span>• Day 3 </span> - <a href="chap1-2.html"> "A possible solution"</a><br>
<span>• Day 4 </span> - <a href="chap1-3.html"> "A decision is reached"</a><br>
<span>• Day 5 </span> - <a href="chap1-4.html"> "Working like a team"</a><br>
<div class="divider"></div>
<strong>After Hours Week 1</strong><br>
• <a href="afterhours1-1.html">"History Lesson"</a><br>
<div class="divider"></div>
<strong>Week 2</strong><br>
<span>• Day 1 </span> - <a href="chap2-1.html"> "We are coders, we use Git!"</a><br>
<span>• Day 2 </span> - <a href="chap2-2.html"> "Making commitments"</a><br>
<span>• Day 4 </span> - <a href="chap2-3.html"> "Let's do this right, not fast"</a><br>
<span>• Summary </span> - <a href="chap2-4.html"> John's Notes</a><br>
<div class="divider"></div>
<strong>After Hours Week 2</strong><br>
• <a href="afterhours2-1.html">"A Little Of Git's Internals"</a><br>
<div class="divider"></div>
<strong>Week 3</strong><br>
<span>• Day 1 </span> - <a href="chap3-1.html"> "How do I see what's going on?"</a><br>
<span>• Day 2 </span> - <a href="chap3-2.html"> "But I need more information"</a><br>
<span>• Day 3 </span> - <a href="chap3-3.html"> "What actually changed?"</a><br>
<span>• Day 4 </span> - <a href="chap3-4.html"> "Finding a good reference point"</a><br>
<span>• Day 5 </span> - <a href="chap3-5.html"> "Putting things back again"</a><br>
<span>• Summary </span> - <a href="chap3-6.html"> John's Notes</a><br>
<div class="divider"></div>
<strong>After Hours Week 3</strong><br>
• <a href="afterhours3-1.html">"A Closer Look At Diffs and Tags"</a><br>
<div class="divider"></div>
<strong>Week 4</strong><br>
<span>• Day 1 </span> - <a href="chap4-1.html"> "We're getting somewhere"</a><br>
<span>• Day 2 </span> - <a href="chap4-2.html"> "Branches galore"</a><br>
<span>• Day 3 </span> - <a href="chap4-3.html"> "Tricking the twigs"</a><br>
<span>• Day 4 </span> - <a href="chap4-4.html"> "I pressed delete..."</a><br>
<span>• Day 5 </span> - <a href="chap4-5.html"> "Conflicting information"</a><br>
<span>• Summary </span> - <a href="chap4-6.html"> John's Notes</a><br>
<div class="divider"></div>
<strong>After Hours Week 4</strong><br>
• <a href="afterhours4-1.html">"Merge merge merge"</a><br>
• <a href="afterhours4-2.html">"Grepping your life away"</a><br>
<div class="divider"></div>
<strong>Week 5</strong><br>
<span>• Day 1 </span> - <a href="chap5-1.html"> "This isn't working for me John"</a><br>
<span>• Day 2 </span> - <a href="chap5-2.html"> "Back to logging"</a><br>
<span>• Day 4 </span> - <a href="chap5-3.html"> "Advanced Techniques"</a><br>
<span>• Summary </span> - <a href="chap5-4.html"> John's Notes</a><br>
<div class="divider"></div>
<strong>After Hours Week 5</strong><br>
• <a href="afterhours5-1.html">"Splitting up commits the easy way"</a><br>
<div class="divider"></div>
<strong>Week 6</strong><br>
<span>• Day 1 </span> - <a href="chap6-1.html"> "My private little stash"</a><br>
<span>• Day 2 </span> - <a href="chap6-2.html"> "What?! No backup?"</a><br>
<span>• Day 3 </span> - <a href="chap6-3.html"> "Is this clone for real?"</a><br>
<span>• Day 4 </span> - <a href="chap6-4.html"> "Help I'm no longer up to date?"</a><br>
<span>• Day 5 </span> - <a href="chap6-5.html"> "I'm putting my foot down"</a><br>
<span>• Summary </span> - <a href="chap6-6.html"> John's Notes</a><br>
<div class="divider"></div>
<strong>After Hours Week 6</strong><br>
• <a href="afterhours6-1.html">"Tug of war"</a><br>
• <a href="afterhours6-2.html">"Referring to objects"</a><br>
<div class="divider"></div>
<strong>Week 7</strong><br>
<span>• Day 1 </span> - <a href="chap7-1.html"> "Networking with a difference"</a><br>
<span>• Day 2 </span> - <a href="chap7-2.html"> "Now let's work together"</a><br>
<span>• Day 3 </span> - <a href="chap7-3.html"> "Rebasing our commitments"</a><br>
<span>• Day 4 </span> - <a href="chap7-4.html"> "Starting to get rebased"</a><br>
<span>• Day 5 </span> - <a href="chap7-5.html"> "I could rebase the world"</a><br>
<span>• Summary </span> - <a href="chap7-6.html"> John's Notes</a><br>
<div class="divider"></div>
<strong>After Hours Week 7</strong><br>
• <a href="afterhours7-1.html">"Network Communicating"</a><br>
<div class="divider"></div>
<strong>Week 8</strong><br>
<span>• Day 1 </span> - <a href="chap8-1.html"> "Give a man a patch"</a><br>
<span>• Day 2 </span> - <a href="chap8-2.html"> "Looking for problems"</a><br>
<span>• Day 3 </span> - <a href="chap8-3.html"> "Filtered repos"</a><br>
<span>• Day 4 </span> - <a href="chap8-4.html"> "Let's make a library"</a><br>
<span>• Day 5 </span> - <a href="chap8-5.html"> "Shhh....we're in a library"</a><br>
<span>• Summary </span> - <a href="chap8-6.html"> John's Notes</a><br>
<div class="divider"></div>
<strong>After Hours Week 8</strong><br>
• <a href="afterhours8-1.html">"Fishing for beginners"</a><br>
<div class="divider"></div>
<strong>A little extra help</strong><br>
• <a href="chap9-1.html">Taking things further</a><br>
• <a href="chap9-2.html">The end of the journey</a><br>
<div class="divider"></div>
<td class="fade_right"> </td>
</tr>
<tr>
<td class="fade_bot"> </td>
<td class="fade_corner"> </td>
</tr>
</table> <h1> </h1>
</td>
<td><table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr>
<td class="read_content">
<h1>Week 8</h1><h2>Day 4 - "Let's make a library"</h2>
<h3>Splitting the atom</h3>
Sometimes, after a project has been running for a while certain components actually grow rather useful.
When this happens, people often want to move it outside of the original project and maintain it as a separate library.
Of course the easiest way to do this is to just copy and paste the files out of the main project and into a subdirectory.
In doing this we would lose or disconnect all of the development history of that subproject up to this point.<br><br>Using the <code class="ncode">git filter-branch</code> we can actually pull out a folder and retain all of its history.
The methodology behind this is that we rewrite the history to a new branch, but we only pull across changes to a particular folder and we store those in the root of the branch.
Let us see how this works with a quick example.
Remember we created the <code class="ncode">tester</code> folder?
We are going to make a few commits to the files in this folder to give it some history.<br><div id="codeblock"><code><strong>john@satsuki:~/coderepo$ echo "More development work" >> tester/newfile1</strong><br/>
<strong>john@satsuki:~/coderepo$ git commit -a -m 'Work on tester nf1'</strong><br/>
[master 1a4956b] Work on tester nf1<br/>
1 files changed, 1 insertions(+), 0 deletions(-)<br/>
<strong>john@satsuki:~/coderepo$ echo "More dev work" >> tester/newfile2</strong><br/>
<strong>john@satsuki:~/coderepo$ git commit -a -m 'Work on tester nf2'</strong><br/>
[master 7156104] Work on tester nf2<br/>
1 files changed, 1 insertions(+), 0 deletions(-)<br/>
<strong>john@satsuki:~/coderepo$ echo "Even more dev work" >> tester/newfile3</strong><br/>
<strong>john@satsuki:~/coderepo$ git commit -a -m 'Work on tester nf3'</strong><br/>
[master 1433223] Work on tester nf3<br/>
1 files changed, 1 insertions(+), 0 deletions(-)<br/>
<strong>john@satsuki:~/coderepo$ </strong><br/>
</code></div><br>Now we are going to split that off into a separate branch which we will then clone into a new Git repository.
After we have copied the history of the <code class="ncode">tester</code> folder to a new branch, see if you can run through in your head, the steps we would need to take to pull this branch into a new repository.<br><div id="codeblock"><code><strong>john@satsuki:~/coderepo$ git checkout -b tester_split</strong><br/>
Switched to a new branch 'tester_split'<br/>
<strong>john@satsuki:~/coderepo$ git filter-branch --subdirectory-filter tester</strong><br/>
Rewrite 1433223d9c8a8abc35410d12cf78128c318b6e42 (4/4)<br/>
Ref 'refs/heads/tester_split' was rewritten<br/>
<strong>john@satsuki:~/coderepo$ git branch</strong><br/>
develop<br/>
master<br/>
* tester_split<br/>
wonderful<br/>
zaney<br/>
<strong>john@satsuki:~/coderepo$ ls</strong><br/>
newfile1 newfile2 newfile3 test.sh<br/>
<strong>john@satsuki:~/coderepo$ git checkout master</strong><br/>
Switched to branch 'master'<br/>
<strong>john@satsuki:~/coderepo$ ls</strong><br/>
another_file cont_dev tester<br/>
<strong>john@satsuki:~/coderepo$ </strong><br/>
</code></div><br>So now the directory has been split away from the original source code into a new branch. Have a think about what steps you would take to bring this into an entirely new repository.<br><div id="calloutblock"><h3>Note - More backups</h3>
Git likes to make things easy for you.
You may not have noticed it before, but when using the <code class="ncode">git filter-branch</code> tool to rewrite a branch, Git keeps a backup of the value of HEAD before you started rewriting your branch.
This backup is kept in <code class="ncode">refs/original/refs/heads/<branch_name></code>.
This file will contain a commit ID which we can use to revert our branch back to its original state, if the filter does horribly wrong.
</div><br><div id="trenchblock"><strong>In the trenches...</strong><br>
"So John, I managed to split the Atom library out into a new branch like you said, but I have no idea how to pull this into a new repo."
Jack was finally feeling like he had gotten to grips with Git, but his latest task had left him feeling a little dejected.
He idly stabbed at his leg with a pen whilst waiting for John to finish his tapping away.<br><br>John lifted his keys from the keyboard and turned his chair.
"You really can't think of a way to copy what we have in one repo into another?"<br><br>Suddenly it was like a light bulb had exploded with light inside Jack's skull. "CLONES!" he shouted.
</div><br>We actually have at least four methods we can use to do this.
<div style="padding-left:10px;"><ol><li>Copy the data from one repo to another with a simple copy and paste</li>
<li>Clone our repository, delete all of the branches other than <strong>tester_split</strong> and then rename it to <strong>master</strong></li>
<li>Initialise a new repository, setup a remote to the original and then fetch our <strong>tester_split</strong> branch</li>
<li>Create a bundle of the <strong>tester_split</strong> and then clone from the bundle into a new repository</li>
</ol></div><br>The first of these will leave us with no history of development at all, so let us ignore it, as it is not what we require.
The second of these is trivial and should require no explanation at all.
We simply clone and then using the usual tools, we delete all unnecessary branches.
However this first method does have its disadvantages, namely the fact that when we clone the repository, we take every single object from the source repository into the new one.
Whilst this is generally not a problem it would mean that we would have to run some fairly aggressive garbage collection to remove all of these unwanted objects.
This would happen natually over time as the objects aged and were no longer referenced, but it would result in a repository that was initially much larger than it needed to be.<br><br>The other two methods deserve a little more consideration as they both perform much better in this respect.
The third method you should be familiar enough with previous material to be able to perform right now.
However, using the fetch command as we have done so before would again pull in many more objects than we require.
As such we are going to do a subtle twist to this command in the following output.<br><div id="codeblock"><code><strong>john@satsuki:~/coderepo$ cd ../</strong><br/>
<strong>john@satsuki:~$ mkdir subrepo</strong><br/>
<strong>john@satsuki:~$ cd subrepo/</strong><br/>
<strong>john@satsuki:~/subrepo$ git init</strong><br/>
Initialized empty Git repository in /home/john/subrepo/.git/<br/>
<strong>john@satsuki:~/subrepo$ git remote add source /home/john/coderepo</strong><br/>
<strong>john@satsuki:~/subrepo$ git fetch source +tester_split:master</strong><br/>
fatal: Refusing to fetch into current branch refs/heads/master of non-bare repository<br/>
<strong>john@satsuki:~/subrepo$ fatal: The remote end hung up unexpectedly</strong><br/>
<strong>john@satsuki:~/subrepo$</strong><br/>
</code></div><br>What we have asked Git to do is to pull only the branch <strong>tester_split</strong> from the remote we called <strong>source</strong> and place it into <strong>master</strong> locally.
Think of the <code class="ncode">+<branch>:<branch></code> as <code class="ncode">+<source>:<destination></code> and all will make sense.
As you can see Git is not too happy about our intentions here as it does not like overwriting the <strong>master</strong> branch of a non-bare repository.
That is OK, we have another way around this.<br><div id="codeblock"><code><strong>john@satsuki:~/subrepo$ git fetch source +tester_split:tmp</strong><br/>
remote: Counting objects: 15, done.<br/>
remote: Compressing objects: 100remote: Total 15 (delta 3), reused 0 (delta 0)<br/>
Unpacking objects: 100From /home/john/coderepo<br/>
* [new branch] tester_split -> tmp<br/>
<strong>john@satsuki:~/subrepo$ git branch -m tmp master</strong><br/>
<strong>john@satsuki:~/subrepo$</strong><br/>
</code></div><br>So we have almost deceived Git a little here, but I think we can live with ourselves.
By first pulling the branch into a <strong>tmp</strong> branch, we were then allowed to rename it as <strong>master</strong>.
Notice the number of objects required for this branch <code class="ncode">15</code>.
If you remember when we cloned our repository a few <em>weeks</em> ago, this value was a lot higher than this.
It was the subtle <code class="ncode">+<source>:<destination></code> which prevented us from pulling every last object from the source repository into our new slim <em>sub</em>-repository.<br><div id="codeblock"><code><strong>john@satsuki:~/subrepo$ ls</strong><br/>
<strong>john@satsuki:~/subrepo$ git checkout master</strong><br/>
Already on 'master'<br/>
<strong>john@satsuki:~/subrepo$ ls</strong><br/>
newfile1 newfile2 newfile3 test.sh<br/>
<strong>john@satsuki:~/subrepo$ </strong><br/>
</code></div><br>Notice that there are no files in the repository until we have checked out.
This is because all the fetch did was to <em>fetch</em> the objects and place them in the repository object directory.
It did not place anything in the working directory.
If you remember this is same behaviour we saw with fetching before.
So now we have a complete copy of our <code class="ncode">tester</code> component of our repository from the source into a new repository.
If we do a <code class="ncode">git log</code>, we can see the history of the development.<br><div id="codeblock"><code><strong>john@satsuki:~/subrepo$ git log --format=oneline</strong><br/>
590e0eb79bc5ba0bc09f611392e643f676b00a04 Work on tester nf3<br/>
785b86d877d2a5c0679d98181a23d06ed2ba7652 Work on tester nf2<br/>
1ff89f787438f081a0d74de2d26eb2d831c9c738 Work on tester nf1<br/>
a5a0d9762dd4b50d8f3228e37b315f6056d5a034 Moved testing suite<br/>
<strong>john@satsuki:~/subrepo$ </strong><br/>
</code></div><br>Unfortunately since some of our development work on these files happened outside of this directory,
this was lost when splitting and this is something to keep in mind should you ever perform this kind of operation.<br><h3>Little bundles of joy</h3>
Git has so many ways to do things.
This is in part what makes it a little daunting for those just starting but after you have gained a little experience, you begin to understand just what is happening in the background.
When this realisation hits, you are able to almost immediately think of at least two different ways of performing the same thing.
There have been numerous examples throughout the book, where there have been multiple ways to complete the same task.
Here we are going to look at just one more way that we can create a new repo from our <strong>tester_split</strong> branch.<br><br>The tool we are going to introduce here is <code class="ncode">git bundle</code>.
The <code class="ncode">bundle</code> utility allows us to export a set of revisions and archive them to a file.
This file then becomes a resource that can be updated and pulled or fetched from.
This is especially useful if you have no physical connection between two computers and wish to sync some of the data from one to the other.
Let us take a quick look at how we could use the bundle tool in this case.<br><div id="codeblock"><code><strong>john@satsuki:~/coderepo$ git bundle create ../tester.bundle tester_split </strong><br/>
Counting objects: 15, done.<br/>
Compressing objects: 100Writing objects: 100Total 15 (delta 3), reused 0 (delta 0)<br/>
<strong>john@satsuki:~/coderepo$ cd ..</strong><br/>
<strong>john@satsuki:~$ git clone tester.bundle subrepo-b</strong><br/>
Cloning into subrepo-b...<br/>
warning: remote HEAD refers to nonexistent ref, unable to checkout.<br/>
<br/>
<strong>john@satsuki:~$</strong><br/>
</code></div><br>The syntax is fairly simple. The word <code class="ncode">create</code> is used to tell Git to create a new bundle.
After this we specify a filename and then the tip of the branch that we want to archive. However, as can be seen above, there is a problem.
When we created the bundle, the branch which was checked out at the time was <strong>master</strong>.
The objects we pulled from the source repository and placed in the bundle were all from the <strong>tester_split</strong> branch.
As such the HEAD of the working tree at the time of the bundle creation, pointed to an object in the <strong>master</strong> branch.
Obviously this object does not exist in our bundle and so Git complains.
If we had checked out <strong>tester_split</strong> before creating the bundle, there would have been no complaints.<br><br>So all we have to do is to remap the HEAD of <strong>master</strong> to that of the HEAD of <strong>tester_split</strong>.
As you can see below, it seems as if there are no branches at all and when we try to checkout master it does not exist.
What actually happened is that the objects were cloned into the repository, but as the object that the source HEAD pointed to was unavailable,
no branch was created.
With a little <code class="ncode">git reset</code> trickery, we can create our <strong>master</strong> branch in our new repository.<br><div id="codeblock"><code><strong>john@satsuki:~$ cd subrepo-b/</strong><br/>
<strong>john@satsuki:~/subrepo-b$ git branch</strong><br/>
<strong>john@satsuki:~/subrepo-b$ git checkout master</strong><br/>
error: pathspec 'master' did not match any file(s) known to git.<br/>
<strong>john@satsuki:~/subrepo-b$ git reset --hard origin/tester_split </strong><br/>
HEAD is now at 590e0eb Work on tester nf3<br/>
<strong>john@satsuki:~/subrepo-b$ git checkout master</strong><br/>
Already on 'master'<br/>
<strong>john@satsuki:~/subrepo-b$ ls</strong><br/>
newfile1 newfile2 newfile3 test.sh<br/>
<strong>john@satsuki:~/subrepo-b$ </strong><br/>
</code></div><br>Now we have our repository complete as before and we have successfully reampped the <strong>master</strong> branch so that it points to <strong>origin/tester_split</strong>.<br><div id="trenchblock"><strong>In the trenches...</strong><br>
Martha and John were sitting together in the office.
The rest of the team had left hours ago and it was getting really late.
Martha broke the silence, "So we've pulled the Atom library out," she giggled before continuing, "but how the heck do we put it back in again?"<br><br>"I'm really not sure said John," taking another swig of coffee before placing the mug back down on the desk.
On the side was written the word GIT in large marker pen, a gift from Klaus.<br><br>Martha sighed. "It's getting pretty late John. I think I'm gonna head out."<br><br>"Yeh, I know what you mean," started John, "I think I'll get going too.
Thanks for the help Martha."<br><br>"Anytime John."
</div><br><table border="0" cellpadding="0" cellspacing="0" width="100%">
<tr>
<td><p align="left"><a href="chap8-3.html"><img src="images/prev.png" alt="Previous Day" height="29" border="0"></a></p></td>
<td><p align="right"><a href="chap8-5.html"><img src="images/next.png" alt="Next Day" height="29" border="0"></a></p></td>
</tr>
</table> </td>
<td class="fade_right"> </td>
</tr>
<tr>
<td class="fade_bot"> </td>
<td class="fade_corner"> </td>
</tr>
</table></td>
</tr>
</table>
</td>
</tr>
<tr>
<td class="foot"><a href="index.html">home</a> | <a href="download.html">download</a> | <a href="intro.html">read now</a> | <a href="http://github.com/cbx33/gitt">source</a> | <a href="feedback.html">feedback</a> | <a href="legal.html">legal stuff</a><br>
</td>
</tr>
</table></td>
</tr>
</table>
</body>
</html>