-
Notifications
You must be signed in to change notification settings - Fork 6
13 how git works
Related appendices: Appendix E: Advanced Git | Appendix D: Git Authentication | Appendix F: Git Security Authoritative sources: Git SCM: Git Basics | Git SCM: Branching in a Nutshell | GitHub Docs: About Git
Day 2, Block 1 Material
Before you start running Git commands, you need a mental model of what Git actually does. This chapter builds that model from the ground up: what a commit is, what a branch is, how local and remote repositories relate, and why merge conflicts happen. Every operation in Chapter 14 will make more sense after reading this.
- Why a Mental Model Matters
- The Three Areas: Working Directory, Staging Area, Repository
- What Is a Commit?
- What Is a Branch?
- Local vs Remote
- Push, Pull, and Fetch
- Why Merge Conflicts Happen
- The Git Timeline
- Putting It All Together
- If You Get Stuck
Challenges 10-16 all depend on the mental model built in this chapter. Understanding the three areas, branches, and push/pull makes every Day 2 Git command predictable.
On Day 1, you edited files on GitHub.com using the web editor. GitHub handled Git for you behind the scenes -- creating commits, managing branches, and tracking changes. You did not need to think about how it worked because the web interface made it invisible.
On Day 2, you will do the same operations locally: clone a repository to your computer, create branches, make commits, and push changes back to GitHub. The commands themselves are not hard. But without understanding what they do, you will hit a wall the first time something goes wrong -- and you will not know how to fix it.
This chapter gives you that understanding. It is not a list of commands (that is Chapter 14). It is the mental model that makes the commands make sense.
Authoritative source: The concepts in this chapter are grounded in the Pro Git book by Scott Chacon and Ben Straub, which is the official Git documentation's recommended resource. It is free to read online.
Git organizes your work into three areas. Understanding these three areas is the single most important concept in this chapter.
The working directory is the folder on your computer where the files live. When you open a project in VS Code, everything you see in the file explorer is the working directory. These are real files on your disk that you can edit, rename, and delete.
When you change a file in the working directory, Git notices. But Git does not automatically record the change. You have to tell Git which changes you want to keep.
The staging area is a holding zone. When you are happy with a change in the working directory, you add it to the staging area. This is like saying: "I want this change to be part of my next save point."
You can add some files to the staging area and leave others out. This lets you make a commit (save point) that includes only the changes that belong together.
The repository is Git's permanent record. When you commit, Git takes everything in the staging area and stores it as a snapshot -- a permanent record of what those files looked like at that moment. The repository is stored in a hidden .git folder inside your project directory.
The flow is always the same:
- Edit files in the working directory
- Stage the changes you want to keep (add to the staging area)
- Commit the staged changes (save to the repository)
In Git commands, this looks like:
edit a file --> git add file.md --> git commit -m "description"
(working directory) (staging area) (repository)
Screen reader note: Many visual Git tutorials use diagrams with arrows to show this flow. The text description above and the three-step sequence are the same information without requiring a visual representation.
Think of it like packing a box to mail:
- The working directory is your desk with papers and items scattered on it
- The staging area is the open box on the floor -- you put items into it as you decide what to ship
- The commit is sealing the box, labeling it, and putting it on the shelf -- once sealed, its contents are recorded permanently
You can put items in and take them out of the box (stage and unstage) as many times as you want before sealing it (committing).
Screen reader users
- Run
git statusin the terminal (`Ctrl+``) -- it announces which files are in each area (working directory, staging, committed) with clear labels - In VS Code Source Control (
Ctrl+Shift+G), files are grouped under "Changes" (working directory) and "Staged Changes" (staging area) -- navigate with arrow keys - Press
Enteron any file in the Source Control panel to hear the diff -- added and removed lines are announced with change-type prefixes
Low vision users
- In Source Control (
Ctrl+Shift+G), staged files appear under a separate "Staged Changes" heading with a green+icon; unstaged files are under "Changes" with an orangeMicon - Use
Ctrl+=to increase editor font size if the Source Control file list is hard to read at default zoom - The gutter indicator (colored bar on the left edge of the editor) shows green for added lines and blue for modified lines
Sighted users
- The Source Control badge on the Activity Bar shows a number indicating how many files have changes -- click it to see the full list
- Look for letter badges next to filenames:
M(modified),U(untracked),A(added to staging),D(deleted) - The inline gutter colors in the editor margin (green = added, blue = modified, red = deleted) show changes at a glance without opening Source Control
A commit is a snapshot of your project at a specific moment in time. It is not a diff (a list of changes). It records the complete state of every file in the staging area when the commit was made.
Every commit has four parts:
| Part | What it is | Example |
|---|---|---|
| Snapshot | The complete state of all staged files | All the files as they were when you committed |
| Message | A human-readable description of the change | "Fix broken link in setup guide" |
| Author | Who made the commit (name and email) | Jane Developer, jane@example.com |
| Parent pointer | Which commit came before this one | A reference to the previous commit's ID |
Every commit gets a unique identifier -- a 40-character string called a SHA hash. It looks like this:
a1b2c3d4e5f6789012345678901234567890abcd
In practice, you usually see only the first 7 characters: a1b2c3d. This short form is enough to uniquely identify a commit in most repositories.
You do not need to memorize these. Git commands accept both the full hash and the short form.
Once a commit is made, it is part of the repository's history. You can make new commits that undo the changes, but the original commit still exists in the timeline. This is what makes Git safe: you can always go back.
The Day 1 connection: When you edited a file on GitHub.com and clicked "Commit changes," GitHub created a commit for you. It did the stage-and-commit steps in a single action. On Day 2, you will do these steps separately, which gives you more control.
Screen reader users
- After committing, run
git log --oneline -5in the terminal to hear the last 5 commit hashes and messages read aloud - In VS Code, press
Ctrl+Shift+Gthen navigate to the commit message input box -- your screen reader announces "Message" -- type your description and pressCtrl+Enterto commit - The 7-character short hash (e.g.,
a1b2c3d) is what Git commands accept -- you do not need the full 40 characters
Low vision users
- The Source Control commit input box is at the top of the Source Control panel -- increase panel width by dragging the panel edge if the text is truncated
- After committing, the file count badge on the Source Control icon drops to zero, confirming the commit succeeded
- Use Timeline view (
Ctrl+Shift+Pthen "Focus on Timeline View") to see a chronological list of commits for the current file
Sighted users
- The commit message input box sits at the top of the Source Control panel with a checkmark button to commit
- After committing, the "Staged Changes" section disappears and the Activity Bar badge number decreases
- Hover over any commit in the Timeline view to see the full message, author, and timestamp in a tooltip
See also: Chapter 14: Git in Practice shows how to create and switch branches hands-on in VS Code.
A branch is a name that points to a specific commit. That is the entire definition. A branch is not a copy of your files. It is not a separate folder. It is a pointer -- a label stuck on one specific commit.
Every repository has a default branch, usually called main. When you clone a repository, Git checks out the main branch, which means it loads the files from the commit that main points to into your working directory.
When you create a new branch, Git creates a new pointer that starts at the same commit you are currently on. Both branches point to the same commit. No files are copied.
Before creating a branch:
main --> commit C
After creating a branch called "fix/typo":
main --> commit C
fix/typo --> commit C (same commit, two names)
When you make a new commit while on the fix/typo branch, the fix/typo pointer moves forward to the new commit. The main pointer stays where it was.
main --> commit C
fix/typo --> commit D --> commit C
Now fix/typo is one commit ahead of main. The files on main have not changed. The files on fix/typo include your new edit.
Git uses a special pointer called HEAD to track which branch you are currently working on. When you switch branches (checkout), Git moves HEAD to point to the new branch and updates the files in your working directory to match.
The Day 1 connection: On Day 1, you created a
learn/[username]branch on GitHub.com. That branch was a pointer to a specific commit on the repository. When you edited files on that branch, new commits moved the pointer forward. Themainbranch stayed unchanged until your pull request was merged.
Screen reader users
- Press
Ctrl+Shift+GthenTabto reach the branch name in the Source Control panel -- your screen reader announces the current branch - The Status Bar at the bottom of VS Code shows the current branch name -- navigate to it with
F6to cycle through Status Bar items - To switch branches, press
Ctrl+Shift+Pthen type "Git: Checkout to" and arrow through the branch list
Low vision users
- The current branch name appears in the bottom-left of the Status Bar -- click it to see a dropdown of all branches
- Branch names in the Status Bar use the same font size as the rest of the bar; zoom the entire window with
Ctrl+=if it is too small - In the Source Control panel, the branch name is shown above the commit input -- verify it before committing
Sighted users
- Look at the bottom-left corner of VS Code for the branch icon and name (e.g., a git-branch icon followed by
main) - Click the branch name to open a picker showing all local and remote branches -- select one to switch
- The branch icon changes to a sync icon with arrows when your branch is ahead of or behind the remote
See also: Appendix D: Git Authentication covers how to set up credentials so push and pull work without password prompts.
So far, we have talked about one repository. In practice, you work with two copies of the same repository.
The remote repository is the one on GitHub.com. It is called origin by convention. When you see a repository URL like github.com/Community-Access/git-going-with-github, that is the remote.
The remote is the shared copy. Everyone on the team can see it. Pull requests happen here. Issues live here. It is the source of truth for the project.
The local repository is the copy on your computer. When you run git clone, Git downloads the entire repository -- all files, all branches, all history -- to your machine. You now have a complete, independent copy.
You can make commits locally without any internet connection. Your commits are saved in your local repository. The remote does not know about them until you push.
| Operation | Direction | What it does |
|---|---|---|
git clone |
Remote to local | Creates a new local copy of the entire remote repository |
git push |
Local to remote | Sends your local commits to the remote repository |
git pull |
Remote to local | Downloads new commits from the remote and merges them into your branch |
git fetch |
Remote to local | Downloads new commits from the remote but does not merge them |
Your computer (local) GitHub.com (remote / origin)
+-------------------+ +-------------------+
| working directory | git push | |
| staging area | --------> | shared branches |
| repository (.git) | <-------- | pull requests |
+-------------------+ git pull | issues |
+-------------------+
Screen reader note: The text diagram above shows two boxes side by side connected by arrows. The left box is labeled "Your computer (local)" and contains working directory, staging area, and repository. The right box is labeled "GitHub.com (remote / origin)" and contains shared branches, pull requests, and issues. Arrows show
git pushgoing from left to right andgit pullgoing from right to left.
Screen reader users
- Run
git remote -vin the terminal to hear which remote URLs are configured -- typicallyoriginpointing to your GitHub repository - After
git push, your screen reader announces the output including the branch name and commit count sent -- listen for "Everything up-to-date" if nothing new to push - Run
git statusto hear whether your local branch is ahead of, behind, or in sync with the remote tracking branch
Low vision users
- The Status Bar sync indicator (bottom-left, next to the branch name) shows up/down arrow counts: up-arrows = commits to push, down-arrows = commits to pull
- Click the sync icon in the Status Bar to push and pull in one action -- the arrows disappear when local and remote are in sync
- The Source Control panel heading shows the repository name and branch so you can confirm which remote you are working with
Sighted users
- Look for the cloud icon or sync arrows next to the branch name in the Status Bar to see push/pull status at a glance
- A number next to the up arrow means you have unpushed commits; next to the down arrow means the remote has commits you have not pulled
- The Source Control panel shows a "Publish Branch" button when you have a local branch that does not yet exist on the remote
These three operations keep your local and remote repositories synchronized.
git push sends your local commits to the remote. After pushing, anyone who looks at the repository on GitHub.com will see your changes.
Push only sends commits on the current branch. If you are on the fix/typo branch and push, only fix/typo commits go to the remote. Other branches are untouched.
git push origin fix/typoIf this is the first push for a new branch, use:
git push -u origin fix/typoThe -u flag sets up tracking so that future pushes from this branch go to the right place without specifying the remote and branch name.
git pull downloads new commits from the remote and immediately merges them into your current branch. This is how you get changes that other people (or you on another computer) have pushed.
git pull origin mainPull is actually two operations combined: fetch (download) + merge (integrate). Most of the time this works automatically. When it cannot merge automatically, you get a merge conflict (see Section 7).
git fetch downloads new commits from the remote but does not change your working directory or current branch. It just updates your local knowledge of what the remote looks like.
This is useful when you want to see if there are new changes before deciding to merge them.
git fetch originAfter fetching, you can compare your branch with the remote's version:
git log main..origin/main --onelineThis shows you what commits exist on the remote's main that you do not have locally.
A merge conflict happens when Git cannot automatically combine two sets of changes. This is not an error. It is Git asking you for help.
Conflicts happen when two branches modify the same lines in the same file. Git knows how to merge changes to different files, and even different parts of the same file. But when two branches change the same line differently, Git cannot decide which version to keep.
When a conflict occurs, Git marks the conflicting section in the file with special markers:
<<<<<<< HEAD
This is the text from your current branch.
=======
This is the text from the branch you are merging in.
>>>>>>> fix/typo
| Marker | Meaning |
|---|---|
<<<<<<< HEAD |
Start of your current branch's version |
======= |
Divider between the two versions |
>>>>>>> fix/typo |
End of the incoming branch's version |
- Open the file with the conflict markers
- Read both versions and decide which text to keep (or write a new version that combines both)
- Delete the conflict markers (
<<<<<<<,=======,>>>>>>>) - Save the file
- Stage and commit the resolved file
The Day 1 connection: In Chapter 7, you resolved a merge conflict on GitHub.com using the web editor. The same markers appeared there. On Day 2, you will resolve conflicts in VS Code, where the editor highlights the markers and offers buttons to accept one side or the other.
Conflicts are not mistakes. They happen in every project where more than one person works at the same time. The fact that Git stops and asks is a safety feature -- it prevents data loss by never silently choosing one version over another.
Screen reader users
- When a conflict occurs, VS Code announces "Merge conflict" and the file appears in Source Control under "Merge Changes" -- navigate with arrow keys
- Use
F7in the diff viewer to step through conflict hunks; each hunk announces the line range and both versions of the conflicting text - After resolving, stage the file (
Ctrl+Shift+G, navigate to the file, press+) then commit to complete the merge
Low vision users
- Conflict markers (
<<<<<<<,=======,>>>>>>>) appear as highlighted blocks in the editor -- look for colored backgrounds (green for current, blue for incoming) - VS Code places "Accept Current Change", "Accept Incoming Change", and "Accept Both" buttons inline above each conflict -- they are large enough to click at high zoom
- Increase editor zoom with
Ctrl+=to make the conflict marker labels easier to read
Sighted users
- Conflict regions are highlighted with distinct background colors: green for your changes (Current), blue for incoming changes
- Click "Accept Current Change", "Accept Incoming Change", or "Accept Both Changes" above each conflict block to resolve with one click
- The Source Control badge shows a merge icon when you are in a merge state -- commit after all conflicts are resolved to complete the merge
Every commit has a parent pointer (except the very first commit). This creates a chain -- a timeline of the project's history.
The timeline reads backward: the most recent commit points to the one before it, which points to the one before that, all the way back to the first commit.
first commit <-- second commit <-- third commit <-- fourth commit (main)
When you run git log, Git follows these pointers from the current commit backward and shows you each commit's message, author, date, and hash.
When two branches diverge (both have commits that the other does not), the timeline splits into two parallel paths:
+-- commit E -- commit F (fix/typo)
/
commit A -- commit B -- commit C -- commit D (main)
Both branches share commits A and B (their common history). After the split point, each branch has its own commits.
When you merge fix/typo into main, Git creates a new merge commit that has two parents: the latest commit on main and the latest commit on fix/typo. The two timelines join back together.
+-- commit E -- commit F (fix/typo)
/ \
commit A -- B -- C -- D -------- merge commit G (main)
After merging, main contains all the changes from both branches.
Screen reader note: The text diagrams in this section show commit history as a horizontal chain reading left to right. Branch points are shown with
+--and merge points are shown with\. The key information is: branches diverge from a common ancestor commit and merge back together with a merge commit.
Here is the complete workflow that you will practice in Chapter 14, translated through the mental model:
| Step | What you do | What Git does |
|---|---|---|
| Clone the repo | git clone URL |
Copies the entire remote repository to your computer |
| Create a branch | git checkout -b fix/typo |
Creates a new pointer at your current commit and switches HEAD to it |
| Edit a file | Open and modify the file | Git detects the change in the working directory |
| Stage the change | git add file.md |
Moves the change from the working directory to the staging area |
| Commit | git commit -m "Fix typo" |
Takes a snapshot of the staging area and stores it in the repository |
| Push | git push -u origin fix/typo |
Sends your commit to the remote repository on GitHub |
| Open a PR | On GitHub.com | Proposes merging your branch into main |
| Merge | PR merged on GitHub.com | Creates a merge commit that joins your branch back into main |
| Pull | git pull origin main |
Downloads the merge commit to your local copy |
Everything in this table maps directly to the three areas (Section 2), the two copies (Section 5), and the timeline (Section 8).
Before running a Git command, ask yourself:
-
Where am I? Which branch is HEAD on? (
git statustells you) -
What has changed? Are there modifications in the working directory? Staged changes? (
git statustells you) - Which direction? Am I pushing (local to remote) or pulling (remote to local)?
- What could conflict? Has anyone else changed the same files on the same branch?
If you can answer these four questions, you can troubleshoot almost any Git situation.
| Situation | What to do |
|---|---|
| "I do not understand which area my file is in" | Run git status. It lists files in each area with clear labels (modified, staged, untracked). |
| "I committed to the wrong branch" | Do not panic. The commit is safe. See Appendix E for how to move commits between branches. |
| "I pushed something I did not mean to push" | The remote now has your commit. You can revert it with a new commit. Never force-push on a shared branch without coordination. |
| "I have merge conflict markers and do not know what to do" | Go to Chapter 7 for step-by-step resolution. The key rule: delete all markers, keep the text you want, stage, and commit. |
| "Git says my branch is behind the remote" | Run git pull to download the new commits. If there are conflicts, resolve them. |
| "I do not understand the error message" | Copy the exact error text and search for it. The Pro Git book troubleshooting section and Stack Overflow both have clear explanations. |
Next: Chapter 14: Git in Practice
Back: Chapter 12: VS Code Accessibility
Related appendices: Appendix E: Advanced Git | Appendix D: Git Authentication