Key Word(s): git, local branches, merge conflicts
Exercise 1¶
Suppose we want to add a feature to our repo. We'll create a new branch to work on that feature, but we don't want this branch to be long-lived. We plan for this branch to be deleted soon after we merge the changes into master
.
For this exercise, you will work in the root directory of your course repo.
- Create a new branch called
feature_branch
and switch to this new branch. - Type
git branch
to make sure you're on this new branch. - Edit your
README.md
by including a subsection (level 2 Markdown header) calledContent
. Under theContent
section, create a bulleted list where each bullet is a directory name (e.g.lectures
,homeworks
,pair_programming
, etc). Provide a one-sentence description next to each bullet title. - Type
git status
to see the state of your local repo after you made these changes. - Stage and commit your changes.
Pause. At this point, you've committed your new feature to your feature_branch
in your local repo. Presumably it's all tested and everything is working nicely. You'd like to merge it into your master
branch now. First, you'll need to switch to the master
branch.
- Switch to the
master
branch. - Look inside
README.md
(usecat
orvim
or whatever you prefer). You should see that thisREADME.md
is different than the one you just edited on yourfeature_branch
. - Now merge the commit from
feature_branch
intomaster
. - Poke around a little bit now. Make the following observations:
- What message did
git
output after you did the merge? - Do a
git status
again. What doesgit status
say about your localmaster
branch relative toorigin/master
? - Look inside
README.md
. What do you see?
- What message did
Pause. Now our master
branch is up to date with our feature_branch
. You can now delete the feature_branch
since it is no longer relevant.
- Delete the
feature_branch
. - Push your changes to your remote repo.
Great! Now you have a basic understanding of how to work with branches. There is much more to learn, but these commands should get you going. You should really familiarize yourself with Chapter 3 of the Git
book for more details and workflow ideas.
Deliverables¶
- An updated
README.md
in your course repo. - The same
README.md
file should also be in your course repo inpair_programming/PP3/
.
Exercise 2¶
You already have experience with merge conflicts from the first homework assignment. Let's do it one more time under supervision, just a bit faster this time. After this, you're on your own.
Setting up¶
Please add your breakout room partners as a collaborator on your playground
repo. One of you should clone the other's playground
repo. For example, suppose Sally and Joe decide to work together. Together, they decide that Joe will clone Sally's playground
repo. This should be done in your own directory somewhere. It's up to you where, just try to be organized.
Making Some Changes¶
Each partner should make some changes to the playground
repo. The easiest way to do this to start will be to change the title of the README.md
file. For the sake of the exercise, each partner should make the title of the README.md
file something different. Feel free to do something more creative / interesting.
Reminder: One partner will be working from their original playground
repo while the other partner will be working from the newly cloned playground
repo.
Once you've each made the changes, please try to stage-commit-push. This should work without a problem for one of the partners. The other partner should get an error similar to:
To https://github.com/dsondak/playground.git
! [rejected] master -> master (fetch first)
error: failed to push some refs to 'https://github.com/dsondak/playground.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
The second partner realizes that they've made a mistake. Always fetch and merge (or pull) from the remote repo before doing your work for the day or pushing your recent changes. However, perhaps you're a little nervous since it only took you a minute to make your changes. You should realize that someone else probably did a push in the meantime. Nevertheless, you decide to proceed.
Resolving Some Conflicts¶
The partner who failed to push should try to do a fetch-merge
sequence. Try out the following command:
git fetch
git merge origin/master
Think about what these commands are doing! Can you explain them? Try to explain to your partner.
You should get an error message similar to: (Note: Take a screenshot of this conflict message and name it exercise_2.png)
Auto-merging intro.md
CONFLICT (add/add): Merge conflict in intro.md
Automatic merge failed; fix conflicts and then commit the result.
From https://github.com/dsondak/playground
999fd74..2658cab master -> origin/master
There is a conflict in intro.md
[in this particular example, but yours might be slightly different] and git
can't figure out how to resolve the conflict automatically. It doesn't know who's right. Instead, git
produces a file that contains information about the conflict.
Do a cat
on the conflicted file. You should see something like:
<<<<<<< HEAD
# A Project by Joe
=======
# A Project by Sally
>>>>>>> origin/master
The partner with the conflict knows that their partner is working on the same project as they are (they're teammates) so don't be alarmed.
Resolve the conflict¶
Talk to your partner and decide on a new title for the README.md
file. Update the file and do a stage-commit-push sequence (with a good commit message!!) to update the remote repo.
The merge conflict has been resolved! Of course, the other parter's local repo doesn't yet know about what just happened. They need to fetch
and merge
to get the updates. Do this now!
You should see output similar to:
Updating 2658cab..51c6b05
Fast-forward
intro.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From https://github.com/dsondak/playground
2658cab..51c6b05 master -> origin/master
Observe: This is reporting a fast-forward operation. Why wasn't there another merge conflict? Please explain.
So what actually happened here?¶
[Note: We'll use Joe and Sally to explain what's going on for clarity.]
And as expected, git
knows how to resolve this conflict. The reason git
can resolve this conflict even though the files differ on the same line is that git
has the commit history, too. When Sally made their original commit, they were given a commit hash (starting with 2658cab). When Joe resolved the merge conflict, Joe created a new commit hash (51c6b05) which unified the changes in commit 2658cab (Sally's original commit) and commit 3b934ee (Joe's original commit). Then, when Joe pushed, all of this information was given to the upstream repository. So git
has a record stating that the merge resolution commit 51c6b05 is a subsequent commit to Sally's original changes in 2658cab. When Sally fetch
ed the upstream repo, Sally got this information, too. So when Sally executed a merge
, Sally was merging a predecessor (2658cab) with its direct successor (51c6b05), which git
handles simply by using the successor.
The tricky conflict resolution that Joe did was effectively a way of taking two separate branches and tying them together.
One more note on binary files¶
A problem that students sometimes run into occurs when they try to update their local repo from another repo after some changes to a .pdf
file have been made.
One of the big lessons here is that versioning binary files with git
requires some special tools. In this case, the binary file was a .pdf
document. In another case it may be an executable file.
The reason why binary files are difficult to version is because git
must store the entire file again after each commit. This is essentially a consequence of the fact that there is no clear way to diff
binary files. Hence, the merg
ing operation has problems.
There is extensive information around for the special tools git
has for working with binary files. For the particular case of .pdf
files, you can use some special arguments to the git checkout
command. A nice discussion can be found at https://stackoverflow.com/questions/278081/resolving-a-git-conflict-with-binary-files.
My recommendation is that you try to stay away from versioning binary files. I put them up on git
because I will not be changing the lectures slides much (if at all) over the course of the semester and because the lecture slides do not take up much space (and will therefore not have much of an effect on the speed of git
). In fact, it is generally best practice to update your .gitignore
file at the root of your repository to ignore binary files altogether.
Deliverables¶
- exercise_2.png in your course repo in
pair_programming/PP3/