Git Get Started (First Repository)
Every Git project starts the same way: an ordinary folder on your computer becomes a repository the moment you run one command inside it. From that point on, Git can track every change you make, let you rewind to any earlier version, and share your work with others through services like GitHub. This lesson walks through creating your very first repository, telling Git who you are, and making your first commit — while explaining exactly what Git is doing behind the scenes.
Overview: How a Git Repository Works
A Git repository is really just a hidden database sitting inside a folder. When you run git init, Git creates a subfolder named .git that contains everything Git needs: a place to store file snapshots, a record of branches, and configuration. The folder you see (your source files) is called the working directory. Nothing you do there is tracked by Git until you explicitly tell it to.
Git moves changes through three areas:
- Working directory — the actual files on disk that you edit.
- Staging area (the index) — a holding area where you list exactly which changes should go into the next snapshot. This is what
git addpopulates. - Repository — the permanent history stored inside
.git/objects, written to bygit commit.
Internally, Git stores three kinds of objects, and every one of them is identified by a SHA-1 hash computed from its content:
- Blob — the raw contents of a single file (no filename, just bytes).
- Tree — a snapshot of a directory: a list of filenames/modes pointing at blobs (for files) and other trees (for subdirectories).
- Commit — a pointer to one tree (the full snapshot at that moment), plus metadata: author, committer, timestamp, commit message, and a pointer to the parent commit (or no parent, for the very first commit).
A branch, such as main, is nothing more than a small file containing a commit hash — a movable pointer. HEAD is itself usually a pointer to a branch (a "symbolic reference"), so when you commit, Git writes the new commit object and then moves the branch that HEAD points to forward to it. This is why branching and switching in Git are so fast: no files are copied, only pointers move.
Before your first commit can carry meaningful history, Git needs to know who you are — every commit permanently records an author name and email. You set this once with git config, and it’s separate from creating the repository itself.
git init vs. git clone
There are two ways to get a repository: git init creates a brand-new, empty one (what this lesson covers), while git clone copies an existing repository — history and all — from somewhere else, such as GitHub. You’ll use git clone constantly once you’re collaborating, but every repository, including the ones you clone, began life with a git init somewhere.
Syntax
git init [<directory>]
git config --global user.name "<your name>"
git config --global user.email "<your email>"
git status
git add <file>...
git commit -m "<message>"
git log
| Command / Flag | Meaning |
|---|---|
git init |
Creates a new, empty repository in the current directory (or the given one). |
git init <directory> |
Creates the directory if needed and initializes the repository inside it. |
--initial-branch=<name> |
Sets the name of the first branch created by this init call (rarely needed once init.defaultBranch is configured). |
git config --global |
Applies a setting for your whole user account, used by every repository unless overridden. |
git config --local |
Applies a setting only to the current repository (the default when you omit a scope flag while inside a repo). |
git status |
Shows the current branch, staged changes, unstaged changes, and untracked files. |
git add <file> |
Copies the current content of a file into the staging area (the index). |
git commit -m "..." |
Records everything currently staged as a new permanent snapshot, with the given message. |
Examples
Example 1: Creating your first repository
mkdir hello-git
cd hello-git
git init
Output:
Initialized empty Git repository in /home/you/hello-git/.git/
Git created a new .git folder inside hello-git. The project folder itself is completely unchanged — no files were added or modified — but it is now a repository Git knows how to track. Because no commit has been made yet, the main branch doesn’t technically exist as a real pointer yet; HEAD just refers to a branch name that will be created the moment you commit.
Example 2: Setting your identity
git config --global user.name "Ada Lovelace"
git config --global user.email "ada@example.com"
git config --global init.defaultBranch main
git config --list --global
Output:
user.name=Ada Lovelace
user.email=ada@example.com
init.defaultBranch=main
These settings are stored in a plain text file at ~/.gitconfig and apply to every repository on your machine. Setting init.defaultBranch to main means every future git init will name its first branch main instead of the older default master. If you need a different name or email for one specific project (say, a work email), run the same commands with --local instead of --global from inside that repository — local settings override global ones.
Example 3: Making your first commit
echo "# Hello Git" > README.md
git status
git add README.md
git commit -m "docs: add project README"
git log --oneline
Output:
On branch main
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
README.md
nothing added to commit but untracked files present (use "git add" to track)
[main (root-commit) 3f2c1a9] docs: add project README
1 file changed, 1 insertion(+)
create mode 100644 README.md
3f2c1a9 docs: add project README
The first git status shows README.md as untracked — Git sees the file but isn’t following it yet. After git add, the file’s content is staged. git commit then writes a blob for the file’s contents, a tree that records "README.md points at this blob", and a commit object pointing at that tree with no parent (it’s the root commit). Git also creates the main branch pointer for the first time here, pointing it at the new commit, and moves HEAD along with it.
How It Works Step by Step
Tracing exactly what happens across these examples:
git initcreates.git/objects(empty, for blobs/trees/commits),.git/refs/heads(empty, for branches), and a.git/HEADfile containingref: refs/heads/main— a pointer to a branch that doesn’t exist as a file yet.git add README.mdreads the file’s bytes, hashes them with SHA-1, compresses the result with zlib, and writes it as a blob object under.git/objects/<first-2-hash-chars>/<remaining-38-chars>. It then records an entry forREADME.md— its mode, its blob hash, and its path — in the index file,.git/index.git commitreads the index, builds a tree object describing the staged snapshot, writes a commit object referencing that tree (with author/committer copied from youruser.name/user.emailconfig and the current timestamp), and finally writes the commit’s hash into.git/refs/heads/main— which is the moment themainbranch starts to really exist.git logsimply follows the chain: read whatHEADpoints to, read that branch ref, read the commit object it names, and walk backward through each commit’s parent pointer.
Common Mistakes
Mistake 1: Committing without configuring identity
git commit -m "initial commit"
Output:
Author identity unknown
*** Please tell me who you are.
Run
git config --global user.email "you@example.com"
git config --global user.name "Your Name"
Modern Git refuses to guess your identity for you. The fix is exactly what the error suggests — run the two git config --global commands from Example 2 once, and every future commit on the machine will carry that identity automatically.
Mistake 2: Forgetting to stage before committing
A very common beginner error is editing a file, then running git commit -m "..." directly, expecting the edit to be included:
echo "new line" >> README.md
git commit -m "update readme"
Output:
On branch main
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
modified: README.md
no changes added to commit (use "git add" and/or "git commit -a")
The commit is rejected because nothing was staged — editing a tracked file does not automatically add it to the index. Run git add README.md (or git commit -a -m "..." to stage all already-tracked, modified files) before committing.
Mistake 3: Initializing a repository in the wrong place
Running git init in your home directory, or inside a folder that’s already a subfolder of another Git repository, creates a mess: either Git starts tracking your entire home folder, or you end up with a confusing nested repository. Always run pwd and confirm you’re in the intended project root, and run git status first if you’re unsure whether you’re already inside a repository — if it prints repository info instead of "not a git repository", you’re already inside one.
Best Practices
- Run
pwdbeforegit initto confirm you’re in the right folder — undoing an accidentalinitin the wrong place just means deleting its.gitfolder, but it’s easy to avoid entirely. - Set
user.nameanduser.emailglobally once, right after installing Git, so you’re never blocked mid-commit. - Set
init.defaultBranch mainglobally so you never have to rename a branch frommastertomainafter the fact. - Create a
.gitignorefile before your first commit so build artifacts, dependency folders, and secrets are never accidentally tracked in the first place. - Write your first commit message like any other — a short, imperative summary such as
chore: initial commitordocs: add project README, following the Conventional Commits style (type: description). - Run
git statusoften; it’s the cheapest way to know exactly what Git will do before you commit.
Practice Exercises
- Exercise 1: Create a folder named
my-first-repo, initialize it, and set a local identity (different name/email than your global one) usinggit config --local. Confirm it took effect withgit config --local --list. - Exercise 2: Inside that repository, create three files. Stage only two of them and commit. Run
git statusafterward and confirm the third file still shows as untracked. - Exercise 3: Temporarily unset your identity with
git config --global --unset user.email, then try to commit and observe the error message. Restore your email and successfully commit, to see the difference firsthand.
Summary
git initturns a folder into a repository by creating a hidden.gitdirectory — it doesn’t touch or track any files by itself.- Git has three working areas: the working directory, the staging area (index), and the repository itself;
git addandgit commitmove changes between them. - Internally, Git stores content as blobs, snapshots as trees, and history as commits, each identified by a SHA-1 hash; a branch is just a movable pointer to a commit.
- Set
user.nameanduser.emailwithgit config --globalbefore your first commit — every commit permanently embeds this identity. - The first commit in a repository has no parent and is what actually creates the
mainbranch pointer. git statusandgit logare your two most important tools for seeing exactly what state your repository is in.
