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.

18 min 9 sections

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:

bash
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 main makes new repositories start on a branch called main, the modern convention. Without it, Git creates master and prints a hint about it.
  • core.editor is the editor Git opens when it needs a longer message. code --wait uses VS Code; nano or vim work too. The --wait matters: 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:

bash
mkdir notes-app && cd notes-app
git init
text
Initialized 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:

bash
echo "<h1>Notes</h1>" > index.html
echo "debug" > debug.log
git status
text
On 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:

StateMeaningShown under
UntrackedGit has never been told about itUntracked files
StagedIts current content is in the index, ready to commitChanges to be committed
ModifiedTracked, but the working tree differs from the indexChanges not staged for commit
UnmodifiedWorking 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:

bash
git status --short
text
MM index.html
?? debug.log

MM 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:

text
# Dependencies and build output
node_modules/
dist/

# Logs and local environment
*.log
.env

A 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:

bash
git check-ignore -v node_modules/react/index.js
text
.gitignore:2:node_modules/	node_modules/react/index.js

Staging and committing

Stage exactly what you want in the next commit with git add, then record it with git commit:

bash
git add index.html .gitignore
git commit -m "Create landing page"
text
[main (root-commit) 834a87f] Create landing page
 2 files changed, 8 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 index.html

The 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/file stages one file; git add src/ stages a directory.
  • git add . stages everything in the current directory that is not ignored. Convenient, but run git status first so you know what "everything" is.
  • git add -p walks through your changes hunk by hunk and asks about each one. This is how you split unrelated edits into separate commits:
text
@@ -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:

text
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:

CommandComparesAnswers
git diffindex → working treeWhat have I changed but not staged?
git diff --stagedlast commit → indexWhat will my next commit contain?
git diff HEADlast commit → working treeEverything I have changed since the last commit
git diff A Bcommit A → commit BHow do two snapshots differ?

After editing index.html:

bash
git diff
text
diff --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:

bash
git log
text
commit 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 page

The full format gets long quickly. These options cover most needs:

bash
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 file
text
01673bb Add tagline
834a87f Create landing page

To look at one commit in detail, use git show, which prints its metadata followed by its diff:

bash
git show --stat HEAD
text
commit 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:

  1. Create a repository journal, add a .gitignore that ignores *.tmp, and an entries.txt with nine lines (the first is Monday: lernt Git). Make your first commit with both files.
  2. Create scratch.tmp, and confirm git status does not list it.
  3. 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 using git add -p.
  4. Show the last two commits as one line each, then show the full diff of only the first of them.
Show solution
bash
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 diff

If 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.email and init.defaultBranch once with git config --global.
  • git status tells you which files are untracked, staged or modified; check it before every commit.
  • git add (especially git add -p) lets you build focused commits; git commit -a never includes untracked files.
  • git diff shows unstaged changes, git diff --staged shows what you are about to commit.
  • .gitignore only affects untracked files; untrack an already committed file with git rm --cached.
  • git log with --oneline, --stat, -p and path filters, plus git show, lets you explore any part of history.

Check yourself

Quiz

0/4 correct · 4 left

  1. 1.You staged all your changes with git add, and now git diff prints nothing. What is happening?

  2. 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. 3.config.env was committed last week. You add config.env to .gitignore. What happens on your next commit?

  4. 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.