-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgit_basics.qmd
More file actions
576 lines (400 loc) · 18.1 KB
/
git_basics.qmd
File metadata and controls
576 lines (400 loc) · 18.1 KB
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
---
title: "Setting up & using git"
---
This session will cover:
- Setting up `git` on your computer
- Installing git
- Setting up your identity
- Basic git workflow
- Cloning a repository from GitHub
- Tracking changes: staging and committing files
- Inspecting changes with `git diff` and `git log`
- Restoring previous versions of a file
# Setting up git on your computer
`MacOSX` and `Linux` computers all come with git pre-installed, but it is not always directly usable. The best way to test if `git` is ready to use is at the command line:
```bash
git --version
# git version 2.39.3
```
It should return something like above. **If you get an error, you will have to install git**
## Installing git
You can download and install `git` from here: [https://git-scm.com/install/](){target="_blank"} and follow the instructions according to your Operating System.
Depending on your OS, you might have to follow different steps to install `git` on your computer:
::: {.panel-tabset}
## {{< bi windows >}} Windows
You can keep the options to default during the installation, until you reach `Configuring the terminal emulator to use with Git Bash` -> be sure `Use MinTTY` is selected. This will install both git and a set of useful command-line tools using a trimmed down Bash shell.
## {{< bi apple >}} Mac OSX
Depending on the version, you might have to run a few commands from the terminal. Please refer to the `README.txt` that comes with the download regarding the exact steps to follow.
:::
## Setting up your `git` identity
Before you start using git on any computer, you should set your identity on your system, as every snapshot of files is associated with the user who implemented the modifications to the file(s).
Open the `Terminal` or `git bash` and then type the following commands.
### Setup your profile
#### At the command line
If you are not sure if you have already set your git identity you can check this running this command:
```bash
git config --global --list
```
If your identity is not set yet, you need to provide your name and email (we recommend to use the same email as used when setting your GitHub account):
```bash
git config --global user.name "your Full Name"
git config --global user.email "your Email"
```
::: {.callout-note collapse="true"}
## Optional: additional `git config` commands
Edit your git config file directly in your text editor:
```bash
git config --global --edit
```
Set your default text editor (e.g. [`nano`](https://www.nano-editor.org){target="_blank"}, `notepad`, `code`, etc.):
```bash
git config --global core.editor nano
```
::: {.callout-tip}
## Text editor for Windows users
Outside of Git Bash, `notepad` is a good default:
```bash
git config --global core.editor notepad
```
:::
:::
::: {.callout-caution}
# Problem with any of those steps?
Check out Jenny Brian [Happy git trouble shooting section](http://happygitwithr.com/troubleshooting.html){target="_blank"}
:::
## Clone a repository
::: {.callout-tip}
If you do not have your `favorite-desserts` GitHub repository, please follow those [steps](handson_github_website.qmd)
:::
Navigate to the folder (e.g `cd ~/Documents`) where you want to save your repository and run the following command (replace `<your-github-username>` with your actual GitHub username):
```bash
git clone https://github.com/<your-github-username>/favorite-desserts.git
```
You should have a new folder on your local machine named favorite-desserts after your repository :
```bash
ls
```
Go inside the repository:
```bash
cd favorite-desserts
ls -al
```
::: {.callout-note}
## In PowerShell
In PowerShell you can run `ls` or `dir` to list the content of a directory, and `cd` to change directory. To replicate the `ls -al` command, you can run `ls -Force` or `dir -Force` to show all files, including hidden ones.
:::
This should return the exact same content that is currently on GitHub!
## Tracking your work
Let's start tracking our work using git. For this exercise, we want to accomplish the following:
1. Create a new Python script called `desserts.py` and add it to our repository.
2. Copy and paste the code provided in the `desserts.py` file and save the change as a commit.
3. Add a new dessert to the csv list and save the change as a commit.
4. Edit the main function in the script to include a destination path for the csv file and save the change as a commit.
### Adding a new file to the repository
From the command line, create a new empty file called `desserts.py`:
```bash
touch desserts.py
```
::: {.callout-note appearance="simple"}
## In PowerShell
`touch` is not available in PowerShell. Use `New-Item` instead:
```bash
New-Item desserts.py
```
:::
Next, copy and paste the following code into the `desserts.py` file (use nano or any text editor you prefer):
```python
import csv
def read_csv(file_path: str) -> list[dict]:
with open(file_path, mode='r') as file:
csv_reader = csv.DictReader(file)
data = [row for row in csv_reader]
return data
def add_dessert(data: list[dict], rank: int, dessert: str) -> list[dict]:
if any(row['dessert'] == dessert for row in data):
print(f"{dessert} is already in the list. No changes made.")
return data
for row in data:
if int(row['rank']) >= rank:
row['rank'] = str(int(row['rank']) + 1)
data.append({'rank': str(rank), 'dessert': dessert})
data.sort(key=lambda x: int(x['rank']))
return data
def to_csv(data: list[dict], file_path: str) -> None:
with open(file_path, mode='w', newline='') as file:
fieldnames = ['rank', 'dessert']
writer = csv.DictWriter(file, fieldnames=fieldnames,
lineterminator='\n')
writer.writeheader()
for item in data:
writer.writerow(item)
def main(rank: int, dessert: str) -> None:
"""Read the iconic desserts CSV,
insert a dessert at the given rank,
and save the updated list.
Args:
rank (int): Rank at which to insert the dessert.
dessert (str): Name of the dessert to add.
"""
data = read_csv('iconic_desserts.csv')
new_data = add_dessert(data, rank, dessert)
to_csv(new_data, 'iconic_desserts.csv')
print(f"Added {dessert} at rank {rank}.")
if __name__ == "__main__":
# Add a new dessert to the list at rank 37
main(37, 'Tiramisu')
```
::: {.callout-note appearance="simple" collapse="true"}
## About the code
The code defines a Python script that manages a list of desserts stored in a CSV file. It includes functions to read the CSV file, add a new dessert to the list while maintaining the correct ranking, and write the updated list back to the CSV file. The `main` function demonstrates how to use these functions by adding "Tiramisu" at rank 37 in the list of iconic desserts.
:::
#### Check git workspace status
Next, we can use `git` to check the status of our repository by running the following command:
```bash
git status
```
The output should be similar to this:
```bash
On branch main
Your branch is up to date with 'origin/main'.
Untracked files:
(use "git add <file>..." to include in what will be committed)
desserts.py
nothing added to commit but untracked files present (use "git add" to track)
```
#### Add the file to the staging area
The list of untracked files includes all the files that are in your repository but are not being tracked by `git`. To start tracking the `desserts.py` file, we need to add it to the staging area:
```bash
git add desserts.py
```
Now, if we check the status again, we should see that the `desserts.py` file is now being tracked:
```bash
git status
On branch main
Your branch is up to date with 'origin/main'.
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: desserts.py
```
#### Committing the changes
At this moment, `git` is tracking the `desserts.py` file, but the changes we made to the file are not "saved" in the git history yet. This is called a **commit**, which is a snapshot of the state of the file(s) at a given moment in time. To create a commit, we need to run the following command:
```bash
git commit -m "add desserts.py script"
```
This will create a new commit with the message *"add desserts.py script"*. The `-m` flag is used to specify the commit message. You can use any message you want, but it should be descriptive of the changes you made in that commit.
### Tracking changes to data
The script we just created is designed to include a new dessert in the `iconic_desserts.csv` file. Running the script will result in a new dessert (Tiramisu) being added to the list at rank 37, and the ranks of the other desserts being updated accordingly. Let's run the script to see how it works:
::: {.callout-note appearance="simple" collapse="true"}
## Quick Python check
Before running the script, confirm which Python command works on your machine:
```bash
python --version
```
If you get an error, try:
```bash
python3 --version
py -3 --version
```
Use the command that returns a Python 3 version to run the script.
If none of the above commands work, you will need to install Python on your machine. You can download it from [https://www.python.org/downloads/](https://www.python.org/downloads/){target="_blank"} and follow the instructions for your operating system.
:::
```bash
python desserts.py
```
::: {.callout-warning collapse="true" appearance="simple"}
## Troubleshooting
Some common issues that might arise when running the script and how to solve them:
- **command not found: python**: Run `python --version` first; if needed use `python3 desserts.py` (macOS/Linux) or `py -3 desserts.py` (Windows).
- **FileNotFoundError: [Errno 2] No such file or directory: 'iconic_desserts.csv'**: Run the command from the folder that contains both files.
:::
If the output shows the message `Added Tiramisu at rank 37.`, then the script ran successfully.
We can use `git` to see what have changed in the `iconic_desserts.csv` file by using the `diff` command:
```bash
git diff iconic_desserts.csv
```
The resulting output shows the differences between the current and the previous version of the file. Lines that start with a `-` were removed, and those that start with a `+` were added. The output should look something like this:
```bash
diff --git a/iconic_desserts.csv b/iconic_desserts.csv
index 351fb57..b80e86b 100644
--- a/iconic_desserts.csv
+++ b/iconic_desserts.csv
@@ -35,8 +35,9 @@ rank,dessert
34,Chess pie
35,Sour cream pound cake
36,Key lime pie
-37,Cherry pie
-38,Seven-layer bars
-39,Coconut cake
-40,Brownies
-41,Blondies
+37,Tiramisu
+38,Cherry pie
+39,Seven-layer bars
+40,Coconut cake
+41,Brownies
+42,Blondies
```
::: {.callout-note appearance="simple"}
## Commit changes
Now is your turn to commit the changes made to the `iconic_desserts.csv` file. Follow the same steps as before and use the following commit message: "add Tiramisu to the list of iconic desserts".
::: {.callout-tip collapse="true"}
## Answer
```bash
git add iconic_desserts.csv
git commit -m "add Tiramisu to the list of iconic desserts"
```
:::
:::
### Control the repository history
So far, we have made changes incrementally by adding and committing new changes to the repository. However, we can also revert to a previous state of the repository. Let's explore the current history of our repository first by using the `log` command:
```bash
git log
```
The output should look something like this:
```bash
commit a3a7278bc511ac1047d722bb9833773fd5636a90 (HEAD -> main)
Author: ...
Date: Tue Apr 14 15:39:59 2026 -0700
add Tiramisu to the list of iconic desserts
commit 227d6cba9fa442459bd4c22054fa640600db8cb4
Author: ...
Date: Tue Apr 14 15:13:59 2026 -0700
add desserts.py script
commit 14a46c09a8dde829ea44bfe5d02492e0b926b74d (origin/main, origin/HEAD)
Author: ...
Date: Tue Apr 14 14:52:37 2026 -0700
Add iconic_desserts.csv
commit 7107af1488152b062ef9c3e60bb54134a6320fe4
Author: ...
Date: Tue Apr 14 14:50:23 2026 -0700
Adding Your's favorite dessert
commit 8fe3ad4ca5c5ad7db4b1ba19e03177407a70bf51
Author: ...
Date: Tue Apr 14 14:39:28 2026 -0700
Initial commit
```
::: {.callout-tip collapse="true" appearance="simple"}
## About the log output
- Each commit is identified by a unique hash (e.g., `a3a7278bc511ac1047d722bb9833773fd5636a90`).
- The `HEAD` pointer indicates the current commit that your repository is on.
- The `Author` and `Date` fields show who made the commit and when.
- The commit message (e.g., "add Tiramisu to the list of iconic desserts") describes the changes made in that commit.
- The `origin/main` indicates that the commit is also present in the remote repository on GitHub.
:::
To avoid having `git log` cover your entire terminal screen, you can limit the number of commits that Git lists by using `-N`, where `N` is the number of commits that you want to view. For example, if you only want information from the last commit you can use:
```bash
git log -1
---
commit a3a7278bc511ac1047d722bb9833773fd5636a90 (HEAD -> main)
Author: ...
Date: Tue Apr 14 15:39:59 2026 -0700
add Tiramisu to the list of iconic desserts
```
Another option to reduce the quantity of information is using the `--oneline` option:
```bash
git log --oneline
---
a3a7278 (HEAD -> main) add Tiramisu to the list of iconic desserts
227d6cb add desserts.py script
14a46c0 (origin/main, origin/HEAD) Add iconic_desserts.csv
7107af1 Adding Your's favorite dessert
8fe3ad4 Initial commit
```
#### Restore iconic_desserts.csv to the previous state
Our current workflow has an issue: we are altering the `iconic_desserts.csv` file directly, which means that if we make a mistake, we might lose the original content of the file. Let's start by restoring the `iconic_desserts.csv` file to the previous state before we added Tiramisu.
To achieve this, we can use the `checkout` command to restore the file to the state it was in the previous commit:
```bash
git checkout HEAD~1 iconic_desserts.csv
---
# Success message should be similar to this:
Updated 1 path from a4090b9
```
::: {.callout-note collapse="true" appearance="simple"}
## About reverting changes
Usually the way to revert changes depends if the file is staged, already commited, if is currently modified, etc. Depending the case, you might have to use different commands, such as `git restore`, `git reset`, `git revert`, etc. For more information on how to revert changes in different scenarios, check out the [Git documentation](https://git-scm.com/docs){target="_blank"}, particularly the commands under the section "Basic Snapshotting" and "Patching".
:::
What we're doing here is telling `git` to restore the `iconic_desserts.csv` file to the state it was in the previous commit (indicated by `HEAD~1`). After running this command, the `iconic_desserts.csv` file should be back to its original state before we added Tiramisu and moved to the staging area. Let's commit this change to the repository:
```bash
git commit -m "restore iconic_desserts.csv to its original state"
```
#### Edit `desserts.py`
Open the `desserts.py` file and edit the `main` function so it looks like this:
```python
def main(rank: int, dessert: str, destination_path: str) -> None:
"""Read the iconic desserts CSV,
insert a dessert at the given rank,
and save the updated list.
Args:
rank (int): Rank at which to insert the dessert.
dessert (str): Name of the dessert to add.
destination_path (str): Path to save the updated CSV file.
"""
data = read_csv('iconic_desserts.csv')
new_data = add_dessert(data, rank, dessert)
to_csv(new_data, destination_path)
print(f"Added {dessert} at rank {rank}.")
if __name__ == "__main__":
# Add a new dessert to the list at rank 37
main(37, 'Tiramisu', 'updated_iconic_desserts.csv')
```
Save the file and run `git diff` to see the changes you made:
```bash
git diff desserts.py
# The output should look something like this:
diff --git a/desserts.py b/desserts.py
index 792959f..a199a68 100644
--- a/desserts.py
+++ b/desserts.py
@@ -29,7 +29,7 @@ def to_csv(data: list[dict], file_path: str) -> None:
for item in data:
writer.writerow(item)
-def main(rank: int, dessert: str) -> None:
+def main(rank: int, dessert: str, destination_path: str) -> None:
"""Read the iconic desserts CSV,
insert a dessert at the given rank,
and save the updated list.
@@ -37,12 +37,13 @@ def main(rank: int, dessert: str) -> None:
Args:
rank (int): Rank at which to insert the dessert.
dessert (str): Name of the dessert to add.
+ destination_path (str): Path to save the updated CSV file.
"""
data = read_csv('iconic_desserts.csv')
new_data = add_dessert(data, rank, dessert)
- to_csv(new_data, 'iconic_desserts.csv')
+ to_csv(new_data, destination_path)
print(f"Added {dessert} at rank {rank}.")
if __name__ == "__main__":
# Add a new dessert to the list at rank 37
- main(37, 'Tiramisu')
+ main(37, 'Tiramisu', 'updated_iconic_desserts.csv')
```
Now, add the changes to the staging area and commit them to the repository:
```bash
git add desserts.py
git commit -m "edit main function to include destination path for csv file"
```
#### Wrapping up
1. Run the `desserts.py` script again to add a new dessert to the list and save the updated list in a new file called `updated_iconic_desserts.csv`.
2. Use `git` to track the changes to the `updated_iconic_desserts.csv` file and commit those changes to the repository with the message "add Tiramisu to the updated list of iconic desserts".
::: {.callout-tip collapse="true" appearance="simple"}
## Answer
```bash
python desserts.py
git add updated_iconic_desserts.csv
git commit -m "add Tiramisu to the updated list of iconic desserts"
```
:::
At the end, the history of your repository should look something like this:
```bash
git log --oneline
---
cf47aa1 (HEAD -> main) add Tiramisu to the updated list of iconic desserts
6d7cbbf edit main function to include destination path for csv file
ab19fd9 restore iconic_desserts.csv to its original state
a3a7278 add Tiramisu to the list of iconic desserts
227d6cb add desserts.py script
14a46c0 (origin/main, origin/HEAD) Add iconic_desserts.csv
7107af1 Adding Your's favorite dessert
8fe3ad4 Initial commit
```