-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathgit_walk_through.Rmd
589 lines (440 loc) · 15 KB
/
git_walk_through.Rmd
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
---
jupyter:
jupytext:
text_representation:
extension: .Rmd
format_name: rmarkdown
format_version: '1.2'
jupytext_version: 1.11.5
prereqs:
- pathlib
---
# Git walk-through
## Basic configuration
We need to tell git about us before we start. This stuff will go into
the commit information by default.
```
$ git config --global user.name "Matthew Brett"
$ git config --global user.email "[email protected]"
```
Git often needs to call up a text editor. We will use Nano as our text editor
(see [associating text editors with
git](https://help.github.com/articles/associating-text-editors-with-git)):
```
$ git config --global core.editor "nano"
```
We also turn on the use of color, which is very helpful in making the output of
git easier to read:
```
$ git config --global color.ui "auto"
```
## Getting help
```
$ git
usage: git [--version] [--help] [-C <path>] [-c <name>=<value>]
[--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
[-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare]
[--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
[--super-prefix=<path>] [--config-env=<name>=<envvar>]
<command> [<args>]
These are common Git commands used in various situations:
start a working area (see also: git help tutorial)
clone Clone a repository into a new directory
init Create an empty Git repository or reinitialize an existing one
work on the current change (see also: git help everyday)
add Add file contents to the index
mv Move or rename a file, a directory, or a symlink
restore Restore working tree files
rm Remove files from the working tree and from the index
sparse-checkout Initialize and modify the sparse-checkout
examine the history and state (see also: git help revisions)
bisect Use binary search to find the commit that introduced a bug
diff Show changes between commits, commit and working tree, etc
grep Print lines matching a pattern
log Show commit logs
show Show various types of objects
status Show the working tree status
grow, mark and tweak your common history
branch List, create, or delete branches
commit Record changes to the repository
merge Join two or more development histories together
rebase Reapply commits on top of another base tip
reset Reset current HEAD to the specified state
switch Switch branches
tag Create, list, delete or verify a tag object signed with GPG
collaborate (see also: git help workflows)
fetch Download objects and refs from another repository
pull Fetch from and integrate with another repository or a local branch
push Update remote refs along with associated objects
'git help -a' and 'git help -g' list available subcommands and some
concept guides. See 'git help <command>' or 'git help <concept>'
to read about a specific subcommand or concept.
See 'git help git' for an overview of the system.
```
Try `git help add` for an example.
## Initializing the repository
We first make a new empty directory that will be version controlled with git.
Create the git repository:
```
$ mkdir our_work
$ cd our_work
$ git init
Initialized empty Git repository in /Volumes/zorg/mb312/dev_trees/psych-214-fall-2016/working/our_work/.git/
hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint:
hint: git config --global init.defaultBranch <name>
hint:
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
hint: 'development'. The just-created branch can be renamed via this command:
hint:
hint: git branch -m <name>
```
Show the new `.git` directory:
```
$ ls .git
HEAD
config
description
hooks
info
objects
refs
```
There are only a couple of empty sub-directories in the `.git/objects`
directory:
```
$ ls .git/objects/*
.git/objects/info:
.git/objects/pack:
```
## git add - put stuff into the staging area
Type this file in Atom and save:
Add to the staging area:
```
$ git add our_paper.txt
```
<!-- git rev-parse :our_paper.txt -->
Check we added the file to the staging area:
```
$ git status
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: our_paper.txt
```
Show yourself there is a new sub-directory and file in `.git/objects`:
```
$ ls .git/objects/*
```
## Looking at real git objects
Now we’re going to read the new object in Python, and find the hash of its
contents. You don’t need to do this kind of thing to use git. This is to
practice some Python, and to show you how git stores its files.
To read the new object, you’ll need a few new bits of Python.
Here’s how to read the binary contents of a whole file into memory:
```{python}
# Read binary content from a file with Pathlib
from pathlib import Path
contents = Path('our_paper.txt').read_bytes()
type(contents)
```
Here’s how to calculate the SHA1 hash value for the file contents:
```{python}
# Import the Python module that calculates hash values
import hashlib
# Generate the SHA1 hash string for these bytes
hashlib.sha1(contents).hexdigest()
```
This is the same value as the terminal command `shasum` calculates on a
file:
```
$ shasum our_paper.txt
cb083f8092a8bfbe55a215e1b45e9f33b9dec86f our_paper.txt
```
The new file in `.git/objects` is *compressed* using a program called
`zlib`. To un-compress some bytes that have been compressed with `zlib`,
use the `decompress` function in the Python `zlib` module:
```{python}
import zlib
zlib.decompress
```
<!-- echo "function sha_fname { echo \${1:0:2}/\${1:2}; }; sha_fname " -->
<!-- fname=$({{ sha_fname }} {{ our_paper_1_hash }})
echo ".git/objects/$fname" -->
Now – what is the *decompressed* contents of the new `.git/objects` file?
Do you recognize it? What is the SHA1 hash of the decompressed contents? Do
you recognize that?
You should start with something like:
```python
from pathlib import Path
pth = Path('.git/objects/d6/05b79accc16319ffe95fdc0a7992e830695c1c')
contents = pth.read_bytes()
```
where `.git/objects/d6/05b79accc16319ffe95fdc0a7992e830695c1c` is the new file
that appeared in your `.git/objects` directory when you staged `our_paper.txt`.
When you are done, have a look at the solution in: [reading git objects](https://matthew-brett.github.io/curious-git/reading_git_objects.html).
## Make a first commit
Remember what will go into this commit:
```
$ git status
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: our_paper.txt
```
Make the commit:
```
$ git commit
```
<!-- $ git commit -m "First version of the paper"
[master (root-commit) 8d1e37f] First version of the paper
1 file changed, 1 insertion(+)
create mode 100644 our_paper.txt
-->
Review what you have so far in your history:
```
$ git log
```
Show what branch you are on, with the hash of the current commit:
```
$ git branch -v
```
## Edit again, check and commit
Edit the paper file again to add some text:
Check the difference between what you had before and what you have now:
```
$ git diff
```
Add the changes to the staging area:
```
# What goes here?
```
<!-- $ git add our_paper.txt
-->
Our customary check:
```
$ git status
```
Make the commit:
```
$ git commit
```
<!-- $ git commit -m "Second version of the paper"
[master cece131] Second version of the paper
1 file changed, 2 insertions(+)
-->
Look at the project history again:
<!-- $ git log
commit cece1310670982408d91bd645b67ec45ddb9c75f
Author: Matthew Brett <[email protected]>
Date: Thu Sep 15 14:35:13 2016 +0100
Second version of the paper
commit 8d1e37fdcefe90487c577435b1fa6ccb70d1ff07
Author: Matthew Brett <[email protected]>
Date: Thu Sep 15 14:30:13 2016 +0100
First version of the paper
-->
Check the parent hashes recorded in each commit. How?:
```
# Check the parents
```
Check which hash the default branch is pointing to now:
```
$ git branch -v
```
## A new file
Make a new file like this:
Check the status of the file.
Add the file to the staging area.
Make a commit.
<!-- $ git add our_analysis.py
-->
<!-- $ git commit -m "Add analysis"
[master 73f471c] Add analysis
1 file changed, 4 insertions(+)
create mode 100644 our_analysis.py
-->
## A prettier log command
```
$ git config --global alias.slog "log --oneline --graph"
```
```
$ git slog
* 73f471c Add analysis
* cece131 Second version of the paper
* 8d1e37f First version of the paper
```
## Thinking about objects again
See if you can guess how many files there are now in `.git/objects`.
What do these objects store?
If you have the hash of an object, you can check the contents with `git
cat-file -p` followed by the first 7 digits of the hash value – e.g.
<!-- echo "function sha_7 { echo \${1:0:7}; }; sha_7 " -->
<!-- {{ sha_7 }} {{ our_paper_1_hash }} -->
```
$ git cat-file -p d605b79
This is the first sentence of the new paper.
```
See if you can find the hash of the object corresponding to the directory
listing for our most recent commit, and display its contents. Hint: Find the
hash for the current commit message. Try displaying the contents for the
current commit message.
## Moving files
Try moving a file (renaming) using `git mv`:
```
$ git mv our_analysis.py our_first_analysis.py
```
Check the status. Do you need to add anything to the staging area?
Make a commit.
Now you have made a commit, check the new directory listing for our latest
commit. What changed?
<!-- $ git commit -m "Move analysis file"
[master 201f081] Move analysis file
1 file changed, 0 insertions(+), 0 deletions(-)
rename our_analysis.py => our_first_analysis.py (100%)
-->
## Making a new branch
Make a new branch with:
```
$ git branch work-from-home
```
Use `git branch -v` to check the hash that this new branch points to.
Have a look at the file `.git/HEAD`. What is it telling us?
Tell git to start working on the new branch instead of our previous branch:
```
$ git checkout work-from-home
Switched to branch 'work-from-home'
```
Have a look at `git branch -v` again. What changed? How about the file
`.git/HEAD`?
<!-- $ echo "" >> our_paper.txt
$ echo "The third sentence starts the crescendo." >> our_paper.txt
-->
Now see if you can replicate the following changes to `our_paper.txt`:
```
diff --git a/our_paper.txt b/our_paper.txt
index d18df62..75fe792 100644
--- a/our_paper.txt
+++ b/our_paper.txt
@@ -1,3 +1,5 @@
This is the first sentence of the new paper.
Crucially, this is the second sentence.
+
+The third sentence starts the crescendo.
```
Your job is to make the output from `git diff` look the same as the output
above.
When you’ve finished, add the changes to the staging area and then commit.
<!-- $ git add our_paper.txt
-->
<!-- $ git commit -m "Move analysis file"
[work-from-home 0adaaf7] Move analysis file
1 file changed, 2 insertions(+)
-->
Check where you are with `git slog`, and `git branch -v`.
Now go back to your previous branch, called `master`:
```
$ git checkout master
Switched to branch 'master'
```
Create this data file, add it to the staging area and commit.
<!-- $ git add our_data.csv
-->
<!-- $ git commit -m "Add data file"
[master 2ff3b13] Add data file
1 file changed, 3 insertions(+)
create mode 100644 our_data.csv
-->
## Merging
Now we want to merge the work from the `work-from-home` branch. Put another
way, we want to merge the `work-from-home` branch into our current branch,
`master`. What git command would do this action? Scan the output of `git
help` for clues, then `git help <command>` when you’ve found the command
you need.
Do the merge.
<!-- $ git merge work-from-home
Merge made by the 'recursive' strategy.
our_paper.txt | 2 ++
1 file changed, 2 insertions(+)
-->
Check the output of `git branch -v` again.
Have a look at the output of `git slog`.
What do you see with `git log --parents`?
## Conflicts
The merge that you just did should have been simple, with no conflicts.
Conflicts can occur when you have made changes to the same file on two
different branches, and you try and merge them. If the changes are on or near
the same lines in the file, git will complain and ask you to work out which
changes you want to keep.
Make and checkout a new branch `asking-for-trouble`.
<!-- $ git branch asking-for-trouble
$ git checkout asking-for-trouble
$ echo "" >> our_paper.txt
$ echo "Fourth sentence gets to the point." >> our_paper.txt
$ git add our_paper.txt
$ git commit -m "Advocate the fourth"
[asking-for-trouble 13fcdf7] Advocate the fourth
1 file changed, 2 insertions(+)
Switched to branch 'asking-for-trouble'
-->
Edit `our_paper.txt` and add a sentence like “Fourth sentence gets to the
point.” Add to the staging area and then commit.
Checkout the `master` branch again.
Edit `our_paper.txt` and add a sentence like “Fourth sentence is still
warm-up.” Add to the staging area and commit.
<!-- $ git checkout master
$ echo "" >> our_paper.txt
$ echo "Fourth sentence is still warm-up." >> our_paper.txt
$ git add our_paper.txt
$ git commit -m "Nay-say the fourth"
[master 57afaba] Nay-say the fourth
1 file changed, 2 insertions(+)
Switched to branch 'master'
-->
Now try merging the `asking-for-trouble` branch into our current
(`master`) branch. What do you see?
<!-- $ git merge asking-for-trouble
Auto-merging our_paper.txt
CONFLICT (content): Merge conflict in our_paper.txt
Automatic merge failed; fix conflicts and then commit the result.
-->
When the merge failed, git wrote some text into the file where the changes
clash. `our_paper.txt` might look like this:
```
This is the first sentence of the new paper.
Crucially, this is the second sentence.
The third sentence starts the crescendo.
<<<<<<< HEAD
Fourth sentence is still warm-up.
=======
Fourth sentence gets to the point.
>>>>>>> asking-for-trouble
```
The lines between `<<<<<<< HEAD` and `=======` are the changed lines from
the branch we are merging *into* (`master` in our case). The lines between
`=======` and `>>>>>>> asking-for-trouble` are the changes from the branch
we are merging (`asking-for-trouble` in our case).
Open the `our_paper.txt` file and remove the new marker lines in the text.
Choose how you’d like to combine your two different changes to the file. When
the file is ready, save it, then add it to the staging area and do a commit.
Check all is well with `git slog`.
<!-- $ cat << EOF > our_paper.txt
$ This is the first sentence of the new paper.
$
$ Crucially, this is the second sentence.
$
$ The third sentence starts the crescendo.
$
$ Fourth sentence is still warm-up, then gets to the point.
$ EOF
$ git add our_paper.txt
$ git commit -m "Resolve conflict"
[master f4a7ae3] Resolve conflict
-->
## The end
Congratulations! You now know the basics of working with a single git
repository.