Lab Session 3: GitHub Continued, Pull Requests#

Friday 02-10-2023, 9AM-11AM & 12AM-2PM

Instructor: Facundo Sapienza

We encourage you to work in the following exercises with a partner. The exercises with the * are meant to be for two persons.

1. Collaborating on GitHub with a small team#

We are going to set up a shared collaboration with one partner (the person sitting next to you). This will show the basic workflow of collaborating on a project with a small team where everyone have write privileges to the same repository.

We will have two people, let’s call them Alice and Bob, sharing a repository. Alice will be the owner of the repository and she will give Bob write privileges.

1.1 Simple Synchronization *#

We begin with a simple synchronization example, much like we just did in the previous lab, but now between two people instead of one person.

  1. Alice creates a new repository in GitHub with some basic text files on it. For now, let’s make this repository hosted in Alice’s personal GitHub account and let’s make the repository public.

  2. Bob clones Alice’s repository.

  3. Bob makes changes to a file and commits them locally.

  4. Bob pushes his changes to GitHub. Now, in order to Bob to be able to push changes, he needs to be added by Alice as a collaborator of her respository. Alice needs to add Bob as collaborator in her Github setting page. One more detail: Alice needs to be sure that the repo has permission to use the GitHub app we are using for the course! in order to do that, Alice needs first to authenticate and then go the config page in the app and be sure the new repository is listed.

  5. Alice pulls Bob’s changes into her own repository.

Next, we will have both making non-conflicting changes each, and commit them locally. Then both try to push their changes:

  1. Alice adds a new file, alice.txt to the repository and commits.

  2. Add a tag to this stage of the repository. You can learn more about tag here. In which cases do you think it will be useful to use tags?

  3. Bob adds bob.txt and commits.

  4. Alice pushes to GitHub.

  5. Bob tries to push to GitHub. What happens here?

The problem is that Bob’s changes create a commit that conflicts with Alice’s, so GitHub refuses to apply the changes in the remote. This forces Bob to first merge in his machine. If there is a conflict in the merge, Bob needs to deal with the conflict manually (git could try to do the merge on the server, but in that case if there’s a conflict, the server repository would be left in a conflicted state without a human to fix things up). The solution is for Bob to first pull the changes.

Next, let’s have Bob creating a new branch, commiting changes in that branch to GitHub and then Alice retrieving the new branch to her local repository.

  1. In his local repository, Bob creates a new branch (see previous lab).

  2. Bob commits new changes to his branch and then try to push this changes to the remote repository in GitHub.

  3. Alice now pull the new branch from GitHub. Can Alice display Bob’s new branch with git branch? What happen when we see git branch --all?.

1.2 GitHub with conflicts *#

Follow the same workflow than before, but now try to induce a conflict. In order to induce a conflict,

  1. Both Alice and Bob need to make changes in the same line of the text files and commit these changes.

  2. After commiting, one of them will push the changes to GitHub.

  3. Right after, Alice will try to pull and she will see the merging conflict happening. How to solve this? Just in the same way you solve branch merging conflicts last lecture! Are you tired of solving the issues during the merge? You can always do a git merge --abort and try to avoid the merge conflict before it happens.

1.3 Working directly in GitHub#

So far we were using GitHub just to host our remote repository, but GitHub also allow us to make operations like quick changes, documenting issues or just viewing the state of our repository, including past versions.

Explore a little bit your GitHub repository. Specifically,

  1. Modify a text file and commit these changes from GitHub.

  2. How to see different branches in GitHub? Are these the same you have in your local machine?

  3. Alice adds Bob as a collaborator in the repository. You will need to go to setting for this.

  4. Open a new issue and tag the other person in that issue.

  5. Review past versions of the repositories.

2. Reconstructing past versions#

Sometimes we make accidental changes to some of the files in a repository, or maybe we just want to comeback to a previous version. In any case, it is easy to restore or even recover old versions of files that have been track in a commit message.

For these next examples, we are going to use the git checkout command to restore past versions of a file. This can lead to some confusion, since this is the same command we use for changing branches. In a sense, git checkout does both the work of git switch and git restore. You can do all the following exercises with git restore instead of git checkout.

2.1. Restoring old versions#

For this example, we are going to make modifications to one of the files in our repository and then recover some of the older versions.

  1. Make more than one change in the same file in your repository, for example you can use write some new text inside text.txt. With echo "..." >> text.txt you will print new lines at the end of text.txt (with > you will just overwrite all the contents).

  2. Try to restore previous version of such file by using

git checkout <commit> <filename>

or

git restore --source=<commit> <filename>

You will need to specify the stage at which you want to restore the file. You can do this by looking at the log of the repository (git log, git slog, git log --all). This is why commit messages are so important!

Observation: you can also see old versions of your files directly on GitHub, in case you need to inspect previous versions of files.

2.2. Recovering deleted files#

Now, let’s practice deleting and recovering an specific file

  1. Remove one of the files in your test repository. You can also just create a new file and remove it. To do so, use the git rm <file name>. You can take a look to this link to see some flags you can add to this command.

  2. If you haven’t commit your changes, you can recover the file just by coming back to the previous snapshot of the repository by using git checkout HEAD

  3. Now, if you make a commit after removing the changes, you need to do a little bit more of work. Use git slog -- <filename> to see all the history associated to the file you removed and then use git checkout <commit> -- <filename> to recover it.

3. Forks and Pull Requests *#

Sometimes is is useful to create a complete new copy of a repository and work on that before merging the new changes to the main repository. This is particularly when working with packages, big projects or just when we want to experiment a little bit having the version control capabilities without adding changes to the main repository. For these cases is when we want to use forks and then pull requests if we want to merge changes across repositories (or inside the repository too).

If you are not familiar with the concept of pull requests, take a look to the pull request chapter in the course book. The idea of a pull request is to merge a branch for any given repository to a branch of another repository.

Let’s practice this following where we stopped with Alice and Bob example.

  1. Bob forks Alice’s repository (alice/test) into his own GitHub account (bob/test). Take a look to Using Other People’s Work.

  2. Bob clones his repository into his local machine.

  3. Bob makes some changes and commit them.

  4. Bob pushes his changes to GitHub.

  5. Once in GitHub, Bob creates a pull request to merge his changes into alice/test. At the moment of doing this, add Alice as reviewer of the pull request.

  6. Now Alice needs to accept Bob changes to the main repository.

Repeat this but now change roles between Bob and Alice.

4. Extra#

If you already finished all the previous tasks, you are welcome to explore some more useful git commands!

Can you think in a situation where these commands may result useful? For example, instead of using git pull, can you do the same with git fetch and then git merge? If so, what can be the advantage of doing such a thing?