Document 03

Git & GitHub Workflow

A guide to version control, collaboration, and keeping a lasting computational record.

§1 Why this matters

The laboratory notebook is science's canonical record. It documents what was done, when, and why: establishing intellectual priority and enabling others to reproduce and extend your work. Computational science requires the same discipline. A script run once, saved locally, and never versioned carries no more lasting value than an experiment written on a scrap of paper. Git is a laboratory notebook for code.

The GitHub repository is also where shared infrastructure is built and maintained. Pushing your code makes it available for PI review and for collaborators to build on. It also creates the foundation for eventual public release, so that others can reproduce your results. When you leave the lab, your work remains here.

Pushing regularly with meaningful commit messages is how the team can help you. Code visible only on your local machine cannot be reviewed or assisted. Treat every commit as a scientific record entry: describe what changed and why.

§2 Prerequisites

Complete the following before working with any Raredon Lab repository. Contact the PI or a senior lab member if you are stuck at any stage.

  1. 1
    Create a personal GitHub account

    If you do not already have one, create a free account at github.com. Choose a professional username: this account will be associated with your publications and scientific identity.

  2. 2
    Provide your username to the PI

    You will be added as a collaborator on relevant Raredon Lab repositories and will receive an email invitation that must be accepted before you can fork or contribute.

  3. 3
    Install a Git interface

    New users: install GitHub Desktop, which provides a clear graphical interface for all routine Git operations. Experienced users may use the command line or manage Git through Claude and other AI tools (see §12).

  4. 4
    Configure Git with your identity

    Open a terminal and run the following. This name and email will appear in all your commits.

Terminal
git config --global user.name "Your Full Name"
git config --global user.email "your.email@yale.edu"

§3 The fork model

Each lab member works from their own personal copy of a repository, called a fork, and proposes changes back to the shared lab copy via pull requests. This design keeps the shared codebase protected while maintaining full PI visibility into all active work.

Raredon Lab fork-based Git workflow Three tiers: RaredonLab origin at top with main and dev branches, personal fork in the middle with a dev branch, and local clone at the bottom. Arrows show fork, clone, commit/push, and pull request flows. RAREDONLAB / repo-name — ORIGIN main protected · PI / authorized only dev default branch · shared workspace PI only YOUR PERSONAL FORK — username / repo-name-AB dev your active working copy LOCAL CLONE ~/projects/repo-name-AB · /hpc/path/repo-name-AB fork (one-time setup) clone (one-time setup) commit + push pull request → dev

Initial setup flows downward (fork, then clone). Daily work and pull requests both flow on the right side: commit/push from local to personal fork, pull request from personal fork up to origin dev. Merging dev into main is reserved for the PI.

TierNaming conventionBranchesWho manages
Origin — the lab's authoritative copy RaredonLab/repo-name main + dev PI; initialized from the RaredonLab account
Personal fork — your working copy username/repo-name-AB dev (minimum) You; forked from origin, cloned to your machines
Protected — main is off limits

The main branch of the origin repository may not be pushed to or targeted by pull requests without explicit PI authorization. It holds only fully functional, milestone-worthy code. All active development happens in dev.

§4 Setting up a repository

For the PI / repository initializer

All new repositories must be created from the RaredonLab GitHub organization account, not from a personal account. Initialize the repository with both a main and a dev branch, set dev as the default, and add lab members as collaborators via Settings → Collaborators.

Forking and cloning (each lab member, one time per repository)

  1. 1
    Navigate to the origin repository on GitHub

    Go to the RaredonLab repository while signed in to your personal account.

  2. 2
    Fork to your personal account

    Click the Fork button in the top right. Append your initials to the repository name so your fork is immediately identifiable: if the origin is LungAtlas, name your fork LungAtlas-AB. Fork the dev branch at minimum; include main if your role requires it.

  3. 3
    Clone to your local machine

    Clone your personal fork (not the origin) to your laptop and/or HPC workspace. In GitHub Desktop: File → Clone Repository, then select your fork. On the command line:

Terminal
git clone https://github.com/yourusername/repo-name-AB.git
cd repo-name-AB

You now have three connected copies: the origin on RaredonLab GitHub, your personal fork on GitHub, and your local clone on disk. All three stay in sync through the commit → push → pull request cycle described in §7.

§5 Standard repository structure

Analysis repositories routinely involve data objects in the 20–50 GB range: large R objects, spatial transcriptomics outputs, processed count matrices. None of this lives in Git. Git holds code, documentation, and lightweight HTML vignettes. Large data and outputs live on the HPC or designated shared storage, with their exact file paths clearly declared at the top of every script that uses them.

The following structure is the recommended default for analysis repositories. Keep it shallow — avoid nesting beyond what is shown here.

Recommended directory structure
repo-name-AB/
│
├── functions/           # Reusable helper functions (generalized, documented)
│   ├── helpers_viz.R
│   ├── helpers_qc.R
│   └── helpers_io.R
│
├── scripts/             # Numbered, dated, initialed analysis scripts
│   ├── 01_20250301_AB_preprocessing.R
│   └── 02_20250308_AB_clustering.R
│
├── markdowns/           # Rmarkdown analysis files
│   ├── 01_20250301_AB_eda.Rmd
│   └── 02_20250308_AB_results.Rmd
│
├── docs/                # Knit HTML vignettes — committed to Git
│   └── 01_20250301_AB_eda.html
│
├── figures/             # Small figures for README / docs only
│   └── .gitkeep
│
├── output/              # Large outputs — NOT committed (gitignored)
│   └── .gitkeep
│
├── data/                # Raw data — NOT committed (gitignored)
│   └── .gitkeep
│
├── .gitignore
├── README.md
├── CLAUDE.md            # AI context file — see Document 06
└── repo-name.Rproj
The .gitkeep convention

Git does not track empty directories. A blank file named .gitkeep inside output/ and data/ preserves the folder structure in the repository even though the contents are gitignored. Create one with touch output/.gitkeep.

Keep it flat

Avoid creating subdirectories within the folders above. Deep nesting makes paths long and fragile, and creates confusion when scripts move between machines or collaborators. If a project feels too large for this structure, ask whether it warrants a second repository rather than adding more directories.

§6 The .gitignore

Every Raredon Lab repository must include a .gitignore that excludes large data objects, generated outputs, session files, and credentials. Copy the following into the root of every new repository on first commit.

.gitignore — Raredon Lab standard
# ── R session artifacts ─────────────────────────────────────────────
.Rhistory
.RData
.Rproj.user/

# ── Large R data objects (never commit) ─────────────────────────────
*.rds
*.rda
*.RData

# ── Genomics and spatial data files (never commit) ──────────────────
*.h5
*.h5ad
*.h5seurat
*.loom
*.mtx
*.fastq
*.fastq.gz
*.bam
*.bai

# ── Output and data directories (contents excluded) ─────────────────
output/*
!output/.gitkeep
data/*
!data/.gitkeep

# ── OS and editor noise ─────────────────────────────────────────────
.DS_Store
Thumbs.db
*.swp
*~
.vscode/

# ── Credentials — never commit ──────────────────────────────────────
.Renviron
*.env
secrets/
Never commit credentials

API keys, HPC passwords, database credentials, and access tokens must never appear in a Git repository, private or otherwise. Store credentials in .Renviron (which is gitignored) and access them in R via Sys.getenv("MY_KEY"). If you accidentally commit a credential, notify the PI immediately and rotate the key before doing anything else.

§7 Daily workflow

After initial setup, your routine has four steps: make changes locally, commit, push to your personal fork, and open a pull request when a meaningful unit of work is ready. The first two happen throughout a working day; the last two happen daily at minimum.

  1. 1
    Make changes locally

    Write and edit code in your local clone, on your laptop or HPC. All work begins here.

  2. 2
    Stage and commit your changes

    Commit at logical stopping points, and always at the end of the day. In GitHub Desktop, review your changed files, write a commit message (see §8), and click Commit to dev. On the command line:

Terminal
git add -A
git commit -m "Add UMAP step to clustering pipeline; parameterize resolution in helpers_qc.R"
  1. 3
    Push to your personal fork

    Push committed changes to your fork on GitHub, not to the origin. In GitHub Desktop, click Push Origin. On the command line:

Terminal
git push origin dev
  1. 4
    Open a pull request to origin dev

    When you have a meaningful unit of work ready, open a pull request from your fork's dev branch to RaredonLab/repo-name's dev branch. You may self-approve and merge if there are no conflicts. Tag the PI if you want review. See §9 for details.

Mandatory — end-of-day push

Committing and pushing to your personal fork at the end of every working day is required. Code that exists only on your local machine is invisible to everyone else: it cannot be reviewed or helped with, and if your machine fails, it is gone. It takes one minute and is not optional.

§8 Commit practices

Frequency

Commit whenever you complete a logical unit of work: a new function, a resolved bug, a completed analysis step. During complex or exploratory work, committing every 30–60 minutes protects against loss and creates a readable trail. During lighter work, end-of-day commits are sufficient. End-of-day commits are never optional.

Commit messages

A good commit message says what changed and why. It does not need to be long, but it must be specific. The commit history is a scientific record and should be interpretable by someone who was not present when the code was written, including yourself in six months.

✓ Informative
Add QC filtering step with doublet removal via scDblFinder; update helpers_qc.R to accept min.cells param Fix incorrect file path in helpers_io read_seurat(); update expected input format in docstring Initial commit: scRNAseq preprocessing pipeline for rat lung cohort 1, n=6 samples
✗ Uninformative
fixes wip update asdf
Claude can write your commit messages

If you are unsure how to describe your changes, ask Claude. Describe what changed or summarize your diff and ask for a commit message. Review and edit the result before committing. The message must be accurate, and you should stand behind what it says. See Document 06 for the full AI usage standard.

§9 Pull requests

All code moving from a personal fork into the shared origin repository travels through a pull request, including straightforward changes with no conflicts. The pull request is the formal record of what changed and why, and it creates an opportunity for comment before code enters the shared codebase.

Opening a pull request

Navigate to your personal fork on GitHub and click "Contribute" → "Open pull request." Verify that the base repository is RaredonLab/repo-name and the base branch is dev. Write a descriptive title and a brief summary. If the PR implements a specific analysis step or resolves an issue, say so.

Self-approval

You may approve and merge your own pull request if there are no merge conflicts and the changes do not touch shared infrastructure: the helper functions in functions/, the CLAUDE.md, the .gitignore, or the README.md. Changes to shared infrastructure should be flagged for PI review regardless of conflict status.

Requesting PI review

For significant changes — new analysis pipelines, refactored helpers, anything affecting how other team members use the repository — add the PI as a reviewer with a note explaining what you would like reviewed and any open questions.

Never pull request to main

All pull requests from personal forks target the dev branch of the origin. Merging dev into main is a deliberate, infrequent operation performed only by the PI or an explicitly authorized lab member, and only when the codebase has reached a stable, fully functional milestone.

§10 Branch rules

BranchLives inPurposeWho may merge into it
main Origin only Fully functional, milestone-worthy code. The stable scientific record. PI and explicitly authorized individuals only
dev Origin + all personal forks Active development. The shared team working space. Lab members via pull request from personal fork

For routine work, no additional branches are needed within your personal fork. If a large experimental feature warrants isolation, discuss it with the PI before creating feature branches. Keep the branching model as simple as possible.

§11 File naming conventions

Consistent file naming allows anyone to understand who created a file, when, and in what order without opening it. Every file you create should be interpretable from its name alone.

The standard pattern

Pattern
NN_YYYYMMDD_AB_descriptive-name.ext
ComponentMeaningFormat
NN Sequence number within the analysis Two-digit integer: 01, 02, 03
YYYYMMDD Date of creation or last major revision ISO 8601, no separators: 20250315
AB Author initials 2–4 uppercase letters: NW, NK, SE, MSBR
descriptive-name What the file does or contains Lowercase words separated by hyphens; no spaces or underscores between words
Examples
01_20250301_AB_preprocessing-qc.R
02_20250308_AB_clustering-umap.Rmd
03_20250315_CD_spatial-niche-analysis.Rmd
helpers_20250220_MSBR_visualization-utils.R
01_20250301_AB_eda-overview.html   # knit vignette in docs/
Stamp your outputs too

The same convention applies to figures, exported tables, and any output files not committed to Git. Name a saved plot 02_20250308_NW_umap-celltype.pdf, not plot_final_v3.pdf. Date stamps on outputs make it possible to match figures to the code and data versions that produced them.

§12 Using Claude and AI tools with Git

AI tools have an explicit, encouraged role in the workflow described here. The goal is to use AI for the mechanical parts of version control so you can focus on the science.

Writing commit messages

Claude writes good commit messages. If you are uncertain what to write, describe your changes in plain language or paste a summary of your diff and ask Claude to draft a message. Review and edit it before committing: the message must be accurate, and you should understand what it says.

The CLAUDE.md file

Every repository should contain a CLAUDE.md file in the root directory. This file gives Claude essential context about the repository: what it does, how it is structured, where data lives, what conventions apply, and the current state of active work.

When you open a Claude session to work on code in a repository, load the CLAUDE.md as context first. Update it when significant structural changes occur: new analysis phases, restructured helpers, new datasets, or major shifts in direction. The CLAUDE.md is a living document and should be treated as such.

The longer-term goal is that each lab member's Claude, working from a current CLAUDE.md, can interact with and learn from the shared codebase, enabling a form of AI-assisted cross-pollination between team members' work. See Document 06 for the full standard.

Git commands via AI

Claude can help with Git syntax when you are unsure. Describe what you want to accomplish and ask for the command. Read and verify the output before running it, particularly for anything involving --force, reset, rebase, or operations that modify history.

§13 Common mistakes to avoid

Not pushing regularly

Code that exists only on your local machine is invisible to the rest of the lab. It cannot be reviewed or helped with, and if your machine fails, it is gone. Push to your personal fork at the end of every working day. During intensive work, push every hour or two. This habit takes seconds and provides considerable protection.

Deep directory nesting

Nested subdirectories make file paths long and fragile, and create confusion when scripts move between machines or collaborators. Keep repositories shallow. If a project feels too large for the recommended structure, ask whether it should be split into two repositories rather than adding more directories.

Committing large files

Git is not designed for large binary files. An accidentally committed .rds or .h5 file becomes part of the repository's permanent history and can make cloning very slow. Verify that your .gitignore is in place before your first commit. If a large file is accidentally committed, notify the PI before attempting to remove it from history.

Pushing to the origin directly

Never push changes directly to the RaredonLab origin repository, even with permission to do so. All changes flow through your personal fork and a pull request. This keeps the shared codebase protected and ensures every change has a review checkpoint.

Vague commit messages

A commit labeled update or wip is not a useful scientific record. When you are writing a methods section or trying to reproduce a figure months later, you will not know what that commit contained or why it mattered. Write a specific message every time, or ask Claude to help.

When in doubt, ask

Git mistakes are recoverable in almost all cases. If you are unsure what to do, especially before running reset, rebase, or any force push, ask the PI or a senior lab member first. A few minutes of consultation can prevent hours of recovery work.