forked from cbx33/gitt
-
Notifications
You must be signed in to change notification settings - Fork 0
/
chap6.tex
839 lines (707 loc) · 39.5 KB
/
chap6.tex
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
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
% chap6.tex - Week 6
\cleardoublepage
%\phantomsection
\chapter{Week 6 - Stashing and Remoting}
\section{Day 1 - ``My private little stash''}
\subsection{Getting interrupted}
\index{stashing}We're getting close to the point where we can really start using Git as we originally intended, the team at Tamagoyaki Inc.
are also getting much more acquainted with the operations of both version control and Git in particular.
Unfortunately things don't always go as smoothly as we would like.
The following scenario demonstrates just this.
\begin{trenches}
``Yeh but Martha, I need you to work on this fix now! Not in five minutes.''
``Klaus I'm kinda in the middle of something else yet, and I'm not ready to commit,'' said Martha, feeling a little concerned.
She was used to Klaus making demands on his time, but she had spent a while working on this particular fix for John and she just wasn't ready to finish up yet.
``You could always use the stash feature.''
It was Rob again, it seemed as if this young user had cottoned on to Git quicker than most of the seasoned developers.''
Klaus seemed unimpressed, ``What the heck does that do?''
``Allows you to move your changes to somewhere else until you are ready to finish them.''
``Please Rob,'' started Martha,
``Can you show me what you mean? Sounds exactly like what I need''
\end{trenches}
Sometimes you could be in the middle of something when another really important task comes up.
When this happens you are often required to drop everything and carry on with another task.
Often this can be quite difficult.
You may be in a development branch, but unable or unwilling to make a commit at this stage.
So how can we deal with this?
Well, one way of dealing with this situation, and this is not necessarily the best way, is to do the steps outlined below;
\begin{enumerate}
\item Make a new branch called something like WIP
\item Pull changes into this new branch
\item Commit changes into WIP branch
\item Switch back to the branch we need to work on
\item Make our changes and commit them
\item Merge in our WIP branch on top with the \texttt{--no-commit} option
\item Delete the WIP branch
\item Continue development in our original branch
\end{enumerate}
That may seem like a lot of work.
OK, the benefit is a fairly awesome one, but at the cost of considerable command line hackery to get there.
It would be nice if there was an easy way to do the above, and though someone of you may be screaming something like \emph{shell script} right about now, you can rest your fingers.
We actually have another tool in the Git toolbox to help us out.
The \indexgit{stash} command is used for exactly these situations.
Let us make a quick example of how to use it in our test repository.
To begin with we are going to make a few changes to the \textbf{master} branch, before we are interrupted.
\begin{code}
john@satsuki:~/coderepo$ git checkout master
Already on 'master'
john@satsuki:~/coderepo$ echo "Number strings rule 1234" >> another_file
john@satsuki:~/coderepo$
\end{code}
\index{stashing!adding}So now we are interrupted and we have to make some important, and urgent changes to our \textbf{master} branch.
The example that follows is one way that we could use the \texttt{git stash} command to help us out.
\begin{code}
john@satsuki:~/coderepo$ git stash
Saved working directory and index state WIP on master: d50ffb2 Merged in zaney
HEAD is now at d50ffb2 Merged in zaney
john@satsuki:~/coderepo$ echo "Some mega important changes" >> newfile1
john@satsuki:~/coderepo$ git commit -a -m 'Important Update'
[master 9cb2af2] Important Update
1 files changed, 1 insertions(+), 0 deletions(-)
john@satsuki:~/coderepo$
\end{code}
So using the \texttt{git stash} command, we have squirrelled all of our developmental changes away into a \emph{stash}.
Now we have completed the mega important change that just could not wait, we are ready to pull our changes back from the stash.
First let us see just what the stash contains.
\begin{code}
john@satsuki:~/coderepo$ git stash list
stash@{0}: WIP on master: d50ffb2 Merged in zaney
john@satsuki:~/coderepo$ git stash show stash@{0}
another_file | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
john@satsuki:~/coderepo$ git stash show stash@{0} -p
diff --git a/another_file b/another_file
index dba885d..b3a5cc5 100644
--- a/another_file
+++ b/another_file
@@ -1 +1,2 @@
New stuff
+Number strings rule 1234
john@satsuki:~/coderepo$
\end{code}
\index{stashing!showing}As you can see, the \texttt{-p} option to the \texttt{git stash show} command shows us exactly what is contained in the stash.
We can apply this stash by running the following;
\begin{code}
john@satsuki:~/coderepo$ git stash apply stash@{0}
# On branch master
# Changed but not updated:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: another_file
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# my_third_committed_file
# temp_file
no changes added to commit (use "git add" and/or "git commit -a")
john@satsuki:~/coderepo$ git commit -a -m 'Continued Development'
[master 37950f8] Continued Development
1 files changed, 1 insertions(+), 0 deletions(-)
john@satsuki:~/coderepo$ git stash list
stash@{0}: WIP on master: d50ffb2 Merged in zaney
john@satsuki:~/coderepo$
\end{code}
Our stash has been applied to the current branch, in our case \textbf{master}, and we have gone ahead and committed these changes into the repository.
In this case we didn't have anything else to add to the index before we went ahead and committed it.
\index{stashing!removing}Interestingly though, our stash still exists.
If we had used the \texttt{git stash pop} command instead of the \texttt{git stash apply}, our stash would have been removed.
Of course we can have multiple stashes in our repository.
For completeness sake, let us learn how to manually remove a stash, and take a look at how our repository looks with our semi-graphical \texttt{git log}
\begin{code}
john@satsuki:~/coderepo$ git stash drop stash@{0}
Dropped stash@{0} (193f27172fc0df278105b981815c7718204030d8)
john@satsuki:~/coderepo$ git log --graph --pretty=oneline --all --abbrev-commit --decorate
* 37950f8 (HEAD, master) Continued Development
* 9cb2af2 Important Update
* d50ffb2 Merged in zaney
|\
| * 7cc32db (zaney) Made another awesome change
| * a27d49e Made an awesome change
* | ed2301b Removed third file
* | b119573 Merge branch 'wonderful'
|\ \
| * | cfbecab (wonderful) Fantastic new feature
| |/
* | 4ac9201 Updated third file
|/
* 9710177 Added another file
* 55fb69f (v2.0) Added two new files
* 4a155e4 Removed a few files
* a022d4d (tag: v1.0b, v1.0a) Messed with a few files
* 9938a0c Finished adding initial files
* 163f061 (v0.9) Made a few changes to first and second files
* cfe23cb My First Ever Commit
john@satsuki:~/coderepo$
\end{code}
So using the \texttt{git stash drop} command, you can see that it is fairly simple to drop a single stash from the list.
\section{Day 2 - ``What?! No backup?''}
\subsection{Attack of the clones}
We now know about basic branching and merging.
At this stage, there is on important topic we must cover briefly, and this is subject of cloning.
Cloning allows you to make a complete copy of your repository, including all of its history and all of the branches.
Let us take a look at a situation which could make use of cloning.
\begin{trenches}
``So John,'' started Rob,
``Just how are we backing up the repository at the moment?''
John thought for a moment before replying.
He knew what Rob was getting at, but he hadn't expected Rob to bring the question up in front of Markus.
In truth he had forgotten all about it.
He turned to Markus.
``I'll be honest Markus. Currently the repository isn't being backed up, but then we are running in parallel with the old system, so it wouldn't be the end of the world if we lost it.''
Markus nodded and smiled.
It seemed that John had gotten away with it for now and with that, Klaus shot Rob a piercing glance.
``Team,'' began Markus,
``we need a definitive way of backing up the new Git repository, and I'd like it done before the end of the day.''
He pointed at a document on the table.
``This project document has been approved by Wayne, and in there it states we will have a defined backup strategy. Please don't let me down.''
\thoughtbreak
``Rob you really got to be careful about things like that,'' Klaus said to one of the younger members of the team.
``You really showed John up in there.''
``Yeh,'' said Rob,
``I realise that now.''
He stood with his back against the wall and tapped his fingers against the painted surface.
``I was wondering, do you think John would let me look at the backup system for him as a way of apologising.''
Klaus smiled, it seemed Rob was finally understanding things,
``Go ask him,'' said Klaus,
``He's so snowed under with the BurnForce release that he'll probably let you implement it too''
``Right'' nodded Rob and off he went.
\end{trenches}
\index{cloning}So cloning is an excellent way of taking a copy of our repository, in essence it is a simple way of taking a backup of our repository and then with a little more work, we can keep that clone up to date.
Obviously we could just take the files and copy them, but a better way of doing this is by utilising the \indexgit{clone} command.
When cloning a repository, we take the entire structure and replicate it, creating an exact copy of the data in an alternative location.
Well, that's what cloning means isn't it?
The git clone tool doesn't just copy the data though, it does several other things.
Let us create a clone of our test repository to another local location.
In this case, we are going to clone the repository into a folder called \texttt{coderepo-cl}.
\begin{code}
john@satsuki:~$ git clone coderepo coderepo-cl
Initialized empty Git repository in /home/john/coderepo-cl/.git/
john@satsuki:~$ cd coderepo-cl
john@satsuki:~/coderepo-cl$ ls
another_file newfile1 newfile2
john@satsuki:~/coderepo-cl$ git status
# On branch master
nothing to commit (working directory clean)
john@satsuki:~/coderepo-cl$
\end{code}
Let us take a few moments to see what has happened here.
It would appear that our data has been copied successfully.
If you were to run a \texttt{git log} on this dir, you would see all the previous log messages for all our previous commits.
You can also see that if we run \texttt{git status} that we are on the same branch here that we were in our repository when we left it.
In this case, we are in the \textbf{master} branch.
So this could be sufficient enough to serve as a backup of our repository, but we will actually find a better way to do this a little later.
\section{Day 3 - ``Is this clone for real?''}
\subsection{Not entirely as expected}
We now have a clone of the repository and we can start to look at how we can play with branches and see how the two are different.
\begin{trenches}
``Klaus, this doesn't make sense though. I cloned my repo, but my branches have vanished,'' started Rob, rather worriedly.
``I'm sure they haven't gone anywhere,'' shouted John.
Rob's reply was quick and certain, ``They have! Run a git branch on your clone and see for yourself''
``Oh!''
Rob smiled the smug smile of a man who is pleased he was right.
\thoughtbreak
``Rob?'' asked John tentatively, aware of his previous state of anguish.
His reply indicated a less than stressed demeanour, ``Sup, dude?''.
John was pleasantly surprised, ``Did you sort out the branch issue?''
Rob began walking over to John, ``Yeh, try running git branch with the r parameter.''
\end{trenches}
\index{branching!remote}You may be thinking that we now have a detached copy of the other branches in our repository.
That's not exactly accurate.
Let us run the command that Rob suggested and see what is happening.
\begin{code}
john@satsuki:~/coderepo-cl$ git branch
* master
john@satsuki:~/coderepo-cl$ git branch -r
origin/HEAD -> origin/master
origin/master
origin/wonderful
origin/zaney
john@satsuki:~/coderepo-cl$
\end{code}
Whilst we have all the objects in our repository, we do not yet have our branches set up locally.
They are available, but they have not yet been set up locally.
To explain this we need to introduce the concept of remote tracking branches.
We are familiar with local branches.
Local branches allowed us to make commits locally in a safe and separated environment.
Remote tracking branches are links to remote branches which allow us to track the development of that branch and bring it in to a local one if we so desire.
Let us take a look at what we can do with these remote tracking branches.
Notice in the output above, we have the word \texttt{origin} in front of the branch names.
When we clone a repository, Git automatically sets up what is called a \emph{remote}.
We can view this by using the \indexgit{remote} tool.
\begin{code}
john@satsuki:~/coderepo-cl$ git remote
origin
john@satsuki:~/coderepo-cl$ git remote -v
origin /home/john/coderepo (fetch)
origin /home/john/coderepo (push)
john@satsuki:~/coderepo-cl$
\end{code}
As you can see from the output above, the \textbf{origin} remote definition points to the original folder that our repository came from.
So now we know that when referring to \texttt{origin/master}, we are really talking about the \textbf{master} branch which is located at the remote location \textbf{origin}.
We are going to spend a little while now learning about remote branches and how they differ to local branches.
Let us spend a few minutes trying some of our normal operations against a remote branch.
The first operation we are going to try is a diff.
We are going to run a diff between our current \textbf{master} branch and the \textbf{wonderful} branch as it stands in the original repository, so we should be diffing between \texttt{master} and \texttt{origin/wonderful}.
For brevity, we are also going to limit the changes shown to those which affect \texttt{newfile1} only, by appending \texttt{ -- <filename>} to the command.
\begin{code}
john@satsuki:~/coderepo-cl$ git diff master origin/wonderful -- newfile1
diff --git a/newfile1 b/newfile1
index f32a0e6..ef20984 100644
--- a/newfile1
+++ b/newfile1
@@ -1,3 +1,2 @@
A new file
-and some more awesome changes
-Some mega important changes
+and some more changes
john@satsuki:~/coderepo-cl$
\end{code}
So we can see that our diff command completed successfully.
Note that this command requires no connection to our \textbf{origin} repository, as all of the data has been cloned locally, more on this later.
Let us run another command now and learn a little more about what the remote reference \textbf{origin} really means.
\begin{code}
john@satsuki:~/coderepo-cl$ git remote show origin
* remote origin
Fetch URL: /home/john/coderepo
Push URL: /home/john/coderepo
HEAD branch: master
Remote branches:
master tracked
wonderful tracked
zaney tracked
Local branch configured for 'git pull':
master merges with remote master
Local ref configured for 'git push':
master pushes to master (up to date)
john@satsuki:~/coderepo-cl$
\end{code}
Though this command introduces some terms that we are not yet familiar with yet, like push, pull and fetch, we can see that the \textbf{origin} remote has been set up to \emph{track} three branches called, \textbf{master}, \textbf{wonderful} and \textbf{zaney}.
So although these branches are not yet usable in the way a local branch would be, it is comforting to know that Git does know about them.
Let us continue playing with the remote branch and run a \texttt{git log} command against it.
\begin{code}
john@satsuki:~/coderepo-cl$ git log origin/master -- newfile1
commit 9cb2af2a00fd2253060e6bf8cc6c377b3d55ecea
Author: John Haskins <[email protected]>
Date: Tue Apr 19 16:43:59 2011 +0100
Important Update
commit d50ffb2fa536d869f2c4e89e8d6a48e0a29c5cc1
Merge: ed2301b 7cc32db
Author: John Haskins <[email protected]>
Date: Fri Apr 1 07:42:04 2011 +0100
Merged in zaney
...
...
...
\end{code}
Again, this requires no connection to the \textbf{origin} repository at all and works as expected.
Let us try something really funky now, let us try checking out a remote branch so that we can view the file system.
We are now going to try checking out the remote branch called \textbf{wonderful}.
\begin{code}
john@satsuki:~/coderepo-cl$ git checkout origin/wonderful
Note: checking out 'origin/wonderful'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:
git checkout -b new_branch_name
HEAD is now at cfbecab... Fantastic new feature
john@satsuki:~/coderepo-cl$
\end{code}
\index{dangling}Interesting.
This is not what we are used to seeing.
When we have checked out branches before, we have always been presented with a \texttt{Switched to branch 'xxxxxx'} message.
Now we are seeing a funny message about having a detached HEAD.
This is because we are not actually on a branch.
We can make changes as we are advised, we can even make commits, but these will not actually become integrated into any branches.
In essence these commits would be left dangling and after time, because no branch points to them, they would get deleted by garbage collection routines.
Running the \texttt{git branch} command below confirms our suspicions.
\begin{code}
john@satsuki:~/coderepo-cl$ git branch -v
* (no branch) cfbecab Fantastic new feature
master 37950f8 Continued Development
john@satsuki:~/coderepo-cl$
\end{code}
\index{branching!tracking}So we really need to figure out how to make these branches exist locally so that we can commit to them and retain those commits.
To do this we use the \texttt{git branch} tool again, but we use it in a slightly different manner.
\begin{code}
john@satsuki:~/coderepo-cl$ git checkout -b wonderful origin/wonderful
Branch wonderful set up to track remote branch wonderful from origin.
Switched to a new branch 'wonderful'
john@satsuki:~/coderepo-cl$
\end{code}
We are now on a local instance of the \textbf{wonderful} branch.
Let us take a minute to understand what that means.
As Git is a distributed environment, our local \textbf{wonderful} branch, is not going to be synchronised with the remote end automatically.
It would require effort on our part.
What this does mean though, is that we are able to begin committing to this branch and experimenting with it.
\section{Day 4 - ``Help I'm no longer up to date?''}
\subsection{Pulling changes, not teeth}
With a remote tracking branch, we can pull in the changes from the remote repository.
In our case, the remote repository is in the \texttt{coderepo} directory that we created at the start of the book.
In the \texttt{coderepo-cl} directory we have a separate, self-contained copy of the repository.
At the moment, because no changes have occurred to either, they contain exactly the same data.
By running the \texttt{git remote} tool again, we can see which branches are set up locally to track their remote counterparts in \textbf{origin}.
\begin{code}
john@satsuki:~/coderepo-cl$ git remote show origin
* remote origin
Fetch URL: /home/john/coderepo
Push URL: /home/john/coderepo
HEAD branch: master
Remote branches:
master tracked
wonderful tracked
zaney tracked
Local branches configured for 'git pull':
master merges with remote master
wonderful merges with remote wonderful
Local refs configured for 'git push':
master pushes to master (up to date)
wonderful pushes to wonderful (up to date)
john@satsuki:~/coderepo-cl$
\end{code}
What we are going to do now is make some changes to our original repository and see how we can view those changes and indeed pull them into our current local working repository, or clone.
Note that in the following code examples we have switched back to working on our original repository, in the \texttt{coderepo} folder.
\begin{code}
john@satsuki:~/coderepo-cl$ cd ../coderepo
john@satsuki:~/coderepo$ git branch
* master
wonderful
zaney
john@satsuki:~/coderepo$ git checkout wonderful
Switched to branch 'wonderful'
john@satsuki:~/coderepo$ git merge master
Updating cfbecab..37950f8
Fast-forward
another_file | 1 +
my_third_committed_file | 1 -
newfile1 | 3 ++-
newfile2 | 2 +-
4 files changed, 4 insertions(+), 3 deletions(-)
delete mode 100644 my_third_committed_file
john@satsuki:~/coderepo$ echo "These changes are in the origin" >> newfile3
john@satsuki:~/coderepo$ git add newfile3
john@satsuki:~/coderepo$ git commit -a -m 'Added a new file'
[wonderful 1c3206a] Added a new file
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 newfile3
john@satsuki:~/coderepo$
\end{code}
As you can see, we have switched back to working on our old \textbf{origin} and have bought \textbf{wonderful} to be in line with master and have added a new file and committed the changes.
Now let us go back to our clone and see if we can see those changes.
\begin{code}
john@satsuki:~/coderepo$ cd ../coderepo-cl/
john@satsuki:~/coderepo-cl$ git diff wonderful origin/wonderful
john@satsuki:~/coderepo-cl$
\end{code}
That seems a little odd at first glance.
We have tried to view a diff between our local \textbf{wonderful} branch and the remote \textbf{origin/wonderful} branch.
Interestingly, Git is telling us that there is no difference.
Hang on though, we just made some changes above.
Remember before we discussed the fact that our clone was disconnected from the \textbf{origin} copy? What this means is that unless we ask Git, it won't update details about what is present in the remote copy.
Once this is up to date, we can pull the changes into our local copy of the remote branch? Interestingly there are actually two ways to do this.
\index{branching!updating remote}The first method is by running a \indexgit{pull} command.
If you remember the output from the \texttt{git remote show origin}, you may remember that it showed that there was a local branch configured for \texttt{'git pull'} and the details it gave for the \textbf{wonderful} branch were as follows; \texttt{wonderful merges with remote wonderful}.
What this means, is that when we run a \texttt{git pull} from inside the \textbf{wonderful} branch, Git will automatically contact the remote repository, update the list of changes and merge them into the local branch if possible.
We mentioned that there were two methods to perform the procedure.
Whilst the first one is to use \texttt{git pull}, the second one actually achieves an almost identical result, but by running two commands instead of one.
In point of fact, these two commands are executed by the \texttt{git pull} command.
Running them as two separate commands allows us to understand a little more about what is happening.
Let us run the command and then explain what we have done.
\begin{code}
john@satsuki:~/coderepo-cl$ git fetch origin
remote: Counting objects: 4, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From /home/john/coderepo
cfbecab..1c3206a wonderful -> origin/wonderful
john@satsuki:~/coderepo-cl$ git diff wonderful origin/wonderful
diff --git a/another_file b/another_file
index dba885d..b3a5cc5 100644
--- a/another_file
+++ b/another_file
@@ -1 +1,2 @@
New stuff
+Number strings rule 1234
...
...
...
john@satsuki:~/coderepo-cl$ git merge origin/wonderful
Updating cfbecab..1c3206a
Fast-forward
another_file | 1 +
my_third_committed_file | 1 -
newfile1 | 3 ++-
newfile2 | 2 +-
newfile3 | 1 +
5 files changed, 5 insertions(+), 3 deletions(-)
delete mode 100644 my_third_committed_file
create mode 100644 newfile3
john@satsuki:~/coderepo-cl$
\end{code}
As you can see, the two commands that we used were \indexgit{fetch} and the more familiar \texttt{git merge}.
The \texttt{git fetch} command literally visits the remote repository, in our case we asked for \textbf{origin}, and finds which objects are new
and do not exist in our local clone.
These are then copied to the local clone, and the HEADs of the various remote branches are updated.
We now rerun our \texttt{git diff}, only this time, we see a great many more changes than before.
Finally we initiate a \texttt{git merge} to pull the changes from the now up to date remote branch to our local one.
We could have used the \texttt{git pull} command here, and if we had supplied no parameters to it, it would have achieved the exact same outcome.
The only difference would have been running one command instead of two.
Please note, that there are occasions when you would require one over the other, but as an introduction, this should be sufficient.
\section{Day 5 - ``I'm putting my foot down''}
\subsection{Pushing back!}
We now know a lot about remote locations right? We are ready to start collaborating with someone.
Let us first see how Tamagoyaki are getting on with things.
\begin{trenches}
``But I know I have the remote right Simon, it's giving some weird error about refusing to update it.''
Rob was getting more than a little cross now.
``Maybe you got the command wrong?'' asked Simon.
Rob slammed his hands down on the keyboard,
``Well then you come over here and type it, but I don't understand how hard it is to write git push.''
He shook his head, ``I even checked using the git remote tool and the push is apparently all set up.''
``Are you trying to push to a non-bare repository?'' Chirped Klaus.
He had been listening to the discussion escalate from mild annoyance to key shattering intrusion.
``You can't push to a non-bare repository, else everything gets out of sync.''
``What do you mean bare?'' asked Rob.
Klaus smiled and his head appeared over the cubicle.
``Come over here genius and I'll show you,'' he said with the slightest amount of gloat at being one of the only people to know something about Git that Rob didn't.
\end{trenches}
\index{bare repository}\index{non-bare repository}\index{pushing}Bare? Non-bare? At first glance, this may seem confusing.
It isn't exactly an intuitive word to describe a repository but what Klaus mentioned was absolutely true.
In Git, if you want to push changes back to a repository, instead of pulling them, the repository that you push to should be what is called a \emph{bare} repository.
What this means is that the repository has no working copy.
\begin{callout}{Note}{Pushing to a non-bare repository}
As mentioned, pushing to a non-bare repository is not a good idea.
When you push to a repository, you update the objects in the objects database.
This will affect commits, blobs and trees.
We should make a distinction here.
We are really only worried about pushing to a branch which is currently checked out.
Pushing to a non-bare repository will mean that the index will get changed, as it should reflect what the branch looks like at HEAD.
\newline
\newline
Now this causes a problem when we are trying to see what has been modified in the working directory when compared to the HEAD.
As our working copy will contain older versions of the files than are in the index, it will appear as if many more changes have occurred and we risk undoing those changes.
For these reasons, it is much simpler just to push only to bare repositories.
\end{callout}
At first glance this may seem like a rather odd thing to want.
Why would we want a repository that doesn't have a working tree? The simple answer is that a \emph{bare} repository allows us to be able to push changes into it.
Let us recreate the error message that Rob was talking about.
\begin{code}
john@satsuki:~/coderepo-cl$ echo "This is another update to newfile3" >> newfile3
john@satsuki:~/coderepo-cl$ git commit -a -m 'Added more to newfile3'
[wonderful dbf1e9a] Added more to newfile3
1 files changed, 1 insertions(+), 0 deletions(-)
\end{code}
We have made a modification to the \textbf{wonderful} branch.
So let us now try to push that back to the \textbf{origin} remote repository with the \indexgit{push} command.
\begin{code}
john@satsuki:~/coderepo-cl$ git push
Counting objects: 5, done.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 335 bytes, done.
Total 3 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
remote: error: refusing to update checked out branch: refs/heads/wonderful
remote: error: By default, updating the current branch in a non-bare repository
remote: error: is denied, because it will make the index and work tree inconsistent
remote: error: with what you pushed, and will require 'git reset --hard' to match
remote: error: the work tree to HEAD.
remote: error:
remote: error: You can set 'receive.denyCurrentBranch' configuration variable to
remote: error: 'ignore' or 'warn' in the remote repository to allow pushing into
remote: error: its current branch; however, this is not recommended unless you
remote: error: arranged to update its work tree to match what you pushed in some
remote: error: other way.
remote: error:
remote: error: To squelch this message and still keep the default behaviour, set
remote: error: 'receive.denyCurrentBranch' configuration
remote: error: variable to 'refuse'.
To /home/john/coderepo
! [remote rejected] wonderful -> wonderful (branch is currently checked out)
error: failed to push some refs to '/home/john/coderepo'
john@satsuki:~/coderepo-cl$
\end{code}
Bingo! There is the error we were looking for.
In order to get round this, we are going to create another clone of the repository in \texttt{coderepo}.
This time however, we are going to pass an option to it when we create it.
\begin{code}
john@satsuki:~/coderepo-cl$ cd ..
john@satsuki:~$ git clone coderepo coderepo-bk --bare
Initialized empty Git repository in /home/john/coderepo-bk/
john@satsuki:~$ cd coderepo-bk/
john@satsuki:~/coderepo-bk$ ls
branches config description HEAD hooks info objects
packed-refs refs
john@satsuki:~/coderepo-bk$ cd ..
john@satsuki:~$ cd coderepo-cl/
john@satsuki:~/coderepo-cl$
\end{code}
As you can see, creating the clone with the \texttt{--bare} option has had a definite effect on the structure of the clone itself.
In fact, the contents of the \texttt{coderepo-bk} folder look remarkably similar to the \texttt{.git} folder found in our normal working tree.
They are in fact, one and the same.
We have removed the need for a separate \texttt{.git} folder because we do not require a working tree.
Therefore, the contents of the \texttt{.git} folder and placed in the root \texttt{coderepo-bk} folder.
\index{remote!adding}We are getting closer to making our push.
We have created a \emph{bare} repository, which we should now be able to push to.
The problem is, we have not yet defined our new repository as a remote location in the \texttt{coderepo-cl} repository.
This is something we will do now and to do this, we will use our \texttt{git remote} tool once more, this time employing the \texttt{add} parameter.
\begin{code}
john@satsuki:~/coderepo-cl$ git remote add backup
/home/john/coderepo-bk
john@satsuki:~/coderepo-cl$ git remote show backup
* remote backup
Fetch URL: /home/john/coderepo-bk
Push URL: /home/john/coderepo-bk
HEAD branch: wonderful
Remote branches:
master new (next fetch will store in remotes/backup)
wonderful new (next fetch will store in remotes/backup)
zaney new (next fetch will store in remotes/backup)
Local refs configured for 'git push':
master pushes to master (up to date)
wonderful pushes to wonderful (fast-forwardable)
john@satsuki:~/coderepo-cl$
\end{code}
We have created a remote called backup.
As you can see, some interrogation of the remote repository has taken place.
It is already aware of the branches present in our remote location.
Let us do a \texttt{git fetch} to update the local references.
\begin{code}
john@satsuki:~/coderepo-cl$ git fetch backup
From /home/john/coderepo-bk
* [new branch] master -> backup/master
* [new branch] wonderful -> backup/wonderful
* [new branch] zaney -> backup/zaney
john@satsuki:~/coderepo-cl$ git remote show backup
* remote backup
Fetch URL: /home/john/coderepo-bk
Push URL: /home/john/coderepo-bk
HEAD branch: wonderful
Remote branches:
master tracked
wonderful tracked
zaney tracked
Local refs configured for 'git push':
master pushes to master (up to date)
wonderful pushes to wonderful (fast-forwardable)
john@satsuki:~/coderepo-cl$
\end{code}
Now we can see that all of the remote references for our \textbf{backup} remote have been updated.
If we run a diff against our local \textbf{wonderful} branch and the remote branch \textbf{backup/wonderful}, we can see the differences.
\begin{callout}{Note}{Pushing your tags}
By default tags are not pushed when using the \texttt{git push} command.
If we want our tags to be push to the remote repository as well, we need to append the \texttt{--tags} parameter to the \texttt{git push} command.
\newline
\newline
In contrast, using \texttt{git pull} will automatically pull down any tags which refer to any objects that have been pulled.
This behaviour can be overridden by using the \texttt{--no-tags} parameter with \texttt{git pull}.
\end{callout}
\begin{code}
john@satsuki:~/coderepo-cl$ git diff wonderful backup/wonderful
diff --git a/newfile3 b/newfile3
index 7268b97..638113c 100644
--- a/newfile3
+++ b/newfile3
@@ -1,2 +1 @@
These changes are in the origin
-This is another update to newfile3
john@satsuki:~/coderepo-cl$ git branch -v
\end{code}
There we go! Those are the changes we just committed to the local repository.
The last thing we need to do is to initiate a \texttt{git push}.
We are going to have to define which remote we wish to push to now for two reasons.
The first is that now we have two remotes, and so Git would not know if we meant \textbf{origin} or \textbf{backup}.
The second reason is that by default, the \textbf{wonderful} branch is set up to push to the \textbf{origin} remote.
\begin{code}
john@satsuki:~/coderepo-cl$ git push backup
Counting objects: 5, done.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 335 bytes, done.
Total 3 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
To /home/john/coderepo-bk
1c3206a..dbf1e9a wonderful -> wonderful
john@satsuki:~/coderepo-cl$
\end{code}
There we go, we have now managed to push our changes to a remote location.
In this case, we have pushed an update from the \textbf{wonderful} branch to the \textbf{backup/wonderful branch}.
If we wanted to, we could have pushed our repository to a new branch name, or indeed any of the existing branch names.
\begin{code}
john@satsuki:~/coderepo-cl$ git push backup wonderful:newbranch
Total 0 (delta 0), reused 0 (delta 0)
To /home/john/coderepo-bk
* [new branch] wonderful -> newbranch
john@satsuki:~/coderepo-cl$ git remote show backup
* remote backup
Fetch URL: /home/john/coderepo-bk
Push URL: /home/john/coderepo-bk
HEAD branch (remote HEAD is ambiguous, may be one of the following):
newbranch
wonderful
Remote branches:
master tracked
newbranch tracked
wonderful tracked
zaney tracked
Local refs configured for 'git push':
master pushes to master (up to date)
wonderful pushes to wonderful (up to date)
john@satsuki:~/coderepo-cl$
\end{code}
By specifying the local and remote branch using the \texttt{local:remote} syntax, we have told Git to push our local \textbf{wonderful} branch to the remote branch called \textbf{newbranch}.
As the \textbf{newbranch} did not exist in the remote \textbf{backup} repository, it was created, as can be seen above.
\begin{callout}{Note}{Killing a remote branch}
Now that we have made branches on the remote end, it is a good idea to know how to delete them also.
After all, if all you ever did was push new branches, pretty soon you may end up with a lot of rubbish in your repository.
To delete a remote branch, all that you need to do is to use the following syntax.
\begin{code}
git push <remote> :<branchname>
\end{code}
Notice that we are using the same syntax as before, but not specifying a local branch name, just the remote.
Git interprets this as a call to delete the remote branch.
If you have a clone of a remote repository and a remote branch is removed, you may see a message like the following if you run \texttt{git remote show <remote>};
\begin{code}
refs/remotes/<remote>/<branchname> stale (use 'git remote prune' to remove)
\end{code}
So we can run \index{remote!pruning}\texttt{git remote prune} to remove local references to remote branches that no longer exist.
If you have created a tracking branch of this remote branch, this will remain unaffected.
\end{callout}
So this ends the Week.
We have learnt a lot more about how to play with branches and remotes.
In the \emph{After Hours} section, we will take a deeper look at remote branches and how they are configured and represented in Git.
\clearpage
\section{Summary - John's Notes}
\subsection{Commands}
\begin{itemize}
\item\texttt{git stash} - Short for \texttt{git stash save}, creates a stash of local modifications
\item\texttt{git stash apply <stash\_name>} - Applies a stash back onto a branch
\item\texttt{git stash drop <stash\_name>} - Remove a stash from the stash list
\item\texttt{git stash list} - Show a list of current stashes
\item\texttt{git stash show <stash\_name>} - Show information about a specific stash
\item\texttt{git stash show <stash\_name> -p} - Show the contents of a stash
\item\texttt{git clone <local> <remote>} - Clone a Git repository, from the local to the remote location.
\item\texttt{git branch -r} - Show all remote branch references
\item\texttt{git remote} - Show a list of remote repositories
\item\texttt{git remote -v} - Show a more detailed list of remote repositories
\item\texttt{git diff <branch> <remote>/<branch> -- <file>} - Show the differences between the two branches, one local, one remote, for a particular file.
\item\texttt{git remote show <remote>} - Show detailed information about tracked branches for the specified remote repository
\item\texttt{git log <remote>/<branch> -- <file>} - Show the log of the remote branch specified for a particular file
\item\texttt{git checkout <remote>/<branch>} - Checkout a remote branch, leaving the local working tree in a detached HEAD state
\item\texttt{git checkout -b <branch> <remote>/<branch>} - Create and switch to a new branch, which is set up to track a remote branch specified
\item\texttt{git fetch <remote>} - Fetch updates to the remote branch specified including all objects and branches
\item\texttt{git pull} - When configured, fetches and merges a remote branch into the currently checked out branch.
\item\texttt{git clone <local> <remote> --bare} - Creates a bare repository, suitable for pushing into
\item\texttt{git push} - When configured, pushes all changes up to the configured remote branch
\item\texttt{git push <remote> <local\_brch>:<remote\_brch>} - Pushes a local branch to a remote location with a different name
\end{itemize}
\subsection{Terminology}
\begin{itemize}
\index{Terminology!Stash}\item\textbf{Stash} - A temporary storage of local modifications that can be brought back onto the branch at a later date
\index{Terminology!Remote}\item\textbf{Remote} - A copy of a repository, or part of a repository in a remote location
\index{Terminology!Pull}\item\textbf{Pull} - Merging changes from a remote branch into a current local one
\index{Terminology!Push}\item\textbf{Push} - Pushing changes from a local branch into a remote one
\index{Terminology!Fetch}\item\textbf{Fetch} - Pull into the local repository, all new objects and update all branch HEADs to point to the same commits as the remote location
\end{itemize}