Git and Version Control for ML Projects
Git and Version Control for ML Projects
Learn how to track source-code changes, collaborate safely, manage experiments, protect sensitive information, and create reproducible Machine Learning projects using Git.
Introduction
A Machine Learning project changes continuously. Developers update Python scripts, notebooks, feature logic, configuration files, evaluation code, documentation, and deployment components. Without version control, it becomes difficult to identify what changed, understand why a result changed, restore a previous working state, or collaborate safely with other contributors.
Git is a distributed version control system. It records changes to files as a sequence of commits. Each contributor can maintain a local copy of the repository, create branches, review differences, combine approved changes, and synchronize work with a remote repository.
Git is highly effective for source code and small text-based files. However, Machine Learning projects may also contain large datasets, trained models, experiment outputs, and generated artifacts. These files usually require additional storage and versioning strategies rather than being committed directly to a normal Git repository.
Learning Objectives
By the End of This Lesson
- Explain version control and the purpose of Git
- Distinguish Git from remote hosting platforms
- Configure Git and create a repository
- Understand working-directory, staging, and commit states
- Create meaningful commits and branches
- Synchronize work with a remote repository
- Create an ML-specific .gitignore file
- Organize a reproducible Machine Learning repository
- Understand which files should and should not be committed
- Recognize the roles of Git LFS, DVC, and experiment trackers
- Protect secrets, credentials, private data, and model artifacts
- Apply a collaborative Git workflow to an ML project
Prerequisites
Recommended Knowledge
- Basic understanding of files and directories
- Basic command-line or terminal navigation
- Basic familiarity with Python project files
- Awareness of datasets, models, and experiment outputs
Required Tools
- Git installed on the local computer
- A terminal, command prompt, or Git Bash
- A code editor such as Visual Studio Code
- A remote Git service account when remote collaboration is required
- Python and a virtual environment for the example ML project
What Is Version Control?
Version control is a system for recording changes to files over time. It creates a structured history that helps developers inspect previous work, compare revisions, restore earlier versions, and collaborate without replacing one another's changes accidentally.
Without Version Control
- Files may be copied with unclear names
- Changes can be overwritten accidentally
- Previous working versions may be lost
- Experiment differences are difficult to trace
- Team collaboration becomes risky
With Version Control
- Changes are recorded as commits
- Differences can be reviewed
- Earlier versions can be restored
- Branches isolate work safely
- Contributors can collaborate through reviews
Git vs Remote Git Platforms
Git and a remote repository platform are related but different. Git is the version control software. A platform such as GitHub, GitLab, Azure Repos, or Bitbucket can host remote Git repositories and provide collaboration features.
| Technology | Primary Role | Examples of Capabilities |
|---|---|---|
| Git | Distributed version control | Commits, branches, merging, tags, and local history |
| Remote Git Platform | Repository hosting and collaboration | Pull requests, access control, issue tracking, and automation |
Important Git Concepts
| Concept | Meaning |
|---|---|
| Repository | A project directory whose selected files and history are managed by Git |
| Working Directory | The current files available for editing |
| Staging Area | The selected changes prepared for the next commit |
| Commit | A recorded snapshot of staged changes with an identifier and message |
| Branch | An independent line of development |
| Merge | The operation that combines changes from different branches |
| Remote | A named connection to another Git repository |
| Clone | A local copy of an existing repository and its history |
| Push | Sends local commits to a remote repository |
| Fetch | Downloads remote history without automatically integrating it |
| Pull | Fetches remote changes and integrates them into the current branch |
| Tag | A human-readable reference commonly used to identify an important version |
| HEAD | A reference to the currently checked-out commit or branch position |
The Basic Git Workflow
Modify Files
Create or update project files in the working directory.
Review Changes
Inspect changed files and exact line-level differences before preparing a commit.
Stage Selected Changes
Add only the logically related changes that belong in the next commit.
Create a Commit
Record the staged changes with a concise message explaining their purpose.
Push to the Remote
Share the local commits through an authorized remote repository.
Configure Git
Git associates an author name and email address with commits. Configure the identity required for the repositories you are authorized to use.
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
git config --global init.defaultBranch main
Review the current Git configuration:
git config --list
Create a New ML Repository
Create a project directory and initialize it as a Git repository.
mkdir customer-churn-ml
cd customer-churn-ml
git init
Check the repository status:
git status
Git creates a hidden .git directory containing the
repository metadata and history. Do not manually edit or delete
this directory unless you fully understand the consequences.
Recommended ML Project Structure
A consistent repository structure helps contributors locate source code, configuration, tests, notebooks, documentation, and generated outputs.
customer-churn-ml/
|
|-- README.md
|-- .gitignore
|-- requirements.txt
|-- pyproject.toml
|-- configs/
| `-- baseline.yaml
|-- data/
| |-- raw/
| |-- interim/
| `-- processed/
|-- models/
|-- notebooks/
| `-- 01_exploration.ipynb
|-- reports/
| |-- figures/
| `-- metrics/
|-- src/
| |-- __init__.py
| |-- data.py
| |-- features.py
| |-- train.py
| `-- evaluate.py
|-- tests/
| |-- test_data.py
| `-- test_features.py
`-- scripts/
`-- run_training.py
| Path | Purpose | Typical Git Treatment |
|---|---|---|
README.md |
Explains setup, usage, data expectations, and project purpose | Track |
configs/ |
Stores non-secret experiment and model configurations | Track |
src/ |
Contains reusable application and ML source code | Track |
tests/ |
Contains automated tests | Track |
notebooks/ |
Contains exploration and demonstration notebooks | Track carefully |
data/ |
Contains datasets or data references | Usually ignore actual data files |
models/ |
Contains generated model artifacts | Usually ignore or use artifact versioning |
reports/ |
Contains generated metrics, figures, or reports | Track selected outputs only |
Create an ML-Specific .gitignore
A .gitignore file contains patterns for intentionally
untracked files that Git should ignore. It is commonly committed so
everyone using the repository shares the same ignore rules.
# Python bytecode and caches
__pycache__/
*.py[cod]
*$py.class
# Virtual environments
.venv/
venv/
env/
# Environment variables and secrets
.env
.env.*
!.env.example
*.pem
*.key
secrets/
# Testing and coverage
.pytest_cache/
.coverage
htmlcov/
# Type checker and linter caches
.mypy_cache/
.ruff_cache/
# Jupyter temporary files
.ipynb_checkpoints/
# IDE and operating-system files
.vscode/
.idea/
.DS_Store
Thumbs.db
# Logs and temporary files
*.log
*.tmp
*.temp
tmp/
cache/
# Build and package outputs
build/
dist/
*.egg-info/
# Local datasets
data/raw/*
data/interim/*
data/processed/*
# Keep documentation files inside data directories
!data/raw/README.md
!data/interim/README.md
!data/processed/README.md
# Generated model artifacts
models/*
!models/README.md
*.pkl
*.joblib
*.h5
*.keras
*.onnx
*.pt
*.pth
*.ckpt
# Generated experiment outputs
runs/
outputs/
artifacts/
mlruns/
# Large array and archive files
*.npy
*.npz
*.parquet
*.zip
*.tar
*.gz
.env.example containing
variable names and non-secret placeholder values.
.gitignore does not remove a file that
Git already tracks. The tracked file must be removed from the Git
index separately, and any exposed secret must be revoked or rotated.
Create the First Commit
Create the initial project files, review them, and add selected changes to the staging area.
git status
git add README.md .gitignore requirements.txt pyproject.toml
git status
Review the staged differences:
git diff --staged
Create the first commit:
git commit -m "Initialize ML project structure"
Review the commit history:
git log --oneline --decorate --graph
Write Meaningful Commit Messages
A useful commit message explains the purpose of a change. It should enable another contributor to understand the project history without opening every modified file.
Weak Messages
- update
- changes
- fixed stuff
- final model
- new code
Better Messages
- Add stratified train-test split
- Prevent leakage in scaling pipeline
- Add recall metric to churn evaluation
- Document dataset schema and target definition
- Add tests for missing-value transformation
Work with Branches
A branch provides an independent line of development. It allows a contributor to work on a feature, experiment, correction, or documentation update without immediately changing the main branch.
Create and switch to a feature branch:
git switch -c feature/add-baseline-model
After making and reviewing the changes:
git status
git add src/train.py tests/test_train.py
git commit -m "Add baseline logistic regression model"
Switch back to the main branch and merge the feature:
git switch main
git merge feature/add-baseline-model
Delete the local feature branch after the change has been merged and is no longer needed:
git branch -d feature/add-baseline-model
Example Branch Names
- feature/add-data-validation
- feature/train-random-forest
- fix/prevent-target-leakage
- docs/update-training-guide
- test/add-pipeline-tests
- refactor/split-feature-module
Connect to a Remote Repository
After creating an authorized empty remote repository, connect the local project to it.
git remote add origin REMOTE_REPOSITORY_URL
git remote -v
git push -u origin main
The -u option establishes an upstream relationship
between the local and remote branches. Later pushes can normally
use:
git push
To copy an existing repository:
git clone REMOTE_REPOSITORY_URL
cd REPOSITORY_DIRECTORY
Collaborative Git Workflow
Update the Local Main Branch
git switch main
git pull
Create a Focused Branch
git switch -c feature/add-model-evaluation
Make and Test the Changes
Update the relevant files and run the required tests, formatting, linting, and evaluation checks.
Review and Commit
git status
git diff
git add src/evaluate.py tests/test_evaluate.py
git diff --staged
git commit -m "Add classification evaluation report"
Push the Branch
git push -u origin feature/add-model-evaluation
Request Review
Open a pull request or merge request according to the hosting platform and team workflow. Include the purpose, testing evidence, affected components, and any important limitations.
Merge Approved Changes
Merge after required reviews and automated checks have passed. Do not bypass repository protections without authorization.
Resolve Merge Conflicts
A merge conflict can occur when Git cannot automatically combine competing changes. The developer must inspect the affected file, choose the correct final content, test the result, and complete the merge.
git status
After editing and testing the conflicted files:
git add PATH_TO_RESOLVED_FILE
git commit
Conflict-Resolution Practices
- Read both versions before selecting the final content
- Understand the intent of each contributor's change
- Do not remove code simply to eliminate conflict markers
- Run tests after resolving the conflict
- Review the final diff before committing
- Ask the original contributors when the correct result is unclear
Use Tags for Important Versions
A tag can mark an important repository state, such as a validated model release, experiment milestone, or deployment version.
git tag -a model-v1.0.0 -m "Validated baseline model"
git push origin model-v1.0.0
List available tags:
git tag
Why Git Alone Is Not Enough for ML
Traditional software repositories primarily contain source code and small configuration files. Machine Learning projects introduce additional versioned components.
| ML Component | Why It Matters | Possible Versioning Approach |
|---|---|---|
| Source Code | Defines preprocessing, training, evaluation, and inference | Git |
| Configuration | Defines hyperparameters and experiment settings | Git |
| Dataset | Determines the examples from which the model learns | Data-versioning or managed storage system |
| Model Artifact | Contains the trained parameters used for inference | Model registry or artifact storage |
| Environment | Defines libraries and execution dependencies | Git-tracked dependency specification and environment image |
| Experiment Metadata | Connects inputs, parameters, metrics, and outputs | Experiment-tracking system |
| Documentation | Explains purpose, limitations, and usage | Git |
Managing Large Data and Model Files
Large datasets and model binaries can make a normal Git repository slow and difficult to maintain. They may also contain confidential information that must not be stored in a source-code repository.
Store in Git
- Python source files
- Small configuration files
- Dependency specifications
- Tests and documentation
- Data schemas and validation rules
- Small safe sample data when permitted
Usually Store Elsewhere
- Large raw datasets
- Confidential or personal data
- Generated model binaries
- Large experiment outputs
- Training checkpoints
- Temporary caches and logs
Git Large File Storage
Git Large File Storage, commonly called Git LFS, replaces selected large files in the repository with lightweight pointer files while storing the actual content in LFS-managed storage.
git lfs install
git lfs track "*.onnx"
git lfs track "*.pt"
git lfs track "*.joblib"
git add .gitattributes
git commit -m "Configure Git LFS for model artifacts"
Data Version Control
A data-versioning tool such as DVC can track metadata in Git while keeping large datasets and model artifacts in separate local or remote storage.
Version ML Experiments
A commit records file changes, but it does not automatically record every detail of an experiment. A reproducible experiment should connect the source-code version with its data, configuration, environment, metrics, and outputs.
| Experiment Detail | Example |
|---|---|
| Git Commit | Unique source-code revision |
| Data Version | Dataset snapshot or managed-data identifier |
| Features | Feature names and transformation version |
| Algorithm | Random forest, logistic regression, or neural network |
| Hyperparameters | Learning rate, depth, or number of estimators |
| Random Seed | Seed used for applicable randomized operations |
| Environment | Python and library versions |
| Metrics | Accuracy, recall, F1 score, MAE, or RMSE |
| Artifact | Trained model or evaluation report |
best_model_final_latest_really_final.pkl as the only
model-versioning strategy.
Version Jupyter Notebooks Carefully
Jupyter notebooks are useful for exploration and communication, but they can create large and noisy Git differences because they contain code, outputs, execution counts, and metadata in one JSON document.
Notebook Practices
- Use notebooks for exploration, explanation, and demonstrations
- Move stable reusable logic into Python modules
- Run cells in a clear top-to-bottom order
- Remove unnecessary output before committing
- Avoid embedding confidential data in output cells
- Use descriptive notebook filenames
- Review notebook differences before committing
- Consider notebook-diff and output-cleaning tools when appropriate
Protect Secrets and Sensitive Data
A Git repository must not be treated as a secret store. Removing a secret in a later commit does not automatically remove it from earlier repository history.
Security Checklist
- Never commit passwords, API keys, or access tokens
- Never commit private keys or certificates containing secrets
- Keep secret files in .gitignore
- Use approved environment variables or secret-management systems
- Commit only safe placeholder templates
- Review staged changes before every commit
- Use secret-scanning tools where available
- Restrict repository access according to least privilege
- Rotate an exposed credential immediately
- Follow the required incident-response process
API_KEY = "real-secret-value"
DATABASE_PASSWORD = "real-password"
import os
api_key = os.environ["API_KEY"]
database_password = os.environ["DATABASE_PASSWORD"]
Inspect and Undo Changes Safely
Inspect Changes
git status
git diff
git diff --staged
git log --oneline --graph --decorate
Unstage a File
git restore --staged PATH_TO_FILE
Discard an Uncommitted File Change
git restore PATH_TO_FILE
Revert a Committed Change
git revert COMMIT_IDENTIFIER
Stash Temporary Work
Git stash can temporarily store uncommitted tracked-file changes when the developer needs a clean working directory.
git stash push -m "Temporary feature-engineering work"
git stash list
git stash pop
Pull Request Review Checklist
Code and Repository Review
- The branch contains one clear and focused change
- Commit messages describe the intent
- No secrets or confidential data are included
- Generated files and large artifacts are excluded appropriately
- Tests pass and new logic has suitable test coverage
- Formatting and linting checks pass
- Documentation and configuration are updated
- The final diff has been reviewed by the author
Machine Learning Review
- The target and prediction point are documented
- Features use only information available at prediction time
- Training and evaluation data remain separated
- Preprocessing is fitted using training data only
- Random seeds are recorded where appropriate
- Metrics match the objective and error costs
- Data and model versions are traceable
- Known limitations are documented
Common Git Mistakes in ML Projects
Essential Git Command Reference
| Command | Purpose |
|---|---|
git init |
Initialize a repository |
git clone |
Create a local copy of an existing repository |
git status |
Show the state of working and staged files |
git diff |
Show unstaged differences |
git add |
Add selected changes to the staging area |
git commit |
Record staged changes |
git log |
Display commit history |
git switch |
Switch branches or create a branch with the proper option |
git branch |
List, create, or delete branches |
git merge |
Combine changes from another branch |
git fetch |
Download remote references and history |
git pull |
Fetch and integrate remote changes |
git push |
Send local commits to a remote repository |
git remote -v |
List configured remote repositories |
git tag |
Create or display tags |
git restore |
Restore working-tree or staged-file state |
git revert |
Create a commit that reverses an earlier commit |
git stash |
Temporarily store selected uncommitted changes |
Hands-On Practice
Create the Repository
Create a small ML repository containing a README, source directory, tests directory, configuration directory, and .gitignore file.
Create the First Commit
Stage only the intended project files, review the staged diff, and create a focused initialization commit.
Create a Feature Branch
Create a branch for adding a baseline training script and commit the change with a meaningful message.
Test the .gitignore
Create a virtual environment, temporary dataset, and example environment file. Verify that Git does not stage them.
Merge the Feature
Return to the main branch and merge the completed feature after reviewing its changes.
Create a Tag
Create an annotated tag for the validated baseline source-code version.
Knowledge Check
What is the primary purpose of Git?
Explain how Git records changes and supports collaboration, inspection, and restoration.
What is a Git commit?
Explain how a commit records staged changes with an identifier and descriptive message.
What is the staging area?
Explain how it allows a developer to choose which changes belong in the next commit.
Why are branches useful?
Explain how a branch isolates a feature, experiment, correction, or documentation change.
What is the purpose of .gitignore?
Explain how it defines intentionally untracked files that Git should ignore.
Why should large datasets not normally be committed directly?
Consider repository performance, storage, privacy, sharing, and access-control requirements.
Why is a Git commit insufficient for complete ML reproducibility?
Consider data, model artifacts, configurations, random seeds, dependencies, and experiment metrics.
What should happen if a secret is committed?
Explain why the credential should be treated as exposed and immediately revoked or rotated.
Lesson Summary
| Concept | Main Point |
|---|---|
| Version Control | Records changes to project files over time |
| Git | A distributed version control system |
| Commit | A recorded snapshot of staged changes |
| Branch | An independent line of development |
| Remote Repository | A shared repository used for synchronization and collaboration |
| .gitignore | Defines intentionally untracked files that Git should ignore |
| Git LFS | Manages selected large files through pointer-based storage |
| Data Versioning | Connects code with traceable dataset versions stored appropriately |
| Experiment Tracking | Records parameters, metrics, environments, and artifacts |
| Reproducibility | Requires code, data, configuration, environment, and artifact traceability |
| Security | Secrets and sensitive data must not be committed |
| Collaboration | Branches, reviews, tests, and focused commits support reliable teamwork |
Key Takeaway
Git provides a traceable history of source code, configuration, tests, and documentation. In Machine Learning projects, reliable versioning goes beyond source code. Teams must also connect each experiment and release to the correct data, environment, configuration, metrics, and model artifact while keeping secrets, sensitive data, generated outputs, and unsuitable large files out of the normal Git repository.
Get Machine Learning updates by email
Short, practical lessons and course updates from Rumman Ansari. No spam.