Appearance
Git & Version Control
Git tracks changes to your code over time. It lets you undo mistakes, experiment without breaking the working version, and collaborate with other people without stepping on each other's work. You do not need to master git to be productive. The handful of commands in this lesson cover what you will actually run on a real project, from starting something new to merging a finished feature.
What you'll learn
git initstarts tracking a directory;git addstages changes;git commitsaves a snapshotgit pushandgit pullmove commits between your machine and a remote like GitHub- Branches isolate work in progress. Merge only when the feature is done and tested
The problem
You are working on a feature. It is going well, so you keep going. At some point you make a change that breaks something, but you have made ten other changes since then and you cannot remember which one caused the problem. You did not save a copy of the working version. You are stuck either debugging blindly or rewriting what you lost.
Version control solves this by saving snapshots of your code at every commit. You can rewind to any previous snapshot, compare what changed between two points, and isolate experimental work in branches until it is ready to merge.
Options & when to use each
| Approach | What it is | When to use it |
|---|---|---|
Manual copies / project-final-v2-bak.zip | Saving copies of the project directory with version names | Never. It is error-prone, uses disk space, and you cannot see what changed between copies |
| Git (local only) | Track changes on your machine without a remote | Solo projects where you want undo and history but no collaboration or backup |
| Git + GitHub/GitLab | Local git plus a remote repository for backup and collaboration | Everything else -- this is the default for the course |
Build it
One-time setup
Tell git who you are. This information is attached to every commit:
bash
git config --global user.name "Your Name"
git config --global user.email "your.email@example.com"
git config --global init.defaultBranch mainStarting a new project
bash
cd my-agent-project
git init
# Output: Initialized empty Git repository in /home/you/my-agent-project/.git/A .git/ directory now exists. That is where git stores all its history and metadata. You never need to look inside it.
The .gitignore file
Before you commit anything, tell git which files to ignore. Create a .gitignore at the root of your project:
text
# Secrets and environment files
.env
# Python
__pycache__/
*.pyc
.venv/
# OS files
.DS_Store
Thumbs.db
# Build artifacts
dist/
*.egg-info/The .gitignore prevents git from tracking generated files, secrets, and the virtual environment. Secrets in version control are a security problem. Generated files bloat the repository and cause merge conflicts.
The staging area -- git's mental model
Git has three zones. Understanding them prevents most confusion:
- Working directory: the files you edit in your editor. Git sees changes here but does nothing with them yet.
- Staging area (also called the index): files you have explicitly marked for the next commit.
git addmoves files here. - Repository: the permanent history.
git commitsaves whatever is in the staging area.
A file can be modified in the working directory, staged, or committed. The same file can even be in different states across zones -- you can stage a change, then make another edit to the working copy before committing.
Your first commit
bash
# Stage everything that is not in .gitignore
git add .
# Save the staged changes as a commit
git commit -m "feat: initial project scaffold"Write commit messages in present tense and be specific about what changed. "Fix bug" tells you nothing six months later. "Fix KeyError when config file is missing" tells you exactly what the commit addresses.
Pushing to GitHub
Create a repository on GitHub (the web UI, do not initialize with a README). Then connect your local repository:
bash
git remote add origin https://github.com/you/my-agent-project.git
git push -u origin mainAfter the first push, future pushes are shorter:
bash
git pushPulling changes
When someone else (or you, from another machine) has pushed to the remote:
bash
git pullThis fetches new commits from the remote and merges them into your current branch.
Branching -- isolate work in progress
A branch is a parallel line of development. When you start a new feature, create a branch so your main branch stays stable while you experiment:
bash
# Create and switch to a new branch
git checkout -b feature/add-rate-limiting
# Work, stage, commit as usual
git add .
git commit -m "feat: add rate limiting to API client"
# Push the branch to GitHub
git push -u origin feature/add-rate-limitingSwitch between branches to work on different things:
bash
# List all branches, current one marked with *
git branch
# Switch to main
git checkout main
# Switch back to the feature branch
git checkout feature/add-rate-limitingMerging
When the feature is done and tested, merge it back into main:
bash
git checkout main
git pull # Make sure main is up to date
git merge feature/add-rate-limiting
git pushIf git cannot merge automatically because both branches changed the same lines, it will report a merge conflict. Open the conflicted file, look for the <<<<<<<, =======, and >>>>>>> markers, decide which version to keep, remove the markers, stage the file, and commit.
Cloning an existing project
When a repository already exists on GitHub and you want a local copy:
bash
git clone https://github.com/someone/some-project.git
cd some-projectViewing history
bash
# Compact log, one commit per line
git log --oneline
# See what changed but is not yet staged
git diff
# See what is staged but not yet committed
git diff --staged
# See which files have changes
git statusWhat goes wrong
| Mistake | How you notice it | The fix |
|---|---|---|
| Committed secrets (.env, API keys) | .env appears in git log or the remote repository | Rotate the secret immediately -- removing it from git does not undo exposure. Then git rm --cached .env, add .env to .gitignore, commit, push |
| Committed large generated files | Repository size balloons, clone takes forever | Add the file pattern to .gitignore, git rm --cached the files, commit. Consider git filter-branch or BFG Repo-Cleaner for deep history cleanup |
| Detached HEAD state | git status says "HEAD detached at ..." | You are not on a branch. git checkout -b temp-branch to save your work to a branch, then switch back to main |
| Merge conflict | Git prints "CONFLICT" and the merge aborts | Open each conflicted file, resolve the markers, git add the resolved file, git commit to complete the merge |
| Pushed to the wrong branch | Changes appear in a branch you did not intend | If nobody has pulled yet: git push --force on the wrong branch to revert, then push to the correct branch. If people have pulled: coordinate, do not force-push |
| Forgot to pull before working | git push rejects because remote has commits you do not have locally | git pull first, resolve any conflicts, then push |
Confirm it worked
After setting up git and making your first commit, verify everything is tracked correctly:
bash
# 1. git status should show a clean working directory
git status
# Expected: "nothing to commit, working tree clean"
# 2. git log should show your commit
git log --oneline
# Expected: one line with your commit message and a hash
# 3. git remote should list origin
git remote -v
# Expected: origin https://github.com/you/my-agent-project.git (fetch)
# Expected: origin https://github.com/you/my-agent-project.git (push)
# 4. Verify .gitignore is working
echo "test" > .env
git status
# Expected: .env does NOT appear in the untracked files list
rm .envNext: PostgreSQL Basics