generated from allisonhorst/meds-distill-template
-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathday1-git-collaboration-conflicts.qmd
232 lines (155 loc) · 10.4 KB
/
day1-git-collaboration-conflicts.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
---
title: "git merge conflicts"
---
## Learning Objectives
In this lesson, you will learn:
- What typically causes conflicts when collaborating
- Workflows to avoid conflicts
- How to resolve a conflict
## Before we start
First thing to know is that actually `git pull` is a two step process: `git pull = git fetch + git merge`
Second: **you did nothing wrong!!** Git tries to merge files automatically. When the changes are on the same file far apart, git will figure it out on his own and do the merge automatically. However if changes are overlapping, `git` will call you to the rescue and ask you how to best merge the two versions.
## Merge conflicts
So things can go wrong, which usually starts with a **merge conflict**, due to both collaborators making incompatible changes to a file. While the error messages from merge conflicts can be daunting, getting things back to a normal state can be straightforward once you've got an idea where the problem lies.
This is most **easily avoided by good communication about who is working on various sections of each file, and trying to avoid overlaps**. But sometimes it happens, and *git* is there to warn you about potential problems. And git will not allow you to overwrite one person's changes to a file with another's changes to the same file if they were based on the same version.
![](img/git-conflict-00-lines-changed.png)
The main problem with merge conflicts is that, when the Owner and Collaborator both make changes to the same line of a file, git doesn't know whose changes take precedence. You have to tell git whose changes to use for that line.
## How to resolve a conflict
### Abort, abort, abort... {-}
Sometimes you just made a mistake. When you get a merge conflict, the repository
is placed in a 'Merging' state until you resolve it. There's a command line command
to abort doing the merge altogether:
```bash
git merge --abort
```
Of course, after doing that you still haven't synced with your collaborator's
changes, so things are still unresolved. But at least your repository is now
usable on your local machine.
### Checkout {-}
The simplest way to resolve a conflict, given that you know whose version of the
file you want to keep, is to use the command line `git` program to tell git to
use either *your* changes (the person doing the merge), or *their* changes (the other collaborator).
- keep your collaborators file: `git checkout --theirs conflicted_file.Rmd`
- keep your own file: `git checkout --ours conflicted_file.Rmd`
Once you have run that command, then run `add`, `commit`, and `push` the changes as normal.
### Pull and edit the file {-}
But that requires the command line. If you want to resolve from RStudio, or if
you want to pick and choose some of your changes and some of your collaborator's,
then instead you can manually edit and fix the file. When you `pull`ed the file
with a conflict, git notices that there is a conflict and modifies the file to show
both your own changes and your collaborator's changes in the file. It also shows the
file in the Git tab with an orange `U` icon, which indicates that the file is `Unmerged`,
and therefore awaiting you help to resolve the conflict. It delimits
these blocks with a series of less than and greater than signs, so they are easy to find:
![](img/rstudio-merge-conflict.png)
To resolve the conficts, simply find all of these blocks, and edit them so that
the file looks how you want (either pick your lines, your collaborators lines,
some combination, or something altogether new), and save. Be sure you removed the
delimiter lines that started with `<<<<<<<`, `=======`, and `>>>>>>>`.
Once you have made those changes, you simply add, commit, and push the files
to resolve the conflict.
### Producing and resolving merge conflicts
To illustrate this process, we're going to carefully create a merge conflict step
by step, show how to resolve it, and show how to see the results of the successful
merge after it is complete. First, we will walk through the exercise to demonstrate
the issues.
#### Owner and collaborator ensure all changes are updated
First, start the exercise by ensuring that both the Owner and Collaborator have all
of the changes synced to their local copies of the Owner's repositoriy in RStudio.
This includes doing a `git pull` to ensure that you have all changes local, and
make sure that the Git tab in RStudio doesn't show any changes needing to be committed.
#### Owner makes a change and commits
From that clean slate, the Owner first modifies and commits a small change inlcuding their
name on a specific line of the README.md file (we will change line 4). Work to only change
that one line, and add your username to the line in some form and commit the changes
(but DO NOT push). We are now in the situation where the owner has unpushed changes that
the collaborator can not yet see.
#### Collaborator makes a change and commits **on the same line**
Now the collaborator also makes changes to the same of the README.md file
in their RStudio copy of the project, adding their name to the line. They then commit.
At this point, both the owner and collaborator have committed changes based on
their shared version of the README.md file, but neither has tried to share their changes
via GitHub.
#### Collaborator pushes the file to GitHub
Sharing starts when the Collaborator pushes their changes to the GitHub repo, which
updates GitHub to their version of the file. The owner is now one revision behind,
but doesn't yet know it.
#### Owner pushes their changes and gets an error
At this point, the owner tries to push their change to the repository, which triggers
an error from GitHub. While the error message is long, it basically tells you everything
needed (that the owner's repository doesn't reflect the changes on GitHub, and that they
need to *pull* before they can push).
![](img/git-conflict-01-push-error.png)
#### Owner pulls from GitHub to get Collaborator changes
Doing what the message says, the Owner pulls the changes from GitHub, and gets
another, different error message. In this case, it indicates that there is a merge
conflict because of the conflicting lines.
![](img/git-conflict-02-pull-error.png)
In the Git pane of RStudio, the file is also flagged with an orange 'U', which stands
for an unresolved merge conflict.
![](img/git-conflict-03-conflict.png)
#### Owner edits the file to resolve the conflict
To resolve the conflict, the Owner now needs to edit the file. Again, as indicated above,
git has flagged the locations in the file where a conflict occcurred
with `<<<<<<<`, `=======`, and `>>>>>>>`. The Owner should edit the file, merging whatever
changes are appropriate until the conflicting lines read how they should, and eliminate
all of the marker lines with with `<<<<<<<`, `=======`, and `>>>>>>>`.
![](img/git-conflict-04-conflict-tags.png)
Of course, for scripts and programs, resolving the changes means more than just
merging the text -- whoever is doing the merging should make sure that the code
runs properly and none of the logic of the program has been broken.
![](img/git-conflict-05-resolved-file.png)
#### Owner commits the resolved changes
From this point forward, things proceed as normal. The owner first 'Adds' the file
changes to be made, which changes the orange `U` to a blue `M` for modified, and then
commits the changes locally. The owner now has a resolved version of the file on their
system.
![](img/git-conflict-06-commit-resolved.png)
#### Owner pushes the resolved changes to GitHub
Have the Owner push the changes, and it should replicate the changes to GitHub without error.
![](img/git-conflict-07-push-resolved.png)
#### Collaborator pulls the resolved changes from GitHub
Finally, the Collaborator can pull from GitHub to get the changes the owner made.
#### Both can view commit history
When either the Collaborator or the Owner view the history, the conflict, associated
branch, and the merged changes are clearly visible in the history.
![](img/git-conflict-08-history.png)
::: {.callout-note}
### Merge Conflict Challenge {- .exercise}
Now it's your turn. In pairs, intentionally create a merge conflict, and then go
through the steps needed to resolve the issues and continue developing with the
merged files. See the sections above for help with each of these steps:
- Step 0: Owner and collaborator ensure all changes are updated
- Step 1: Owner makes a change and commits
- Step 2: Collaborator makes a change and commits **on the same line**
- Step 3: Collaborator pushes the file to GitHub
- Step 4: Owner pushes their changes and gets an error
- Step 5: Owner pulls from GitHub to get Collaborator changes
- Step 6: Owner edits the file to resolve the conflict
- Step 7: Owner commits the resolved changes
- Step 8: Owner pushes the resolved changes to GitHub
- Step 9: Collaborator pulls the resolved changes from GitHub
- Step 10: Both can view commit history
:::
## Workflows to avoid merge conflicts
Some basic rules of thumb can avoid the vast majority of merge conflicts, saving
a lot of time and frustration. These are words our teams live by:
- Communicate often
- Tell each other what you are working on
- Pull immediately before you commit or push
- Commit often in small chunks.
**Always start your working sessions with a pull** to get any outstanding changes, then
start doing your editing and work. Stage your changes, but before you commit, Pull
again to see if any new changes have arrived. If so, they should merge in easily
if you are working in different parts of the program. You can then Commit and
immediately Push your changes safely. Good luck, and try to not get frustrated. Once
you figure out how to handle merge conflicts, they can be avoided or dispatched
when they occur, but it does take a bit of practice.
---
## Your turn
- Use your favorite desserts to create a merge conflict. Resolve it using RStudio
- Mixing the fun: try to create a merge conflict using the forking workflow. How would you do this? Try to resolve the conflict on the GitHub website! [hint](https://docs.github.com/en/github/collaborating-with-pull-requests/addressing-merge-conflicts/resolving-a-merge-conflict-on-github)
---
# Aknowledgement
This section had been adapted from [NCEAS Reproducible Research Techniques for Synthesis](https://learning.nceas.ucsb.edu/2021-02-RRCourse/index.html)
Individual units were created by (in alphabetical order): Julien Brun, Amber Budden, Jeanette Clark, Matt Jones, Erin McLean, Bryce Mecum, William Michener.