Skip to main content
Logo image

Chapter 6 Collaborating with Others

Section 6.1 Collaborators and Pull Requests

A direct way to allow multiple people you trust to work on the same repository is to add these GitHub users as collaborators.

Definition 6.1.1.

A collaborator for a GitHub repository has the ability to commit and sync changes to the project, as well as adjust certain settings of the repository. GitHub documentation
 1 
docs.github.com/en/account-and-profile/setting-up-and-managing-your-personal-account-on-github/managing-user-account-settings/permission-levels-for-a-personal-account-repository
provides some details on the different permissions/abilities that owners have in comparison to collaborators.
Collaborators are added by going to your repository’s Settings tab, using the Collaborators link in the sidebar. Each collaborator will need their own GitHub account, and must accept the invitation to collaborate before gaining access.
Once they have access, a collaborator can either use GitHub.dev (Note 2.4.2) or create their own Codespace (Definition 3.1.1).

Warning 6.1.2.

If two collaborators on the same repository make commits on the same branch, they will desynchronize your project’s history: person A’s history will think that commit X is followed by Y on branch main, but person B’s history will think that commit X is followed by Z on branch main.
As seen in Figure 1.1.1, Git is meant to support non-linear history. However, to support this, contributors must name their distinct branches.

Note 6.1.3.

Our recommendation to support multiple collaborators on the same repository is to never directly commit to the main branch, even if you’re the owner.
To commit to an alternative branch in GitHub.dev or Codespaces, select main in the bottom toolbar, then type the name of your new branch, and select “Create new branch”. It’s a good idea to name your branch in the form UserName/short-description-of-topic, or if you’re unsure of the topic, you can just use the current date: UserName/YYYYMMDD. Note that prefixing with your UserName helps prevent two people from accidentally using the same branch name.
Once a collaborator is working on a branch, they are free to edit as they wish, and can (and should) commit and push/sync with GitHub to persist their contributions to the team’s repository.
To facilitate communication among collaborators working on different branches, it’s good practice to open a draft pull request once a new branch is created.

Definition 6.1.4.

A pull request (or PR for short) is a discussion thread for a branch that proposes changes to a different (often, the main) branch. When the branch’s changes are ready to be merged, this can be accomplished by pressing a button on the pull request webpage.
A PR can be marked as a draft or ready to review.

Note 6.1.5.

Depending on whether the collaborator is using GitHub.dev or Codespaces, they may be prompted to create a pull request when first pushing/syncing changes. If not, a pull request can be created by navigating to the repository page on GitHub.com.
Recent pushes to a branch will reveal a prompt to create the pull request immediately. Otherwise, the PR can be created by using the Pull Requests tab of the page.
Unless the PR is for a single commit that’s immediately “ready for review”, a new PR should be created as a draft.
With a draft pull request created, the contributor can continue to commit and push/sync to the branch until it is ready for review. The discussion features of GitHub can allow contributors to discuss the proposed changes, whether they are in draft or review-ready status.

Note 6.1.6.

A draft pull request has a large button near the end of the discussion thread to mark the pull request as ready for review.
A ready for review pull request can be converted to a draft by using a small link on the right sidebar.
Depending on the complexity or maturity of the project, you may wish to develop a review process with your collaborators, or simply use the PR workflow to clearly communicate when changes are being made to the main branch, and ensure no two collaborators make incompatible changes to the same branch. Whatever you choose, you’ll eventually want to incorporate these branched changes into your main branch.

Note 6.1.7.

There are several options for merging a branch’s pull request. I recommend the “Squash and Merge” option, which converts all the branch’s commits/changes into a single new commit extending the target branch.
As long as contributions are made using appropriate branches and pull requests, you will have minimal problems with conflicting changes made between different collaborators, with GitHub handling the merging process automatically, even if two collaborators edit the same file. (But not always, see Section 6.4.)
But a common error that I frequently make myself: what if you forget to create a branch with your work, and you acccidentally commit to main directly? The first safety rail I recommend is to set up a policy on your repository that will prevent this accidental commit to be pushed to GitHub.

Note 6.1.8.

To prevent unintended changes to your main branch, follow the instructions at GitHub’s documentation
 2 
docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/managing-a-branch-protection-rule#creating-a-branch-protection-rule
, using main as your “Branch name pattern”, and enabling required pull requests.

Section 6.2 Undoing accidental commmits to main

Unfortunately, there’s no button to push that will fix a commit made to the local copy of main accidentally, but there is a quick-enough fix nonetheless.

Warning 6.2.1.

This fix must be done in a Codespace, not GitHub.dev.

Note 6.2.2.

With branch protection Note 6.1.8 enabled, if you accidentally make updates directly to your personal main branch, attempting to push these from a Codespace will result in the error message Can't push refs to remote. Try running "Pull" first to integrate your changes.
To fix this, open a Terminal (Remark 3.2.4) and type Listing 6.2.3, changing my-new-branch to the branch name you want to create. Use Enter to execute the command.
Then, copy-paste Listing 6.2.4 and your local main branch will match the official repository, and any changes you’ve made will be reflected on the my-new-branch branch instead.
BRANCH=my-new-branch
Listing 6.2.3. Defining the name for a new branch
git stash
git branch $BRANCH
git reset --hard origin/main
git checkout $BRANCH
git stash pop
Listing 6.2.4. Moving local changes to main to a branch

Section 6.3 Forks

One great thing about working with open source on GitHub is that not only can you collaborate with your trusted colleagues, but you can also work with collaborators who do not have write access to your repository.

Definition 6.3.1.

A fork for a public repository is a copy of the project’s entire history, made either for the main branch or for all publicly shared branches.
Managing contributions from forked repositories is done using the same workflow as we recommend for collaborating with trusted colleagues that you’ve given write access to your repository (Section 6.1). The only difference is that an outside collaborator is creating branches and making commits on their forked copy of your project, not a branch of your original repository. But GitHub still gives essentially the same options for the outside collaborator to create a pull request to your project, without given them access to any data you aren’t already sharing with the public.

Note 6.3.2.

To create a fork of a public repository, press the “Fork” button on its GitHub.com homepage. You can name this fork whatever you like, it will be tracked on GitHub as a fork of the original project, with the ability to make “upstream” contributions by way of pull requests.
Those of us who work in open source typically love getting pull requests from random collaborators. For example, if you find a typo in this book, you can fxi it by creating a fork at https://github.com/StevenClontz/github-for-mathematicians/fork, editing the appropriate source/*.ptx file to fix the word, and open a pull request.

Section 6.4 Handling Merge Conflicts

Perhaps the most complicated scenario when collaborating on a Git repository is the dreaded merge conflict.

Definition 6.4.1.

While Git is fairly good about merging together changes made by different contributors to different files within a project into a cohesive whole, a merge conflict can occur when two different contributors attempt to make changes to the same file (particularly, the same line) at the same time. When the second contributor opens a pull request, GitHub will warn about this conflict.
Handling merge conflicts can be tricky! Git/GitHub have various tools to help you review and correct a merge conflict. If you’re fortunate, you’ll be able to resolve things on the pull request page: see Resolving a merge conflict on GitHub
 1 
docs.github.com/en/pull-requests/collaborating-with-pull-requests/addressing-merge-conflicts/resolving-a-merge-conflict-on-github
for full details.
You’ll be presented with files with some strange markers as in Listing 6.4.2. The lines between <<<<<<< HEAD and ======= were merged first, and the lines between ======= and >>>>>>> branch-a are the conflicting changes trying to be merged.
If you have questions, please
<<<<<<< HEAD
open an Issue
=======
ask them in Discussions.
>>>>>>> branch-a
Listing 6.4.2. A merge conflict
You can then choose which change to retain, deleting all the extra <<<<<<< HEAD, =======, and >>>>>>> branch-a lines.
However, sometimes the merge conflict is too involved to be corrected using the web interface. In that situation, you will need to use a Codespace and follow the instructions at either Resolving a merge conflict using the command line
 2 
docs.github.com/en/pull-requests/collaborating-with-pull-requests/addressing-merge-conflicts/resolving-a-merge-conflict-using-the-command-line
or Using Git source control in VS Code | Merge conflicts
 3 
code.visualstudio.com/docs/sourcecontrol/overview#_merge-conflicts
.