Step 02 of 10
Your first repository
Configure Git, create a repository, and use status, add, commit, log and diff to record and inspect clean, focused history.
This lesson turns the mental model from the previous lesson into muscle memory. You will configure Git once, create a project, and practise the loop you will run hundreds of times a week: edit, inspect, stage, commit. Along the way you will learn to read git status, git diff and git log fluently, and to keep junk out of your history with .gitignore.
One-time setup
Every commit records an author name and email, so tell Git who you are. The --global flag writes to ~/.gitconfig, which applies to every repository on your machine:
git config --global user.name "Ada Lovelace"
git config --global user.email "[email protected]"
git config --global init.defaultBranch main
git config --global core.editor "code --wait"init.defaultBranch mainmakes new repositories start on a branch calledmain, the modern convention. Without it, Git createsmasterand prints a hint about it.core.editoris the editor Git opens when it needs a longer message.code --waituses VS Code;nanoorvimwork too. The--waitmatters: Git must wait until you close the file.
Check what Git will use with git config user.email. If you use a hosting service, use the same email address you registered there so your commits are linked to your account.
Creating a repository
Turn any folder into a repository with git init:
mkdir notes-app && cd notes-app
git initInitialized empty Git repository in /home/ada/notes-app/.git/That created the hidden .git directory and nothing else. Your files are untouched, and nothing is tracked yet. To stop using Git in a folder you would simply delete .git (which also deletes all history, so think twice).
Two rules keep you out of trouble. Run git init at the root of a project, not in your home directory, and never create a repository inside another repository's folder by accident. If git status reports files from all over your disk, you initialised in the wrong place.
Reading git status
git status is the command you will run most. Create a couple of files and ask:
echo "<h1>Notes</h1>" > index.html
echo "debug" > debug.log
git statusOn branch main
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
debug.log
index.html
nothing added to commit but untracked files present (use "git add" to track)Every file in your project is in one of these states:
| State | Meaning | Shown under |
|---|---|---|
| Untracked | Git has never been told about it | Untracked files |
| Staged | Its current content is in the index, ready to commit | Changes to be committed |
| Modified | Tracked, but the working tree differs from the index | Changes not staged for commit |
| Unmodified | Working tree, index and last commit agree | (not shown) |
Once you are comfortable, the short format is quicker to scan. The left column is the index, the right column is the working tree:
git status --shortMM index.html
?? debug.logMM means "modified and staged, then modified again"; ?? means untracked; A means a newly added file is staged.
Ignoring files
Logs, build output, dependency folders and secrets should never be committed. List patterns in a .gitignore file at the project root:
# Dependencies and build output
node_modules/
dist/
# Logs and local environment
*.log
.envA trailing / matches directories only, * matches anything except /, and a leading ! re-includes something an earlier pattern excluded. Commit .gitignore itself so everyone on the team shares it. When you cannot work out why a file is being ignored, ask Git:
git check-ignore -v node_modules/react/index.js.gitignore:2:node_modules/ node_modules/react/index.jsStaging and committing
Stage exactly what you want in the next commit with git add, then record it with git commit:
git add index.html .gitignore
git commit -m "Create landing page"[main (root-commit) 834a87f] Create landing page
2 files changed, 8 insertions(+)
create mode 100644 .gitignore
create mode 100644 index.htmlThe output tells you the branch, the new commit's short ID, and a summary of what changed. root-commit appears only for the very first commit.
Useful forms of git add:
git add path/to/filestages one file;git add src/stages a directory.git add .stages everything in the current directory that is not ignored. Convenient, but rungit statusfirst so you know what "everything" is.git add -pwalks through your changes hunk by hunk and asks about each one. This is how you split unrelated edits into separate commits:
@@ -1,4 +1,4 @@
-<h1>Notes</h1>
+<h1>My Notes</h1>
<p>Write things down.</p>
(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,?]?Answer y to stage, n to skip, s to split a large hunk (when it can be split), q to quit, or ? for help.
There is also a shortcut, git commit -a -m "..." (or -am), which stages every change to already tracked files and commits in one step. It never picks up new, untracked files, which is a classic way to forget a file.
Writing a good message
Run git commit without -m and Git opens your editor so you can write a proper message:
Add search box to the notes list
Users with more than a few dozen notes could not find anything.
Filter the list client-side as the user types; server-side search
can come later if lists get large.The conventions are simple: a summary line of about 50 characters written as a command ("Add", "Fix", not "Added" or "Fixes"), a blank line, then a body explaining why the change was made. The diff already shows what changed. Teams often add further conventions on top, which you will meet in the workflows lesson.
Inspecting changes with git diff
git diff compares two of the three areas. Which two depends on the flags:
| Command | Compares | Answers |
|---|---|---|
git diff | index → working tree | What have I changed but not staged? |
git diff --staged | last commit → index | What will my next commit contain? |
git diff HEAD | last commit → working tree | Everything I have changed since the last commit |
git diff A B | commit A → commit B | How do two snapshots differ? |
After editing index.html:
git diffdiff --git a/index.html b/index.html
index 1cc1758..0618f11 100644
--- a/index.html
+++ b/index.html
@@ -1 +1,2 @@
<h1>Notes</h1>
+<p>Write things down.</p>Read it like this: --- is the old version and +++ is the new one. The hunk header @@ -1 +1,2 @@ says "starting at line 1, one old line became two new lines". Lines starting with + were added, - removed, and a space means unchanged context.
A frequent surprise: you stage a file and git diff suddenly prints nothing. That is correct, because the working tree now matches the index. Use git diff --staged to review staged work, and make that review a habit before every commit. Add --stat to any diff for a one-line-per-file summary.
Exploring history with git log
git log lists commits, newest first:
git logcommit 01673bb42e0d2093fda140b06d104e5a48e0acd3
Author: Ada Lovelace <[email protected]>
Date: Sun Oct 11 08:03:40 2026 +0000
Add tagline
commit 834a87ff6216c6f107488c68f879fc2cd67201dd
Author: Ada Lovelace <[email protected]>
Date: Sun Oct 11 08:01:12 2026 +0000
Create landing pageThe full format gets long quickly. These options cover most needs:
git log --oneline # one line per commit
git log --oneline --graph --all # draw branches (useful from the next lesson on)
git log -3 # only the last three commits
git log --stat # which files each commit touched
git log -p # the full diff of each commit
git log --author="Ada" # filter by author
git log --since="2 weeks ago" # filter by date
git log -- index.html # only commits that changed this file01673bb Add tagline
834a87f Create landing pageTo look at one commit in detail, use git show, which prints its metadata followed by its diff:
git show --stat HEADcommit 01673bb42e0d2093fda140b06d104e5a48e0acd3
Author: Ada Lovelace <[email protected]>
Date: Sun Oct 11 08:03:40 2026 +0000
Add tagline
index.html | 1 +
1 file changed, 1 insertion(+)When the output is longer than your screen, Git shows it in a pager: use the arrow keys or space to scroll and q to quit.
Finally, when you delete or rename tracked files, use git rm old.txt and git mv old.txt new.txt. They change the file and stage the change in one step. (Deleting or renaming with your file manager and then running git add -A achieves the same result.)
Practice
Build a tiny project with a deliberately messy working session, then turn it into clean history:
- Create a repository
journal, add a.gitignorethat ignores*.tmp, and anentries.txtwith nine lines (the first isMonday: lernt Git). Make your first commit with both files. - Create
scratch.tmp, and confirmgit statusdoes not list it. - In
entries.txt, fix a typo on line 1 and add a new line at the end (with seven or more lines between the edits, Git shows them as separate hunks). Commit these as two separate commits usinggit add -p. - Show the last two commits as one line each, then show the full diff of only the first of them.
Show solution
mkdir journal && cd journal
git init
printf '*.tmp\n' > .gitignore
printf 'Monday: lernt Git\n' > entries.txt
for i in 2 3 4 5 6 7 8 9; do echo "line $i" >> entries.txt; done
git add .gitignore entries.txt
git commit -m "Start journal"
touch scratch.tmp
git status # scratch.tmp is not listed: it is ignored
sed -i 's/lernt/learnt/' entries.txt # macOS: sed -i '' 's/lernt/learnt/' entries.txt
echo "Tuesday: staged with -p" >> entries.txt
git add -p entries.txt # answer y for the typo hunk, n for the new line
git diff --staged # check: only the typo fix
git commit -m "Fix typo in Monday entry"
git add entries.txt
git commit -m "Add Tuesday entry"
git log --oneline -2
git show HEAD~1 # the typo-fix commit with its diffIf both edits landed in one hunk, press s at the prompt to split it; if Git cannot split it, use e to edit the hunk, or simply move the edits further apart. The key check is git diff --staged before each commit.
Key takeaways
- Set
user.name,user.emailandinit.defaultBranchonce withgit config --global. git statustells you which files are untracked, staged or modified; check it before every commit.git add(especiallygit add -p) lets you build focused commits;git commit -anever includes untracked files.git diffshows unstaged changes,git diff --stagedshows what you are about to commit..gitignoreonly affects untracked files; untrack an already committed file withgit rm --cached.git logwith--oneline,--stat,-pand path filters, plusgit show, lets you explore any part of history.
Check yourself
Quiz
0/4 correct · 4 left
1.You staged all your changes with git add, and now git diff prints nothing. What is happening?
2.You created a new file report.py and edited an existing tracked file app.py, then ran git commit -am "Add report". What does the commit contain?
3.config.env was committed last week. You add config.env to .gitignore. What happens on your next commit?
4.Which command lists only the commits that changed the file styles.css, one line per commit?
Concepts in this lesson
One-page notes on each idea, for review or a quick lookup later.
Finished reading?
Mark it complete to fill in your roadmap.