DEV Community

Cover image for Forks and Pull Requests: How to Contribute to Github Repos
Daniel Wagener
Daniel Wagener

Posted on

Forks and Pull Requests: How to Contribute to Github Repos

I recently worked with a team that was lacking a bit of documentation, so I took it upon myself to create some. In the process, I gained sympathy for authors of documentation. Documentation can often seem incomprehensible, and that's in part because when you write documentation, you have to assume your audience has some baseline level of knowledge. We can all agree, your project's README isn't the place to explain if/else statements! So I wrote some documentation outlining the steps required to make a pull request… only to realize some people on my team didn't know what a pull request was. Whoops. So let's clear that up!

The Problem with Collaborative Repositories

If you're reading this article, I'm going to assume you've used Github before. You've made a personal repository for your own code, created commits, and then pushed those commits to that repository. This is a fantastic milestone in your development journey! Now you want to contribute to someone else's repository. Perhaps this repository is open source, or perhaps it is a team's repository. Okay, but simple enough, right? Let's just clone this repo and push commits to it, just like you did with your personal repo.

BUT WAIT! That's dangerous territory. What if someone pushes error-filled code to this shared repository? Or even worse, what if some malicious Github user intentionally breaks the app with pernicious code? We can't have that! Therefore, this collaborative repo needs one or more trusted maintainers that review all incoming changes. Now the question is: how do you run your code by these maintainers?

Answer: You Make a Fork

A fork is simply a copy of the repo that lives on your own personal Github profile. You can make any changes you want to this fork and experiment all you want with its code, and that's fine! Any changes you make to your fork have no effect on the original (henceforth, "upstream") repository you forked from. In fact, the only way your changes make it into the upstream repo is through pull requests.

"Pull requests? Tell me more!"

Let's say you code an awesome feature for the project. You make your final commit and push it to your fork. Great work! Now we just need to show your awesome feature to the upstream repo maintainers so it can get included in the project.

If you make a pull request, the maintainers can look at your new code, make sure it jives with the rest of the project, and then merge it into the upstream. And if your code doesn't 100% jive just yet, the maintainers can comment on your pull request to tell you what you need to fix.

Sounds great, right? Now let's learn how to get this done.

Making a Pull Request

I actually have to make a pull request today. It's super simple and doesn't even involve code! I'm just updating the README to let my team members know I'm no longer actively working on the project (sad day). Let's make this pull request together.

To the fork!

I've been working on this project for a while, and I already have a fork. If you don't have a fork for the project you want to contribute to, you'll have to make one by clicking the Fork icon in the top right of the repo:

Github's fork icon

Then, of course, you'll run git clone on your new fork (not the upstream!) to download it to your computer. After you clone, you'll have to run git remote add upstream insert_upstream_repo's_url_here to connect your local repo to the upstream repo. After you've done so, you can run git remote -v to make sure you have both origin and upstream remotes.

Now let's begin! If you've literally just cloned a new fork, this first step doesn't apply to you. But imagine you've had this repository on your computer for a while, and since you last contributed to it, other people have made changes to the upstream repo. Perhaps they've written code that's going to affect the way you approach your issue. Perhaps someone has already solved the issue you were about to solve! In any case, we don't want to be working with outdated code. We want the latest and freshest code on our computer before we start working on anything.

Getting the Latest Code

To get this most current code, we'll run two commands. First, we have to download the upstream repo's code. Here's how:

git fetch --all

Easy, right? Though if you want to specify that you only want to download from upstream, you'd you'd run:

git fetch upstream

Note that this works because we defined upstream earlier when we ran git remote add upstream whatever_the_upstream's_url_was.

So now we've downloaded the upstream's code! But hold up. Our code doesn't look any different. Well, we've downloaded the code, but we still have to merge it into our local project. Let's do that now:

git merge upstream/master

Excellent! You should now see that the code on your computer is the same as the upstream repo's master branch. Great job getting this far.

One last step! If the project is using something like npm or Yarn, someone might have added an npm package since you last worked on the code. Therefore, to get everything running correctly, we need to add those new packages:

npm install
*****OR*****
yarn install

"What about git pull?"

Git has a command, git pull, that actually has nothing to do with making a pull request. That command is simply a combination of the git fetch and git merge upstream/master commands we just ran. All this Git stuff is actually way more intricate than I'm making it sound, so if you'd like, you can read more about fetching and pulling.

Making a Change

Whew! Now let's code our new feature. Whenever we code a new feature, it's best practice to make a new branch. That way, if everything devolves into a fiery mess, we can always escape by going back to our master branch.

The process of navigating between branches and commits is called a git checkout. Here's a neat command that lets us create a new branch and checkout it immediately:

git checkout -B your_new_branch_name_here

Like I said, I'm removing my name from the README, so I'll make my branch:

git checkout command

I make the changes to the README, and then commit and push my changes:

git push command

Note that since I made a new branch, I'm running git push origin remove_daniel instead of git push origin master. Also note that here, origin is my fork. Again, if you get lost, git remote -v is your friend.

We're almost there! Time for…

The Actual Pull Request

If I now go to Github and navigate to the upstream repo, I'll probably see this notification:

Github pull request notification

Github makes things easy, thankfully. But if you don't see this notification for some reason, no problem! Just click on the "Pull requests" tab and click the green "New pull request" button.

Github compare changes

We don't see our fork anywhere, and that's because we have to click "compare across forks." Now you'll see dropdowns for two repositories: the base repository and the head repository. In this scenario, the base repository is the upstream repo and the head repository should be my fork. Thus, I go to the second set of dropdowns and select my repo and branch accordingly:

Github compare changes across forks

At last! I now click "Create pull request" so the maintainers can see my changes.

Accepting and Merging a Pull Request

As it so happens, I am (for now) a maintainer of the repo I just contributed to. So from a maintainer's perspective, here's what the new pull request looks like:

Github pending pull request

As a maintainer, I can click on a commit to inspect the changes that were made. I also have the ability to leave a comment, among other things. If I decide everything looks good, I click "Merge pull request" to complete the process.

We're done! My update is now in the upstream repo. The concept of pull requests should be demystified now that you've seen one in action from beginning to end.

Hope this helps!

Follow me on LinkedIn, GitHub, and Twitter.

Top comments (0)