### The problem before Git It is 6 PM on a Friday. Two engineers have been editing the same config file for an hour. One of them just emailed the other a file called `config-FINAL-v2-ACTUALLY-FINAL.py`. Neither of them is sure which version is running in production right now. Before Git, this was normal. Developers tracked changes by copying files: project/ deploy-tool.sh deploy-tool-backup.sh deploy-tool-FINAL.sh deploy-tool-FINAL-v2.sh deploy-tool-FINAL-v2-working.sh No one knows which file is current. There is no record of what changed between versions, who changed it, or why. If something breaks, the only option is manually comparing files and hoping to spot the difference. **Version control** replaces this entirely. It records every change to your files over time as a series of snapshots called commits. Each commit stores exactly what changed, who changed it, when, and a message explaining why. > 📌 **Remember:** This module is not about memorizing every command. Focus on the mental model - how Git thinks, how history works, how teams collaborate. Once that clicks, any command is a quick lookup away. ### 🟢 Core - what version control gives you * A complete history of every file, going back to the first line ever written * The ability to compare any two versions down to the exact line that changed * The ability to travel back to any point in history with one command * Isolated work - new changes don't touch stable code until they're ready * Safe collaboration across an entire team without overwriting each other * Accountability - every change has an author, a timestamp, and a reason ### 🟢 Core - centralized vs distributed There are two fundamentally different approaches to version control, and understanding this is what makes Git's behavior make sense. In a **centralized system** like SVN, one central server holds the entire history. Every developer connects to that server to commit, view history, or compare files. If the server goes down, the team stops. In **Git**, every developer has a complete copy of the entire repository, including every commit ever made. Cloning a repo downloads the full project history, not just the latest files. This means you can commit, browse history, and create branches with zero network connection. | | Centralized (SVN) | Distributed (Git) | |:---|:---|:---| | History lives | Only on central server | Every developer's machine | | Works offline | No | Yes - most operations are local | | Risk of data loss | High - one server failure | Low - every clone is a backup | ### 🟢 Core - Git vs GitHub, two different things **Git** is version control software that runs on your local machine. It has no concept of the internet, accounts, or a web interface. It just tracks changes to files. You can use Git entirely offline. **GitHub** is a company that built a web platform for hosting Git repositories online. GitHub adds features on top of Git - a web interface, pull requests for code review, issue tracking, and CI/CD through GitHub Actions. Git is the database engine. GitHub is a web application built on top of it. | | Git | GitHub | |:---|:---|:---| | What it is | Version control software | Cloud hosting platform | | Internet required | No | Yes | | Alternatives | None - Git is Git | GitLab, Bitbucket, Gitea | > 📌 **Remember:** You need Git to use GitHub. You do not need GitHub to use Git. Git was created in 2005 by Linus Torvalds - the same person behind the Linux kernel - because the Linux project needed version control that could handle thousands of contributors. ---
### 🟢 Core - installation ```bash ## Check if Git is already installed git --version ## Ubuntu or Debian sudo apt update && sudo apt install git ## macOS with Homebrew brew install git ``` ### 🟢 Core - first-time setup Every commit is permanently stamped with your name and email. This is not authentication - it is metadata identifying the author of each snapshot. ```bash ## Set your identity - use the same email as your GitHub account git config --global user.name "Rahul Verma" git config --global user.email "rahul@company.com" ## Set the default branch name to main git config --global init.defaultBranch main ## Verify everything saved correctly git config --list ``` > 💡 **Tip:** The `--global` flag applies to every repository on your machine. Run the same command without `--global` inside one specific repo folder if you need different settings there, like a separate work email. ### 🟢 Core - what the .git folder actually is Running `git init` creates a hidden `.git` directory inside your project. This directory **is** the repository. Your source files are just working copies Git manages on top of it. ```bash mkdir rag-service && cd rag-service git init ``` .git/ HEAD -> pointer to your current branch config -> settings for this repository objects/ -> the database - every commit and file snapshot refs/heads/ -> one file per branch > **Note:** When you commit, Git conceptually stores a full snapshot of your project, which is the right mental model for a beginner. Under the hood it is smarter than that - unchanged files are reused across commits rather than duplicated, so the `.git` folder does not balloon in size with every commit. You do not need the internals to use Git well, but it explains why Git stays fast even on huge histories. > ⚠️ **Security:** If you delete the `.git/` folder, your project history is gone from that machine. If a teammate has cloned the repo, or it's pushed to GitHub, that copy is safe - but a local-only repo with no clone or push has no backup at all. ---
### 🟢 Core - the mental model This is the single most important concept in Git. Every project moves through three places as you work: the Working Directory, the Staging Area, and the Repository. Working Directory --git add--> Staging Area --git commit--> Repository (where you edit) (queued for (permanent next commit) snapshots) Within that model, a file also has a status - untracked, modified, staged, or committed - describing where it currently sits. ```bash ## Create a new file echo "def embed_query(text):" > retriever.py ## Git sees it but is not tracking it yet git status ## Untracked files: retriever.py ## Stage it - move from Working Directory to Staging Area git add retriever.py git status ## Changes to be committed: new file: retriever.py ## Commit - permanently save the snapshot git commit -m "feat: add embed_query stub for retriever" ``` | State | What it Means | How to Get There | |:---|:---|:---| | Untracked | New file Git has never seen | Create a new file | | Modified | Tracked file has changed | Edit a tracked file | | Staged | Change queued for the next commit | Run `git add` | | Committed | Snapshot permanently saved | Run `git commit` | > 📌 **Remember:** The staging area is not an unnecessary extra step - it lets you be precise. If you changed 5 files, stage 2 and commit just those as one logical unit. This produces clean, meaningful commits instead of giant "changed everything" commits. ---
### 🟢 Core - the loop every engineer repeats ```bash ## Start by getting the latest changes from the team git pull ## Check current state git status ## Make your changes to files... ## See exactly what changed before staging git diff ## Stage what you want in this commit git add src/retriever.py git add configs/ ## entire directory git add . ## everything changed ## Review what is staged before committing git diff --staged ## Commit with a clear message git commit -m "feat: add hybrid retrieval for RAG pipeline" ## Push so the team can see it git push ``` ### 🟢 Core - viewing history ```bash ## One line per commit - use this constantly git log --oneline ## Visual graph of branches and merges git log --oneline --graph --all ## Only commits that touched a specific file git log --oneline -- src/retriever.py ``` ### 🟢 Core - writing commit messages that actually help A commit message is a permanent record future engineers - including future you - will read to understand why the code looks the way it does. Bad: `update`, `fix`, `wip`, `final` Good, following the **Conventional Commits** format `type: short description`: ```bash feat: add hybrid retrieval for RAG pipeline fix: prevent race condition in cache invalidation chore: pin transformers to 4.44.0 for reproducibility docs: add runbook for rotating API keys refactor: extract chunking logic into standalone module test: add integration tests for retriever reranking ``` | Type | When to Use | |:---|:---| | `feat` | New feature or capability | | `fix` | Bug fix | | `chore` | Maintenance, deps, tooling | | `docs` | Documentation only | | `refactor` | Restructure with no behavior change | | `test` | Adding or updating tests | > 📌 **Remember:** Tools like `semantic-release` read these prefixes to automatically determine version bumps and generate changelogs. On teams using these tools, conventional commits are not optional style - they're functional. ---
### 🟢 Core - SSH vs HTTPS To push to GitHub, it needs to verify who you are. There are two common options. **SSH** authenticates automatically once set up - no password or token prompts after the initial setup. **HTTPS** with a credential manager or personal access token is also a fully legitimate, widely used option, especially on machines where generating and managing SSH keys is inconvenient (some managed CI runners, for example). Neither is objectively required; SSH is simply the more common default for individual developer machines. ```bash ## Generate an SSH key pair ssh-keygen -t ed25519 -C "rahul@company.com" ## View your public key - copy this whole line cat ~/.ssh/id_ed25519.pub ## Test the connection ssh -T git@github.com ## Clone using the SSH URL format git clone git@github.com:my-team/rag-service.git ``` Add the public key at GitHub -> Settings -> SSH and GPG keys -> New SSH key. > 📌 **Remember:** `id_ed25519` is your private key - it never leaves your machine. `id_ed25519.pub` is your public key - that's what you share. If the private key ever leaks, regenerate immediately and remove the old public key from GitHub. ### 🟢 Core - remotes, fetch, and pull A **remote** is a version of your repository living elsewhere, usually GitHub. Cloning automatically creates a remote called `origin`. ```bash ## See configured remotes git remote -v ## Push commits on main to origin git push origin main ## First push of a new branch git push -u origin feat/hybrid-retrieval ``` ```bash ## Fetch - downloads changes but applies nothing locally git fetch ## See what came in that you don't have yet git log HEAD..origin/main --oneline ## Pull - fetch + merge in one step git pull ``` > 💡 **Tip:** In a team, `git fetch` first, inspect with `git log origin/main --oneline`, then merge once you know what's coming in. `git pull` is convenient but can drop you straight into a merge conflict you weren't ready for. ---
### 🟢 Core - how branches work A **branch** is an independent line of development. In many professional teams, `main` is protected and kept stable and deployable. Changes normally enter through short-lived branches and pull requests rather than direct commits. main: A -- B -- C ------------------ G \ / feat/hybrid-retrieval: D -- E -- F ------ (merged at G) ```bash ## Create a new branch and switch to it git switch -c feat/hybrid-retrieval ## See all local branches git branch ## Switch to an existing branch git switch main ## Merge your feature branch into main git switch main git merge feat/hybrid-retrieval ## Delete the branch after merging git branch -d feat/hybrid-retrieval ``` | Command | What it Does | |:---|:---| | `git switch -c name` | Create and switch to a new branch | | `git switch name` | Switch to an existing branch | | `git branch` | List all local branches | | `git branch -d name` | Delete a merged branch | Naming that tells the team what's happening: ```bash feat/rag-hybrid-retrieval fix/embedding-dimension-mismatch chore/pin-torch-version ``` > 🔴 **Common Mistake:** Committing directly to `main`. Common professional practice: on teams with protected branches, changes normally go through a short-lived branch and a pull request rather than direct commits to `main`, since that's what makes reviews and CI checks actually happen before code lands. ### 🟢 Core - resolving merge conflicts Conflicts happen when two people changed the same lines in the same file and Git can't automatically decide which version is correct. This is normal on every team. ```bash git switch main git merge feat/reranker ## CONFLICT (content): Merge conflict in src/retriever_config.py ``` Git marks the conflict inside the file: ```python <<<<<<< HEAD TOP_K = 5 ======= TOP_K = 10 >>>>>>> feat/reranker ``` Everything between `<<<<<<< HEAD` and `=======` is your version. Everything between `=======` and `>>>>>>>` is the incoming version. Decide the correct final code, delete the markers, and commit: ```python TOP_K = 10 ``` ```bash git add src/retriever_config.py git commit -m "merge: resolve conflict in retriever top_k config" ``` > 🔴 **Common Mistake:** Forgetting to delete the conflict markers before staging. They are not valid code - if they stay, the file breaks. Always search for `<<<<<<<` before running `git add`. > 💡 **Tip:** If a conflict gets too messy, `git merge --abort` cancels the entire merge and returns your branch to exactly how it was before you started. ---
The problem before Git It is 6 PM on a Friday. Two engineers have been editing the same config file for an hour. One of ...
🟢 Core - installation 🟢 Core - first-time setup Every commit is permanently stamped with your name and email. This is ...
🟢 Core - the mental model This is the single most important concept in Git. Every project moves through three places as...
🟢 Core - the loop every engineer repeats 🟢 Core - viewing history 🟢 Core - writing commit messages that actually help...
🟢 Core - SSH vs HTTPS To push to GitHub, it needs to verify who you are. There are two common options. SSH authenticate...
🟢 Core - how branches work A branch is an independent line of development. In many professional teams, main is protecte...
🟢 Core - undo at every stage > ⚠️ Security: --amend rewrites the commit and its hash. Only do this before pushing - nev...
🟢 Core - what to ignore and why .gitignore tells Git which files to never track. Without it, dependency folders, enviro...
🟢 Core - what GitHub adds on top of Git GitHub hosts your Git repository on the internet and adds collaboration feature...
🟢 Core - what CI actually does for you Once a workflow file exists, every push and every PR automatically spins up a fr...
🟣 Advanced - merge vs rebase Merging creates a merge commit tying two histories together - the record shows exactly wha...
🟢 Core - the boundary every engineer needs to know Git versions code, configuration, and small text files extremely wel...
> 📌 Remember: Work through every step in order. This covers the complete daily workflow used on real teams every workin...
Command What it Does git status Show current state of tracked/untracked files git add <file> Stage changes for the next ...
Committing directly to main on a team that expects protected branches bypasses the review and CI checks that exist to ca...
Aligns directly with DevOps, Site Reliability (SRE), and Platform Engineering job descriptions.