8.4 Collaborating

One of the strengths of using git is that it provides an efficient means of collaborating. However, not just anyone can contribute to your repo directly. There are two primary ways you can collaborate on a repo with colleagues: (a) add collaborators to an existing repo, or (b) create an organization and add collaborators to specific repos, or the organization as a whole. The primary difference between these is that organizations typically have many repos, and you can grant access to all repos simultaneously. You might consider creating an organization for your entire lab, for example, and then have different repos for different projects. Even within organizations, however, you can add collaborators to individual repos without providing access to the entire organization.

To add collaborators to a repository, go to Settings -> Manage Access -> Invite a collaborator

You can then search for individuals by their GitHub username, email, or their first/last name. Once an invite is sent, the individual must accept the invite and they will then have push access to the repo. Collaborators should generally be reserved for people who have ongoing roles in the project, with direct contributions. Small bug fixes, etc., can be handled with repository forks (described below).

8.4.1 Branching

Branching is a really powerful framework for working with git, and one we suggest you become comfortable with as early as possible. When you create a branch, you effectively create a parallel copy of the entire repo. You can make any changes you want on that branch and be assured that you will not break anything on the main branch because it is completely separate. Once you’ve built out whatever it is you were working on in your branch, and you have decided with your collaborators that it should be part of the main branch, you can merge it in. Alternatively, you may decide you don’t want to actually make those changes, and then you can just trash the branch and move on without any disruption to the main branch.

As a general rule, you should try to never make changes directly to the main branch. Instead, create branches, make changes there, and then merge them in. This helps ensure changes are implemented into the main branch in a planful way, and you can use review systems with your colleagues to ensure everyone is on the same page.

To create a branch in GitKraken, you right click on the most recent commit and select “Create branch here”.

It will then prompt you to provide the branch with a new name. Here we’ll use “example-branch”. As soon as you provide the name, GitKraken will automatically checkout the branch for you. In the below, notice that the green check mark is next to example-branch and not main. If we were to double click main, we would checkout the main branch instead, but at present they are the identical.

Let’s now go make some changes in our repo. In this case, I’ve made some edits to the script file which produces the plot, and re-saved the plot. Let’s look at the diff.

In the above we can see that I added a new line after loading the {tidyverse}, changed the points so they are colored according to drv and removed the transparency, alpha. I’ve also added a line to change the default colors for the points, added labels, placed the plot legend at the bottom, and changed the styling of the code a bit (mostly additional line breaks). You can see that some of the text was already existing, but is now on a new line (e.g., line 13 of the new file) while other pieces are brand new (e.g., line 24 of the new file). The ggsave() code was unchanged.

Next, let’s add one additional file to our repo, which will just be the default Rmd template. We’ll save and render this file in a new folder we’re calling “reports”. GitKraken now looks like the below, with two new files added, and Rmd and html file in the report directory, and the edited exploration and ggplot-example files.

Let’s go ahead and stage and commit these files through two commits. First we’ll commit the plot changes with the commit message “styled plot”, then we’ll commit the report with the commit message “created report template”. Note that these commits have been made to the example-branch branch, and not the main branch. Our example-branch is now two commits ahead of our main branch.

We also still have example-branch checked out. Our local folder for the repo currently looks like the below.

If we go back to GitKraken and double click on “main” on the left side, however, the edits we made to the plot and the report folder overall disappear from our local folder.

This is because those edits (and commits) were made on example-branch, but we are no longer on that branch, so we can’t see those changes.

Let’s switch back to example-branch and push those changes to the remote. It will ask us what remote branch it should push to. Just leave the default settings, which will be the name of the branch, and click submit.

8.4.1.1 Pull Requests

After pushing a branch to your remote repository, go to GitHub and you should see something like the below.

This is noting that a new branch has been created on the remote, and it’s asking if you’d like to submit a pull request to compare the changes between this branch and the main branch and (potentially) merge the branch with the main branch. Right below this flagged message, you will also see that we now have 2 branches. You can click on the drop down next to main and see the second branch, as well as the repo at that state (i.e., viewing the repo through GitHub as if you have checked out example-branch).

Let’s go ahead and click “Compare and pull request” to start a pull request. Note that if this flag were not there, you could do the same thing by clicking on “Pull requests” along the top navigation bar (next to Issues), click “New pull request” and then change the drop-down menus so you’re comparing “main” to “example-branch”, with the latter being merged into the former (i.e., an arrow pointing toward main). If you take this route, it should look like the below. Click “Create pull request” to actually start the pull request to merge example-branch into the main branch.

Once you open a pull request (PR), the title will be filled in for you by the commit message, but you can change this if you’d like. Generally, you will want to then leave a comment with a brief description of the enhancement the PR adds or the problem it solves. On the right side, you can also request reviewers for your PR (they must be collaborators on the repo). GitHub has a pretty nice system for reviewing code that allows you to provide comments to specific lines. You can also add labels (e.g., “Bug”, “Enhancement”) or assignments (although these are more common for Issues than PRs). You can also choose to link to an Issue, which will cause the issue to automatically close once the PR has been merged.

In the below, I’ve created the PR with a very basic description and added the enhancement tag. I’m not requesting any reviewers or linking any issues in this case because it’s so simple (and I actually never invited any collaborators), but these are generally good things to do as well.

Note that GitHub will do an automatic check to make sure the PR can be merged without any conflicts. If it cannot, I recommend doing the merge locally through GitKraken so you can use the merge conflict editor, then pushing the changes. GitHub will detect if a PR has been merged in a previous commit and close automatically (i.e., after you push the main branch that has the previously conflicted branch merged). Most of the time you will not have conflicts and you can just merge the pull request.

Note that GitHub will immediately ask you if you’d like to delete the branch. Except in rare circumstances, you will nearly always want to delete the branch after merging. This will delete the branch on the remote, but not on your local.

If we go back to our local, GitKraken now looks like the below.

Notice that we still have example-branch checked out. Additionally, we can see that the main branch on the remote is ahead of example-branch on our local (because it’s been merged) and it is also ahead of our local main branch.

Let’s switch to the main branch (double-click on “main” on the left pane under LOCAL) and pull for the most recent changes.

And we can now see that our main branch on our local is up to date with the remote, but the example-branch is now behind. At the point, those changes have also been merged in with main, and we can safely delete this branch (right click on the branch name with main checked out - select “Delete [branch name]”).

8.4.2 Forking

The process described above assumes that you either own the repo or are a direct collaborator on the repo. What happens, however, if you are want to contribute to somebody else’s project? For example, maybe you’re working with a new R package and you notice a minor bug that would be easy to fix. Rather than filing an issue, you could fork the repo to your account, make the changes there, and then submit a pull request while comparing across forks. Note this does not mean you should do this instead of filing an issue, and best practice would be to communicate with the package developer ahead of time. You could, for example, file and issue and offer to provide the fix through your fork and a subsequent PR. This is a powerful framework and allows enormous gains in development through crowdsourcing problems. The {broom} package, for example, has three core authors, but contributions from nearly 120 other individuals (at the time of this writing). Beyond contributing to a repo directly, you might choose to fork a repo because you want to make some small changes that probably shouldn’t be implemented in the actual repository, but makes sense to change for your purposes. It’s also common to fork things like personal websites, where you use somebody else’s website as the basis for developing your own.

To fork a repo, navigate to the repo you want to copy to your account, and click the “fork” button near the top right.

It will then ask you where you want to fork the repo. If you only have one account, you’ll just click your account. In my case, I have my individual account, and a few different organizations. I’ll fork this repo to my individual account.

It will then take a few minutes to fork and then you’ll have a copy of the repo on your local account. The benefit here is that you have full access to this copy. You can make whatever edits you’d like and commit/push them to your fork.

If you’d like to make a pull request from your fork (after you’ve made some edits that you think should be incorporated into the main repo), you just need to go back to the original repo, click “Pull requests” then “New pull request”. Once you get there, it will ask you what branch you want to merge in, just as before. In this case, however, you want to “compare across forks”. Select your fork, and you should be able to complete the pull request just as before.

One thing worth noting with forks is that it is very common for your fork to end up behind the main repository. You then need to sync your fork with the upstream repository. This is one of the few operations that I do not know how to handle through GitKraken, but it is relatively straightforward (see here).

8.4.3 Stashing

When you’re working across multiple branches, you may find yourself accidentally making changes on one branch that should have been made on another branch. You don’t want to commit those changes, because they should be committed on a different branch that you do not currently have checked out. This is where stashing can be helpful. The below is a very simple example where I have a report branch but I have accidentally made edits to the report on the main branch. Depending on the situation, you may be able to just switch to the report branch and make your commits there. Ofen, however, you will need to first stash your changes. You do this by first selecting your files in the “Unstaged Files” area, then clicking the “Stash” button at the top (next to “Branch”).

This will place the files in, essentially, a temporary branch, which allows you to then checkout other branches.

Next, you checkout the branch you want the changes on (report) and click “Pop” (next to “Stash”).

You can then stage and commit the files on that branch, as intended.

Another common area where stashing can com into play is if you have pulled for recent changes without having first committed all the changes you’ve made locally. In this case the stash will be created automatically (but will look similar to the screenshot above), but you can pop it on the branch you’d like in the same way. Note that stashes do not prevent merge conflicts and it is fairly common to have a merge conflict between a stash and the branch you are trying to pop it on.