-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbasic-git-workflow.qmd
729 lines (520 loc) · 28.4 KB
/
basic-git-workflow.qmd
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
# Basic Git Workflow
In this section, we'll put together the basic Git workflow, and show how all these many terms and commands actually fit together.
We'll start completely from scratch, and work our way up to a full-fledged Git repository.
I find that the best way to learn anything is to actually do it on a real project, as it's hard to conceptualize what's going on when you're just reading about it, or even working through a toy example.
And because we research infectious diseases in CIDD, we'll build up a repository that contains a notebook for an SIR model (Susceptible-Infected-Removed), and do it in both Python and R as that should allow most people to follow along with the code in a language they're familiar with.
Look for the following drop-down sections to reveal the simulation code you need.
<details><summary>R Code</summary></details>
<details><summary>Python Code</summary></details>
Throughout this section, we'll be demonstrating the workflow using GitKraken, but the same principles apply to the command line.
In fact, below each section that highlights a GitKraken feature, I've included a drop-down section that shows the equivalent command line commands.
Just look for the following drop-down sections to reveal the commands.
<details><summary>Terminal Commands</summary></details>
## Creating a New Repository
We'll create a new repository on GitHub, and then clone it to our local machine.
We'll follow the steps outlined in the [GitHub First section](making-your-first-repo.qmd#github-first).
So, in summary:
1. On your computer, decide where you want to store all your Git repositories, and create a folder for them
- Mine has the path ***~/Documents/Repos/***, but you can put it wherever you want
2. Create a new repository on GitHub, and name it `sir-model`
- Make sure you inialize it with a ***README.md***, Description, R/Python ***.gitignore*** template (depending on the language you'd like to follow along with), and an MIT license
3. Open GitKraken
4. Open the *"Clone"* window using **cmd+N**/**ctrl+N**
5. Click on the *"GitHub"* button and select the `sir-model` repository
- Make sure the clone path is set to the folder you created in step 1
6. Click *"Clone"* and wait for the repository to be cloned to your computer
The repo should now be cloned to your computer, and you should be able to see it in the *"Open a repo"* section of GitKraken, which you can access using **cmd+O**/**ctrl+O**.
<details>
<summary>Terminal Commands</summary>
<p>
```bash
# Make the directory to store all your Git repos
# -p flag will create the directory and any parent directories that don't exist, but not overwrite anything
mkdir -p ~/Documents/Repos
# Change into the directory
cd ~/Documents/Repos
# Clone the repository
[email protected]:GITHUB_USERNAME/sir-model.git
# Change into the repository
cd sir-model
```
</p>
</details>
## Giving Our Repository Some Structure
Now that we have a repository, we need to give it some structure.
We'll start by fleshing out the ***README***, which will act as a guide for how we want to structure our repository.
This is a good practice to get into as it will help you think carefully about how you want to organize your code, and will help you and others understand what's going on in your repository, as it's easy to skip this step and end up with a repository that's hard to decipher.
Let's first add the core components.
Copy the following into the ***README.md*** file:
```markdown
## Repository Title
### About This Project
### Repository Structure
### Built With
### Getting Started
### Usage
### License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details
### Contact
### Acknowledgements
```
::: {.callout-note}
The `##` and `###` are used to denote different levels of headings in Markdown.
I prefer to use a level-2 heading for the title of the repository, and level-3 headings for the different sections, as I find it makes the README easier to read; level-1 headings are quite large.
:::
Now, rename the "Repository Title", and this is a good spot to create our first **commit** before we start to fill in a few of the sections.
### Creating The First Commit
At this stage, we have a repository with a README, but we haven't actually saved any changes to the repository as far as Git is concerned.
When we cloned our repository, the ***README.md*** only contained the text that GitHub added by default (the repo name and short description - you can check this on GitHub if you'd like).
If you open up GitKraken, you'll see that it is showing that we have made changes to a file, indicated by the pencil icon in the commit history section, as well as the note above the commit message box that says *"1 file change in working directory"*.
![](figs/Basic-workflow_first-commit-changes01.png)
Clicking on either of these sections will present you will the below window, which shows you the changes that have been made to the file.
You will also notice that the changes are **unstaged**, which means they will not be included in the next commit.
![](figs/Basic-workflow_first-commit-changes02.png)
Clicking on the ***README.md*** file will open up the file **diff** in the GitKraken editor, and you can see that the changes are highlighted in green (for additions) and red (for deletions).
Once we are happy with the changes, we can **stage** them and write the **commit** message.
The **commit** message title should be short and descriptive, and the body should contain more details about the changes that were made, if necessary for clarity.
![](figs/Basic-workflow_first-commit-changes03.png)
::: {.callout-note}
Your **diff** view may look different than mine shown here e.g., it may default to lines being shown above each other, rather than side-by-side.
You can change this if you would like, by clicking on the buttons in the top-right corner of the editor window, just below the button that says *"Unstage File"*.
:::
Now that we've made our first **commit**, we will see that the pencil icon has disappeared and we have a similar view to what we started with when we cloned the repository.
The key difference is now there are two `main` branches being shown in the Git history.
The one with the computer that is highlighted is the **local** branch, which is the branch that is stored on our computer.
The other branch is the **remote** branch, which is the branch that is stored on GitHub.
Because we've just made a commit, the **local** branch is ahead of the **remote** branch by one commit as we haven't pushed our changes to GitHub yet.
We'll do that later after we've added a few more things to the README.
![](figs/Basic-workflow_first-commit-changes04.png)
So for now, let's continue to flesh out the README.
<details>
<summary>Terminal Commands</summary>
<p>
```bash
# Check what files have been changed
# -vv flag will show where the files have changed and display the diff
git status -vv
# Stage all changes
git add .
# Commit changes
git commit -m "Add structure to README" -m "Added structure to the README to outline the points that need to be expanded upon. As a license was generated on repo creation, I have linked to this in the README"
```
</p>
</details>
### About This Project
Our project is going to contain an SIR model with births and deaths, which is a simple model of infectious disease transmission.
The SIR model is a compartmental model, which means that it divides the population into different compartments (Susceptible, Infected, and Removed), and tracks how people move between these compartments.
Not everyone is familiar with this, so we'll probably want to include this information in the README.
Similarly, we'll likely want to include the basic differential equations that govern the model, and the parameters that we'll use to run the model (as well as a short description of what they mean).
As we're going to use some code from Ottar's Epidemics book (chapter 2), we'll also want to include a link to the book (and citation).
To add this to a ***README.md*** file, we can use the following syntax:
````markdown
```math
\begin{align}
\frac{dS}{dt} &= \mu (N - S) -\beta S \frac{I}{N} \\
\frac{dI}{dt} &= \beta S \frac{I}{N} - \gamma I - \mu I \\
\frac{dR}{dt} &= \gamma I - \mu R
\end{align}
```
```math
\begin{align}
\mu &= \frac{1}{50*52} \\
\beta &= 2 \\
\gamma &= \frac{1}{2} \\\\
N &= 1000 \\
S_0 &= 999.0 \\
I_0 &= 1.0 \\
R_0 &= 0.0
\end{align}
```
````
This will render as:
\begin{align}
\frac{dS}{dt} &= \mu (N - S) -\beta S \frac{I}{N} \\
\frac{dI}{dt} &= \beta S \frac{I}{N} - \gamma I - \mu I \\
\frac{dR}{dt} &= \gamma I - \mu R \\\\
\mu &= \frac{1}{50*52} \\
\beta &= 2 \\
\gamma &= \frac{1}{2} \\\\
N &= 1000 \\
S\_0 &= 999.0 \\
I\_0 &= 1.0 \\
R\_0 &= 0.0
\end{align}
Fill in these details, and then we'll move on to the next section we can complete.
### Repository Structure
We can't fill in all of this section until we know exactly what the code is going to do, but we can at least give a rough outline.
To start, I like to use the following folders to help organize my code, but you are welcome to use whatever structure works best for you:
````markdown
```
.
├── data/
├── figs/
├── funs/
├── out/
└── src/
```
- `data/` contains ...
- `figs/` contains ...
- `funs/` contains ...
- `out/` contains ...
- `src/` contains ...
````
- ***data/*** will contain any raw data that we use in our analysis, and is not edited by hand
- ***figs/*** will contain any figures that we generate
- ***funs/*** will contain any functions that we write to help us with small, repeatable things e.g. functions to format tables in a notebook
- ***out/*** will contain any output from our analysis, e.g. intermediate datasets that have been cleaned and are ready for analysis, tables, etc
- ***src/*** will contain any code that we write to do our analysis, e.g. notebooks, scripts, etc
- If you work with multiple languages, it might make sense to have subfolders for each language, e.g. ***src/python/*** and ***src/R/***
You will want to ensure that your descriptions of each of the folders includes enough detail that you (and anyone else reading your project) can understand what's going on, but not so much detail that it becomes hard to read.
And remember, these folders will not appear in the Git history until they contain a file that Git can track.
It's quite nice to include an ASCII tree to visualize the structure of the repository, and there are a couple of ways to generate this.
If you use VSCode, you can install the [ASCII Tree Generator](https://marketplace.visualstudio.com/items?itemName=aprilandjan.ascii-tree-generator) extension, which will allow you to right-click on a folder and select *"Generate Tree String"* to generate a tree for that folder.
If you use R with RStudio, you can use the `fs::dir_tree()` function from the [{fs} package](https://fs.r-lib.org).
If you want to do it semi-manually, you can just use [this website](https://tree.nathanfriend.io/?s=(%27options!(%27fancy!true~fullPath!false~trailingSlash!true~rootDot!false)~5(%275%27Edit%20me%20to%20generate4a0nic6tre6*diagram%27%3A3*%3A%7D4Use%20indentation0to%20indicat6fil6and3folder3nesting.02You%20can%20even32us6*2markdown3*2bullets%27%3A%27)~version!%271%27)*%20%2004*2-%2030*4%5Cn*5source!6e3%01654320*).
### Contact and Acknowledgements
These are pretty self-explanatory, and easy to fill in now.
### Making a Second Commit
Now we've added a bit more to the README, let's make another **commit**.
The process is exactly the same as before, so nothing much to go through here.
## Installing the Necessary Packages
To run the code, we'll need to install a few packages.
In both R and Python I'm using packages to manage the environments to try and make the code more reproducible.
In R, this is the [`{renv}`](https://rstudio.github.io/renv/articles/renv.html) package, and in Python, this is the [`{poetry}`](https://python-poetry.org) package.
If you use Python, you are likely already familiar with the `pip` package manager and the concept of virtual environments, and but R users may not be.
This is too big of a topic to go into detail here, but the basic premise is that the package manager takes a snapshot of all the installed packages and their dependencies, along with their version numbers, and stores this information in a file called a *lockfile*.
Doing this means that if someone **clones** your repository, and your repo has a *lockfile*, they can run just one command to install all of the packages that you used to run your code, and not worry about incompatible versions of packages being installed that would cause errors.
Here, I've provided the *lockfiles* for both R and Python, so you can just run the commands below to install the packages.
<details>
<summary>
R Code
</summary>
<p>
Install the `{renv}` package if you don't already have it installed:
```r
install.packages("renv")
```
Copy the ***renv.lock*** file to the root of your repository.
Then, run the following command in your R terminal:
```r
renv::restore()
```
</p>
</details>
<details>
<summary>
Python Code
</summary>
<p>
Install the `{poetry}` package if you don't already have it installed.
How you do this will depend on your operating system, but you can find instructions [here](https://python-poetry.org/docs/#installation).
Make sure the poetry package is available in your PATH by running the following command in your terminal:
```bash
poetry --version
```
Copy the ***poetry.lock*** and ***pyproject.toml*** files to the root of your repository.
Then, run the following command in your terminal:
```bash
poetry install
```
::: {.callout-note}
This code was developed in a pyenv virtual environment, using Python 3.11.0.
:::
</p>
</details>
## Adding Simulation Code
Let's start writing our simulation.
As mentioned, we'll adapt code from Ottar's book.
We'll start by creating the ***src/*** folder, and then creating a new file called ***sir_model.R*** / ***sir_model.py*** in that folder.
Copy the below code into that file.
<details>
<summary>
R Code
</summary>
<p>
```r
library(deSolve)
library(tidyverse)
theme_set(theme_minimal())
sirmod <- function(t, y, parms) {
# Pull state variables from y vector
S <- y[1]
I <- y[2]
R <- y[3]
# Pull parameter values from parms vector
beta <- parms["beta"]
mu <- parms["mu"]
gamma <- parms["gamma"]
N <- parms["N"]
# Define equations
dS <- mu * (N - S) - beta * S * I / N
dI <- beta * S * I / N - (mu + gamma) * I
dR <- gamma * I - mu * R
res <- c(dS, dI, dR)
# Return list of gradients
list(res)
}
times <- seq(0, 26, by = 1/10)
parms <- c(mu = 0, N = 1, beta = 2, gamma = 1/2)
start <- c(S = 0.999, I = 0.001, R = 0)
out <- ode(y = start, times = times, func = sirmod, parms = parms)
out_df <- as_tibble(out) %>%
pivot_longer(cols = -time, names_to = "state", values_to = "number") %>%
mutate(
time = as.numeric(time),
number = as.numeric(number),
state = factor(state, levels = c("S", "I", "R")),
number = round(number, 6)
)
ggplot(out_df, aes(x = time, y = number, color = state)) +
geom_line(linewidth = 2) +
labs(x = "Time", y = "Number", color = "State")
```
</p>
</details>
<details>
<summary>
Python Code
</summary>
<p>
```python
import numpy as np
import pandas as pd
from scipy.integrate import solve_ivp
from plotnine import *
def sirmod(t, y, beta, mu, gamma, N):
# Unpack states
S, I, R = y
# Define equations
dS = mu * (N - S) - beta * S * I / N
dI = beta * S * I / N - (mu + gamma) * I
dR = gamma * I - mu * R
# Return list of gradients
return dS, dI, dR
tmin = 0
tmax = 26
tstep = 1 / 10
times = np.arange(tmin, tmax, tstep)
beta = 2
mu = 0
gamma = 1 / 2
N = 1
parms = (beta, mu, gamma, N)
S0 = 0.999
I0 = 0.001
R0 = 0
start = (S0, I0, R0)
out = solve_ivp(
sirmod, [tmin, tmax], np.array(start), args=parms, t_eval=times
)
out_df = (
pd.DataFrame(out.y).transpose().rename(columns={0: 'S', 1: 'I', 2: 'R'})
)
out_df['time'] = out.t
out_df = out_df.melt(id_vars='time', value_vars=['S', 'I', 'R']).rename(
columns={'variable': 'state', 'value': 'number'}
)
theme_set(theme_minimal())
(
ggplot(out_df, aes(x='time', y='number', color='state'))
+ geom_line(size=2)
+ labs(x='Time', y='Number', color='State')
)
```
</p>
</details>
We've now made some substantial changes to the repository, so let's make a **commit**.
The process is exactly the same as before.
## Updating the README
### Mistake in our Model Description
Now that we've added some code, let's go back and update the README.
Looking at what we've written, we can see that the code is actually different from what we had in the README, so we'll need to update that.
Examining the code, we can see that we've run the model on fractional populations, not whole numbers, so we'll need to update the description of the model to reflect that.
Go back and adjust the $S_0$ ... values in the equations to represent fractions, and then update the description of the model to reflect that.
Because we've made some changes that are distinct from the other changes we've made, we'll again want to make a **commit** for these changes.
### Expanding Upon the README
Now we have some code, we can expand upon sections of the README.
The first thing we can do is to add some text to the "Getting Started" section.
I've used the `{renv}` package to manage the R environment for this project, so I'll add some text to the README to reflect that.
<details>
<summary>
R Code
</summary>
<p>
```markdown
I've used the `{renv}` package to manage the R environment for this project.
For more details on how to use `{renv}`, see [this article](https://rstudio.github.io/renv/articles/renv.html), but in brief, it creates a snapshot of the installed packages and their versions.
To get started, you will need to install `{renv}` as usual (i.e., `install.packages("renv")`), and then run `renv::restore()` to install the packages that are used in this project (the record in the ***renv.lock*** file).
```
The following text can be added to the "Usage" section.
```markdown
To run the SIR model, you can open the ***src/sir_model.R*** file and run the code as usual.
```
</p>
</details>
<details>
<summary>
Python Code
</summary>
<p>
```markdown
I've used the `{poetry}` package to manage the R environment for this project.
For more details on how to use `{poetry}`, see [this page of the documentation](https://python-poetry.org/docs/basic-usage/), but in brief, it creates a snapshot of the installed packages and their versions.
To get started, you will need to install `{poetry}` using system-dependent commands (see [the official documentation](https://python-poetry.org/docs/) for these commands), and then run `poetry install` to install the packages that are used in this project (the record in the ***poetry.lock*** file).
```
The following text can be added to the "Usage" section.
```markdown
To run the SIR model, you can open the ***src/sir_model.py*** file and run the code as usual.
```
</p>
</details>
### Amending the README Commit
We forgot to update the "Built With" section of the README, but we don't want to make a whole new **commit** just for that, as making tons of tiny small **commits** will make it harder to read and navigate the Git history if you need to reference past work.
Thankfully, this change aligns with the previous **commit**, so we don't need to make a new **commit**.
Instead, we can **amend** the previous **commit** to include the changes we've made.
We want to add the following text to the "Built With" section of the README.
<details>
<summary>
R Code
</summary>
<p>
```markdown
- [R version 4.2.1 (2022-06-23)](https://cran.r-project.org/bin/macosx/)
- [`{renv}`](https://rstudio.github.io/renv/articles/renv.html) for package management
```
</p>
</details>
<details>
<summary>
Python Code
</summary>
<p>
```markdown
- [Python version 3.11.0](https://www.python.org/downloads/)
- [`{poetry}`](https://python-poetry.org/docs/) for package management
```
</p>
</details>
::: {.callout-warning}
We can only **amend** **staged** changes to the most recent **commit**, and only if we haven't **pushed** it to GitHub yet.
If we've already **pushed** the **commit**, we'll need to make a new **commit**.
If you do not make a new **commit** and try and just **amend** it, you'll get an error because Git wants to avoid rewriting history that might have been accessed by others, resulting in conflicting Git histories on different machines.
:::
Once we've made and saved the changes to the ***README.md***, we can **stage** them and then **amend** the previous **commit**.
As per usual, when we save and **stage** the changes, we'll see the **diff** in the GitKraken interface, as below.
![](./figs/Basic-workflow_amend01.png)
You can see that just above the "Commit Message" input section, there is a button for "Amend".
Clicking this will **amend** the previous **commit** to include the changes we've made.
As such, it will set the **commit** message to the same as the previous **commit**, so there is nothing else to do.
During the **amend** process, GitKraken will also change the text of the "Commit" button from *"Commit changes to X file(s)"* to *"Amend Previous Commit"*, as below.
![](./figs/Basic-workflow_amend02.png)
Once we've **amended** the **commit**, can examine the Git history and see that there is only one **commit** that refers to the changes we've made to the ***README.md*** file.
Equally, if we look at the **diff** of this **commit**, we can see that our **amended** changes are included.
![](./figs/Basic-workflow_amend03.png)
<details>
<summary>Terminal Commands</summary>
<p>
```bash
# Check and stage changes
git status -vv
git add .
# Amend changes
git commit --amend
# Examine the Git history and find the commit ID for the commit you want to diff
# --oneline: show each commit on a single line, rather than the default multi-line format which shows the commit message and other details
# --graph: show a graphical representation of the Git history, which is useful when you have branches and merges
# --decorate: show the names of all references (branches, tags, etc.) that point to the commit
# --all: show the Git history for all branches
git log --oneline --graph --decorate --all
# Diff the commit (replace with your commit ID)
git diff 0de4674
```
::: {.callout-note}
If you do not specify the **commit ID**, the **diff** of the most recent **commit** will be shown.
:::
::: {.callout-warning}
If you try to **diff** a **commit** that is particularly long i.e., has a lot of line changes, you will enter a special interactive mode that is based on Vim.
There are a number of commands you'll need to know.
- `d`: scroll the page down
- `u`: scroll the page up
- `j`: move the cursor down one line
- `k`: move the cursor up one line
- `q`: quit the interactive mode and return to the terminal
To see a cheat sheet with more Vim commands, see [here](https://devhints.io/vim).
:::
See [here](https://stackoverflow.com/questions/1057564/pretty-git-branch-graphs) for some git aliases that can make your git log prettier.
</p>
</details>
## Our First Push
Now that we've made some substantial changes to the repository, we can **push** them to GitHub.
This is pretty straightforward to do, and we can do it from the GitKraken interface.
On the GitKraken client, there is a button in the top toolbar that is an up arrow, with the description "Push".
When we hover over it, it shows the text "Push to origin/main".
![](./figs/Basic-workflow_push01.png)
Pushing the changes will bring the version of the code on GitHub up-to-date with the version of the code on our local machine.
We can see that the **main** branch with out GitHub user photo is now in-line with the **main** branch of our local machine.
![](./figs/Basic-workflow_push02.png)
We can also confirm this is the case by navigating to our repository on GitHub and looking at the Git history.
![](./figs/Basic-workflow_push03.png)
::: {.callout-note}
The Git history on GitHub will show the relative time that the **commit** was made, not **pushed** to GitHub.
:::
<details>
<summary>Terminal Commands</summary>
<p>
```bash
# Push changes
git push
```
</p>
</details>
## Collaborating on a Project
Up until now, we've just been working on our own, but what if we want to collaborate with others on a project?
There are a couple of ways we can do this, but the easiest is to add collaborators to our repository on GitHub.
::: {.callout-note}
Just for reference, you could set up a GitHub organization and then add collaborators to that, but that's a bit more complicated than what we're doing here.
For open-source projects where you want to allow others to make suggestions for their contributions, without directly giving them access to the repository, you can use the "**fork** and **clone**" model, where people can **fork** the repository and then make a **pull request** to merge their changes into the original repository.
This is far more complicated than what we're doing here, so we won't cover it, but you can learn more about it in Jenny Bryan's [Happy Git with R](https://happygitwithr.com/fork-and-clone.html) book chapter, the [Atlassian tutorial](https://www.atlassian.com/git/tutorials/setting-up-a-repository/git-clone), and/or the official [GitHub tutorial](https://docs.github.com/en/get-started/quickstart/contributing-to-projects) that demonstrates with a repository that you can practice on.
:::
We'll practice where you can add me as a collaborator to your SIR repository.
First, go to *"Settings > Access > Collaborators"* on your repository on GitHub.
![](./figs/Basic-workflow_collaborate01.png)
You can see that there are no collaborators at the moment, but click on the "Add people" button to add me as a collaborator.
From here, you can type in my GitHub username, `arnold-c`, and then click on the *"Add arnold-c to this repository"* button.
From here, I'll make the following change to the ***README.md*** file under the "Built With" section.
```markdown
- [`{deSolve}`](https://cran.r-project.org/web/packages/deSolve/index.html) for solving differential equations
```
What you will notice is that when I make this change, it will be reflected in the Git history on GitHub, but not in your local repository.
However, this will discrepancy will not immediately be apparent, as our computer hasn't checked in with GitHub to see if there are any changes since we last **pushed**.
To do this, we will use the **fetch** command.
::: {.callout-note}
In this instance, I've just made the change myself directly in GitHub, which will have a similar effect to it being made by a collaborator.
:::
To **fetch** the changes, we can use the GitKraken interface.
Clicking on the *"Pull"* button will bring up a menu, where we can select the *"Fetch All"* option.
Once the changes have been **fetched**, we can see that there is a new **commit** in the Git history, and our **remote** branch is now ahead of our **local** branch.
![](./figs/Basic-workflow_collaborate02.png)
::: {.callout-note}
In some cases, GitKraken will automatically **fetch** changes, but here's how you can do it manually (this is worth doing routinely if you're collaborating with others, just to be safe).
:::
**Pulling** the changes will bring our **local** branch up-to-date with the **remote** branch.
The default **pull** behavior is to *"**fast-forward** if possible"*, which means that the **local** branch will be moved to the **commit** that the **remote** branch is pointing to.
It does this by performing a **merge**.
There are some instances (that we are unlikely to run into for a while) where this can cause issues, which is why there are options to *"fast-forward only"* and *"rebase"*.
If you want to learn more, you can read about it [here](https://blog.sffc.xyz/post/185195398930/why-you-should-use-git-pull-ff-only) and [here](https://stackoverflow.com/questions/25430600/difference-between-git-pull-rebase-and-git-pull-ff-only).
For the time-being, just stick with the default behavior and you'll be fine!
::: {.callout-tip}
When working on a collaborative project, get into the habit of **fetching** routinely to see if there are any changes that you need to **pull**. If you leave it too long, you might end up with a lot of changes to **pull** and it might be difficult to figure out what's going on. Even worse, you might end up making changes to old versions of the code, which will cause conflicts when you try and **pull**/**push**/**merge** the changes.
:::
<details>
<summary>Terminal Commands</summary>
<p>
```bash
# Fetch changes
git fetch
# Pull changes
git pull
```
</p>
</details>