
Biomedical Open Case Studies: Making version controlled reproducible analyses
Disclaimer
This case study is still getting reviewed by a team of experts. While it is complete and has undergone some review by experts, we are continuing to improve the case study. If you have any suggestions, please email us at bioOCS@fredhutch.org. This case study is scheduled to be finalized by October 19, 2026.
Disclaimer
The purpose of the Open Case Studies project is to demonstrate the use of various data science methods, tools, and software in the context of messy, real-world data. A given case study does not cover all aspects of the research process, is not claiming to be the most appropriate way to analyze a given data set, and should not be used in the context of making policy or clinical decisions without external consultation from scientific experts or medical care professionals. In addition, due to size constraints, datasets used within a case study may be a subset of the original/full dataset.
License information
This work is licensed under the Creative Commons Attribution-NonCommercial 4.0 (CC BY-NC 4.0) United States License unless otherwise noted.
Funding information
This work is funded through the National Institutes of Health, specifically the National Institute of General Medical Sciences: Grant Number 1R25GM160622.
To cite this case study, please use:
Teichman, Sarah and Wright, Carrie. (2026). https://github.com/opencasestudies/ocs-bio-version-control/. Making version-controlled reproducible analyses (Version v1.0.0).
GitHub Repository
To access the GitHub repository for this case study see here: https://github.com/opencasestudies/ocs-bio-version-control
Keywords
- version control
- Git
- GitHub
- reproducibility
- meta-analysis
- infant gut microbiome
Prerequisites
Prerequisites
To follow along with this case study, you’ll need the following installed:
- R (install here)
- RStudio (install here) or Positron (install here) or another IDE compatible with R
It will also be helpful to be have the following skills:
- basic R skills (many introductory courses can be found online, including this one)
- familiarity with
dplyrandggplot2, or willingness to learn (thesedplyrandggplot2cheatsheets may be helpful, as well as the original open case studies)
You do not need to have any previous Git and GitHub knowledge or experience for this case study.
Motivation
In this case study, we ask you to imagine that you are working with a collaborator on a scientific project. You receive the following email, with a request for your help performing a preliminary data analysis. Don’t worry if you don’t understand the context of this analysis right now, background will be given later in the case study.

If you were to start working on this project with your collaborator, it may look something like this.


Between your own edits as you work on this project and the back-and-forth with your collaborator, it will quickly become challenging to keep track of all of the files and changes to them over time. A solution to this is !

In this case study, you will learn how to use and to track this project and perform the requested comparison of studies used in the . You will also learn how version control can facilitate collaboration and make a scientific project more .
Main Question
Our main question(s)
- How does the use of version control contribute to transparent and reproducible science?
- How can Git and GitHub be used to facilitate collaboration on a research project?
- In this meta-analysis of infant gut microbiome samples, how do the original studies compare in their sampling designs?
Learning Objectives
In this case study, we will introduce version control and describe why and how to use it to track a scientific project. We will use Git and GitHub to track a comparison of the sampling designs of studies used in a meta-analysis.
The skills, methods, and concepts that students will be familiar with by the end of this case study are:
Data Science Learning Objectives:
- Understand ways in which version control facilitates reproducible science
- Understand how version control works by recording differences between versions of a project
- Follow a workflow to create and make changes to a repository with Git and GitHub
- Make pull requests to propose changes to a codebase and request review from a collaborator
- Organize a repository for a project with a README file and folders for data, figures, and results
Biological/Bioinformatics Objectives:
- Understand the value and limitations of combining data from multiple studies in a meta-analysis.
- Use visualizations to compare sampling designs across a set of studies.
Objectives Map
| Learning Goal | Explanation / Practice | Location |
|---|---|---|
| Understand how version control facilitates reproducible science | Learn what reproducibility means and how version control contributes to reproducible analyses | Introduction to Git and GitHub |
| Understand how version control works | Learn about how version control works in terms of differences between commits | Introduction to Git and GitHub |
| Create and make changes to a repository with Git and GitHub | Create new repositories (both locally with Git and remotely with GitHub) and track changes over the course of an analysis | Introduction to Git and GitHub, Data Visualization |
| Make a pull request | Open a pull request to propose changes to a codebase, practice requesting a review from a collaborator | Pull Requests |
| Organize a repository | Learn about why the files in this project are organized in this way, understand best practices in scientific project organization | Scientific Project Organization |
| Learn about meta-analyses | Learn about what meta-analyses are, why they are used, and limitations to combining data from multiple studies. | Context |
| Use visualizations to compare sampling designs | Make plots to compare the sampling designs of the original studies used in the meta-analysis described in this case study | Data Visualization |
Context
What is a microbiome?
A microbiome is a collection of microorganisms that live in a particular environment. One commonly studied microbiome is the human gut microbiome. The bacteria that live in our gut help regulate our metabolism, protect us against pathogens, and perform other important roles in our health (Han et al. 2026). Studies have shown associations between changes to the gut microbiome and many diseases, including diabetes, autoimmune diseases, and Alzheimer’s disease.
Many features of the gut microbiome are established early in life, making the infant gut microbiome an important area of study (Wang et al. 2021). Researchers are particularly interested in understanding how the infant gut microbiome develops over time and how it relates to the maternal microbiome. To address these questions, several studies have collected samples from infant-mother pairs. Sequencing microbiome samples is expensive, and individual studies are often limited in size. Wang et al. (2021) conducted a meta-analysis of eight of these studies, using this large data set to compare gut microbiome composition (which microbes are there?) and functional potential (what are the microbes capable of doing?) between infants and mothers.
What is a meta-analysis?
A meta-analysis combines data or results from multiple studies investigating a common research question (DerSimonian and Laird 1986). By pooling information across studies, researchers can increase sample size, make better use of existing data, and generate a consensus result from a set of studies. However, meta-analyses must be conducted with care, as combining data from studies with different participant populations and different study designs can lead to misleading results.
One approach to meta-analysis combines summary results from each study. Another approach combines the original data from all studies and re-analyzes them jointly, accounting for systematic differences between studies (Andrade 2025). The latter approach requires access to the raw data from each study, but allows researchers to ask new questions and analyze the data from all studies using a common protocol.

Wang et al. (2021) used the second meta-analysis approach. They pulled the raw data from eight studies of infant and mother gut microbiomes, processed all samples with a unified protocol, and conducted analyses on the pooled dataset while accounting for differences between studies. However, the success of this approach depends on how comparable the original studies are. This motivates our exploration of the similarities and differences between the various study cohorts. We want to understand how comparable these studies are, both in terms of sample size (how many samples are in each study?), and in terms of their longitudinal sampling study design (when in the lifespan of the infants did they take samples?).
Introduction to Git and GitHub
Before we start to address your project with Collab O. Rator, we will provide an introduction to version control with Git and GitHub. In this section, you will learn more about what Git and GitHub are, create a GitHub account, download Git software, and create your first version controlled project. Towards the end of this section we will return to the infant microbiome meta-analysis project.
Reproducibility and version control
Reproducibility
The ability for someone else the run the same analysis on the same data and get the same results.
When conducting a scientific project, reproducibility is very important. If another researcher can use your data and code and generate the same results, then your conclusions are more credible to the scientific community. Version control is a tool that enables reproducible research by recording changes to a project over time. It has the following benefits:
- When used carefully, it gives a complete history of changes made over the course of a project. This can be helpful for a research team to better understand what they did in one of their own previous studies!
- It also provides a digital backup and an online repository of code and possibly also data (if it doesn’t contain sensitive data). This can be very valuable if something happens to your computer.
- Version control makes collaboration easier, automating the sharing of work in-progress and providing a system to propose and accept changes.
While several tools exist for version control, we will introduce Git and GitHub, two of the most commonly used version control tools. Common alternatives to GitHub include GitLab and Bitbucket
More information on how reproducibility fits into the scientific process.
Reproducibility considerations
Reproducibility is one concept that helps ensure that scientific projects and their results are valid and can be trusted by the scientific community. It can be considered as the intermediate goal between repeatability and replicability.
An experiment or analysis is repeatable if the same researcher can run it a second time, with the same data and code, and get the same results.
For that experiment or analysis to be reproducible, a new researcher needs to be able to run it with the same data and code and get the same result.
Finally, conclusions from an experiment or analysis are replicable if a new researcher can run the same experiment or analysis with new data and draw the same conclusions.

Why use version control?
Consider a typical workflow when you have a project with multiple files (for example: data, code, resulting figures). You likely have a folder on your computer where you keep these files. When you edit a file you save it, and you have access to the most recent version. You might run into a situation where you want to try something new, so you save “project_file_old.R” along with “project_file_updated.R” or perhaps “project_file_july_2026.R” or eventually “project_file_final_version_4_final.R”. If you haven’t saved an older version of a file but you wish you could revert to the version from last week before you tried something new, you would be out of luck.

Similarly, think about how you might work on that same project with a collaborator. Perhaps you both have a folder on your computer for that project, and when you make an update you email the file to your collaborator, and they copy that update into their file, or save your file in their folder. Perhaps the two of you update the same file at the same time and then you have to go through line by line to merge the updates into a single version of the file.

While both of these organizational systems can work well when carefully maintained, they are time consuming and prone to error. Version control is a tool that makes it easier to manage sets of files for projects. It automates several of the processes described above, and makes others dramatically easier. While version control was originally made for software engineers to work together on large projects, it is now commonly used for scientific projects as well.
At its core, version control lets the user track sequential changes to a set of files, with a short message attached to each version. Multiple people can work with the same version controlled folder, and different versions of files can automatically be merged, unless they are directly in conflict.
Our discussion of version control is inspired by the following two papers. They both provide a helpful introduction to version control with Git and GitHub.
Version control resources:
- Blischak, J. D., Davenport, E. R., & Wilson, G (2016). A Quick Introduction to Version Control with Git and GitHub, PLoS Computational Biology, 12(1).
- this paper provides an overview of Git and GitHub for scientists who primarily work with the command line
- Bryan, J (2018). Excuse Me, Do You Have a Moment to Talk About Version Control? The American Statistician, 72(1), 20-27.
- this paper provides an overview of Git and GitHub for data scientists who primarily work with R and RStudio
What are Git and GitHub?
Git is a version control tool, and GitHub is an website for hosting folders that are tracked with Git. Git works locally on your computer to record different versions of a project, and GitHub works online to provide a digital backup of files, let you connect with collaborators, and optionally create a web presence for your project.

Git
The files that are tracked as part of a version controlled project are contained in a repository.
Repository (or repo for short)
A folder in Git that contains all of the files to be tracked for a project.
When you set up a repository, Git will save an initial version of the files in that repository. Git works by tracking the evolution of files in a repository through a series of commits.
Commit
A snapshot of a the files in a repository at a certain time.
Another way to think about a commit is as a save point in a video game. This means that it saves your work up to a certain point in time. In the image below, a repository called analysis_project is tracked using version control, and it is made up of four commits. Each commit has a message that explains what the commit does. Within a commit, files can be added, edited, left unchanged, or deleted.

Each time that you tell Git to commit a version of your project, it will save it as a series of changes that list the differences between each file in the most recent commit and the current commit. We can look closer at an individual file and see how it changes across commits.

Git will not automatically make commits for you. You need to decide when to commit. If you want to return to a previous version of a project, you can only return to the version of files at any commit.
GitHub
While you could only use Git locally to track versions of files, it is much more powerful when combined with GitHub. You can use GitHub to host a Git-tracked repository online. We will use the terms local repository and remote repository to distinguish between these.
Local
The Git-tracked repository on your computer.
Remote
The online version of the repository tracked on GitHub.
There are several benefits to pairing your local repositories with remote repositories on GitHub.
- You have a backup of files in case something happens to your computer
- You can easily work with collaborators
- You have a central location where your data and code are stored for a project that can be viewed by and shared with other scientists
Reproducibility considerations
A scientific paper is more reproducible if the data (or instructions to access the data) and code are publicly available, because other researchers can directly inspect and reproduce the analysis. While some papers have data and code “available upon request”, hosting data and code on GitHub makes it easier to share these files without requiring additional time and effort from the authors to respond to emails. This aligns with the open science movement, which aims to make research, data, and scientific software more transparent and accessible.
Creating new repositories
There are two ways to start new version controlled projects with Git and GitHub. You could create a new repository locally on your computer, track it with Git, and then “push” it to GitHub, creating a remote version of the repo. Or, you could create a new remote repository on GitHub and then “clone” it to your computer, creating a local version. We will provide examples of both workflows in the next section.
Push
Sending commits from the local version of a repository to the remote version of the repository on GitHub.
Clone
Creating a local repository that is a copy of a remote repository on GitHub.

Getting started with Git and GitHub
Creating a GitHub account
We will start with GitHub. If you do not have an account, make one here.
When you choose a username, consider advice from Jenny Bryan (a data scientist who has thought a lot about version control). She suggests choosing a username that incorporates your real name and that you would be comfortable sharing with professional colleagues.
Creating a new GitHub repository
Now that you have a GitHub account, you can create your first repository.
To create your repository:
- click on the menu bottom (three horizontal lines)
- click “Repositories”
- click the green button that says “New repository”
This will take you to a new page. GitHub will automatically set you as the owner of the repository, and you can choose a name. Let’s call this repository “my-first-repository”.
A few notes on naming repositories:
- keep the name descriptive but short
- don’t use spaces, instead use “-”, “_“, or”.”
Next, add a short description for this repository. Toggle the bottom next to “Add README” to “On”. For now, we won’t worry about visibility, a template, .gitignore, or license.

Use the drop-down sections to learn about each of the configuration options.
Visibility
By default your repository will be set to public, which means that anyone can view all of the files contained in it. If you would prefer that only you and collaborators that you add can view the contents, you can set the visibility to private.
Template
A template is an existing repository that you can use as a template for new repositories. A repository made from this template will have the same folders and files as the template repository. You can make any repository that you have access to into a template. Typically, you will not use a template when creating a new repository.
README
We will discuss README files in more detail in the project organization section, but a README file explains what your repository is used for and what files it contains. If you are creating a repository from scratch, we strongly suggest that you include a README.
.gitignore
You may have files in your repository that you don’t want to commit, such as large data files or intermediate files (we will discuss which files you may not want to commit later in the project organization section). If there is a file that you don’t want to track with version control, you can add it to the .gitignore file, to tell Git to ignore it. When you click the down arrow next to “No .gitignore” it will provide several templates. For a project using R, the “R” template is a good place to start. It includes files often associated with projects in R that are not typically tracked with version control.
License
A license is a legal document that states who can use your code. Although it may seem counterintuitive, a license typically makes your code more “open”, which means that other people can use it with fewer restrictions. There are two main types of licenses used for most R projects hosted on GitHub: permissive (MIT) and copyleft (GPL). A permissive license means that people can use your code with minimal restrictions. A copyleft license means that any code that incorporates your code must also be open-source. You can read more about licenses for open-source projects here, or use this resource to see what license might be most appropriate for your project.
For more information on any of these components of a new repository, see GitHub’s documentation for creating new repositories.
Once you click “Create repository”, you will be brought to the GitHub page for your repository. GitHub URLs all have the same format: “https://github.com/your_user_name/your_repository_name”.
If you look at your repository, you will see that it has one file, README.md. This is where you will document what is contained in your repository, and it will serve as a homepage for your project. It is written in Markdown, a language that can be used to format documents (you can find more information about how Markdown works and its syntax here). You will now edit the README:
- click the pencil on the upper right of the README
- add a new line to your README document that says “Adding a new commit to my README.”
- click the green button that says “Commit changes”
- provide an informative commit message, something like “Add new line to README.md”
- click the green button that says “Commit changes”
- click the repository name in the upper left to navigate back to the home page

Let’s now look at the commit history for this repository. We can do that by clicking where it says “2 Commits” just below the green “Code” button.
This brings us to a list of commits for this repository. You should see two commits, the initial commit that created the repository and the one you just made when you edited the README file. Click on the title of the newer commit.

This will bring you to information about the commit. Each commit has an alphanumeric hash (set of letters and numbers), which uniquely identifies that commit. In this view, you can see each file that has been changed in your commit, as well as the changes to the files. Here, we can see with the plus signs that you’ve added a line to the README. This type of visual representation of a commit, in terms of the changes between files, can be helpful when you want to understand the history of a project.
GitHub issues: a convenient to-do list for your repository
One thing that you’ll see when looking at your new repository is a tab in the upper left corner (just above the repository name) that says “Issues”. Click on this “Issues” button.
An issue is a way to keep track of ideas, tasks to complete, errors to resolve, or anything else related to a GitHub repo (see how GitHub describes issues here). Issues are also a good place to collaborate. You can tag people with their GitHub usernames in an issue, which will trigger an email notification. Multiple people can comment on an issue, so you can have a discussion about how to resolve the issue. The benefit of this over an email thread is that other collaborators can view this conversation, as well as other GitHub users who may want to know about the issue and resolution as well. Once an issue is considered resolved (for example, the task it mentions has been completed or the error it mentions has been fixed), then the issue can be closed. However, the GitHub repo will retain a searchable list of closed issues. When used frequently, this can be a helpful record of the development of a project.Installing GitHub Desktop
Next, we will move from interacting with GitHub to interacting with Git. First, we recommend that you install GitHub Desktop. This is a GUI (graphical user interface) that makes it easier for us to interact with Git locally. While we will use GitHub Desktop in this case study, another common way to interact with Git is through the on your computer. If you are already comfortable using the command line, you may prefer this to GitHub Desktop. When we use GitHub Desktop for version control tasks in this case study, we will also provide the command line code for all Git operations.
More information about the command line.
You may have also heard this called the shell, terminal, console, or command prompt. The command line lets us interact with our computers by typing commands (as opposed to using a graphical interface which involves clicking buttons and menus). These commands let you perform tasks such as navigating and modifying your file system, installing programs, running code, and working with Git. Each of these tasks can also be performed using a graphical interface. Some people prefer the visual layout of a GUI, while others prefer the simplicity and centralized control of the command line.
Follow this link to install GitHub Desktop.
If you are using a Mac, it will ask you if your Mac has a Apple silicon or Intel chip. Click here for more information.
To check whether your Mac has an Apple silicon chip or an Intel chip, click the Apple menu -> “About This Mac”. If the information window shows “Chip” then your Mac uses Apple silicon. If the information window shows “Processor” then your Mac uses an Intel processor.
Installing Git
If you have successfully installed GitHub Desktop, then Git is already installed on your system and no further installation is required.
If you are unable to install GitHub Desktop or would prefer not to install GitHub Desktop, you can install Git using the command line. Click here for more information.
First, we will see if Git is installed on your computer, and install it if not. We will start by opening the command line.
Open the application called “Terminal”. You can find this by using Spotlight Search and searching for “Terminal”.
Open the application called “Command Prompt”. You can find this by using the Start menu and searching for “Command Prompt”. You could instead use the PowerShell by searching for “PowerShell” instead.
Open the application called “Terminal”. You can find it by using your system’s application menu and searching for “Terminal”.
In the command line, type:
git versionIf the output tells you which version of Git is installed, then you already have Git. For example, if Git is already installed, the output may look like:
git version 2.50.1If you see a message like “git: command not found” or “git is not recognized” or a prompt to install something, then Git is not installed and you’ll need to install it.
To install Git, follow these instructions:
Connecting Git to GitHub
If you have GitHub Desktop installed, we can use it to authenticate your GitHub account with Git. We could also do this with the command line, but GitHub Desktop makes it easier.
When you open GitHub Desktop, it will prompt you to sign into GitHub. If it does not, then follow these instructions, choosing instructions for Mac or Windows based on your operating system.
Next, we will configure Git. This means that you will tell Git your name and email. Follow these instructions, again choosing instructions for Mac or Windows based on your operating system.
First we will tell Git your name and email address. Open the command line and enter the following:
git config --global user.name "Your name here"
git config --global user.email "Your email here"
git config --global --listThe third line should print your name and email correctly.
Next, you need to connect your GitHub account to your local Git.
GitHub no longer supports using passwords to connect Git and GitHub, so you’ll instead need to use a Personal Access Token (PAT). To create a token, follow these instructions. In order to connect your token to your computer do the following:
- click “Generate new token”
- choose “Generate new token (classic)”
- give your token a name and expiration date
- select the “repo” scope
- click “Generate Token”
- copy the token to your clipboard, or keep this window open (you will not be able to access this again)
Now, open the command line and run the following:
git config --global credential.helper osxkeychaingit config --global credential.helper managerIf available, run:
git config --global credential.helper managerIf that does not work, use:
git config --global credential.helper cacheThis tells Git to remember the login credentials that we will provide so you won’t need to enter them each time.
Next, we need to trigger a GitHub credentials check. We will do this by cloning the repository that you made (this means we will make a local version of this repo). Run the following, replacing “your_username” with your username:
git clone https://github.com/your_username/my-first-repository.git Running this command should prompt you to give a username and password. Use your GitHub username, and the PAT you just generated as the password (do not use your GitHub password). Git will now store these credentials so you won’t need to enter them again. When your PAT expires, you will need to follow these steps again.
Creating a local clone of your GitHub repository
You’ve finished setting up GitHub, Git, and GitHub Desktop, great job! Now, we can create a local version of “my-first-repository” that you made on GitHub earlier.
Making a local copy of a repository that is hosted on GitHub is called “cloning”. Start by navigating to your repository on GitHub, and copy the URL.

From GitHub Desktop, go to “File -> Clone Repository” and then provide the URL to your GitHub repository. Now, you should be able to see a window in GitHub Desktop that corresponds with “my-first-repository”. If you click on history, you can see a list of commits to this repository.
You were already asked to clone this repository in the last section, in order to trigger Git’s login credentials. If you haven’t done that, open the command line and enter the following, replacing “your_username” with your username:
git clone https://github.com/your_username/my-first-repository.git You will know that this has worked if you see the following output:
Cloning into 'my-first-repository'...
Next, you will open the local repository. RStudio and Positron have different approaches to opening folders.
The easiest way to work with a Git-tracked repository in RStudio is to make an RStudio project. A project is a folder that R can open as a self-contained unit. The most useful part of an RStudio project is that you can use relative file paths, with the folder that you used to create the project as the root. Using relative file paths for a project, as opposed to absolute file paths that are specific to your personal computer, make it easier to collaborate with other people.
In order to open your Git-tracked repository as an RStudio project, open RStudio and click “File -> Open Project”. This should prompt you to open your file browser, and you should navigate to the folder called “my_first_repository”, which was created when you cloned the repository. Once you select the correct folder, RStudio will open the project. If you look at the “Files” panel, you’ll see the README that you made for “my_first_repository” on GitHub. You will additionally see a file called “my_first_repository.Rproj”. This file is automatically made by RStudio when opening a new project, and saves information about the project.
In Positron, click “File -> Open Folder…” and then navigate to the folder called “my_first_repository”, which was created when you cloned the repository. Once you select the correct folder, Positron will open it. In the file explorer, you will be able to see the README that you made for “my_first_repository” on GitHub.
If you are using another R IDE besides RStudio or Positron, you should look up instructions for opening a folder in your environment.
Stage, commit, push
Next, we will create a new file locally. Create a new R file with “my-first-repository” and call it “01-calculations.R”. In this file, include the following:
x <- 103
y <- 5
x * ySave this file. Now, we will discuss how to track a new file with Git.
Now, navigate back to GitHub Desktop. Where it previously said “no local changes”, it now will show changes to your repository. You should see your new file name “01-calculations.R” with a green plus next to it.

If you are using RStudio, you will likely see additional added files here.
When you created a RStudio project, RStudio automatically created a “my-first-repository.Rproj” file to manage the project, and a “.gitignore” file to avoid tracking several hidden files that manage the project. Because these files were added, they are now included in the changed files that you see in GitHub Desktop. It is typically recommended to track your .Rproj and .gitignore files with Git.By default, the box next to added or updated files is checked. This means that each of these files are “staged”, or ready to be included in a commit and added to the repository history. If you uncheck the box, you are telling Git that for now you would not like to track that file with version control. If you would like to tell Git to never track files, you should add them to a .gitignore file.
In the lower left corner you will see a box that says “Summary (required)” and “Description”. This is where you will put your commit message.
A few pieces of advice to consider for your commit messages:
- A commit message should be informative. Think of a collaborator (or yourself in a few months) reading the commit message. It should tell the reader why you’ve made this commit. Did you add a file? Did you fix a bug in the code? Did you remove an outdated data file? Your commit history, when maintained thoughtfully, can provide a record of why you made changes throughout a project.
- A commit message should be concise. Avoid adding too many unnecessary details here. The reader can always look at the differences in files for the commit to see exactly what you’ve done.
- In a public repository, the commit message will be visible to anyone and exist as long as the repository does. Make sure that your message is appropriate and you’d be comfortable with colleagues seeing it.

For this commit, you might use the summary “Add new file ‘01-calculations.R’ to do calculations.”
Once you’ve added the commit message, you are ready to commit these files. Click “commit to main”. Now these changes have been entered into the version control history of your repository in Git.
We have one more step to update the GitHub repository, which is to “push” these files to GitHub. This is the step that transfers local changes to the remote repository. Once you commit you will see a box in GitHub Desktop that says “Push commits to the origin remote”. Click this box.
Now, open your project in GitHub. You should now see the file that you added locally, as well the commit message.
Open the command line, navigate to the folder that contains your repository, and enter the following:
cd my-first-repositoryThis will move you into the repository folder. Next, enter:
git statusThis will list untracked files, which are files that Git is not keeping track of.
If you are using RStudio, you will likely see additional added files here.
When you created a RStudio project, RStudio automatically created a “my-first-repository.Rproj” file to manage the project, and a “.gitignore” file to avoid tracking several hidden files that manage the project. Because these files were added, they are now included in the changed files that you see in GitHub Desktop. It is typically recommended to track your .Rproj and .gitignore files with Git.In order to tell Git to start tracking files, we need to “stage” the files for version control. We do this with the git add command:
git add 01-calculations.RIf you are using RStudio, you can also track the additional files that have been created.
git add my-first-repository.Rproj .gitignoreNext, we will commit the staged files (remember, this is similar to creating a snapshot of these files, or to creating a save point in a video game). The command git commit -m "..." commits the staged files and the flag -m adds a commit messages.
A few pieces of advice to consider for your commit messages:
- A commit message should be informative. Think of a collaborator (or yourself in a few months) reading the commit message. It should tell the reader why you’ve made this commit. Did you add a file? Did you fix a bug in the code? Did you remove an outdated data file?
- A commit message should be concise. Avoid adding too many unnecessary details here. The reader can always look at the differences in files for the commit to see exactly what you’ve done.
- In a public repository, the commit message will be visible to anyone and exist as long as the repository does. Make sure that your message is appropriate and you’d be comfortable with colleagues seeing it.

For this commit, you might use the summary “Add new file ‘01-calculations.R’ to do calculations.”
git commit -m "Add new file '01-calculations.R' to do calculations."We have one more step to update the GitHub repository, which is to “push” these files to GitHub. This is the final step that updates the GitHub repository to include the changes that we made locally. To push, enter:
git push Now, open your project in GitHub. You should now see the new file that you made locally, as well the commit message.
Pulling updates from GitHub
You’ve learned how to make updates locally, and stage, commit, and push these changes so that the GitHub repository includes those updates. While “pushing” sends updates from a local repository to the remote repository on GitHub, “pulling” sends updates from the remote GitHub repository to your local repository. To practice pulling, we’re going to make another change and commit from GitHub, and then pull that commit into our local repository. We’ll follow the same steps to make a change and commit on GitHub:
- click the pencil on the upper right of the README
- add a new line to your README document that says “Adding another commit from GitHub.”
- click the green button that says “Commit changes”
- provide an informative commit message, something like “Add one more new line to README”
- click the green button that says “Commit changes”
- click the repository name in the upper left to navigate back to the home page
Now, return to GitHub Desktop. Do the following:
- In the upper banner, click where it says “Fetch origin”. It should then update and say “Pull origin”.
- Click “Pull origin”.
- Go to the “History” pane, and you’ll see the most recent commit that you made on GitHub, now included in your local repository.
If you return to RStudio or Positron and open “README.md”, you will now see the update that you made on GitHub.
Open the command line, navigate to the folder that contains your repository, and enter the following:
git pullIf you return to RStudio and open “README.md”, you will now see the update that you made on GitHub.
What you’ve done
In this section you have made a GitHub account, installed Git and GitHub Desktop, configured Git and GitHub to talk to each other, and made your first repository. You’ve learned how to make changes to the remote on GitHub and transfer them to the local repository on your computer, as well as do the opposite.
In a typical GitHub workflow, you will rarely be making changes from GitHub. Instead, you will often be working with one or multiple collaborators on a repository. Once your collaborator makes changes locally, they can push those changes to GitHub, and then you can pull those changes to your local copy of the repository. This process will continue cyclically while you collaboratively work on a project. Note that this is a simplified system where you take turns to make changes, in practice you can work on the project at the same time.

Create a version controlled repository for your project
Now, we will return to the project with Collab. O. Rator. In the previous section, we created a repository on GitHub, and then cloned to make a local copy. Here, we will start with a local folder, track it with Git, and then create a remote version on GitHub.
First, download the .zip file here. Your browser may automatically unzip this file to create a folder called “infant_gut_files”, if not then unzip the file.
Now, go to GitHub Desktop and do the following:
- click the button “Add” in the top right
- click “Create New Repository”
- give your repository the name “infant_gut_analysis”.
- leave the box “Initialize this repository with a README” unchecked (because a README is already included in the set of files).
- under Git Ignore choose “R” and under License choose “MIT License”.
Now, copy the contents of the “infant_gut_files” into the new repository that you just created with GitHub Desktop
Once you add these files, return to GitHub Desktop. You should see a set of changed files, with check marks next to them to denote that they are staged.
- add a commit message and commit this change
- you should then see an option to “Publish repository”, click this
- you should now see the option “Open the repository page on GitHub in your browser”.
Clicking this will bring you to the new GitHub repo that you just made for this project!
Open the command line, navigate to the folder that you have unzipped, and enter the following:
git init -b mainThis command tests Git to create a version controlled repository in the current folder. Don’t worry about understanding the -b main part of the command for now, we will discuss it in a later section about branches.
If you look into your folder you will not see any changes. However, this command creates a hidden .git folder within the current folder, which contains the files that are needed to start tracking this folder with Git. It is now a Git-tracked repository.
Because we’ve created a Git repository from a folder of existing files, we should be sure to add a .gitignore file before staging and committing. While we could create an empty file called “.gitignore” and add files to it that we don’t want to track, we will instead download a .gitignore file from GitHub that includes files that are typically not tracked in workflows that use R. While most of the files in this .gitignore won’t be included in your project, there is no harm in including files in a .gitignore file that don’t exist in the repository.
In the command line, enter:
curl -o .gitignore https://raw.githubusercontent.com/github/gitignore/main/R.gitignoreNow we will stage files, so that Git knows to track them, and commit them, so that Git saves the set of files as part of the history.
First, check which files are currently untracked or modified.
git statusWhen you run git status, look for files listed under “Untracked files” (new files not yet tracked) or “Changes not staged for commit” (modified files that have not yet been added). You can then choose which files to add. In this repo, because the data is small and publicly available, we will add and commit the data folders. If this is not the case for your data, you should add data files or folders to your .gitignore file, to avoid tracking them.
git add README.md 01_pull_study_data.R 02_wrangle_data.R
processed_data raw_data .gitignore
git commit -m "track all files for infant gut project" In the git add command above, we track all scripts (.R files) and data. We do not track the figures and results folders for now because Git will not track empty folders. Once we add figures and results to these folders, we can then version control them (if we want to include these outputs in our version controlled repository).
Note on staging all files in a repository
You may see examples in other Git tutorials usinggit add ., which stages all files in the current directory. While convenient, you should use this with caution, as it can unintentionally include files you do not want to track, such as large data files, sensitive data, or auxiliary files generated by your computer (e.g., .Rproj, .Rproj.user, .DS_Store). While this can be avoided by adding all of these files to your .gitignore file, it is generally safer to add individual files and folder to your git add command that you’d like to track.
Next, you will need to create an empty repository on GitHub. Go to GitHub and create a new repository called “infant_gut_analysis”. Importantly, this time do not check “Initialize with README”, this should be a fully empty repository. Copy the URL of this repository.
Now, return to the command line and enter (replacing the URL below with the URL that you just copied):
git remote add origin https://github.com/your_username/infant_gut_analysis.gitFinally, we’ll push the files that we have locally to the remote repository on GitHub. Use the following command:
git push -u origin mainBecause this is the first time pushing to the remote repository, we need the -u flag to tell Git to remember where to send our changes. origin refers to the remote GitHub repository (that we set in the previous command), and main refers to the default version of the repository.
Open this repository in RStudio or Positron
Finally, we will open this repository with RStudio or Positron.
In order to open your Git-tracked repository as an RStudio project, open RStudio and click “File -> Open Project”. This should prompt you to open your file browser, and you should navigate to the folder called “infant_gut_analysis”. Once you select the correct folder, RStudio will open the project.
In Positron, click “File -> Open Folder…” and then navigate to the folder called “infant_gut_analysis”, which was created when you opened the .zip file. Once you select the correct folder, Positron will open it.
If you are using another R IDE besides RStudio or Positron, you should look up instructions for opening a folder in your environment.
Branches
One useful feature of Git is the ability to make branches. A branch is a history of commits, and by default a repository that is tracked by Git starts with the “main” branch. Multiple branches provide parallel versions of the repository that can be developed separately. For example, you may have a version of your analysis and results in the main branch, but you want to experiment with changing a parameter. You could do this in a separate branch. This would let you work on the experimental version of your analysis while also having a stable version of your analysis elsewhere. You can switch between branches depending on what version of the analysis you want to work with on a given day. If you eventually decide that you want to move forward with the changed parameter, you can merge your experimental branch back into your main branch.
Merge
Integrating changes from one branch into another branch.
Here is an example of a workflow, in which a Git user makes a “plotting” branch from the “main” branch, adds commits to both branches, and then eventually merges the “plotting” branch back into “main”. Click through the tabs from left to right to follow the branching process.





If there are no lines of code in any files that are directly in conflict, then merging will automatically combine the sets of files into a single version to move forward with. If there are lines that are directly in conflict, this will create what is called a merge conflict (merge conflicts are explained further in this section.
Here is an example of a file from the branching workflow above that can be merged automatically. The lines with red minus signs are deleted within the particular commit, and the lines with green plus signs are added within the particular commit.

Branches are also helpful when working with collaborators. If you are developing a new part of an analysis, you can do it in a separate branch. When you are ready for your collaborator to review your work, you can submit a “pull request”, which is a request to merge your branch with the main branch. Your collaborator can review all of the changes between your branch and the new branch, and either approve the pull request or request edits before merging. You can read more about pull requests in this section.
Create a new branch for this analysis
You will create a new branch with GitHub Desktop.
In GitHub Desktop:
- navigate to the tab in the top left of the window that says “Current Branch”
- click on this tab, and you should see a button that says “New Branch”
- name your new branch “study_comparison”.
Open the command line, navigate to the folder that you have unzipped, and enter the following:
git checkout -b study_comparisonWhen you create a new branch, you can name it by providing a new branch name (we name the new branch “study_comparison” above).
Tips for Git and GitHub
Tips
Commit often. A history will not be helpful if you run an entire analysis locally and then commit everything in a single commit.
If you are working on a repository with multiple contributors, make sure to pull each time you work in order to work on the most up-to-date version of the repository
Never use version control to track files with passwords or other sensitive information. If you have there are ways to remove these files and change the Git history, but this should be considered a last resort. Instead, add any files with sensitive information to your .gitignore.
- If passwords, access tokens, API keys, or other credentials are accidentally committed and pushed to a remote repository on GitHub (either public or private), they should be considered compromised and changed as soon as possible, and all collaborators who work with that repository should be alerted.
Scientific Project Organization
Reproducibility considerations
Although this is not directly related to , there are some useful ideas to know about organizing a scientific project, that will improve . While most people have their own approaches to scientific project organization, there are a few principles that most successful organization schemes have in common. More information can be found in this reproducibility course.
- file names are concise but informative
- there is one central folder to contain all files for each project
- there is a central file (often called the ) that explains what files are included and how to use them to run the analysis
- there are folders to keep similar files together
- data folder (this could be split into raw data and processed data)
- figures folder for any figures made for the analysis
- results folder for any results that should be shared or would take moderate or more computation to re-generate
- scripts are numbered in the order that they should be run to generate results
Organization of this project
If we look at the files contained in the “infant_gut_analysis” repository, they follow the recommendations provided above.

README
A README file should describe the files related to your scientific project. It should describe where inputs come from, what each script does, and where outputs are generated. If someone reads through your README, they should know where to find each component of your analysis.
Question opportunity
Answer
The script “01_pull_study_data.R” generates “sample_metadata.csv”.Project organization with Git and GitHub
Empty folders
One thing that often surprises new Git users is that any empty folders may exist on your computer but will not be tracked by Git until they have content. So while we see “figures” and “results” in the set of files from the folder “infant_gut_files”, they cannot be tracked by Git or hosted on GitHub until they have content. If you want to track an empty folder before it has content, you can add a placeholder file into the folder, and remove it later once the folder has content.
Which files to track with Git
Recall that version control lets you track project files as they change throughout the research process. Therefore, there are some files that should always be tracked with version control, some files that should never be tracked with version control, and some files that depend more on personal preference. Deciding which files to track is another topic that different people take different approaches to, but there are some rules that are typically followed:
- track source files that you’ve written (such as R scripts, shell scripts, LaTeX files, etc)
- track configuration files (such as .gitignore) that tell your tools how to interact with this repository
- do not track intermediate files (such as log files), these are files that are generated automatically during a certain part of your workflow but are not needed on their own
- sometimes track derived products (such as intermediate data, figures, or reports)
- this depends if you would like a copy of these products to live on GitHub
- this also depends on how you want other people to interact with figures or report, do you want them to be able to view or download them from GitHub, or do you want them to download your data and scripts from GitHub and generate the outputs for themselves
- do not track large data files that never change (we’ll explain this more below)
- typically avoid tracking binary files (although there are exceptions)
Binary files
From a Git perspective, files are either text files or binary files. Text files are human-readable. They work nicely with Git because they can be represented in terms of differences between versions. In contrast, binary files are readable by certain programs but are not human-readable. They cannot be represented in terms of diffs, and therefore a new version of the file is saved at each commit. Examples of binary files are images (.png, .jpeg), word and excel files (.doc, .xlsx) and PDFs (.pdf). Tracking many binary files with Git can eventually slow down Git operations.
How to use the .gitignore file
The best way to avoid tracking a file is to add it to your file. If a file or folder is included in your .gitignore file, it will not be staged when you use the command git add ..
If you open an RStudio project for a Git-tracked repository, you’ll have a .gitignore file that looks similar to the following:
# History files
.Rhistory
.Rapp.history
# Session Data files
.Rdata
.RDataTmp
# User-specific files
.Ruserdata
# RStudio files
.Rproj.user/
If you would like Git to avoid tracking a file called “large_data.csv”, which lives in a folder called “data”, you would add the following line to the end of your .gitignore file:
data/large_data.csv
You could also tell Git to avoid tracking an entire folder. If you didn’t want to track any data from a folder called “restricted_data”, you would add the following line to your .gitignore file:
restricted_data/
Git and large files
An important consideration for which files to track is file size. Tracking large files can slow down common Git operations and may eventually exceed GitHub’s repository limits. GitHub recommends that the maximum size of a single object being pushed to GitHub be 1MB, and enforces this size limit at 100 MB. For binary files or moderately large files that still need version control, Git Large File Storage (often referred to as Git LFS) is an option. Git LFS stores large files outside the main repository while preserving version tracking. You can read more about Git LFS here.
However, large data files or results that are not expected to change over time should generally not be tracked with Git at all. Instead, they are better stored in dedicated research data repositories such as figshare or Zenodo, which are designed for long-term storage, sharing, and citation. If data files are not tracked by Git or Git LFS, and are not therefore not included in the GitHub repository, it is important for the repository to contain download instructions for these data files for other users who may want to run the code and reproduce results. The README file is a good place to include these download instructions.
What are the data?
In this case study, we will investigate data about samples from this meta-analysis of mother and infant gut studies. Wang et al. identified a set of eight studies that collected mother and infant gut microbiome samples over time and performed metagenomic sequencing. These studies collectively include 1,496 samples. The variables that we will use to answer our questions include:
| Variable | Details |
|---|---|
| Study | Original study the sample comes from |
| SampleID | ID for sample |
| PersonID | ID for participant the sample came from |
| Category | Either “mother” or “infant” |
| Sampling from papers | Sampling time frame described in paper |
| Sampling, day | Day after birth that the sample was collected on |
Limitations
There are some important considerations regarding this data analysis to keep in mind:
- In the original studies included in this , some studies describe sampling date in terms of days, and some in terms of weeks or months. Although this is converted into days in the variable
Sampling, day, time has been measured in finer resolution for some studies compared to others. - In this analysis we are only comparing the original studies based on the number of samples they have and when they collected their samples. There are several other ways we may want to compare these cohorts to understand how comparable they are, including based on measured information (like maternal age, mode of delivery, birth weight, maternal antibiotic use, etc.) as well as unmeasured information.
There are also limitations of version control:
- Git does not automatically make commits for you. Any work that you have locally that you have not staged and committed is not under version control. As a version control user, you need to make commits in order to create a record of changes over time.
- As described in the scientific project organization section, version control is not ideal for large binary files.
- Git and GitHub are currently the most widely used tools for version control, with extensive documentation and active development. However, like any software tool, their long-term availability is not guaranteed. While the principles of version control will remain integral to reproducible research, the specific technologies used to implement these principles may evolve over time.
Ethical Considerations
There are some important ethical considerations when working with version control, as well as with health related data in general and when collaborating on scientific projects.
When hosting data, code, and results on , make sure to never include personally identifiable information (PII) or protected health information (PHI) in a repository (even private repositories are not secure enough for sensitive data). This includes names, dates of birth, medical records and diagnosis, lab results, identifiable genomic sequencing data, as well as other types of data. You can read more about PII and PHI in this course about ethical data handling. For more general information about data management, you can explore this course.
- If you do commit sensitive information to a version controlled repository on GitHub, it is not sufficient to simply remove the file, commit the changes, and push again. If you do this, any files with sensitive information will be part of a commit, and will therefore be a part of the history of the repository. While there are ways to remove sensitive information from a local commit, and from a GitHub repository, these are more complicated operations and will affect collaborators that work on the repository with you. It is important to inform collaborators of the sensitive information that has been committed.
Make sure to keep comprehensive documentation for scientific projects to avoid losing track of which data generated a set of results or figure, or which version of a software that you used in an analysis. Reproducible science is ethical science: without a transparent and well-documented process, others in the scientific community cannot easily verify or trust your results.
For projects with large teams, it can be challenging to track individual contributions. histories can be helpful to see who worked on each component on an analysis, in order to fairly acknowledge each contributor’s work. You can read this paper for more ethical considerations related to large team science.
When performing a such as the one described in this case study, it is important to be transparent about inclusion and exclusion criteria for studies and for individual observations within studies. Criteria should be determined before analysis, to avoid choosing studies that will support a desired conclusion. It is also important to properly cite the original studies and recognize the groups that collected the data.
Packages and Setup
Before we get into the coding, we want to describe the R packages that we’ll use in this case study, or that are used in other scripts contained in our repository:
| Package | Use |
|---|---|
| here | To construct file paths within folders |
| readxl | To read excel files into R |
| dplyr | To combine and manipulate data tables |
| ggplot2 | To visualize data |
| stringr | To manipulate strings |
The first time we use a function, we will use the :: to indicate which package we are using. Unless we have overlapping function names, this is not necessary, but we will include it here to be informative about where the functions we will use come from.
Data Import
Now that you have set up this project with and , you can start working on the study comparison in R. Open RStudio or Positron or your preferred R IDE to the “infant_gut_analysis” folder. We will start by taking a look at the data. Take a look at the file to determine which file contains commands that can read in the raw data. Open this file and run the code.
Question opportunity
Hint
Data is imported in the file “01_pull_study_data.R”. You can find out how many rows are in a data frame with the function nrow(name_of_data_frame). You can find out how many columns are in a data frame with the function ncol(name_of_data_frame).
Answer
nrow(sample_metadata)[1] 1499
ncol(sample_metadata)[1] 20
Data Wrangling
Data wrangling includes cleaning data to fix mistakes and reorganizing data to make it easier to use in visualizations and analyses. Again, use the to identify which file contains commands that wrangle the data. Open this file and run the code.
Question opportunity
What are the earliest and latest time points that samples were taken, relative to an infant’s birth date, in the data set?
Hint
Data are wrangled in the file “02_wrangle_data.R”. You can use the functions max() and min() to get the maximum and minimum values in a vector. The variable in the cleaned data set that gives the sampling day relative to the infant’s birth date is called sampling_day.
Answer
min(clean_metadata$sampling_day, na.rm = TRUE)[1] 0
max(clean_metadata$sampling_day, na.rm = TRUE)[1] 480
The earliest day that a participant was sampled after birth was 0, and the latest day was 480.
Data Visualization
We will now generate visualizations to compare the study cohorts.
First, we will make sure that we are on the correct branch. We want to use a development branch for this analysis, which we will request to merge back into the main branch once the analysis is ready. We already created the branch “study_comparison” in the introduction to Git and GitHub section, so we just need to make sure that we are working on that branch.
- In the upper panel, under “Current Branch”, look to see if it says the current branch is “study_comparison” or “main” or something else.
- If it says “study_comparison”, then you are already working on the correct branch.
- If it says “main”, then you can click the drop-down button next to “Current Branch” and select “study_comparison”.
- If “study_comparison” does not appear, you can click the “New Branch” button to create it.

Open the command line and navigate to your repository. Use the git branch command.
git branchThis should list the branches for your repository, with the current branch highlighted and marked with an asterisk (*). If the highlighted branch is “study_comparison”, then you are already working on the correct branch. If the highlighted branch is “main” or something else, you can switch over to “study_comparison” using the git checkout command.
If “study_comparison” appears in your list of branches, you can move to it with the following command:
git checkout study_comparisonHowever, if “study_comparison” doesn’t appear in your list of branches, you can create it with git checkout -b.
git checkout -b study_comparisonBecause this is a new component of the analysis, we will create a new file in the “infant_gut_analysis” folder for this code.
Reproducibility considerations
There are different types of files that you can create to run R code. The most basic file is a .R script, which is used for the scripts that we ran in the data import and wrangling sections: “01_pull_study_data.R” and “02_wrangle_data.R”. An R script assumes that all contents are R code, except for comments (which are preceded by #).
Another file type is a notebook-style document, which combines text components with code components. The code is broken into pieces, which are referred to as “code chunks”. Two common types of these files are R Markdown files (.Rmd) and quarto files (.qmd). These files can be rendered, which means that all code chunks are run in order (typically in a fresh R session), and any output (calculations, tables, plots) is included in the resulting document. These notebook-style formats also make it easier to explain what each step of an analysis is doing, improving both readability and reproducibility by clearly linking code, output, and interpretation in a single document.
To start, we will create a new quarto document and call it “03_visualize_study_cohorts.qmd”. Make sure to give your quarto document an appropriate title.
In this section, we will go through the steps to make two visualizations to compare the study cohorts. As you go, include the relevant code (as well as explanations of what the code is doing) into your quarto document. When you are done, you or someone else with access to the data and your document, should be able to run the code and create the visualizations.
In your quarto document, you should start by making a code chunk to load the required packages.
Adding a code chunk to a quarto file
To add a new R code chunk, go to a new line and enter: ```{r}
Then, type your code, starting on the following line. To end a code chunk, go to another new line and enter: ```
You can also add a code chunk in RStudio by navigating to “Code” -> “Insert Chunk”. There is also a keyboard shortcut: Ctrl + Alt + I in Windows and Linux, and Cmd + Option + I on Mac.
In Positron there is a keyboard shortcut to add a code chunk: Ctrl + Shift + I in Windows and Linux, and Cmd + Shift + I on Mac.
Include this code in your .qmd file, to load the packages that we’ll need.
library(here)
library(dplyr)
library(ggplot2)Next, we will load the wrangled data. We will use the function here(), which creates relative file paths.
More information about the here() function:
The here() function creates file paths that always start from the main project folder (the top-level folder that contains all of your project files). In a Git-tracked repository, this is the folder that contains the .git directory, which was created when you initialized the repository. Using relative file paths (i.e., paths that only reference folders within your project) makes your code more portable and easier for collaborators to run. In contrast, absolute file paths depend on the specific file structure of your personal computer and will not necessarily work on other machines.
We want to load data from the file “clean_sample_metadata.rda”, contained within the “processed_data” folder. Include this code in your .qmd file to load the data.
load(here::here("processed_data", "clean_sample_metadata.rda"))Now that you have created a new file and loaded packages and data, this is a good time to track this new file and your work.
Navigate back to . You should see your new file name “03_visualize_study_cohorts.qmd” with a green plus next to it, meaning that this is a new file. The check in the checkbox means that this file is staged. Add an appropriate commit message and commit this file.
Open the and navigate to your repository. Recall that you can stage the new file (tell Git to track it with):
git add 03_visualize_study_cohorts.qmdNext, add a commit with an appropriate commit message.
git commit -m "Add new file '03_visualize_study_cohorts'"Now that we’ve started tracking our work with Git, let’s start by considering the first question: how do these studies compare in terms of the number of observations?
Use the dplyr functions group_by() and count() to view the number of observations per study.
clean_metadata %>%
group_by(Study) %>%
count(name = "total")# A tibble: 8 × 2
# Groups: Study [8]
Study total
<chr> <int>
1 Asnicar 16
2 Backhed 392
3 Chu 27
4 Ferretti 102
5 Parnanen 64
6 Shao 588
7 Wampach 49
8 Yassour 258
A note on the pipe operator %>%
The pipe operator %>% chains R commands together. It takes the preceding object and inputs it as the first argument to the function that follows it. It often is used to make code more readable and to avoid using intermediate objects or nested functions. The code above is equivalent to both of these expressions:
grouped_data <- group_by(clean_metadata, Study)
count(grouped_data, name = "total")# A tibble: 8 × 2
# Groups: Study [8]
Study total
<chr> <int>
1 Asnicar 16
2 Backhed 392
3 Chu 27
4 Ferretti 102
5 Parnanen 64
6 Shao 588
7 Wampach 49
8 Yassour 258
count(group_by(clean_metadata, Study))# A tibble: 8 × 2
# Groups: Study [8]
Study n
<chr> <int>
1 Asnicar 16
2 Backhed 392
3 Chu 27
4 Ferretti 102
5 Parnanen 64
6 Shao 588
7 Wampach 49
8 Yassour 258
The pipe operator that we use, %>%, is part of the magrittr R package. There is also a pipe operator in base R, |>. In most cases, these two pipe operators will work equivalently.
clean_metadata |>
group_by(Study) |>
count(name = "total")# A tibble: 8 × 2
# Groups: Study [8]
Study total
<chr> <int>
1 Asnicar 16
2 Backhed 392
3 Chu 27
4 Ferretti 102
5 Parnanen 64
6 Shao 588
7 Wampach 49
8 Yassour 258
We can see that there is quite the spread of study sizes. Let’s also break this down by whether observations are from infants vs mothers. Whether the observation comes from an infant or a mother is contained in the variable Category.
Your turn: Modify the code above to count the number of observations by Study and by Category, and save the results as a data frame named sample_counts. Add this code to your .qmd file.
View code:
sample_counts <- clean_metadata %>%
group_by(Study, Category) %>%
count(name = "total")
sample_counts# A tibble: 16 × 3
# Groups: Study, Category [16]
Study Category total
<chr> <chr> <int>
1 Asnicar infant 8
2 Asnicar mother 8
3 Backhed infant 294
4 Backhed mother 98
5 Chu infant 12
6 Chu mother 15
7 Ferretti infant 81
8 Ferretti mother 21
9 Parnanen infant 32
10 Parnanen mother 32
11 Shao infant 410
12 Shao mother 178
13 Wampach infant 35
14 Wampach mother 14
15 Yassour infant 152
16 Yassour mother 106
Now that we’ve looked at this data in a table format, let’s make a plot so that we can compare this data visually. We’ll make a bar plot, with separate bars for each study and for observation category (infant vs mother). Include this code in your .qmd document to make a bar plot.
sample_counts %>%
ggplot(aes(x = Study, y = total, fill = Category)) +
geom_col(position = position_dodge())
While this plot looks good, it would be visually easier to compare if the studies were ordered by the number of observations. We can make a vector that orders the studies from the least observations to the most observations by using the dplyr functions group_by(), summarise(), arrange(), and pull().
More information about these dplyr functions:
dplyr function |
operation |
|---|---|
group_by() |
groups rows by a variable |
summarise() |
computes table of summaries |
arrange() |
sorts rows by one or more variables |
pull() |
pulls a variable from the data frame as a vector |
Include this code in your .qmd document to make a new vector for the desired study order.
study_order <- sample_counts %>%
group_by(Study) %>%
summarise(total_both = sum(total)) %>%
arrange(total_both) %>%
pull(Study)
study_order[1] "Asnicar" "Chu" "Wampach" "Parnanen" "Ferretti" "Yassour" "Backhed"
[8] "Shao"
We can now order the bar plot by increasing sample size. Include this code in your .qmd document to make the bar plot with increasing bar heights.
sample_counts %>%
mutate(Study = factor(Study, levels = study_order)) %>%
ggplot(aes(x = Study, y = total, fill = Category)) +
geom_col(position = position_dodge()) 
Finally, we can update the colors of the plot and add labels. Include this code in your .qmd document to refine your bar plot.
sample_counts %>%
mutate(Study = factor(Study, levels = study_order)) %>%
ggplot(aes(x = Study, y = total, fill = Category)) +
geom_col(position = position_dodge()) +
theme_minimal() +
labs(y = "Number of samples",
x = "Study",
title = "Number of Samples by Study and Category") +
theme(plot.title = element_text(hjust = 0.5))
We will now use ggsave() to save this plot in the figures folder. Include this code in your .qmd document to save this bar plot with the file name “study_sizes_by_category.png” within the “figures” folder.
ggsave("figures/study_sizes_by_category.png", height = 6, width = 9)This is another great time to commit your current work.
Navigate back to GitHub Desktop. You should now see that “03_visualize_study_cohorts.qmd” has a check in the checkbox (meaning it is staged) and has an orange box next to it, which means the file has been modified. Add an appropriate commit message and commit this file.
Even though Git is already tracking “03_visualize_study_cohorts.qmd”, we still need to use git add to tell Git to stage this file for this commit.
git add 03_visualize_study_cohorts.qmdNext, add a commit with an appropriate commit message.
git commit -m "Add plot of study sizes to '03_visualize_study_cohorts'"Next we will consider the second question: how do these studies compare in terms of when they took samples after the birth of the infants? You may have noticed in the script “02_wrangle_data.R” that two studies took samples from mothers during pregnancy. This information is contained in the variable sampling_before_birth. We would like to exclude these observations from our plots, because their sampling_day is counted from the beginning of pregnancy and not since birth.
Your turn: create a data frame observations_after_birth that does not include these observations that were taken before birth. Include this code in your .qmd document.
Hint:
The function filter() will remove rows that match a certain logical condition.
View code:
observations_after_birth <- clean_metadata %>%
filter(!sampling_before_birth) Now, we will make a histogram of sampling day, where we separate the data by Category and Study. There are multiple ways to do this, but we will color the bars by Category and then use facet_wrap() to make separate panels for each study. Include this code in your .qmd document to make histograms of sampling day for each study.
observations_after_birth %>%
ggplot(aes(x = sampling_day, fill = Category, group = Category)) +
geom_histogram(position = position_dodge(), bins = 20) +
facet_wrap(~Study, scale = "free_y") Warning: Removed 7 rows containing non-finite outside the scale range
(`stat_bin()`).

Notice that because we set scale = "free_y" in the facet_wrap(), each of the y-axes of the panels is different. Let’s order the studies in the same order that we used in the bar plot earlier. We will also update the theme and add axes labels. Include this code in your .qmd document to order the studies and refine your histograms.
observations_after_birth %>%
mutate(Study = factor(Study, levels = study_order)) %>%
ggplot(aes(x = sampling_day, fill = Category, group = Category)) +
geom_histogram(position = position_dodge(), bins = 20) +
facet_wrap(~Study, scale = "free_y") +
labs(x = "Days since birth at sampling",
y = "Count",
title = "Distribution of sampling day across studies") +
theme_minimal() +
theme(plot.title = element_text(hjust = 0.5))Warning: Removed 7 rows containing non-finite outside the scale range
(`stat_bin()`).

More information about this warning message.
ggplot will give you warning messages when there are data in the dataframe that it cannot include in a plot due to missing information. In this warning, we can see that 7 observations in the data (representing samples taken) cannot be plotted because of non-finite values. Typically, this means there are observations with missing data. We can investigate what is missing with the following:
observations_after_birth %>%
# only keep rows that have NA values for Study, sampling_day, or Category
filter(is.na(Study) | is.na(sampling_day) | is.na(Category)) %>%
# view a smaller subset of variables
select(Study, SampleID, PersonID, sampling_day, Category)# A tibble: 7 × 5
Study SampleID PersonID sampling_day Category
<chr> <chr> <chr> <dbl> <chr>
1 Backhed 201_4M 201 NA infant
2 Backhed 229_M 229 NA mother
3 Backhed 229_B 229 NA infant
4 Backhed 544_B 544 NA infant
5 Backhed 624_B 624 NA infant
6 Backhed 633_B 633 NA infant
7 Shao C01831_NA C01831 NA infant
Here we can see that there are 6 observations from the Backhed study and one observation from the Shao study for which sampling_day is missing. Therefore, these observations cannot be included in the plot.
Finally, we will save this plot in the figures folder. Include this code in your .qmd document to save this plot with the file name “sampling_timepoints.png” within the “figures” folder.
ggsave("figures/sampling_timepoints.png", height = 6, width = 9)Now that we have two plots, go back through your file “03_visualize_study_cohorts.qmd” to make sure that it contains all relevant code to make these two plots, and that there are explanations before each code chunk. Render your file to confirm that when rendered it will create these two plots.
Question opportunity
Recall one of the main questions of this case study: In this meta-analysis of infant git microbiome samples, how do the original studies compare in their sampling designs? Specifically, how do they compare in terms of the number of samples and the sampling timeline?
Use the two plots you’ve made to make a few observations to compare and contrast the sampling designs of the original studies. Include these observations at the end of your “03_visualize_study_cohorts.qmd” document.
Answer
Possible observations from the plots:
- Two studies have small samples sizes (Asnicar with 16 samples and Chu with 27 samples), three studies have more moderate sample sizes (Wampach with 49 samples Parnanen with 64 samples, and Ferretti with 102 samples), and three studies have larger sample sizes (Yassour with 258 samples, Backhed with 392 samples, and Shao with 588 samples).
- Some studies take the same number or similar numbers of samples from mothers and infants (Asnicar, Chu, Parnanen) and other studies take significantly more samples from infants than mothers (Wampach, Ferretti, Yassour, Backhed, and Shao).
- Wampach sampled only in the first days after birth, Chu, Parnanen, Ferretti, and Yassour sampled only in the first six months since birth, and Asnicar, Backhed, and Shao took samples in the first year and a half since birth.
- Some studies appear to have sampled at specific time points (Asnicar, Chu, Wampach, Parnanen, and Ferretti) and other studies appear to have sampled at a wider variety of timepoints (Yassour, Backhed, Shao).
Since you’ve performed the requested analysis, make sure to document any new files in this repository in the README.md file. Specifically, describe what the file “03_visualize_study_cohorts.qmd” does, and describe the two plots that are now saved in the figures folder. After doing this, make another commit and push your work.
Navigate back to GitHub Desktop. You should now see the modifications that you’ve made to “03_visualize_study_cohorts.qmd”, as well as the added .png files for the figures. Add an appropriate commit message and commit. Then click “Push origin”, to push these changes that you’ve made locally to your remote repository.
We need to now make sure to stage “03_visualize_study_cohorts.qmd” and the figures that we’ve added. We can use git add . to tell Git to track all files that have changes in this repository.
git add .Next, add a commit with an appropriate commit message.
git commit -m "Add plot of sampling days to
'03_visualize_study_cohorts' and document new files in README"Finally, these changes that you’ve made locally to your remote repository. Because this is your first time pushing from a new branch, you will need to tell Git where you want to push to, adding the flag --set-upstream origin branch_name.
git push --set-upstream origin study_comparisonPull Requests
What is a pull request?
Recall that in the initial description of branches, you learned that branches can be used for development of a new part of a project, separate from the stable version of a repository. A pull request is a way to take a collection of commits on a branch and request to those into another , typically “main”. A pull request will provide a list of each file that is changed in the branch, as well as the difference between each file and the version of that file on the branch that you are trying to merge your changes into. While you can review your own pull requests, GitHub also has features that make it convenient for collaborators to review your pull requests.
How to make a pull request
In the previous section, you worked locally to make the visualizations that Collab O. Rator had asked you for, and you staged, committed, and pushed these changes. Recall that you were working on a branch called “study comparison”. Let’s take a look at this branch on GitHub.
- Navigate back to “https://github.com/your_username/infant_gut_analysis” (replacing your username).
- Click underneath the repository name where is says “Branches”. This should take you to a page that shows you the existing branches (this should include “main” and “study_comparison”).
- Click on “study_comparison”.
- You should see a yellow banner with a green button that says “Compare & pull request”. Click on this button.
This set of steps will bring you to a page where you can make your pull request. The first thing to note is the panel at the top of the page, which gives you the base branch (this will by default be “main”) and the compare branch (this will be the branch you’ve been working on, in this case “study_comparison”). There is an arrow, showing that you are trying to merge the updates that you’ve made in the compare branch into the base branch.
There are a few useful components of this page in which you make a pull request. First, you have a spot to add a title and a description. If you scroll down, you’ll see a list of commits that make up this pull request along with the commit messages, and each of the files changed. On the right panel next to the title you’ll see an option for reviewers. If other users have access to this repository, then you can add them as a reviewer. Depending on how they have configured their notification preferences, they may get an email notification that you’ve requested a review from them. It is good practice for you to also reach out to them and send them the link to your pull request to review!
Components of a good pull title and description
- A concise but descriptive title
- A description of the changes you want to merge. This is a good place to list files added and modified and give a quick description of those changes. Give plenty of context, you’ve likely been thinking about the code you want to merge more recently than your collaborator who will review it
- One good way to describe changes is in a checklist of what you’ve done
- It can also be helpful to include a checklist of what is left to do, especially if your pull request is a work in progress
- A request for code review (make specific requests: do you want your collaborator to review all changes? Do you want them to focus on a specific file or part of an analysis? do you just a bigger picture review to see if your approach to the problem makes sense?)
For additional suggestions on making good pull requests, you can read more in this reproducibility course. See here for an example of a pull request with these components, followed by back-and-forth between the author and reviewer to iterate on the proposed changes to the analysis.
Add a title and a description for your pull request now.
Example pull request for this analysis

Merging or closing pull requests
Once you have created a pull request, it is considered an “open” pull request and there are two potential actions, either merging it or closing it.
Merging pull requests
Let’s say that you submitted a pull request, you or your collaborator has decided that the changes look good, and you want to integrate the changes from your development branch into the base branch. This is called “merging” your pull request. In most cases, you will see a box that says “No conflicts with base branch”, and you can click the button that says “Merge pull request”. However, in some cases, you will not be able to merge until you resolve merge conflicts. See the troubleshooting section for more information about merge conflicts and how to resolve them.
Closing pull requests
If you close a pull request without merging it, this means that you’ve decided not to integrate the changes from the compare branch into the base branch. This may happen if you decide to go in another direction with an analysis. You can close a pull request by clicking the “Close pull request” button at the bottom of the pull request page. It is important to close pull requests that are no longer active so that the set of open pull requests accurately represents the current state of the project.
Additional notes on pull requests
While your pull request is open, any additional changes that you commit and push to this branch will be automatically added to the pull request.
It is recommended to not let your pull requests get too large. A pull request should be a set of changes that address a certain component of an analysis. Try to avoid combining multiple parts of a project in a single pull request. If you decide to start working on a different part of a project, you can create a new branch for this, and eventually submit a new pull request from that branch. This is a great way to stay organized for complex projects that have different components happening in parallel. Additionally, using more branches and smaller pull requests, each focused on a single set of related changes, can make it easier to review the pull requests and to identify where changes were introduced to a project.
Summary
Synopsis
In this case study, you’ve learned about why is used as part of science workflows. You’ve been introduced to and , and learned procedures for managing Git-tracked locally using or the , and remotely using GitHub. You’ve practiced using the “pull -> stage -> commit -> push” workflow to make changes locally that are then tracked remotely. In your analysis, you worked in a , and you submitted a in order to integrate new changes into a stable version of the code and as a way to ask a collaborate to review your code.
Along the way, you’ve also learned about the advantages and challenges of and best practices for scientific project organization.
Summary Activity
Reconstruct the workflow
Drag each workflow block into the correct position below and click Check Answer or Reset to start over. This diagram provides a high-level overview of the steps that you took in this case study. While some of these will not always be necessary for all projects or follow this exact order, each of these steps represent parts of a version controlled project workflow and are important to understand.
Summary Image
Now that you’ve reconstructed the version control workflow from this case study, recall the motivation for version control.

Main Questions Revisited
| Question | Current answer | Caveat |
|---|---|---|
| How does the use of version control contribute to transparent and reproducible science? | As we describe in the introduction to Git and GitHub section, version control provides a full history of a project, showing who made which changes and when. Additionally, commit messages and pull request descriptions explain why changes were made. Version control also provides an easy way to make a public online code repository for a project. | Versions of a project are only tracked when the user manually makes a commit, changes are not automatically tracked. Commit messages and pull request descriptions are only useful when they are concise and meaningful. |
| How can Git and GitHub be used to facilitate collaboration on a research project? | GitHub provides a central location to store the files for a project, and collaborators can pull changes to their local repository, make updates, and push changes back to the remote repository. An individual can suggest a series of changes through a pull request (see the pull request section for more information), and request a code review from a collaborator before merging the changes into the main branch of the repository. | It is important for collaborators to pull before they begin work locally, otherwise they will likely create merge conflicts (see the troubleshooting section for advice for working through merge conflicts). The careful use of branches will let collaborators work on different aspects of projects at different times and help organize work to be reviewed in pull requests. More information about branches can be found in the branches section. |
| In this meta-analysis of infant git microbiome samples, how do the original studies compare in their sampling designs? | From the plots created in the data visualization section, we can identify major differences across studies in terms of number of samples, proportion of samples from infants versus mothers, and different times at which samples were collected from infants and from mothers. | As described in the limitations section, the sampling date is measured differently in different studies, and there are other potentially relevant study characteristics that we don’t consider in this analysis. |
Troubleshooting Git and GitHub
Most new and experienced users of Git and GitHub will run into problems occasionally. Luckily, version control is designed so that these problems can be solved, it just may take some time to get used to. There are many helpful resources online for common Git and GitHub problems, and AI chatbots can provide advice (please see our AI disclaimer below for advice on using AI for version control!). In this section, we will mention a few common Git and GitHub problems and provide solutions.
I’ve created a merge conflict. What is this? How do I fix it?
Typically, Git is able to automatically changes from one into another. However, a merge conflict happens when there are competing changes between the two branches, and Git needs you to manually decide how to resolve these differences. A merge conflict may arise in a scenario in which you made a branch from main, worked on that branch, and by the time you submit a pull request back to main, someone else has already committed to main and updated the same file as you have.
Merge conflict
When Git cannot automatically reconcile differences between branches it is attempting to combine, typically because the same part of a file (or closely related parts) were edited in incompatible ways, or because one branch modified something the other removed.
You will know that you have a merge conflict when Git attempts to combine changes (for example, during git merge or git pull) and reports that it cannot automatically resolve some differences.
You will see a pop-up window that says “Resolve conflicts before Merge”, along with a list of files with conflicts. You will need to open the files in a text editor in order to manually resolve the merge conflicts.
When you try to run git pull, you’ll get a response that includes: “Automatic merge failed; fix conflicts and then commit the result”.
Recall the hypothetical branch workflow from earlier in the case study.





Here is an example of a file from the branching workflow that will result in a merge conflict.

When you open a file with a merge conflict, you will see that conflict markers have been added. For lines that are in conflict, you’ll see “<<<<<<< HEAD” and “=======”. The code in between these two markers is the code that is contained locally in the branch that you are working with. Lower in the file, you’ll see “>>>>>>> incoming_change_tag”, where “incoming_change_tag” references the commit or branch that identifies the incoming change. You need to manually edit the file to remove the tags, and to include whatever content you would like (either the content in your local branch, the content from the remote commit that is being pulled, or a combination of the two). Once you’ve edited this file, you should save and stage the file.
In some cases (such as when one branch deletes a file and another edits it), you may not see conflict markers inside a file. Instead, you will need to either remove the file if you want it to be deleted, or stage the file if you would like it to be kept.
After you resolve and stage all files that had merge conflicts, you should commit these changes. This will resolve your merge conflict.
I’ve accidentally been working in the main branch, but I actually want my work to all go into a new branch. How do I switch branches and move this work with me?
Luckily, this is an easy problem to resolve!
If you have made changes locally but haven’t yet committed, you can do the following:
Open GitHub Desktop, and create a new branch. If you have changes in main that haven’t been committed, GitHub Desktop will open a pop-up to ask you if you’d like to leave your changes on main or bring your changes to the new branch. Choose to bring the changes to the new branch.
If you have made changes locally and have committed, you can follow the steps above and then additionally do the following:
Switch back to the main branch, and click on History in the upper left panel. Then, right-click on the commit that you would like to return to in your main branch and choose “Reset to Commit…” from the right-click menu.
If you have made changes locally but haven’t yet committed, you can do the following:
Use the following command, replacing “new_branch_name” with your desired branch name.
git checkout -b new_branch_name If you have made changes locally and have committed, you can follow the steps above to create a new branch, and then additionally do the following to revert main back to match the remote version of main:
git reset --hard origin/mainHowever, make sure that you only git reset --hard after you’ve created the new branch and moved your commits, otherwise you risk losing your updated work.
I’ve staged and committed a file, but I don’t want to track it anymore. How can I remove it?
This is another common problem. We’ll first tell Git to stop tracking the file (but keep it locally), and then we will add it to the .gitignore file to avoid tracking it with Git in the future. First, we will stop tracking the file.
Make sure you are starting in the correct branch that you have been working in. Click “Repository -> Open in Terminal”. This will open a command line for you to work with. In this command line, use the following command, replacing “path_to_file” with the path to the file to stop tracking, including the file name.
git rm --cached "path_to_file" Next, open the .gitignore file and add the file to the list of files to avoid tracking.
Then, return to GitHub Desktop and commit these changes.
Use the following command, replacing “path_to_file” with the path to the file to stop tracking, including the file name.
git rm --cached path/to/fileNext, open the .gitignore file and add the file to the list of files to avoid tracking.
Then, return to the command line and stage and stage and commit these changes.
git add .gitignore
git commit -m "removing file_name from Git tracking and adding it to .gitignore" I’ve accidentally committed a large file and when I try to push I get an error from GitHub saying that the file is too big. How do I resolve this?
This is a common error that can be a little tricky to resolve. You need to remove this file from Git tracking and also amend the commits that include the file. We will assume that the large file was added in the most recent commit. If it was added multiple commits previously, then it can still be removed but will include additional steps that we will not cover here (see here for a workflow for removing a file from multiple commits).
Make sure you are starting in the correct branch that you have been working in. Click “Repository -> Open in Terminal”. This will open a command line for you to work with. In this command line, use the following command, replacing “path_to_file” with the path to the file to stop tracking, including the file name.
git rm --cached "path_to_file"
git commit --amend Including the git commit --amend rewrites the most recent commit as if the large file was not added. Don’t close the terminal yet, we will come back to it.
Next, open the .gitignore file and add the file to the list of files to avoid tracking. In GitHub Desktop, stage the .gitignore, but do not commit it yet.
Return to the terminal. Repeat the git commit --amend command, which will add this update to the .gitignore to the most recent commit.
git commit --amend Then, return to GitHub Desktop and commit these changes.
Use the following command, replacing “path_to_file” with the path to the file to stop tracking, including the file name. Including the git commit --amend rewrites the most recent commit as if the large file was not added.
git rm --cached path/to/file
git commit --amendNext, open the .gitignore file and add the file to the list of files to avoid tracking.
Then, return to the command line and stage and stage and commit these changes. Note that we include git commit --amend a second time to add the changes to the .gitignore file to the previous commit.
git add .gitignore
git commit --amend
git commit -m "removing file_name from Git tracking and adding it to .gitignore" The best way to avoid this problem is when you add large files to a folder that is tracked with Git, immediately add them to the .gitignore. If you really do want to track them with version control, consider using Git Large File Storage (LFS).
AI use considerations
Context:
When you ask an AI chatbot for assistance with version control, make sure to give appropriate background. Describe the specific task that you would like to do, or the problem that you are encountering. It can be helpful to include any error messages that you might be receiving from Git. For example, imagine that you’ve created a merge conflict.
Suggested Prompt:
I am working with a Git-controlled repository, in a branch called new_feature. I have made several changes locally, and have staged those files and committed them. I just went to pull changes from the remote version of this branch that my collaborator made recently, and I'm getting a merge conflict. Specifically, I've received the following message:
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
Auto-merging 01_import_data.R
CONFLICT (content): Merge conflict in 01_import_data.R
Automatic merge failed; fix conflicts and then commit the result.
How can I resolve this merge conflict?Validation: You should always be careful when taking advice on Git and GitHub from an AI chatbot. If you are asking for commands to use with Git for a situation that is very new to you, it could be helpful to do a quick search of the commands the chatbot tells you to use, to confirm that they do what you want to do. You could also ask multiple chatbots the same question.
You should be especially careful when using agentic AI with Git and GitHub. Agentic AI systems can use external tools and execute tasks, often performing steps without human supervision. There are many git commands (and command line commands in general) that are challenging to reverse and can cause major problems to scientific projects. For example, running git reset --hard will reset a local branch to the remote version of the branch, removing all uncommitted changes, which could remove valuable content. Therefore, it is recommended to monitor the ways that agentic AI can make changes with version control and to prevent them from from performing potentially destructive actions without human supervision.
AI Use Disclaimer:
Follow any relevant required guidelines/policies for AI use.
Examples
Your team or lab, institution, funding organization, or publisher. These requirements should take precedence over our suggestions.
Check AI responses critically, as they may be inaccurate, out-of-date, incomplete, or unnecessarily complicated.
Examples
- Always validate the existence and relevance of suggested citations or packages.
- Review, test, possibly simplify, and work to understand generated code or functions.
- Validate factual information using reliable sources.
- Exercise extra caution with code in certain instances: code that installs packages, accesses or modifies files or data, uses credentials, or sends information over the internet.
Disclose your AI use (including model and versions).
Never provide sensitive data to a public AI tool.
Examples
Patient or student data, passwords, credentials, API keys, unpublished manuscripts or grants, and other proprietary code or internal documents.
Be specific in your prompts and ask the AI tool to help you understand the code.
The confidence of an AI tool does not indicate if its responses are correct. They may also agree with you when you are wrong.
AI may respond differently to the same repeated prompt. Be sure to document what you can for the sake of reproducibility.
Recognize that you may need to iteratively improve your prompt to reach the desired output.
Continued Learning
Common Next Steps
Now that you’ve learned how to how to make and use version-controlled repositories, you are ready to use Git and GitHub for your work! Common next steps include:
- adding collaborators to your repository
- making more branches for other components of your analysis
- using GitHub issues to keep track of to-do’s related to your GitHub repository
Reinforcement Exercises
A good way to reinforce these version control skills is to make a current scientific project that you’ve been working on into a Git tracked repository, and connecting it to a remote GitHub repository. See if you can integrate the Git workflow that you’ve learned here into your scientific process. Even if you are the only one working on this project, this is a good way to practice skills. This will get you into the habit of staging, committing, and pushing changes as you work, and working on different branches for different components of a project.
Advancement Exercises
Beginner
Moving work in progress into a new branch
In this exercise, we will follow a process where we start to make changes to the main branch, but then realize that we would rather keep this work in a separate branch and only merge it into the main branch of the repository through a pull request after code review.
Complete the following steps:
- Open repository for this case study
- Check out the main branch
- Add a new line to the README (add whatever you’d like here!)
- Follow the instructions on the troubleshooting section to move this update to the README to a new branch called updated_readme
- Commit and push your changes to a remote updated_readme branch
- Submit another pull request on GitHub to contribute this change into the main branch.
Question opportunity
What are some advantages to making changes to a repository within a new branch and using a pull request to merge these changes into the main branch?
Answer
There are several advantages to this workflow:
- Using a new branch lets you try new things without disrupting a stable version of the code and project
- Multiple people can work on different components of a project on their own branches, and then merge the branches into main when they are ready to contribute their work
- A branch and pull request lets you group several related commits together, and describe in more detail in the pull request why you made them
- A pull request lets you request a code review from a collaborator before merging your work into main, making you less susceptible to mistakes in your code
Intermediate
Going through a project’s history
In this exercise you will search through the history in a GitHub repository to find when a change took place. Open this GitHub repository which contains the contents of this case study. Feel free to spend some time poking around here, all of the content that is used to create different components of this case study are stored in this repository.
Your goal is to find the pull request number and commit tag from when the learning objectives map table was filled in within the case study (the learning objectives table can be found here). Do this by searching through the files, commits, or pull requests in this repository.
Hints:
There are multiple ways to search for this change:
- Open the file _lo_map.qmd and click the “History” button to see a history of commits that affected this file.
- Go to the “Pull requests” tab, click on the “Closed” pull requests, and search a relevant search term. Once you find the correct pull request, look at the commits that make up that pull request.
Answer:
Content was added to the learning objectives map in pull request 18, within the commit tagged 34a4550.
Advanced
Forking
So far, you’ve created repositories to work with. This means that GitHub considers you the repository owner. If you are working with collaborators who you want to be able to push to your GitHub repo, you can add them to your repository with write permissions (you can also make them a maintainer or admin to have additional abilities). However, let’s consider a different situation. You want to contribute to a GitHub repository, but you do not have permission to push to this repository. This is where forks come in.
Fork
A copy of a repository, often used to make changes when the user does not have write access to the original repository.
We will call the original repository (which you do not have write permissions for) the upstream. Earlier, when you cloned a GitHub repository, you made a local version of that repository. In contrast, when you fork from the upstream, you make a remote copy of the GitHub repository, that you own with your GitHub account. You can then clone this fork, so that you can work locally.

When you want to propose changes back to the upstream repository, you can submit a pull request from your fork into the upstream.

Practice making and using a fork
To practice using a fork, go to this GitHub repository. You’ll see that this repository contains the files that you originally downloaded when you started working on this infant gut analysis project.
Look for the button that says “Fork” on the top right, above the “Code” button that you previously used to clone a repository. Click on “Fork”.
This will bring you to a page that is very similar to when you had created a new repository at the beginning of the case study. However, there are a few differences. You’ll see now that you are the owner of this repository, and by default it has the same name as the repository that you are forking from. Click “Create fork”.
Once you create the fork, you’ll be brought to this repository. Now, follow the same process that you used previously to clone this repository (note: make sure that you are cloning the fork, and not the upstream repository!). Open the repository locally. Make a copy of the file “03_visualize_study_cohorts.qmd”, and add it to your local version of your forked repo. Follow the workflow to stage this file, commit it, and push it.
After you push, you should now see the file on GitHub in your forked repo, along with a notification that this branch is a commit ahead of the upstream repository. There will be a button with the option to “Contribute” these changes. Click that button. This will take you to a page on the upstream repository where you can make a pull request from your fork.
Fill in the title and description of your pull request.
Question opportunity
How does this pull request from a fork to an upstream repository look different from the pull request that you made earlier, between two branches in the same repository? How does it look similar?
Click “Create pull request” and inspect your pull request.
Finally, please close this pull request, as we do not actually want to include these changes in this repository.
Additional Information
Helpful Links
- happy git with R: online book that covers most relevant topics for using Git and GitHub with R
- How to Use Git/GitHub with R: blog post about getting Git and GitHub set up and working with RStudio. This uses the built-in Git GUI in RStudio instead of GitHub Desktop
- Dangit, Git!?!: brief description of some common Git errors and how to resolve them
- Intro to reproducibility in cancer informatics: short course on reproducibility for scientific projects, includes Git and GitHub in chapter 4 and provides other resources on reproducibility
- Advanced reproducibility in cancer informatics: short course on more advanced reproducibility for scientific projects, includes GitHub in chapter 3 and provides other resources on reproducibility
- Carpentries:
- Install Git: instructions on installing Git (and other types of software)
- Set up Git: instructions on setting up Git
- Build on existing branch: instructions on how to work from a branch on someone else’s fork of a repository
- Hands on introduction to Git and GitHub: another introduction to Git and GitHub, covering some overlapping material and some additional material
- Contributing to Galaxy Training Network with GitHub: tutorial on how to contribute to an open source project with GitHub
- GitHub cheatsheet: cheatsheet with Git commands that can be used in the command line
Glossary
| Term | Definition |
|---|---|
| .gitignore | File that tells Git what files to avoid tracking |
| branch | A history of commits in a Git-tracked repository (there can be multiple parallel branches in a repository) |
| command line | A window that lets a user interact with a computer through typing commands |
| commit | A snapshot of all files in a repository at a moment in time |
| fork | A copy of a remote GitHub repository, owned on a personal GitHub account |
| Git | A popular version control tool that works to track files on a local computer |
| Git LFS | Git large file storage, an option to version control large files that are too large to track using Git and GitHub |
| GitHub | A website for hosting folders that are tracked with GitHub |
| GitHub Desktop | A graphical user interface for interacting with Git on a local computer |
| license | A legal document that states who can use your code and for what purposes |
| local | The Git-tracked repository on your computer |
| longitudinal | Over time (a longitudinal study follows a group of participants over time) |
| merge | Integrating changes from one branch to another branch |
| merge conflict | When Git cannot automatically reconcile differences between branches it is attempting to combine, typically because the same part of a file (or closely related parts) were edited in incompatible ways, or because one branch modified something the other removed |
| meta-analyses | Analyses of data from a collection of studies targeting a common research question |
| meta-analysis | An analysis of data from a collection of studies targeting a common research question |
| microbiome | A collection of microorganisms that live in a shared environment |
| pull request | A request to integrate a collection of commits from one branch (or from a fork) into another branch (or another repository) |
| push | Sending commits from the local version of a repository to the remote version of the repository on GitHub |
| quarto | A type of document that combines code with the output of the code and text |
| README | A document that describes what files are in a folder, as well as other relevant information |
| remote | The online version of the repository tracked on GitHub |
| repo | A shortened version of "repository", a folder in Git that contains all of hte files to be tracked for a project |
| repositories | Folders in Git that contains all of the files to be tracked for a project |
| repository | A folder in Git that contains all of the files to be tracked for a project |
| reproducibility | The ability for someone else the run the same analysis on the same data and get the same results |
| reproducible | A project in which a new researcher can re-run an experiment or analysis with the same data and code and generate the same results |
| version control | A tool that records changes to a project over time |
References
Session info
Reproducibility considerations
While using version control to track the data and code that produce a given output improves the reproducibility of a project, two people can be working from the same GitHub repository and get different results when they run an identical script. This can happen if they have different versions of the software they are using (for example, different versions of the same R package). To learn more about standardizing the versions of tools to use in an analysis, you can work through this open case study about containers. However, a good first step is to print the versions of software that you are using for a project. We do that here, using the R function session_info() from the devtools package.
devtools::session_info()─ Session info ───────────────────────────────────────────────────────────────
setting value
version R version 4.3.2 (2023-10-31)
os Ubuntu 22.04.4 LTS
system x86_64, linux-gnu
ui X11
language (EN)
collate en_US.UTF-8
ctype en_US.UTF-8
tz Etc/UTC
date 2026-09-07
pandoc 3.1.1 @ /usr/local/bin/ (via rmarkdown)
─ Packages ───────────────────────────────────────────────────────────────────
package * version date (UTC) lib source
cachem 1.0.8 2023-05-01 [1] RSPM (R 4.3.0)
cellranger 1.1.0 2016-07-27 [1] RSPM (R 4.3.0)
chromote 0.5.1 2025-04-24 [1] CRAN (R 4.3.2)
cli 3.6.5 2025-04-23 [1] CRAN (R 4.3.2)
colorspace 2.1-0 2023-01-23 [1] RSPM (R 4.3.0)
curl 7.0.0 2025-08-19 [1] CRAN (R 4.3.2)
devtools 2.4.5 2022-10-11 [1] RSPM (R 4.3.0)
digest 0.6.34 2024-01-11 [1] RSPM (R 4.3.0)
dplyr * 1.1.4 2023-11-17 [1] RSPM (R 4.3.0)
ellipsis 0.3.2 2021-04-29 [1] RSPM (R 4.3.0)
evaluate 1.0.5 2025-08-27 [1] CRAN (R 4.3.2)
fansi 1.0.6 2023-12-08 [1] RSPM (R 4.3.0)
farver 2.1.1 2022-07-06 [1] RSPM (R 4.3.0)
fastmap 1.1.1 2023-02-24 [1] RSPM (R 4.3.0)
fs 1.6.3 2023-07-20 [1] RSPM (R 4.3.0)
generics 0.1.3 2022-07-05 [1] RSPM (R 4.3.0)
ggplot2 * 3.5.0 2024-02-23 [1] RSPM (R 4.3.0)
gitcreds 0.1.2 2022-09-08 [1] RSPM (R 4.3.0)
glue 1.7.0 2024-01-09 [1] RSPM (R 4.3.0)
gtable 0.3.4 2023-08-21 [1] RSPM (R 4.3.0)
here * 1.0.2 2025-09-15 [1] CRAN (R 4.3.2)
hms 1.1.3 2023-03-21 [1] RSPM (R 4.3.0)
htmltools 0.5.7 2023-11-03 [1] RSPM (R 4.3.0)
htmlwidgets 1.6.4 2023-12-06 [1] RSPM (R 4.3.0)
httpuv 1.6.14 2024-01-26 [1] RSPM (R 4.3.0)
httr 1.4.7 2023-08-15 [1] RSPM (R 4.3.0)
jsonlite 2.0.0 2025-03-27 [1] CRAN (R 4.3.2)
knitr 1.50 2025-03-16 [1] CRAN (R 4.3.2)
labeling 0.4.3 2023-08-29 [1] RSPM (R 4.3.0)
later 1.3.2 2023-12-06 [1] RSPM (R 4.3.0)
lifecycle 1.0.4 2023-11-07 [1] RSPM (R 4.3.0)
magrittr 2.0.3 2022-03-30 [1] RSPM (R 4.3.0)
memoise 2.0.1 2021-11-26 [1] RSPM (R 4.3.0)
mime 0.12 2021-09-28 [1] RSPM (R 4.3.0)
miniUI 0.1.1.1 2018-05-18 [1] RSPM (R 4.3.0)
munsell 0.5.0 2018-06-12 [1] RSPM (R 4.3.0)
ottrpal 2.0.0 2025-12-16 [1] Github (ottrproject/ottrpal@6d1267e)
pillar 1.9.0 2023-03-22 [1] RSPM (R 4.3.0)
pkgbuild 1.4.3 2023-12-10 [1] RSPM (R 4.3.0)
pkgconfig 2.0.3 2019-09-22 [1] RSPM (R 4.3.0)
pkgload 1.4.1 2025-09-23 [1] CRAN (R 4.3.2)
png 0.1-8 2022-11-29 [1] CRAN (R 4.3.2)
processx 3.8.6 2025-02-21 [1] CRAN (R 4.3.2)
profvis 0.3.8 2023-05-02 [1] RSPM (R 4.3.0)
promises 1.2.1 2023-08-10 [1] RSPM (R 4.3.0)
ps 1.9.1 2025-04-12 [1] CRAN (R 4.3.2)
purrr 1.0.2 2023-08-10 [1] RSPM (R 4.3.0)
R6 2.6.1 2025-02-15 [1] CRAN (R 4.3.2)
Rcpp 1.0.12 2024-01-09 [1] RSPM (R 4.3.0)
readr 2.1.5 2024-01-10 [1] RSPM (R 4.3.0)
readxl * 1.4.3 2023-07-06 [1] RSPM (R 4.3.0)
remotes 2.4.2.1 2023-07-18 [1] RSPM (R 4.3.0)
rlang 1.1.6 2025-04-11 [1] CRAN (R 4.3.2)
rmarkdown 2.25 2023-09-18 [1] RSPM (R 4.3.0)
rprojroot 2.1.1 2025-08-26 [1] CRAN (R 4.3.2)
rvest 1.0.5 2025-08-29 [1] CRAN (R 4.3.2)
scales 1.3.0 2023-11-28 [1] RSPM (R 4.3.0)
sessioninfo 1.2.2 2021-12-06 [1] RSPM (R 4.3.0)
shiny 1.8.0 2023-11-17 [1] RSPM (R 4.3.0)
spelling 2.3.2 2025-08-18 [1] CRAN (R 4.3.2)
stringi 1.8.3 2023-12-11 [1] RSPM (R 4.3.0)
stringr * 1.5.1 2023-11-14 [1] RSPM (R 4.3.0)
tibble 3.3.0 2025-06-08 [1] CRAN (R 4.3.2)
tidyr 1.3.1 2024-01-24 [1] RSPM (R 4.3.0)
tidyselect 1.2.0 2022-10-10 [1] RSPM (R 4.3.0)
tzdb 0.4.0 2023-05-12 [1] RSPM (R 4.3.0)
urlchecker 1.0.1 2021-11-30 [1] RSPM (R 4.3.0)
usethis 2.2.3 2024-02-19 [1] RSPM (R 4.3.0)
utf8 1.2.4 2023-10-22 [1] RSPM (R 4.3.0)
vctrs 0.6.5 2023-12-01 [1] RSPM (R 4.3.0)
webshot2 0.1.2 2025-04-23 [1] CRAN (R 4.3.2)
websocket 1.4.4 2025-04-10 [1] CRAN (R 4.3.2)
withr 3.0.2 2024-10-28 [1] CRAN (R 4.3.2)
xfun 0.55 2025-12-16 [1] CRAN (R 4.3.2)
xml2 1.5.1 2025-12-01 [1] CRAN (R 4.3.2)
xtable 1.8-4 2019-04-21 [1] RSPM (R 4.3.0)
yaml * 2.3.12 2025-12-10 [1] CRAN (R 4.3.2)
[1] /usr/local/lib/R/site-library
[2] /usr/local/lib/R/library
──────────────────────────────────────────────────────────────────────────────
Acknowledgments
We would like to acknowledge Candace Savonen, Casey Greene, Emma Lathouwers, and Taylor Reiter for their expert review of this case study.
We would also like to acknowledge the National Institute of General Medical Sciences for funding this work (1R25GM160622).
Icons are from iconpacks.
Avatars are from avataaars
AI Attribution Statement
The text in this work was primarily human-created. AI was used to make content edits, such as changes to scope, information, and ideas. AI was prompted for its contributions. AI-generated content was reviewed and approved. The following model(s) or application(s) were used: Microsoft 356 Copilot (GPT-5).
AIA Primarily human, Content edits, Human-initiated, Reviewed, Microsoft 356 Copilot (GPT-5) v1.0
The code for the drag-and-drop activity was entirely AI-generated. AI was prompted for its contributions. AI-generated content was reviewed and approved. The following model(s) or application(s) were used: Microsoft 356 Copilot (GPT-5).
AIA Entirely AI, Human-initiated, Reviewed, Microsoft 356 Copilot (GPT-5) v1.0
More information about this AI attribution can be found here.

