Course Lessons

Git, GitHub

Back to Course

Git Fundamentals

Git, GitHub Lesson 1 of 5 17 min

Webbo3 Data Analysis Bootcamp · Git & Version Control Module · Lesson 1

Git Fundamentals: Version Control, Your First Repository, and Managing Changes Safely

A foundational lesson covering why version control matters, how to initialize a Git repository, stage and commit changes, write good commit messages, inspect history, and undo mistakes without panic.

Git version control and branching

If you have ever saved a file as report_final.docx, then report_final_v2.docx, then report_final_v2_ACTUAL.docx, you already understand the problem that version control solves. You are trying to keep track of changes, but your filenames are lying to you. There is no final version. There is only the version you are working on now, the version that worked yesterday, and the version that broke everything. Git is the tool that replaces this chaos with a structured, searchable, reversible history of every change you ever made. It is not optional for data analysts. It is the safety net that lets you experiment with a new analysis, delete half your code, realize it was a mistake, and restore the working version in ten seconds. This lesson starts from zero. You will understand why version control matters, create your first repository, make your first commits, and learn to undo changes without fear.

1. What Is Version Control and Why It Matters

Version control is a system that records changes to a file or set of files over time so that you can recall specific versions later. Think of it as an unlimited undo button for your entire project, combined with a detailed log of who changed what, when, and why. The most widely used version control system today is Git, created by Linus Torvalds in 2005 to manage the Linux kernel source code. It is now the industry standard for software development, data science, and technical writing.

Why version control matters for data analysts. Your work is not just Excel files and SQL queries. It is Python scripts that clean data, Jupyter notebooks that run models, SQL files that define reports, and documentation that explains your methodology. All of these are text files that Git can track. Without version control, you have no way to answer basic questions: When did this formula change? Who added this filter? Why did the dashboard numbers shift last Tuesday? With Git, every change is documented, reversible, and attributable.

The three states of Git. Git thinks about your files in three states: modified, staged, and committed. Modified means you have changed the file but not yet told Git to care about that change. Staged means you have marked the modified file to go into your next commit snapshot. Committed means the file is safely stored in your local repository history. This three-state workflow, modify, stage, commit, is the core rhythm of working with Git. You will live inside this loop.

Local versus remote. Git is a distributed version control system. This means every copy of a repository is a complete, independent backup of the entire history. You commit changes to your local repository first. Only when you are ready do you push those commits to a remote server like GitHub, GitLab, or Bitbucket. This matters because you can work offline, experiment freely, and only share when your changes are clean. You are not constantly syncing with a central server the way older systems like Subversion required.

Git is not a backup system. A common misconception is that Git replaces cloud backup. It does not. Git tracks changes to text files efficiently, but it is not designed to store large binary files like Excel workbooks, image datasets, or video files. For those, use cloud storage like OneDrive, Google Drive, or a data lake. Use Git for your code, your SQL scripts, your Python notebooks, and your documentation. Use it for anything you edit in a text editor and want to version.

Developer working with code and version control

2. git init, git status, git add, git commit

These four commands are the foundation of every Git workflow. You will use them hundreds of times per week once Git becomes part of your routine. Learn them until they are muscle memory.

git init: creating a repository. A Git repository is just a folder with a hidden .git subdirectory that stores the entire history, configuration, and metadata. To turn any folder into a repository, open your terminal or command prompt, navigate to the folder, and type:

git init

Git responds with a message like "Initialized empty Git repository in /path/to/your/folder/.git/". That is it. The folder is now a repository. Every file inside it can now be tracked, though none are tracked yet. You only run git init once per project, at the very beginning.

git status: checking the current state. After making changes to files in your repository, run:

git status

Git tells you which files are modified, which are staged, which are untracked, and which branch you are on. Untracked files are files Git sees in the folder but is not yet monitoring. Modified files are tracked files that have changed since the last commit. Staged files are modified files that you have marked for the next commit. git status is your compass. Run it constantly. It costs nothing and prevents mistakes.

git add: staging changes. To tell Git which modified files you want to include in your next commit, use:

git add filename.py
git add .

The first form stages a specific file. The second form, git add with a dot, stages all modified and untracked files in the current directory and its subdirectories. Use the specific form when you want precise control over what goes into a commit. Use the dot form when you have made a cohesive set of changes across multiple files and want to commit them all at once. After running git add, run git status again to confirm the files moved from modified to staged.

git commit: saving a snapshot. Once your changes are staged, you save them permanently to the repository history with:

git commit -m "Add initial data cleaning script for Q1 sales"

The -m flag stands for message. The text in quotes is your commit message, which describes what this snapshot contains. After the commit, git status will show a clean working tree, meaning there are no modified or staged files. The changes are now part of your repository's permanent history. You can see them, revert them, or compare them to any other commit at any time.

The complete workflow loop. Here is the rhythm you will repeat forever: make changes to your files, run git status to see what changed, run git add to stage the changes you want to keep, run git commit -m "descriptive message" to save them, then run git status again to confirm everything is clean. This loop is Git. Everything else is an extension of this loop.

Code on screen with terminal

3. Commit Messages Best Practices

Your commit message is the only documentation many of your changes will ever have. A good message explains why the change was made, not just what was changed. The code itself shows what changed. The message explains the reasoning. This matters when you return to a project after six months, or when a colleague needs to understand your decisions without reading every line of code.

Use the imperative mood. Write your message as if you are giving a command to the codebase. "Add filtering for null regions" not "Added filtering for null regions." "Fix off-by-one error in revenue calculation" not "Fixed off-by-one error." This convention aligns with how Git itself generates messages, for example "Merge branch feature-x," and it makes the history read like a set of instructions.

Keep the subject line under 50 characters. The first line of your commit message is the subject. It should summarize the entire change in one brief sentence. Many Git tools truncate subject lines longer than 50 or 72 characters, so brevity matters. If you need more detail, add a blank line after the subject and write a longer body:

git commit -m "Refactor sales aggregation query

The previous query used a subquery that performed poorly on
tables over 100k rows. Replaced it with a JOIN and added
an index on the order_date column. Query time dropped from
4.2 seconds to 0.3 seconds."

The body explains the context: what was wrong, what you changed, and what the impact was. This is invaluable when someone, possibly you, needs to understand why a change was made without reverting to trial and error.

Reference issues and tickets. If your team uses a project management tool like Jira, Trello, or GitHub Issues, include the ticket number in your commit message:

git commit -m "Fix currency formatting in dashboard [WEB-142]"

This creates a link between the code change and the task that motivated it. Many platforms automatically hyperlink commit messages to issue trackers when they detect ticket numbers.

Bad commit messages to avoid. "fix stuff" tells you nothing. "asdf" is worse. "Final version" is a lie. "Changes" is so vague it might as well be blank. If you find yourself writing these, stop and think about what you actually did in this commit. Break large changes into smaller, focused commits with clear messages. A commit should represent one logical change, not a day's worth of unrelated edits.

A practical template for data analysts. Use this structure for your commit messages: Action + What + Why. For example: "Add [action] monthly revenue summary [what] to support Q2 board report [why]." Or "Remove [action] hardcoded region filter [what] after stakeholder confirmed national rollout [why]." This template forces you to think about the purpose of every commit, which leads to better commits and a more useful history.

4. git log and git diff

Once you have made several commits, you need tools to inspect your history and understand what changed between versions. git log and git diff are those tools. They are how you answer the questions: What did I do yesterday? What changed between these two versions? Who introduced this bug?

git log: viewing commit history. Run:

git log

Git displays a list of commits in reverse chronological order, showing the commit hash, the author, the date, and the commit message. The commit hash is a long alphanumeric string like a1b2c3d4. You rarely need to type the full hash. The first seven characters are usually enough to identify a commit uniquely in a small repository. To see a more compact view, use:

git log --oneline

This shows each commit on one line with its short hash and subject. It is the fastest way to scan recent history. To see what files changed in each commit, add --stat:

git log --oneline --stat

To see the actual code changes in each commit, add -p, which stands for patch:

git log -p

This is verbose but essential when you need to understand exactly what changed in a specific commit. Use it when debugging: find the commit where a bug was introduced, then read the patch to see what logic changed.

git diff: comparing versions. git diff shows the differences between two states. To see what you have changed but not yet staged:

git diff

To see what you have staged but not yet committed:

git diff --staged

To see the difference between two specific commits:

git diff a1b2c3d e4f5g6h

Lines prefixed with a minus sign were removed. Lines prefixed with a plus sign were added. Lines without a prefix were unchanged and shown for context. The diff format is standard across all version control systems, and learning to read it quickly is a core skill. Run git diff before every commit. It is your final review. If you see changes you did not intend to make, unstage or restore them before committing.

Terminal and command line interface

5. Undoing Changes: git restore and git reset

Mistakes are inevitable. You delete a file you meant to keep. You modify a working script and break it. You stage a file by accident. Git gives you multiple ways to undo changes, and choosing the right one depends on whether the change is unstaged, staged, or committed. Understanding the distinction prevents you from making a bad situation worse.

git restore: discarding unstaged changes. If you have modified a file but not yet staged it, and you want to revert it to the last committed version:

git restore filename.py

This permanently discards the modifications in that file. The file returns to exactly the state it was in at the last commit. There is no undo for git restore, so use it with confidence only when you are certain you do not want the changes. If you want to discard all unstaged changes in the repository:

git restore .

This is the nuclear option for your working directory. Every modified file reverts to its last committed state. Untracked files, those Git has never seen, are not affected.

Unstaging a file: git restore --staged. If you have staged a file with git add but realize you do not want it in the next commit, you can unstage it without losing the modifications:

git restore --staged filename.py

The file moves from staged back to modified. The changes are still in the file, but they are no longer marked for the next commit. You can then either restore the file to discard the changes entirely, or edit it further and stage it again later.

git reset: undoing commits. git reset moves the current branch pointer to a different commit, effectively undoing commits. It has three modes: soft, mixed, and hard. The default is mixed. To undo the last commit but keep the changes in your working directory:

git reset HEAD~1

HEAD is a reference to the current commit. HEAD~1 means one commit before the current commit. This command removes the last commit from history but leaves the files modified, as if you had made the changes but never committed. You can then restage and recommit with a better message, or modify the changes further. This is the safest way to undo a recent commit.

To undo the last commit and discard all changes completely:

git reset --hard HEAD~1

This is destructive. The commit is gone, and the changes are gone. There is no recovery unless you have a backup. Use --hard only when you are absolutely certain you want to erase the last commit entirely. A safer workflow is to use git reset without --hard, review the changes, and then use git restore to discard individual files selectively.

git reset to a specific commit. If you need to undo multiple commits, specify the commit hash you want to return to:

git reset --hard a1b2c3d

This moves your branch back to commit a1b2c3d and discards every commit after it. All changes from those discarded commits are lost. This is why regular commits are a safety net: the more frequently you commit, the smaller the blast radius of any reset.

When to use restore versus reset. Use git restore for changes that have not been committed yet. It is surgical and safe. Use git reset for changes that have already been committed and you want to remove them from history. If you have already pushed commits to a remote server, do not use git reset. Instead, use git revert, which creates a new commit that undoes the changes of a previous commit without rewriting history. Rewriting history after pushing causes confusion for everyone else who has pulled those commits. You will learn git revert in a later lesson on collaboration.

Technology and digital systems

Quick recap: Version control tracks every change to your files with a searchable, reversible history · Git is a distributed system: every copy is a complete backup · git init creates a repository, git status shows the current state, git add stages changes, git commit saves a snapshot · Write commit messages in the imperative mood, keep subjects under 50 characters, explain why not just what · git log shows history, git diff compares versions, git log -p shows the actual code changes · git restore discards unstaged changes, git restore --staged unstages files without losing modifications · git reset HEAD~1 undoes the last commit but keeps changes; git reset --hard HEAD~1 erases the commit and the changes · Use restore for uncommitted changes, reset for committed changes, and never reset after pushing to a remote.

Using AI to Move Faster in Git Workflows

Git is a command-line tool, and its syntax can be intimidating at first. AI can help you remember commands, write better commit messages, and recover from mistakes without searching through documentation. Here is how to use it effectively.

1. Generate commit messages from your code changes.
After making changes, run git diff to see what you modified, then paste the diff into Copilot or ChatGPT and ask: "Write a concise, imperative-mood Git commit message for these changes, following best practices." AI will analyze the additions and deletions and suggest something like "Refactor sales query to use JOIN instead of subquery for performance." Review the suggestion, adjust if it misses nuance, and use it. This is especially helpful when you have made many small changes and struggle to summarize them in one sentence.

2. Ask AI to explain what a Git command will do before you run it.
If you are unsure whether to use git restore or git reset, or whether --hard will destroy work you care about, describe your situation to AI: "I staged a file by mistake and want to remove it from the next commit without losing the changes. Should I use git restore --staged or git reset? What is the exact command?" AI will explain that git restore --staged is the correct choice and give you the exact syntax. This prevents panic-driven mistakes and teaches you the reasoning behind each command.

3. Use AI to interpret complex git log or git diff output.
When you run git diff between two commits and see a wall of plus and minus signs, it can be hard to spot the meaningful changes. Paste the diff into AI and ask: "Summarize the key changes in this Git diff and flag any changes that look like they might introduce bugs." AI can highlight that a hardcoded value was removed, that a new dependency was added, or that a function signature changed in a way that might break callers. This is a fast code review for your own work.

4. Generate a .gitignore file for data analysis projects.
A .gitignore file tells Git which files to ignore completely. For data analysts, this typically includes large CSV datasets, Excel files, Python virtual environment folders, and API key files. Instead of writing one from scratch, ask AI: "Generate a .gitignore file for a Python data analysis project that uses Jupyter notebooks, excludes CSV files over 10MB, and ignores API key files." AI will produce a tailored .gitignore that you can drop into your repository root. This prevents you from accidentally committing sensitive data or bloating your repository with binary files.

5. Never let AI run destructive commands for you blindly.
AI might suggest git reset --hard when git restore --staged is what you actually need. It might suggest commands that erase uncommitted work. Always read the explanation AI provides, verify that the command matches your intent, and when in doubt, run git status first to see exactly what state your repository is in. AI accelerates your Git workflow, but the final decision to delete work is always yours. Treat AI suggestions the way you treat Stack Overflow answers: useful, but requiring your own judgment before execution.

A habit worth building from this lesson onward: commit early, commit often, and write messages that explain why. Use git status and git diff as constant sanity checks. When you are unsure which undo command to use, describe your situation to AI, get the recommendation, verify it against your understanding, and then execute. Git becomes less intimidating the more you use it, and AI can bridge the gap between knowing you need version control and feeling confident using it every day.

Next lesson: branching with git branch and git checkout, merging, and remote repositories with GitHub.

Complete this lesson

Mark as complete to track your progress