Automate the Boring Stuff with Go, Ch. 0.3: git in an Afternoon
Part of Automate the Boring Stuff with Go, a beginner-friendly guide to programming in Go.
git is how programmers keep the history of their files. Not a backup, not a sync folder: a history, where every step you choose to save is kept forever, with a note saying what it was, and you can look at or return to any of them. Every program in this book lives in a git repository, and by chapter 16 you will be publishing your own.
git has a reputation for being hard. The whole of it is hard. The part you need is a handful of commands, and they fit in an afternoon. This chapter is that part and nothing else: no branches, no servers, no merging. Those come in 0.4 and later, one at a time, when there is a reason.
Install it, and introduce yourself
Chapter 1 has the install steps per operating system: winget install Git.Git on Windows, the developer tools prompt on macOS, sudo apt install git on Linux. Check:
git --version
git version 2.45.2
Every snapshot you save carries your name and email, so git asks you for them once:
git config --global user.name "Ada Gopher"
git config --global user.email "ada@example.com"
Use the email you will sign up to GitHub with in the next chapter, so the two match. --global means “for every repository on this machine”.
On Windows, run git from PowerShell or from Git Bash, whichever terminal you have open; the commands are identical.
The idea: a commit is a snapshot
A repository is a folder git is watching. A commit is a snapshot of every file in that folder at one moment, plus a message, plus who and when. Commits form a chain, newest first. That chain is the history, and it never changes behind your back: a commit, once made, stays exactly as it was.
The one idea that makes everything else make sense: git does not save your changes automatically. You decide what goes into the next snapshot, and when. Saving a file in your editor changes the folder. Only git commit adds to the history.
Start a repository
Make a folder for a practice project and tell git to watch it:
mkdir notes
cd notes
git init -b main
Initialized empty Git repository in /Users/t/notes/.git/
-b main names the first line of history main, which is what GitHub expects. (An older git may not know -b; run git init and then git branch -M main.) The .git folder it created is git’s memory; you never edit it, and deleting it deletes the history.
The loop: status, add, commit
Ask git what it sees. You will type this command more than any other:
git status
On branch main
No commits yet
nothing to commit (create/copy files and use "git add" to track)
Create a file in the folder with your editor, todo.txt, with a few lines in it:
Things to learn
- the terminal
- git
Now:
git status
On branch main
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
todo.txt
nothing added to commit but untracked files present (use "git add" to track)
Untracked means git sees a file it has never been told about. git add puts a file on the list for the next snapshot; programmers call that list the staging area, and “staged” means “on the list”:
git add todo.txt
git status
On branch main
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: todo.txt
And take the snapshot, with a message that says what it is:
git commit -m "Start a to-do list"
[main (root-commit) 245e615] Start a to-do list
1 file changed, 3 insertions(+)
create mode 100644 todo.txt
245e615 is the first few characters of the commit’s id, a fingerprint of its contents. You will see these everywhere; you rarely type them.
That is the loop. Change files, git status to see what changed, git add what belongs in the next snapshot, git commit -m with a message. Everything else in this chapter is looking at history and fixing mistakes.
Seeing what changed
Add a line to todo.txt, - GitHub, and save. Before committing, see exactly what is different from the last snapshot:
git diff
diff --git a/todo.txt b/todo.txt
index f69bf85..4b52c0b 100644
--- a/todo.txt
+++ b/todo.txt
@@ -1,3 +1,4 @@
Things to learn
- the terminal
- git
+- GitHub
Lines starting with + were added, lines starting with - were removed, the rest is context. git status --short is the one-line-per-file version, where M means modified:
git status --short
M todo.txt
Commit it, then look at the history:
git add todo.txt
git commit -m "Add GitHub to the list"
git log --oneline
e6708f0 Add GitHub to the list
245e615 Start a to-do list
git log without --oneline shows author, date and the full message for each commit, in a pager: press q to get out. Newest is at the top.
A good commit message is a short sentence in the present tense saying what the change does, the way these two do. “Fix typo in README”, “Add the census project”. You are writing it for someone reading the history a year from now, and that someone is usually you.
Ignoring files
Some files should never go into history: passwords, logs, the output your program writes, your editor’s settings. Create a file with a password in it, secrets.env, and look:
git status --short
?? secrets.env
?? is untracked. git is waiting for you to add it, and one careless git add . would put the password into history forever. Tell git to ignore it instead, with a file named .gitignore containing one pattern per line:
secrets.env
*.log
git status --short
?? .gitignore
secrets.env is gone from the list, and *.log covers every log file you will ever create here. The .gitignore itself is committed, so the rule travels with the project:
git add .gitignore
git commit -m "Ignore secrets and logs"
The book’s own .gitignore is in the repository you will clone next chapter; it lists every output file the projects write, which is why running them never dirties your history.
Undoing mistakes
Three mistakes cover a beginner’s first year, and each has one command.
You changed a file and want the last snapshot back. Suppose you overwrite todo.txt with the single word oops. git diff --stat shows the damage, and git restore throws it away:
git diff --stat
todo.txt | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
git restore todo.txt
cat todo.txt
Things to learn
- the terminal
- git
- GitHub
There is no undo for restore; it discards work you had not committed. Which is the argument for committing often.
You wrote the wrong commit message. Fix the most recent one:
git commit --amend -m "Add GitHub to the list of things to learn"
git log --oneline
70f7d46 Add GitHub to the list of things to learn
245e615 Start a to-do list
Notice the id changed: amending replaces the last commit with a new one. That is fine while the commit is only on your machine. Once it has been shared (0.4), you do not amend; you make a new commit.
You committed something that turned out to be wrong. Do not delete history. Make a new commit that undoes it:
git revert --no-edit HEAD
git log --oneline
436d3bb Revert "Ignore secrets and logs"
ce47be8 Ignore secrets and logs
70f7d46 Add GitHub to the list of things to learn
245e615 Start a to-do list
HEAD means “the latest commit”. The revert is itself a commit, so the history shows both the mistake and the correction, which is exactly what you want when someone asks what happened. (Revert the revert if you change your mind: git revert HEAD again.)
You will read about git reset and --force on the internet. Leave them until you know why you would want to rewrite history, because that is what they do, and the day you need them you will know.
The whole vocabulary
| You want to | Command |
|---|---|
| start watching a folder | git init -b main |
| see what changed | git status, git diff |
| put a file on the list for the next snapshot | git add file (git add . for everything not ignored) |
| take the snapshot | git commit -m "What this change does" |
| read the history | git log --oneline (q leaves the pager) |
| discard uncommitted changes to a file | git restore file |
| fix the last commit’s message | git commit --amend -m "Better message" |
| undo a commit, keeping history | git revert HEAD |
| never commit a file | add its name to .gitignore |
Conclusion
A repository is a watched folder, a commit is a snapshot you choose to take, and the daily loop is status, add, commit. You can see what changed, read the history, keep secrets out, and undo the three common mistakes without losing anything. Next: putting a repository on GitHub, getting the book’s code, and sending your first change to someone else’s project.