2020-CS107 / AC207 / CSCI E-207

  • Syllabus
  • Schedule
  • Course Flow
  • Resources
  • Materials
  • Project

Key Word(s): git, local branches, merge conflicts

Download Notebook


Pair Programming Exercises¶

Week 3 (September 17th - September 22nd)¶

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.

  1. Create a new branch called feature_branch and switch to this new branch.
  2. Type git branch to make sure you're on this new branch.
  3. Edit your README.md by including a subsection (level 2 Markdown header) called Content. Under the Content 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.
  4. Type git status to see the state of your local repo after you made these changes.
  5. 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.

  1. Switch to the master branch.
  2. Look inside README.md (use cat or vim or whatever you prefer). You should see that this README.md is different than the one you just edited on your feature_branch.
  3. Now merge the commit from feature_branch into master.
  4. 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 does git status say about your local master branch relative to origin/master?
    • Look inside README.md. What do you see?

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.

  1. Delete the feature_branch.
  2. 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 in pair_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 fetched 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 merging 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/
Copyright 2018 © Institute for Applied Computational Science