# Git for Virus Scientists: Tracking Changes

By the end of this guide you will be able to turn a folder of analysis scripts into a versioned Git repository, record every change with a message a reviewer can follow, branch and merge without losing work, publish the repository to GitHub, tag a citable release, and recover from the errors that trip up most new users. You will also know which files should never enter Git at all, which matters as much as anything you put in.

You need a computer with a terminal, a text editor, and, for the sharing steps, a free GitHub account. On Windows the installer gives you Git Bash, a terminal configured for Git. On macOS and Linux use the built-in Terminal. Every command below runs in the shell, and each one shows the output you should expect.

The worked example is a small quality-control script for influenza hemagglutinin (HA), the surface protein that promotes fusion between the viral and host membranes during entry [1]. The commands are identical for SARS-CoV-2 lineage reports, RSV surveillance summaries, or any other virus project. Git for virus scientists carries one extra rule compared with most fields: the raw data are usually far too large, and sometimes too sensitive, to live in the repository, so this guide spends as much time on what to keep out of Git as on what to put in. This guide is written as a step-by-step path for virus researchers who have never used version control before.

## Why Virus Scientists Need Version Control

Virus research moves on its own schedule. When [avian influenza](/knowledge/bacteria/avian-bacteria/avian-influenza-new-zealand-kerala-outbreaks-jessamine-county-updates) circulates uncontrolled in poultry, mutation and reassortment become more likely, and vaccination and control strategies are revised as new evidence accumulates [2]. Every revision ripples outward into analysis code, reference data, figures, and manuscripts. Without version control, that history lives in folder names such as final_v2_REAL and in the memory of whoever made the change.

Git (a distributed version control system, meaning every user holds a complete copy of the project plus its full history) replaces that arrangement with a chain of commits (permanent, labeled snapshots of every tracked file). Each commit records the author, the timestamp, the message, and a hash (a 40-character hexadecimal identifier computed from the commit contents), so any past state can be retrieved exactly. A Git repository is the project folder plus the hidden history database Git maintains inside it.

The habit is now standard in research computing, and published virus bioinformatics shows it. CAPTVRED, a pipeline for tracking viral species in capture-based metagenomic samples, is distributed through a public GitHub repository [3]. Machine learning models for viral proteins follow the same pattern, with the hemagglutinin identification classifier sharing its code through a public repository [1]. When you clone such a repository (download a full copy with its history), you get the exact code the authors ran.

Version control also changes how a lab shares work. Instead of emailing scripts, you push commits (upload them) to a remote (a repository hosted on another machine, usually GitHub), and colleagues pull them (download and merge). GitHub for researchers adds pull requests (proposals to merge one line of work, called a branch, into another, with a review thread), issues (numbered, searchable discussions of bugs and tasks), and releases (downloadable, versioned snapshots). The same loop of edit, commit, share is what makes git for scientists work in any quantitative field.

## What Git Does Well and Where It Struggles

Git records the line-by-line history of text files. That makes it ideal for the files a virus project actually edits by hand: Python, R, and Shell scripts, Snakemake or Nextflow workflow definitions (workflow managers for pipelines), YAML configuration, CSV metadata tables, small FASTA reference sets, Markdown notes, and .gitignore rules. A commit stores a full snapshot, but Git compares versions line by line, so a one-line fix produces a one-line diff (the readable record of what changed).

Git handles binary and very large files poorly. Compressed raw reads (FASTQ), alignments (BAM), and compressed variant calls cannot be meaningfully compared line by line, so Git stores a fresh copy of every new version and the history balloons. GitHub blocks files larger than 100 MB and warns above 50 MB, so a single sequencing run can be impossible to push and would make the repository unusable for colleagues.

The working rule for virus research has three parts.

1. Git holds code, small metadata, configuration, and documentation.
2. A data store (a lab server, cloud bucket, or controlled database) holds reads, alignments, and large outputs.
3. A committed versions file links the two with file names, download dates, and checksums (fixed-length fingerprints computed from a file, so any change to the file changes the fingerprint).

The provenance section below shows that file in full.

## Installing and Configuring Git

### Step 1: Install Git and verify it

macOS: run `xcode-select, install` for Apple's developer tools, or `brew install git` if you use Homebrew.

Windows: run the Git for Windows installer from git-scm.com and keep the defaults.

Ubuntu or Debian Linux:

```
sudo apt install git
```

Verify the installation:

```
git --version
```

```
git version 2.44.0
```

Any recent 2.x release supports every command in this guide.

### Step 2: Set your identity and defaults

```
git config --global user.name "Ada Lovelace"
git config --global user.email "ada@lab.example.edu"
git config --global init.defaultBranch main
git config --global core.autocrlf input
```

Each line matters:

- `-global` writes to your user-level Git configuration, so the settings apply to every repository on this machine.
- `user.name` and `user.email` are written into every commit you make. Use the email linked to your GitHub account so GitHub attributes the commits to your profile.
- `init.defaultBranch main` names the first branch in new repositories main, matching GitHub's default.
- `core.autocrlf` controls line-ending conversion between Windows (CRLF) and Unix (LF) text. Use `input` on macOS and Linux, `true` on Windows. Setting it prevents whole-file diffs caused by line endings alone.

Check the result:

```
git config --global --list
```

```
user.name=Ada Lovelace
user.email=ada@lab.example.edu
init.defaultBranch=main
core.autocrlf=input
```

## Git for Virus Researchers, Step by Step

The steps below build one small repository from nothing to a tagged release on GitHub. Type the commands rather than pasting them the first time, because the muscle memory is the point.

### Step 3: Create a repository

```
mkdir -p ~/projects/flu-ha-analysis
cd ~/projects/flu-ha-analysis
git init
```

```
Initialized empty Git repository in /home/ada/projects/flu-ha-analysis/.git/
```

Git stores all history in the hidden `.git` directory inside the project. Never edit files inside `.git` by hand. Nothing is recorded yet. If you run a Git command outside a repository you will see:

```
fatal: not a git repository (or any of the parent directories): .git
```

The fix is to `cd` into the project folder, or to run `git init` if the folder is meant to be one.

### Step 4: Add your first files

Create three files. FASTA is the plain-text sequence format whose header lines begin with `>`, and GC content is the fraction of a sequence made of guanine and cytosine.

README.md:

```markdown
# flu-ha-analysis

GC-content QC for influenza A hemagglutinin sequences.

## Layout
- analyze_ha.py, the QC script
- data/, input FASTA files (not tracked, see .gitignore)
- versions.yaml, data provenance record
```

analyze_ha.py:

```python
"""GC-content QC for sequences in a FASTA file."""

def gc_content(seq):
    seq = seq.strip().upper()
    if not seq:
        return 0.0
    gc = seq.count("G") + seq.count("C")
    return round(gc / len(seq), 2)

def read_fasta(path):
    records = {}
    name = None
    chunks = []
    with open(path) as handle:
        for line in handle:
            line = line.strip()
            if line.startswith(">"):
                if name is not None:
                    records[name] = "".join(chunks)
                name = line[1:].split()
                chunks = []
            elif name is not None:
                chunks.append(line)
    if name is not None:
        records[name] = "".join(chunks)
    return records

if __name__ == "__main__":
    import sys
    for header, seq in read_fasta(sys.argv[1]).items():
        print(f"{header}\t{gc_content(seq)}")
```

.gitignore:

```
# raw data and large outputs stay out of Git
data/raw/
*.fastq.gz
*.fq.gz
*.bam
*.bai
*.vcf.gz
results/

# editor, notebook, and operating system noise
__pycache__/
*.pyc
.Rhistory
.RData
.ipynb_checkpoints/
.DS_Store

# credentials never belong in a repository
.env
credentials.json
```

Now ask Git what it sees:

```
git status
```

```
On branch main

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)
	.gitignore
	README.md
	analyze_ha.py

nothing added to commit but untracked files present (use "git add" to track)
```

Untracked means Git can see the files but has not recorded them. Note that `.gitignore` itself is tracked, which is what makes the exclusions travel with the repository.

### Step 5: Stage and make the first commit

```
git add README.md analyze_ha.py .gitignore
git status
```

```
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	new file:   .gitignore
	new file:   README.md
	new file:   analyze_ha.py
```

`git add` moves changes into the staging area (also called the index, the holding area for the next commit). Staging is what lets you edit five files and commit them as two logical changes, staging each group separately. Commit what is staged:

```
git commit -m "Add HA GC-content script, README, and ignore rules"
```

```
[main (root-commit) 3f2a9c1] Add HA GC-content script, README, and ignore rules
 3 files changed, 61 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 README.md
 create mode 100644 analyze_ha.py
```

`-m` supplies the message on the command line. `3f2a9c1` is the shortened commit hash, seven characters of the full identifier. `root-commit` marks the first commit in the history. Verify with `git log, oneline`, which should list the new commit.

### Step 6: Edit, then read the diff and the history

Change the rounding in analyze_ha.py from 2 to 4 decimals, then look at what changed before committing anything:

```
git diff
```

```
diff --git a/analyze_ha.py b/analyze_ha.py
index 5b2f4a8..9c1d2e3 100644
--- a/analyze_ha.py
+++ b/analyze_ha.py
@@ -8,7 +8,7 @@ def gc_content(seq):
     seq = seq.strip().upper()
     if not seq:
         return 0.0
     gc = seq.count("G") + seq.count("C")
-    return round(gc / len(seq), 2)
+    return round(gc / len(seq), 4)
```

Lines starting with `-` were removed and lines starting with `+` were added. The `@@` line locates the change inside the file. Commit and review the history:

```
git add analyze_ha.py
git commit -m "Report GC content to four decimals"
git log --oneline
```

```
9c1d2e3 (HEAD -> main) Report GC content to four decimals
3f2a9c1 Add HA GC-content script, README, and ignore rules
```

`HEAD` is a pointer to the commit you are working on, normally the tip of the current branch. Two more views cover most needs: `git diff, staged` shows what will go into the next commit, and `git show HEAD` prints the last commit's message and diff together.

### Step 7: Keep data out of Git with .gitignore

The patterns in `.gitignore` are simple: `*.fastq.gz` matches any file with that suffix, `data/raw/` matches a folder, and a bare name matches any file of that name anywhere in the repository. Git applies the file to untracked files only, so a large file that is already tracked keeps being tracked. If you stage a big file by mistake:

```
git add data/raw/run42.fastq.gz
git rm --cached data/raw/run42.fastq.gz
```

`-cached` removes the file from tracking while leaving it on disk. To learn which rule is hiding a file:

```
git check-ignore -v data/raw/run42.fastq.gz
```

```
.gitignore:3:*.fastq.gz	data/raw/run42.fastq.gz
```

The output names the file, the line number, and the pattern that matched.

### Step 8: Branch for every analysis question

A branch is a movable label pointing at one commit, which lets parallel lines of work coexist without copying folders. Create one for a threshold change:

```
git switch -c h3n2-threshold
```

```
Switched to a new branch 'h3n2-threshold'
```

Edit the script, commit on the branch, then return to main and merge:

```
git add analyze_ha.py
git commit -m "Flag sequences below 45 percent GC as low confidence"
git switch main
git merge h3n2-threshold
```

```
Updating 9c1d2e3..b4e5f6a
Fast-forward
 analyze_ha.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
```

Fast-forward means main simply moved to the branch tip because nothing else had changed on main. When both branches edit the same lines, the merge stops:

```
Auto-merging analyze_ha.py
CONFLICT (content): Merge conflict in analyze_ha.py
Automatic merge failed, fix conflicts and then commit the result.
```

The conflicted file now contains:

```
<<<<<<< HEAD
threshold = 0.45
=======
threshold = 0.50
>>>>>>> h3n2-threshold
```

The section between `<<<<<<< HEAD` and `=======` is your current version, and the section between `=======` and `>>>>>>>` is the incoming version. Keep the correct line, delete all three marker lines, then finish:

```
git add analyze_ha.py
git commit -m "Merge h3n2-threshold after lab meeting decision"
```

`git status` lists conflicted files until every one is resolved, and `git merge, abort` cancels a merge and restores the pre-merge state. Older tutorials use `git checkout -b` where this guide uses `git switch -c`. The two do the same job.

### Step 9: Publish to GitHub and clone published pipelines

Create an empty repository named flu-ha-analysis on GitHub, and do not add a README through the web form. A remote repository that already has a commit will reject your first push of unrelated history. Then connect and upload:

```
git remote add origin git@github.com:alab/flu-ha-analysis.git
git push -u origin main
```

```
Enumerating objects: 12, done.
Writing objects: 100% (12/12), 2.41 KiB, done.
To github.com:alab/flu-ha-analysis.git
 * [new branch]      main -> main
branch 'main' set up to track 'origin/main'.
```

`origin` is the conventional nickname for the remote. The SSH address form (`git@github.com:user/repo.git`) requires an SSH key (a cryptographic key pair you register with your account, generated with `ssh-keygen`). The HTTPS form (`https://github.com/user/repo.git`) uses a browser login or a personal access token, because GitHub no longer accepts account passwords for Git over HTTPS. `-u` (short for `-set-upstream`) records that local main tracks origin/main, so later pushes and pulls need no arguments. Confirm the wiring any time with `git remote -v`.

The daily cycle from here is short:

```
git pull
# edit, test, commit
git push
```

If a colleague pushed first, your push is refused:

```
 ! [rejected]        main -> main (fetch first)
error: failed to push some refs to 'github.com:alab/flu-ha-analysis.git'
```

Run `git pull` to merge their work (or `git pull, rebase` to replay your commits on top of theirs), resolve any conflict, and push again.

To use someone else's pipeline, clone it and read before you run:

```
git clone https://github.com/CompGenLabUB/CAPTVRED.git
cd CAPTVRED
git log --oneline -3
```

The same one line brings down a published model such as the hemagglutinin identification classifier:

```
git clone https://github.com/Zouxidan/HA_predict.git
```

### Step 10: Tag a release

When results are final for a manuscript, or a pipeline version is stable enough to share widely, mark the exact commit:

```
git tag -a v1.0.0 -m "HA QC scripts, first shared release"
git push origin v1.0.0
```

```
 * [new tag]         v1.0.0 -> v1.0.0
```

`-a` creates an annotated tag (a named pointer to one commit that carries a message, author, and date). The common convention is semantic versioning, vMAJOR.MINOR.PATCH, bumped for breaking changes, additions, and fixes respectively. On GitHub the tag becomes a Release, a downloadable snapshot that collaborators and reviewers can cite. When you reuse a published model or pipeline, record the tag or commit hash you used, because the default branch keeps moving after publication.

Check the result with `git tag`, which lists every tag, and `git show v1.0.0`, which prints the tag message and the commit it marks.

## Tracking Data Provenance Alongside Code

Git solves versioning for text. Data needs its own discipline, recorded in files that Git does track. Commit a versions.yaml with every dataset the analysis touches:

```yaml
reference_sequences:
  description: "Influenza A hemagglutinin reference set"
  source: "NCBI Virus"
  download_date: "2026-03-14"
  file: "data/references.fasta"
  sha256: "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"
analysis_environment:
  python: "3.12"
  notes: "exact package versions live in requirements.txt"
```

Generate the checksum and commit the checksum file next to the record:

```
sha256sum data/references.fasta > data/references.fasta.sha256
```

On macOS use `shasum -a 256 data/references.fasta`. When a collaborator downloads the same file months later, matching checksums prove the input is identical.

Record the date of every data snapshot. Living analyses make this explicit: a recent meta-analysis of nirsevimab against respiratory syncytial virus reports that its literature searches ran on 25 November 2024 and were updated on 18 April 2025, so readers know exactly which evidence snapshot the pooled estimates describe [4]. Reference sets and case line lists deserve the same treatment.

The cost of skipping this is documented outside virology too. A national evaluation of perinatal quality collaboratives found that inconsistent measurement over time, driven by staggered adoption of revised certificates and coding changes, confounds attempts to separate real improvement from data artifacts, and its authors call for systematic tracking of initiatives and harmonized data across states and periods [5]. The lesson generalizes cleanly: an untracked change in a data definition is indistinguishable from a real change in the world.

Two boundaries are absolute. Never commit identifiable human data, such as case line lists with names, dates of birth, or precise locations, to any repository, public or private. Never commit credentials, such as database passwords or API tokens. Both belong in systems with access control separate from code.

## Testing Your Analysis Before You Commit It

A commit message says what you think changed. A test says what must not change. Research software has converged on this practice: the DrugUtilisation R package, built for drug utilization studies on the OMOP Common Data Model (a standardized structure for observational health data), ships comprehensive unit tests and standardized output formats that kept results consistent across databases in the United Kingdom, Estonia, and the Netherlands while minimizing coding errors [6]. The same practice scales down to a two-script virus project.

Add a test file named test_analyze_ha.py:

```python
from analyze_ha import gc_content

def test_all_gc():
    assert gc_content("GCGC") == 1.0

def test_all_at():
    assert gc_content("AAAA") == 0.0

def test_empty_sequence():
    assert gc_content("") == 0.0
```

Run the suite:

```
python -m pytest
```

```
================= test session starts =================
collected 3 items

test_analyze_ha.py ...                                   [100%]

================== 3 passed in 0.02s ==================
```

Commit the tests with the code they cover. If a future edit changes what GC content means, the tests fail before the figure is wrong. Pin the software environment in the repository as well: a requirements.txt for Python (generate one with `pip freeze > requirements.txt`), an environment.yml for conda (a package and environment manager), or renv for R. GitHub Actions, the continuous integration service that runs commands you specify on every push, can execute the test suite on each commit so a broken push is visible in minutes. None of this replaces judgment, but it turns "I think it still works" into a checkable claim.

## Collaborating on GitHub: Pull Requests, Issues, and Releases

GitHub for researchers turns a repository from a personal archive into a bench others can work at. The core loop has four moves:

1. Each collaborator clones the repository and works on branches.
2. When work is ready, they push the branch and open a pull request with a description.
3. A colleague reviews the diff line by line, comments, and requests changes or approves.
4. Merging the pull request records both the change and the review conversation.

Issues keep decisions attached to the code. A question such as why the pipeline flags low-GC sequences becomes an issue, the decision is written into the thread, and the implementing commit references the issue number. Six months later the reasoning is searchable instead of oral.

This is also how you interact with published tools. After cloning a pipeline such as CAPTVRED, run its included test dataset before your own samples, and if something fails, open an issue on the project's GitHub repository with the exact command and the full error text [3]. A reproducible report lets maintainers fix the problem quickly, and every future user inherits the fix.

### Practical Tips That Prevent Pain Later

These tips for virus researchers come from watching repositories fail in slow motion.

- Commit small and often. One commit per logical change keeps diffs reviewable and messages honest.
- Pull before you push. Merging remote changes first prevents most rejected pushes.
- Branch per question, and keep main in a state you would show a reviewer.
- Write messages for the colleague you will be in eight months. State what changed and why.
- Check `git status` before every `git add .`, because that form stages everything, including the files you forgot to ignore.

## Key Git Commands at a Glance

| Command | What it does | Notes |
|, - |, - |, - |
| `git init` | Creates a repository in the current folder | One time per project |
| `git status` | Shows branch, staged, and untracked files | Run before every commit |
| `git add FILE` | Stages a file for the next commit | `git add .` stages everything, use deliberately |
| `git commit -m "msg"` | Records staged changes as a snapshot | Message in imperative mood |
| `git log, oneline` | Compact history, one line per commit | Add `-p` to see diffs |
| `git diff` | Shows unstaged edits | `git diff, staged` shows staged edits |
| `git switch -c NAME` | Creates and enters a branch | Older form: `git checkout -b` |
| `git merge NAME` | Merges NAME into the current branch | Conflicts stop the merge for manual fixes |
| `git remote add origin URL` | Connects the local repo to GitHub | Once per repository |
| `git push -u origin main` | Uploads main and sets upstream tracking | Later pushes need only `git push` |
| `git pull` | Fetches and merges remote updates | Run before starting work |
| `git clone URL` | Downloads a full copy of a remote repository | Includes all history |
| `git tag -a vX.Y.Z -m "msg"` | Creates an annotated release tag | Push tags with `git push origin vX.Y.Z` |
| `git restore FILE` | Discards unstaged edits to FILE | Destructive, unstaged work is gone |
| `git reset, soft HEAD~1` | Undoes the last commit, keeps changes staged | Only before pushing |
| `git revert HASH` | Adds a commit that undoes HASH | Safe on shared branches |
| `git reflog` | Lists recent HEAD positions | The recovery tool for lost commits |

Sensible next steps once these are routine: learn `git bisect` for finding the commit that introduced a bug, read about interactive rebase for cleaning up private branch history, and adopt a continuous integration workflow once tests exist.

## Common Mistakes and Limitations

1. **Committing raw reads and alignments.** A single flowcell (one sequencing run of reads) exceeds every hosting limit, and even modest BAM files bloat history because each new version is stored whole. Put `.gitignore` in place before the first `git add`. If a large file is already staged, `git rm, cached FILE` untracks it. If it was already pushed, history must be rewritten with a tool such as git filter-repo, which requires a force push and coordination with everyone who cloned the repository.

2. **Committing credentials and then pushing.** A token in a pushed commit is compromised the moment the push lands, especially on a public host. Remove the file, rotate the credential immediately, then rewrite history if the repository is shared. Prevention is cheaper: keep `.env` and credential files in `.gitignore` from the first commit.

3. **Committing identifiable patient data.** A Git repository, public or private, is not an access-controlled clinical data store. De-identify before data leaves the source system, keep line lists in approved systems, and track only checksums in Git.

4. **Vague commit messages.** "fix", "update", and "changes" tell a reviewer nothing in six months. Write what and why: "Raise GC threshold to 0.50 after H3N2 calibration review".

5. **Weeks of work between commits.** One giant commit cannot be reviewed, reverted, or searched. Commit at every point where the code runs and the results make sense.

6. **Destructive commands on shared branches.** `git reset, hard` deletes uncommitted work with no confirmation, and a force push can erase commits colleagues already have. On shared branches, undo with `git revert`, which adds a new commit that reverses an old one. For local losses, `git reflog` lists recent positions of HEAD and lets you recover commits that no branch points to.

7. **Long-lived branches.** A branch open for months accumulates a conflict that takes a day to untangle. Merge or open a pull request within days.

8. **Versioning binary documents as if they were text.** Word and PowerPoint files cannot be diffed line by line, so their history is a pile of opaque snapshots. Prefer Markdown or LaTeX for manuscripts that live beside the code.

9. **Expecting Git to manage data.** Git versions text at human scale. Reads, alignments, and imaging belong in data stores linked by checksums and a versions file. Tools that extend Git to data versioning exist, but they add complexity a disciplined versions file often makes unnecessary.

A final limitation is honest rather than technical. Git has a learning curve, and its model of commits pointing to parents and branches as pointers feels abstract for the first few weeks. Rewritten history confuses collaborators who pulled the old version. And version control proves nothing about scientific validity: a clean, reproducible repository can still contain the wrong model. These practices make errors findable, not impossible.

## Frequently Asked Questions

### Should I commit raw FASTQ files to Git?

No. Raw read files are large, Git stores a fresh copy of every changed binary in history, and GitHub blocks files over 100 MB. Track code and small metadata in Git, keep reads in a data store, and record checksums for the data files instead.

### What is the difference between git add and git commit?

`git add` stages selected changes in the staging area, and `git commit` records everything staged as one permanent snapshot with a message and a hash. You can stage in several passes and commit once.

### How do I undo my last commit?

![Decision path asking if the commit was pushed, leading to soft reset or revert, with amend as an option for messages only.](/article-images/illustrations/git-for-virus-researchers-undo-commit-path.webp)

Before pushing, run `git reset, soft HEAD~1` to undo the commit and keep the changes staged, or fix the message with `git commit, amend`. After others have pulled, undo with `git revert` so shared history stays intact.

### Do I need GitHub to use Git?

No. Git runs entirely on your machine, and a repository keeps its full history offline. GitHub adds a shared remote, pull requests, issues, and releases, which matter once more than one person works on the code.

### How do I contribute a fix to an existing viral genomics pipeline?

Fork the repository on GitHub, clone your fork, create a feature branch, commit the fix with a clear message, push the branch, and open a pull request describing what changed and why. The maintainers review and merge.

### What belongs in a .gitignore file for a sequencing project?

Raw reads and alignments such as `*.fastq.gz`, `*.bam`, `*.bai`, and `*.vcf.gz`, output folders, notebook checkpoints and caches, operating system noise such as `.DS_Store`, and any file holding credentials. Commit the `.gitignore` itself so the exclusions travel with the repository.

### I deleted a branch and lost commits. Can I get them back?

Usually yes. `git reflog` lists recent positions of HEAD, and `git branch NAME HASH` recreates a branch at any hash in that list. Entries expire after weeks to months, so recover soon.

### How do I make my analysis rerunnable for a reviewer?

Tag the exact commit as a release, pin the software environment in a requirements or conda environment file, and record data sources, download dates, and checksums in a committed versions file.

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": [
    {
      "@type": "Question",
      "name": "Should I commit raw FASTQ files to Git?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "No. Raw read files are large, Git stores a fresh copy of every changed binary in history, and GitHub blocks files over 100 MB. Track code and small metadata in Git, keep reads in a data store, and record checksums for the data files instead."
      }
    },
    {
      "@type": "Question",
      "name": "What is the difference between git add and git commit?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "git add stages selected changes in the staging area, and git commit records everything staged as one permanent snapshot with a message and a hash. You can stage in several passes and commit once."
      }
    },
    {
      "@type": "Question",
      "name": "How do I undo my last commit?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Before pushing, git reset in soft mode against the previous commit undoes the commit and keeps the changes staged, and git commit with the amend option fixes the message. After others have pulled, undo with git revert so shared history stays intact."
      }
    },
    {
      "@type": "Question",
      "name": "Do I need GitHub to use Git?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "No. Git runs entirely on your machine, and a repository keeps its full history offline. GitHub adds a shared remote, pull requests, issues, and releases, which matter once more than one person works on the code."
      }
    },
    {
      "@type": "Question",
      "name": "How do I contribute a fix to an existing viral genomics pipeline?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Fork the repository on GitHub, clone your fork, create a feature branch, commit the fix with a clear message, push the branch, and open a pull request describing what changed and why. The maintainers review and merge."
      }
    },
    {
      "@type": "Question",
      "name": "What belongs in a .gitignore file for a sequencing project?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Raw reads and alignments such as FASTQ, BAM, BAI, and VCF files, output folders, notebook checkpoints and caches, operating system noise, and any file holding credentials. Commit the .gitignore itself so the exclusions travel with the repository."
      }
    },
    {
      "@type": "Question",
      "name": "I deleted a branch and lost commits. Can I get them back?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Usually yes. git reflog lists recent positions of HEAD, and you can recreate a branch at any hash in that list. Entries expire after weeks to months, so recover soon."
      }
    },
    {
      "@type": "Question",
      "name": "How do I make my analysis rerunnable for a reviewer?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Tag the exact commit as a release, pin the software environment in a requirements or conda environment file, and record data sources, download dates, and checksums in a committed versions file."
      }
    }
  ]
}
</script>

## Sources

1. [Accurately identifying hemagglutinin using sequence information and machine learning methods.](https://pubmed.ncbi.nlm.nih.gov/38020152/)
2. [Strategies for enhancing immunity against avian influenza virus in chickens: a review.](https://pubmed.ncbi.nlm.nih.gov/35297706/)
3. [CAPTVRED: an automated pipeline for viral tracking and discovery from capture-based metagenomics samples.](https://pubmed.ncbi.nlm.nih.gov/39440005/)
4. [Efficacy and safety of a single dose of nirsevimab against respiratory syncytial virus infection in infants: a meta-analysis and time-to-event analysis.](https://pubmed.ncbi.nlm.nih.gov/41469925/)
5. [Scaling evidence: national causal evaluation of perinatal quality collaboratives needs better data.](https://pubmed.ncbi.nlm.nih.gov/42253882/)
6. [DrugUtilisation: An R Package to Support Drug Utilisation Research Using the OMOP Common Data Model.](https://pubmed.ncbi.nlm.nih.gov/42448616/)