The Essential Git WorkflowIntroductionGit is a distributed version control system used to record, inspect, compare, and coordinate changes to files. For data science students, Git is particularly valuable because projects contain not only source code, but also notebooks, configuration files, documentation, tests, environment specifications, and sometimes data-processing scripts. A disciplined Git workflow makes these artefacts traceable and recoverable. Git does not automatically understand whether a change is good, correct, or scientifically valid. It records snapshots and relationships between snapshots. The quality of a repository therefore depends on human decisions: what to track, when to commit, how to describe changes, and how to prevent sensitive or unnecessary files from entering the repository. This chapter develops the essential local workflow: Working directory → Staging area → Repository history
↑ │ │
└──── restore ─────┴──── inspect ─────┘The staging area is an important design feature. It allows a user to select precisely which changes will form the next commit rather than committing every modification in the working directory. Learning objectivesBy the end of this chapter, you should be able to: - inspect repository status and interpret its output;
- distinguish the working directory, staging area, and repository history;
- track files and stage selected changes;
- create meaningful, focused commits;
- review differences and inspect commit history;
- safely restore files and undo unsuitable changes;
- rename and remove tracked content correctly;
- design an effective
.gitignore file; - apply a reliable workflow to a small data-science project.
The three states of GitA file in a Git project can exist in three practically important states. | State | Meaning | Typical command |
|---|
| Working directory | The files currently being edited | git status | | Staging area (index) | Changes selected for the next commit | git add | | Repository history | Committed snapshots stored by Git | git commit, git log |
A commit is not simply a save operation. It is a recorded snapshot with an author, timestamp, message, and parent relationship. A commit normally contains only the content placed in the staging area at commit time. Suppose analysis.py is modified after it was staged. The staged version and the working version can then differ. This explains why git diff and git diff --staged answer different questions: git diff compares the working directory with the staging area.git diff --staged compares the staging area with the latest commit.
The distinction is central to controlled versioning. Inspecting repository statusThe first command in most Git tasks should be: git status A typical result may say that a file is modified but not staged, identify untracked files, or confirm that the working tree is clean. “Untracked” means that Git sees a file in the project directory but has not yet been instructed to include it in version control. “Modified” means that a tracked file differs from the version represented by the index or latest commit. A useful routine is: git status --short The short format uses two columns. The first position describes the index, and the second describes the working directory. For example: | Status | Interpretation |
|---|
M file.py | Modified in working directory, not staged | M file.py | Modified and staged | MM file.py | Changes staged, with additional unstaged changes | ?? notes.txt | Untracked file | A file.py | New file staged for addition | D file.py | Deletion staged |
Status should be inspected before staging, before committing, and before changing branches or restoring content. It is a diagnostic command, not merely a progress display. Tracking and staging filesTo begin tracking a new file, use: git add analysis.py The command places the current content of analysis.py into the staging area. It does not create a commit. Several files can be staged explicitly: git add analysis.py README.md requirements.txt A directory can be staged recursively: git add src/ The command git add . stages changes beneath the current directory. Although convenient, it should not be used thoughtlessly. It may stage generated files, large outputs, credentials, or unrelated edits. A professional workflow usually checks status and uses targeted staging when a project contains multiple kinds of files. Interactive stagingWhen one file contains unrelated changes, interactive staging can separate them: git add -p Git presents portions, called hunks, and asks whether each should be staged. This supports focused commits such as “correct date parsing” rather than a mixed commit containing formatting, refactoring, and bug fixes. Interactive staging is especially useful for notebooks or scripts that have accumulated several edits. However, notebook files may contain large output changes, making review difficult. Clearing unnecessary outputs and relying on reproducible execution can improve reviewability. Unstaging without discarding workIf a file was staged accidentally, it can be removed from the index while retaining its working-directory edits: git restore --staged analysis.py The file remains modified, but it is no longer part of the next commit. On older Git versions, an equivalent command is commonly written as git reset HEAD -- analysis.py; git restore communicates the intended operation more clearly. Creating meaningful commitsA commit should represent a coherent change that can be understood, reviewed, and, if necessary, reverted. After staging, create the commit with: git commit -m "Handle missing values in customer data" A useful commit message answers, briefly, what changed. Good messages are specific and use an imperative style, for example: Add validation for input datesDocument model evaluation procedureFix division by zero in feature scaling
Weak messages include stuff, changes, and final version, because they provide little information when reviewing history. A commit should generally: - contain one logical purpose;
- be small enough to review;
- leave the project in a usable state where practical;
- avoid secrets and unnecessary generated artefacts;
- explain behaviour rather than merely naming a file.
A commit is not a substitute for a backup strategy. Local history can be lost through disk failure, and a repository containing sensitive information remains sensitive even if a file is later deleted. Remote hosting, access control, and secret-management practices are separate responsibilities. Author identityGit records an author identity. Configure it once on a machine: git config --global user.name "Your Name"
git config --global user.email "[email protected]" In an institutional or professional setting, the configured identity should comply with organisational policy. Commits create an accountability record, so identities must not be misrepresented. Reviewing changes with git diffBefore committing, inspect the proposed work: git diff This shows unstaged changes. To inspect what is already selected for the next commit, use: git diff --staged A complete review commonly follows this sequence: git status
git diff
git diff --staged The review should ask: - Is every changed line intentional?
- Are debug statements, passwords, tokens, or local paths present?
- Does the change belong in this commit?
- Are tests or documentation needed?
- Could the change alter analytical results?
Useful variations include: git diff --stat
git diff HEAD git diff --stat gives a compact summary. git diff HEAD compares the working directory and index together with the latest commit, showing all current changes whether staged or unstaged.
Reviewing historyThe basic history command is: git log A compact, graph-oriented view is often more readable: git log --oneline --graph --decorate --all To inspect one commit and its patch: git show <commit-id> To identify a commit, Git accepts a complete or sufficiently distinctive commit identifier. A commit history can answer questions such as: - When was a file changed?
- Which commit introduced a behaviour?
- What was the state before a change?
- Which person recorded the commit?
For file-specific history: git log -- data/README.md For line-level attribution: git blame analysis.py git blame identifies the commit associated with each line; it should be used for investigation, not personal criticism. A line may have been moved, generated, or changed under constraints not visible from the line alone.
Restoring files and undoing changesRestoration must be chosen according to the state that should be preserved. Destructive commands should be preceded by status and diff inspection. Discarding unstaged changesTo replace a working-directory file with its staged version: git restore analysis.py This discards unstaged modifications to that file. If the file has no staged version, Git restores the version from the latest commit. The discarded content may be difficult or impossible to recover, so this command should be used only when the edits are no longer needed. Restoring a file from a commitTo retrieve a file as it existed in a particular commit: git restore --source=<commit-id> -- analysis.py This changes the working copy; it does not automatically create a commit. The resulting change should be reviewed and either staged or discarded. Reverting a committed changeFor a shared history, the safer way to undo a published commit is usually: git revert <commit-id> Git creates a new commit that reverses the selected commit. The original history remains visible. This is preferable to rewriting shared history. Reset and history rewritinggit reset can move a branch reference and alter the staging area or working directory depending on its mode. For example, git reset --soft preserves changes staged, while git reset --hard can discard uncommitted work. Because reset can rewrite local history and --hard is destructive, it should be used only with a clear recovery plan and not casually on shared branches.
The practical rule is simple: use restore for file-state operations, revert for undoing published commits, and treat reset --hard as a high-risk command. Renaming and removing contentGit can detect many renames by comparing file content, but explicitly recording a rename communicates intent: git mv old_name.py new_name.py
git commit -m "Rename preprocessing module" Similarly, to remove a tracked file from both the working directory and the index: git rm obsolete.csv To stop tracking a file while retaining it locally: git rm --cached local_config.yml This is useful when a file was tracked accidentally and should subsequently be ignored. It does not remove the file from earlier commits, so exposed secrets must be rotated and, where necessary, removed from repository history using specialised procedures. Using .gitignore effectivelyA .gitignore file contains patterns for files Git should not normally track. A typical data-science example is: # Python caches
__pycache__/
*.py[cod]
# Virtual environments
.venv/
venv/
# Notebooks and local tools
.ipynb_checkpoints/
.vscode/
# Secrets and machine-specific settings
.env
*.local
# Generated outputs
reports/generated/
models/*.bin Patterns may match files or directories. A trailing slash conventionally identifies a directory. The asterisk is a wildcard, so *.log matches files ending in .log. .gitignore is itself normally committed because it communicates project policy to collaborators. It should not be used as a security mechanism: ignored files can still be deliberately added with git add -f, and files already tracked are not automatically untracked when a pattern is added.
If a tracked file should now be ignored: git rm --cached settings.local Then commit the .gitignore change and the removal from tracking. Ignore rules should be selective. Source code, dependency specifications, documentation, small configuration templates, and reproducible project metadata generally belong in Git. Large raw datasets, secrets, personal credentials, temporary files, caches, and reproducible generated outputs generally do not. Whether a dataset is tracked also depends on licensing, privacy, size, and organisational policy. A disciplined end-to-end workflowA reliable local workflow can be expressed as follows: # 1. Inspect
git status
# 2. Edit files using an editor or notebook
# 3. Inspect the edits
git diff
# 4. Stage only the intended files or hunks
git add src/analysis.py tests/test_analysis.py
# 5. Review the proposed snapshot
git diff --staged
# 6. Record a coherent commit
git commit -m "Validate analysis input schema"
# 7. Confirm the result
git status
git log --oneline -3 The workflow is iterative rather than strictly linear. A failed review may lead to more editing, selective unstaging, or restoration. The essential principle is that the user should know what is changing at each boundary. Applied case: a reproducible student analysis projectThe following is an illustrative case. A student team analyses bicycle rental demand. The repository contains src/, tests/, notebooks/, README.md, and a local virtual environment. Background and problemThe team begins with a notebook that reads a downloaded dataset and produces charts. The first commit accidentally includes the virtual environment, notebook checkpoints, and a file containing an API token. Review becomes slow, and another team member cannot reproduce the analysis. AnalysisThe team inspects the repository: git status --short
git ls-files They identify three categories: project material, generated material, and sensitive local material. They also inspect previous commits to determine whether the token was committed. Adding the token to .gitignore alone would not remove it from earlier history. Approach and solutionThe team takes these steps: - Revokes and replaces the exposed API token.
- Adds
.venv/, .ipynb_checkpoints/, .env, and generated report paths to .gitignore. - Moves reusable transformations into
src/cleaning.py. - Adds tests for date parsing and missing values.
- Uses
git add -p to separate refactoring from bug correction. - Reviews
git diff --staged before each commit. - Adds a
requirements.txt file and documents how to obtain the dataset legally. - Uses a history-cleaning procedure approved by the hosting platform if policy requires removing the token from old commits.
Example commits are: Add reproducible cleaning pipeline
Test missing-date handling
Document dataset acquisition
Ignore local environments and generated reports OutcomeThe repository becomes smaller, easier to review, and more reproducible. A collaborator can create an environment from the dependency specification, obtain data through documented lawful means, run the pipeline, and distinguish source files from generated outputs. Learning pointsThe case demonstrates that Git practice is also data governance. Version control supports reproducibility, but it does not by itself guarantee privacy, licensing compliance, scientific validity, or secure secret management. Those requirements must be addressed through project design and institutional policy. Challenges, limitations, and professional practiceGit has a steep conceptual threshold because a file can simultaneously have staged and unstaged versions. Large binary files and frequently changing notebook outputs are difficult to review. Merge conflicts require human interpretation, and a clean commit does not prove that code is correct. Data-science projects present additional challenges: - Large data: use approved object storage or data-versioning systems when repositories are unsuitable.
- Privacy: do not commit identifiable or restricted data without lawful authority and appropriate controls.
- Reproducibility: record dependency versions, random seeds where appropriate, preprocessing decisions, and data provenance.
- Notebooks: keep outputs purposeful, clear unnecessary outputs, and move stable logic into tested modules.
- Secrets: use environment variables or a secrets manager; never treat
.gitignore as protection after exposure. - Collaboration: agree on commit conventions, review rules, branch policies, and ownership.
Automated tests, linters, and continuous integration can run after commits or when changes are proposed. These tools improve quality but do not replace critical review. In analytical work, a test may confirm that code executes while failing to establish that a model is unbiased or that the dataset is representative. AI-assisted coding introduces additional governance concerns. Generated code should be reviewed, tested, licensed appropriately, and checked for leaked confidential data or unsupported claims. The Git history should document meaningful human decisions rather than become a record of unexamined generated fragments. Best-practice checklistBefore committing, ask: - Is the repository status understood?
- Are only relevant files staged?
- Has the staged diff been reviewed?
- Does the message describe one coherent change?
- Are secrets, private data, caches, and unnecessary outputs excluded?
- Can another person understand how to reproduce the work?
- If undoing a change, is
restore, revert, or a history rewrite the appropriate operation?
Chapter SummaryGit organizes project work through a working directory, staging area, and repository history. git status reveals the current state; git add selects content for the next snapshot; git commit records a coherent change. git diff and git diff --staged provide complementary reviews, while git log and git show support historical investigation. Restoration commands must be chosen carefully because some discard work. git restore manages file content, git revert safely reverses a published commit, and destructive history-rewriting commands require special care. git mv, git rm, and git rm --cached support content reorganisation. A committed .gitignore prevents routine tracking of unsuitable files, but it is not a security control and cannot erase secrets from history. In data science, effective Git practice supports reproducibility, collaboration, accountability, and responsible data governance. Key TermsWorking directory: The checked-out project files currently available for editing. Repository: Git’s database containing project history and metadata. Staging area: The index containing content selected for the next commit. Commit: A recorded snapshot with metadata and parent relationships. Tracked file: A file known to Git through a commit or staging operation. Untracked file: A file present in the directory but not yet recorded by Git. git status: A command that reports working-directory and staging states.
git add: A command that stages file content.
git diff: A command that compares versions of content.
git log: A command that displays commit history.
git restore: A command for restoring file content or unstaging changes.
git revert: A command that creates a new commit reversing an earlier commit.
git reset: A command that can move references and alter index or working-tree state.
Rename: A change in a file’s path or name, often recorded with git mv. .gitignore: A pattern file specifying files Git should normally ignore.
Hunk: A contiguous portion of a diff that can be staged independently. Repository history: The sequence of connected commits recorded by Git. Reproducibility: The ability to obtain consistent analytical results using documented inputs and procedures. Secret: Sensitive authentication or access information, such as a token or password. Review QuestionsShort Answer Questions- What are the three principal states in the Git workflow?
- What is the difference between
git diff and git diff --staged? - Why should commits normally contain one coherent logical change?
- What does
git rm --cached do? - Why is
.gitignore not a security mechanism?
Long Answer Questions- Explain how a file can have different versions in the working directory, staging area, and latest commit. Illustrate your explanation with commands.
- Describe a professional workflow for reviewing and committing changes to a data-science project.
- Compare
git restore, git revert, and git reset, including the risks associated with each. - Explain how
.gitignore should be designed for a Python-based data-science project. - Discuss how Git supports reproducibility while remaining insufficient by itself for privacy and scientific validity.
Analytical / Application Questions- A developer stages
analysis.py, edits it again, and runs git commit. Which version is committed, and which command displays the later unstaged edit? Explain. - A repository contains a committed API token. The developer adds
.env to .gitignore and commits the change. Analyse why this is insufficient and propose responsible next steps. - A team has a notebook containing model code, charts, cached outputs, and three unrelated fixes. Design a staging and commit strategy that produces reviewable, reproducible history.
Multiple Choice Questions with AnswersQuestion 1Which command reports the current working-directory and staging-area state? A. git status B. git show C. git blame D. git mv Correct Answer: A. git status Question 2What does git diff --staged compare? A. Two remote branches B. The staging area with the latest commit C. The working directory with an untracked file D. Two unrelated repositories Correct Answer: B. The staging area with the latest commit Question 3Which command stages a file without creating a commit? A. git log B. git revert C. git add D. git show Correct Answer: C. git add Question 4A file is staged and then edited again. Which statement is correct? A. The later edit is automatically staged B. The staged and working versions may differ C. Git deletes the staged version D. The file becomes untracked Correct Answer: B. The staged and working versions may differ Question 5Which command is generally appropriate for undoing a published commit while preserving history? A. git revert B. git restore --hard C. git clean D. git init Correct Answer: A. git revert Question 6What is the principal purpose of .gitignore? A. Encrypt repository files B. Prevent specified untracked files from normally being added C. Delete files from all previous commits D. Create a remote repository Correct Answer: B. Prevent specified untracked files from normally being added Question 7Which command renames a tracked file and stages the operation? A. git mv old.py new.py B. git log old.py new.py C. git diff old.py new.py D. git blame old.py new.py Correct Answer: A. git mv old.py new.py Question 8Which command removes a file from tracking but keeps the local file? A. git rm file.txt B. git rm --cached file.txt C. git restore file.txt D. git show file.txt Correct Answer: B. git rm --cached file.txt Question 9What is a key advantage of interactive staging with git add -p? A. It automatically tests every program B. It permits selected hunks to form a focused commit C. It encrypts sensitive files D. It permanently deletes unstaged changes Correct Answer: B. It permits selected hunks to form a focused commit Question 10Which practice best supports reviewable commit history? A. Use vague messages such as “changes” B. Commit generated caches with source code C. Combine unrelated fixes into one commit D. Use specific messages for coherent logical changes Correct Answer: D. Use specific messages for coherent logical changes
|