0.5 Git, enough for infrastructure work
Checked against the git-scm reference manual, August 2026
What this is and why it exists
Git is not on this course because you will write software. It is here because in a few modules your servers, networks and permissions stop being clicks in a console and become files — and files need history, review and a way back. Everything later in this subject assumes this lesson. You need enough Git to record work, read what changed, work on a change safely, and recover from a mistake.
The vocabulary
- Repository — a directory whose history Git is keeping, plus the hidden
.gitdirectory holding it. - Working tree — the files as they exist on disk right now.
- Index (staging area) — the reference calls it both; it is the tray you place changes into before committing them.
- Commit — a permanent, named snapshot of the whole project with a message explaining why.
- Pull request — a proposal on the hosting platform to bring one line of work into another, with review attached.
- .gitignore — a file listing things Git should never pick up.
The mental model
Git has three places, and almost every beginner confusion is a question about which one you are looking at. The working tree is the files on disk. The index is what you have deliberately selected for the next snapshot — the reference calls it "the staging area" and says it "is what you use to prepare the contents of the next commit". The repository is the permanent chain of snapshots already made. git add moves a change from the first place to the second; git commit moves everything in the second into the third, and the reference says it plainly: "create a new commit containing the current contents of the index and the given log message describing the changes".
That is why there are two diffs, and why people mix them up. git diff with no arguments shows "the changes you made relative to the index" — what is not staged yet. git diff --staged shows "the changes you staged for the next commit" — what you are about to record. Reading the second before every commit is the habit that catches the credential you did not mean to include.
Branches are the second idea, and lighter than they sound: a branch is a movable name for a commit, making one costs nothing, and switching moves your working tree to match. The workflow always has the same shape — start a short-lived branch for one piece of work, commit on it, open a pull request so somebody reads it, merge. The reference describes merging as incorporating changes from the named commits into the line you are on. Where the two sides edited different things, Git resolves it silently. Where they edited the same lines it stops, writes both versions into the file between markers, and waits for a person — because a machine guessing which of two intentions was right is worse than a machine asking.
The third idea has cost real people real money: a repository remembers everything. A password committed and then deleted in the next commit is still in the history, still in every clone, still on the hosting platform, and automated scanners find published keys within minutes. So the rule is about prevention, not cleanup: credentials never enter a repository at all. They live in environment variables or a secrets manager, and the file that would have held them is named in .gitignore. Note the limit the reference states exactly — "files already tracked by Git are not affected" — so adding a line does nothing about a file already committed. If a secret does get in, treat it as published: rotate the credential first, clean the history second. In that order, always.
Which answers the last question, why infrastructure lives in Git at all. A console click leaves no record of who, when or why; a commit answers all three, a pull request puts a reviewer before production rather than after the outage, and "put it back the way it was on Tuesday" becomes an executable operation instead of an act of memory and hope.
Portable operations
Checked against the git-scm reference manual; identical on every platform Git runs on.
git init
git status
git add infra/network.tf
git commit -m "Add the production network definition"
git log --oneline
git diff
git diff --stagedgit init "creates an empty Git repository - basically a .git directory". git status shows what differs between the index and HEAD, between the working tree and the index, and which files Git is not yet keeping — the first group is what you would commit, the rest what you could commit after a git add. --oneline is "a shorthand for --pretty=oneline --abbrev-commit", the readable form of history.
Working on a change without disturbing anyone:
git switch -c add-billing-alerts
git switch main
git merge add-billing-alertsgit switch moves you, updating "the working tree and the index" to match; -c creates the new name before switching to it. When a merge stops, the file holds both versions between markers of this shape:
<<<<<<< HEAD
the version already on this side
=======
the version arriving from the other side
>>>>>>> add-billing-alertsEdit the file until it is what you want, remove the markers, git add it to say it is resolved, and commit. The other route the reference gives is git merge --abort, which resets the index and cleans up if you would rather step back and think.
Undoing, before it is too late:
git restore --staged infra/network.tf
git restore infra/network.tfThe first "will only restore the index" — your change stays in the file but leaves the tray. The second restores the file from the index, discarding your edit, so read it twice before running it.
And the file that keeps secrets out:
.env
*.pem
*.tfstate
.terraform/A trailing slash means the pattern "will only match directories"; a leading slash anchors it to the directory holding the gitignore file rather than any level below. For something already committed, the reference names the fix: git rm --cached takes it out of the index so the rule applies from then on — which changes the future, not the history.
What you should now be able to explain or do
Name Git's three places and say which command moves a change between which. Read git diff --staged before a commit and say why that is the moment a leaked credential is cheapest to catch. Start a piece of work under its own name, commit on it, and merge it. Resolve a conflict by editing the file rather than picking a command at random. Explain in one sentence why deleting a committed password does not remove it. Write four sensible lines of a .gitignore for infrastructure work.
Check yourself
What is the difference between git diff and git diff --staged?
The first shows changes in your files that are not staged yet; the second shows what is staged and about to be committed. Reading the second before committing is how you catch what you did not mean to include.
You committed a cloud access key, noticed, and deleted it in the next commit. Are you safe?
No. The key is still in the history and in every copy of the repository, and public scanners find published keys quickly. Rotate the credential first — that is what makes it harmless — then deal with the history.
What does adding a filename to .gitignore do about a file already committed?
Nothing. The reference is explicit that files already kept by Git are unaffected; you have to remove it from the index with git rm --cached before the rule applies.
A merge stops and reports a conflict. What has Git done, and what do you do?
It merged everything it could, and for the clashing file wrote both versions in between markers rather than guessing. You edit the file into the state you actually want, stage it, and commit — or abort the merge and reconsider.
Why keep infrastructure definitions in Git rather than in the provider's console?
Because history, review and reversal come free with a repository and do not exist in a console. A commit records who changed what and why, a pull request puts a second pair of eyes before production, and returning to a previous state becomes a command instead of a memory exercise.
Go deeper
We haven't checked most of these for screen reader use yet.
Back to Git, enough for infrastructure work: work through the checklist