Managing contributions to code
Overview
Teaching: 25 min
Exercises: 10 minQuestions
How do I keep my local branches in sync with the remote branches?
What is the difference between forking and branching?
How can my group use GitHub pull requests to manage changes to a code?
How can I suggest changes to other people’s code?
What makes a good pull request review?
Objectives
Create a pull request from a branch within a repository.
Create a pull request from a forked repository.
Motivation for remote repositories
Access and Permissions
Developer 1 - “Just email me your changes. I’ll save them into the master copy.”
Developer 2 - “Ok… so why do all of my changes have to go through you?”
GitHub gives you a central place to collaborate!
Need to Coordinate Efforts
Developer 1 - “I’m still waiting on those changes to the data analysis workflow.”
Developer 2 - “Huh? I added those a month ago.”
Issues help keep track of tasks.
Different Points of View
Developer 1 - “Here’s what I’ve been working on for the last month.”
Developer 2 - “Hmmm… if we tweak things here then it might be faster.”
Pull Requests allow for easily reviewing collaborators’ changes.
Multiple branches in remotes
The same way you might have different branches in your local repository, you could manage different branches in your remote - the same branches or different ones.
As a reminder, remote and local repositories are not automatically synchronised, but
rather it is a manual process done via git pull
and git push
commands. This
synchronisation needs to be done branch by branch with all of those you want to keep
in sync.
Pushing
- Its basic use is to synchronise any committed changes in your current
branch to its upstream branch:
git push
. - Changes in the staging area will not be synchronised.
- If the current branch has no upstream yet, you can configure one by doing
git push -u origin BRANCH_NAME
, as done withmain
in the exercise above. push
only operates on your current branch. If you want to push another branch, you have tocheckout
that branch first.- If the upstream branch has changes you do not have in the local branch, the command will fail, requesting you to pull those changes first.
Pulling
- Opposite to
push
,pull
brings changes in the upstream branch to the local branch. - You can check if there are any changes to synchronise in the upstream branch by
running
git fetch
, which only checks if there are changes, and thengit status
to see how your local and remote branch compare in terms of commit history. - It’s best to make sure your repository is in a clean state with no staged or unstaged changes.
- If the local and upstream branches have diverged - have different commit history - the command will attempt to merge both. If there are conflicts, you will need deal with them in the same way described above.
- You can get a new branch existing only in
origin
directly withgit switch BRANCH_NAME
without the need of creating the branch locally and then pulling the remote.
Pull Requests
Pull requests are a GitHub feature which allows collaborators tell each other about changes that have been pushed to a branch in a repository. Similar to issues, an open pull request can contain discussions about the requested changes and allows collaborators to review proposed amendments and follow-up commits before changes are either rejected or accepted and merged into the base branch.
Why the name?
The term “Pull Request” may sound counterintuitive because, from your perspective, you’re not actually requesting to pull anything. Essentially it means “Hey, I have some changes I would like to contribute to your repo. Please, have a look at them and pull them into your own.”
You may see the term
merge request
instead ofpull request
. These are exactly the same thing. Different platforms use different terms but they’re both asking the receiver of the request to review those changes prior to merging them.
There are two main workflows when creating a pull request which reflect the type of development model used in the project you are contributing to;
- Pull request from a branch within a repository and,
- Pull request from a forked repository.
Essentially, the way you use pull requests will depend on what permissions you have for the repository you are contributing to. If the repository owner has not granted you write permission, then you will not be able to create and push a branch to that repository. Conversely, anyone can fork an existing repository and push changes to their personal repository.
About forks
Before we get into understanding pull requests, we should first get to grips with what a fork is, and how it differs from a branch.
- By default, a public repository can be seen by anyone but only the owner can make changes e.g. create new commits or branches.
Forking
a repository means creating a copy of it in your own GitHub account.- This copy is fully under your control, and you can create branches, push new commits, etc., as you would do with any other of your repos.
fork
is a GitHub concept and not Git.- Forks are related to the original repository, and the number of forks a given repository has can be seen in the upper right corner of the repo page.
- If you have some changes in your fork that you want to contribute to the original repo, you open a
pull request
.- You can bring changes from an upstream repository to your local fork.
Now let’s take a closer look at those two types of development models;
1. Pull request from a branch within a repository
This type of pull request is used when working with a shared repository model. Typically, with this development model, you and your collaborators will have access (and write permission) to a single shared repository. We saw in a previous episode how branches can be used to separate out work on different features of your project. With pull requests, we can request that work done on a feature branch be merged into the main
branch after a successful review. In fact, we can specify that the work done on our feature branch be merged into any branch, not just main
.
Pull requests can be created by visiting the Pull request
tab in the repository.
Changing head and base branch
By default, pull requests are based on the parent repository’s default branch. You can change both the parent repository and the branch in the drop-down lists. It’s important to select the correct order here; the head branch contains the changes you would like to make, the base branch is where you want the changes to be applied. The arrow between the drop-downs is a useful indicator for the direction of the “pull”.
Now you try
Let’s revisit our
recipe
repository.
- Create a new branch, make some changes and push the branch to the remote repository.
- Create a pull request with a suitable title and description to merge the branch containing your changes into the main branch.
Solution
$ git branch more_avocados
$ git switch more_avocados
$ # make, stage and commit changes
- On GitHub.com, navigate to your repository and choose your branch which contains your changes from the “Branch” menu.
- From the “Contribute” drop-down menu, choose the “Open pull request” button.
- From the base branch drop-down menu, choose the branch you want your changes to be merged into, and in the compare drop-down menu, choose the branch which contains your changes.
- After giving a suitable title and description for your pull request, click the “Create pull request” button.
For a deeper dive into this “feature branch workflow”, have a read of the Atlassian example - Git Feature Branch Workflow
2. Pull request from a forked repository
Forks are often used in large, open-source projects where you do not have write access to the upstream repository (as opposed to smaller project that you may work on with a smaller team). Proposing changes to someone else’s project in this way is called the fork and pull model, and follows these three steps;
- Fork the repository.
- Make the changes.
- Submit a pull request to the project owner.
This fork and pull model is a key aspect of open-source projects, allowing community contributions whilst reducing the amount of friction for new contributors in terms of being able to work independently without upfront coordination. Another benefit of forking is that it allows you to use someone else’s project as a starting point for your own idea.
After forking the repository, the second step is to make our fix/changes. First we will need to clone our fork so that we have the files in that repository locally on our computer (clone
command was covered in the introductory course). From here we can go ahead and create a new fix/feature branch and make our changes. When we are happy with the changes we have made, we can commit
and push
our upstream, forked repository.
The third and final step in the workflow is to create a pull request. This is done in the same way as in the shared repository model above (navigate to your forked repository, click on the “Contribute” drop-down menu, then click the “Open pull request” button), only this time instead of the base branch being one in your repository, it is a branch in the upstream repository that you forked.
Another difference with pull requests from forked repositories is that you can allow anyone with push access to the upstream repository to make changes to your pull request. This is done by selecting Allow edits from maintainers.
As with the shared repository model, Atlassian has a nice Forking Workflow example if you want a deeper dive.
Requesting reviewers
- When opening a PR, you can request it to be reviewed by someone else, so there is another pair of eyes making sure that your contribution is correct and does not introduce any bugs.
- Reviewers can just comment on the PR, approve it, or request changes before it can be approved.
- Some repositories might require the approval of one or more reviewers before the changes can be merged into the target branch. This can be set up by the repository manager(s) as a branch protection rule.
- Only maintainers of the target repository can merge a PR.
Reviewing a PR
- When reviewing a PR, you will be shown, for each file changed, a comparison between the old and the new version, much like the
git diff
command (indeed, it isgit diff
between the original and target branches, just nicely formatted). - You can add comments and suggest changes to specific lines in the code.
- Comments and suggestions must be constructive and help the code to become better. Comments of the type “this can be done better” are discouraged. The CONTRIBUTING or the CODE_OF_CONDUCT files often contain information on how to make a good review.
Closing GitHub Issues
The introductory course - Using GitHub Issues - describes how issues work on GitHub, but one handy functionality that is specific to pull requests is being able to automatically close an issue from a pull request.
If a PR tackles a particular issue, you can automatically close that issue when the PR is merged by indicating
Close #ISSUE_NUMBER
in any commit message of the PR or in a comment within the PR.
Key Points
Forks and pull requests are GitHub concepts, not git.
Pull request can be opened to branches on your own repository or any other fork.
Some branches are restricted, meaning that PR cannot be open against them.
Merging a PR does not delete the original branch, just modifies the target one.
PR are often created to solve specific issues.