Version Control for Experiment Code with Git
After Completing This Topic
You'll be able to record the change history of your analysis code with Git, revert to past versions, and back up to GitHub.
Why You Need Git
Have you ever seen filenames like these in your lab?
analysis_final.py
analysis_final_v2.py
analysis_final_v2_advisor_edits.py
analysis_final_v2_advisor_edits_REAL_FINAL.pyGit stores the entire change history in a single file. No need to copy files.
Installation & Initial Setup
Git is already installed on Google Colab. You just need to set your name and email.
git config --global user.name "Your Name"git config --global user.email "your@email.com"
# Verify settingsgit config --list --global | grep userCreating Your First Repository
git init is like opening a fresh lab notebook.
# Create a practice directory + initialize Gitmkdir -p /tmp/bio-analysis && cd /tmp/bio-analysisgit init
# A .git folder is created (where Git stores history)ls -la .git/Your First Commit: Taking a Snapshot
A commit is like writing the date in your lab notebook and noting "completed up to here."
cd /tmp/bio-analysis
# Create an analysis scriptcat > gc_analysis.py << 'SCRIPT'"""GC Content Analysis Script v1"""
def calculate_gc(sequence: str) -> float: seq = sequence.upper() gc = seq.count("G") + seq.count("C") return (gc / len(seq)) * 100
sequences = { "BRCA1": "ATGGATTTATCTGCTCTTCG", "TP53": "ATGGAGGAGCCGCAGTCAG",}
for name, seq in sequences.items(): print(f"{name}: GC={calculate_gc(seq):.1f}%")SCRIPT
# Git's 3 steps: Work โ Stage โ Commitgit add gc_analysis.py # 1. Stage (select files for the snapshot)git status # Check: green = stagedgit commit -m "feat: initial GC content analysis script" # 2. Commit (snapshot!)
# View historygit log --onelineTracking Changes: Viewing Diffs
Just as you mark changes with a red pen when proofreading a paper, git diff shows you what changed.
cd /tmp/bio-analysis
# Create the environment if it doesn't existif [ ! -f gc_analysis.py ]; then git init cat > gc_analysis.py << 'SCRIPT'"""GC Content Analysis Script v1"""
def calculate_gc(sequence: str) -> float: seq = sequence.upper() gc = seq.count("G") + seq.count("C") return (gc / len(seq)) * 100
sequences = { "BRCA1": "ATGGATTTATCTGCTCTTCG", "TP53": "ATGGAGGAGCCGCAGTCAG",}
for name, seq in sequences.items(): print(f"{name}: GC={calculate_gc(seq):.1f}%")SCRIPT git add gc_analysis.py git commit -m "feat: initial GC content analysis script"fi
# Modify the script: add EGFR genecat > gc_analysis.py << 'SCRIPT'"""GC Content Analysis Script v2 โ Added EGFR"""
def calculate_gc(sequence: str) -> float: seq = sequence.upper() gc = seq.count("G") + seq.count("C") return (gc / len(seq)) * 100
sequences = { "BRCA1": "ATGGATTTATCTGCTCTTCG", "TP53": "ATGGAGGAGCCGCAGTCAG", "EGFR": "ATGCGACCCTCCGGGACGGC",}
for name, seq in sequences.items(): gc = calculate_gc(seq) label = "HIGH" if gc > 60 else "NORMAL" print(f"{name}: GC={gc:.1f}% [{label}]")SCRIPT
# View changesgit diff gc_analysis.py
# Commitgit add gc_analysis.pygit commit -m "feat: add EGFR + HIGH label for GC > 60%"
git log --onelineReverting: Traveling to the Past
Just as you return to a previous protocol when an experiment fails, Git lets you go back to any point in time.
cd /tmp/bio-analysis
# Create the environment if it doesn't existif [ ! -d .git ]; then git init git config user.name "Test" && git config user.email "test@test.com" echo "v1" > gc_analysis.py git add gc_analysis.py && git commit -m "v1" echo "v2" > gc_analysis.py git add gc_analysis.py && git commit -m "v2"fi
# View historygit log --oneline
# Revert a specific file to a previous commit stateFIRST_COMMIT=$(git log --oneline | tail -1 | cut -d' ' -f1)echo "First commit: $FIRST_COMMIT"
# Check current contentecho "--- Current ---"cat gc_analysis.py
# Preview the first commit's content (before reverting)echo "--- First commit ---"git show $FIRST_COMMIT:gc_analysis.pyCaution:
git checkout -- filenamereverts modifications (uncommitted changes will be lost). Commit important changes first.
.gitignore: Excluding Files from Tracking
Just as you don't keep intermediates from experiments, you exclude large data files and temp files from Git.
cd /tmp/bio-analysis
# Create .gitignore โ for bio projectscat > .gitignore << 'EOF'# Large data (don't put in Git)*.fastq*.fastq.gz*.bam*.sam
# Python cache__pycache__/*.pyc.ipynb_checkpoints/
# Environment settings (may contain personal info).env*.log
# OS files.DS_StoreThumbs.dbEOF
# Test: create a large file and verify Git ignores itecho "fake fastq data" > sample.fastqgit status # Success if sample.fastq doesn't appear in UntrackedTry It Yourself (Faded Example)
Fill in the blanks to complete Git's basic workflow.
# 1. Create a new repositorygit# 2. Add a file to the staging areagit analysis.py# 3. Save a snapshotgit -m "first analysis script"
Common Errors & Solutions
Q: fatal: not a git repository
The current directory is not a Git repository. Initialize with git init, or cd into a Git repo folder.
Q: nothing to commit, working tree clean
There are no changes. Modify a file and git add it. If you already did git add, it's already committed.
Q: I accidentally committed a large FASTQ file
Add *.fastq to .gitignore, then run git rm --cached sample.fastq to untrack it (the file itself won't be deleted).
Q: I wrote the wrong commit message
You can fix the last commit message with git commit --amend -m "new message" (only if you haven't pushed yet).
In the next article, we'll learn how to visualize experiment data with Python.