Git Init Explained: How to Initialize a Git Repository Step-by-Step (Complete Beginner's Guide)

Introduction
Every Git project starts with a single command: git init. It's the first thing you run when you begin tracking a project with version control, and understanding exactly what it does — not just how to type it, but what happens when you do — makes everything else in Git click into place.
This guide is written for beginners who are just getting started with Git, developers who use Git but never quite understood what's actually happening under the hood, and students who need to set up version control for a project. It covers what Git is, what a repository actually is, exactly what git init creates, the full workflow from initialization to GitHub, every git init option, common mistakes and how to avoid them, and real project examples across different tech stacks.
By the end you'll be able to initialize any project confidently, understand what you're doing and why at each step, and know how to connect your local repository to GitHub for backup and collaboration.
What is Git?
Before git init makes sense, Git itself needs to be clear.
Git is a distributed version control system — software that tracks changes to files over time so you can recall specific versions, see exactly what changed and when, and collaborate with others without overwriting each other's work.
Without Git (or some version control system), you'd manage versions manually: project_final.zip, project_final_v2.zip, project_ACTUALLY_final.zip. Anyone who has done this knows exactly how badly it breaks down. Git replaces that chaos with a clean, structured history of every meaningful change ever made to a project.
Git is distributed, which means every developer has a complete copy of the project history on their machine. There's no single "master" copy that everyone depends on — this makes Git fast, offline-capable, and resilient.
Git was created by Linus Torvalds in 2005 to manage the development of the Linux kernel. It's now the standard version control system used by essentially every software project in the world, from a student's first assignment to the Linux kernel itself.
What is a Git Repository?
A Git repository (repo) is a project folder that Git is tracking. It contains:
- Your actual project files (code, assets, documentation)
- A hidden
.gitfolder that stores all of Git's tracking data (history, configuration, branches, commits)
The .git folder is what makes an ordinary folder a Git repository. When you run git init, you're asking Git to create that .git folder and start tracking the project.
Two types of repositories:
| Type | Description | Use Case |
|---|---|---|
| Local repository | On your machine, has working directory | Your daily development |
| Remote repository | Hosted on GitHub/GitLab/Bitbucket | Backup, collaboration, sharing |
A project typically has one local repository per developer and one remote repository that everyone syncs to.
What Does git init Actually Do?
When you run git init in a directory, Git creates a hidden .git subfolder containing everything Git needs to track your project. Before git init:
my-project/
├── index.html
├── style.css
└── script.js
After git init:
my-project/
├── .git/ ← hidden folder (this is the repository)
│ ├── HEAD
│ ├── config
│ ├── description
│ ├── hooks/
│ ├── info/
│ ├── objects/
│ └── refs/
├── index.html
├── style.css
└── script.js
Your project files are untouched. Git just added the .git folder.
Inside the .git Folder
Most tutorials treat .git as a black box. Understanding what's inside makes Git much less mysterious.
.git/
├── HEAD ← Points to the current branch you're on
├── config ← Local repository configuration (author, remote URLs, etc.)
├── description ← Repository description (mainly for GitWeb)
├── hooks/ ← Scripts that run automatically on Git events (pre-commit, post-push, etc.)
├── info/
│ └── exclude ← Local .gitignore that isn't committed (only for this machine)
├── objects/ ← All commits, trees, and file contents are stored here as hashed objects
│ ├── info/
│ └── pack/
└── refs/ ← References (pointers to commits)
├── heads/ ← Local branches (refs/heads/main = your main branch's latest commit)
└── tags/ ← Tags (named references to specific commits)
What each piece does:
HEAD: A pointer to the current branch. When you switch branches with git checkout or git switch, HEAD updates to point to the new branch. It's how Git knows "where you are" in the repository.
config: Local settings for this repository — the remote URL, author name/email overrides, merge preferences. When you run git remote add origin <url>, it writes to this file.
objects/: This is where all your actual data lives. Every file version, every commit, every directory structure is stored here as a SHA-1 hashed object. Git never stores file diffs — it stores complete snapshots, compressed and deduplicated.
refs/heads/: When you make a commit on main, Git updates refs/heads/main to point to that new commit's hash. That's all a branch is — a named file containing a commit hash.
hooks/: Scripts that run automatically at specific points in the Git workflow. A pre-commit hook runs before every commit (useful for running linters or tests automatically). The sample files in this folder have .sample extension so they don't run until you rename them.
Prerequisites
Before running git init, you need:
1. Install Git:
# macOS (using Homebrew)
brew install git
# Ubuntu/Debian Linux
sudo apt-get install git
# Windows
# Download Git for Windows from git-scm.com
2. Configure your identity (only needed once per machine):
git config --global user.name "Your Name"
git config --global user.email "youremail@example.com"
Git records your name and email with every commit. If you skip this, commits will have no author information.
3. Verify installation:
git --version
# Expected output: git version 2.x.x
The Git Workflow
Here's the big picture of how Git works from initialization to GitHub. Every step in this diagram will make sense by the end of this guide:
Create/Navigate to project folder
│
▼
git init
(Creates .git folder)
│
▼
Create/edit files
│
▼
git add .
(Stage files for commit)
│
▼
git commit -m "message"
(Save snapshot to history)
│
▼
git remote add origin <url>
(Link to GitHub)
│
▼
git push -u origin main
(Upload to GitHub)
│
▼
Continue: edit → add → commit → push
Step-by-Step: Initialize a New Project
Step 1: Create and enter your project folder
mkdir my-project
cd my-project
mkdir creates the folder. cd enters it. You can also create the folder in your file manager and navigate there in your terminal.
Step 2: Run git init
git init
Expected output:
Initialized empty Git repository in /path/to/my-project/.git/
If you see this, the repository was created successfully. The .git folder now exists (hidden by default in most file managers — show hidden files to see it).
Step 3: Check status
git status
Output on a fresh repository with no files:
On branch main
No commits yet
nothing to commit (create/copy files and start working)
Step 4: Create some files and check status again
# Create a simple README
echo "# My Project" > README.md
git status
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)
Git can see the file but isn't tracking it yet. "Untracked" means Git knows the file exists but hasn't been told to include it in version control.
Step 5: Stage files
git add .
The . adds all files in the current directory (and all subdirectories) to the staging area. The staging area is a preparation zone — you choose which changes to include in your next commit before actually saving them.
To add a single specific file instead:
git add README.md
Step 6: Make your first commit
git commit -m "Initial commit"
Output:
[main (root-commit) a1b2c3d] Initial commit
1 file changed, 1 insertion(+)
create mode 100644 README.md
A commit is a permanent snapshot of your staged files saved to the repository's history. The -m flag provides the commit message. The hash (a1b2c3d) is a short version of the unique SHA-1 identifier for this commit.
Step 7: Connect to GitHub (Optional but Standard)
Create a new repository on github.com (don't initialize it with a README — you already have one locally). Then:
git remote add origin https://github.com/yourusername/my-project.git
git push -u origin main
git remote add origin saves the GitHub URL as a named remote called origin. git push -u origin main uploads your commits and sets origin/main as the default tracking branch for future pushes (so you can just type git push afterward).
Initialize an Existing Project
If you already have a project folder with files and want to start tracking it with Git:
cd existing-project
git init
git add .
git commit -m "Initial commit: add existing project files"
That's it. The files are untouched — Git just starts tracking them from this point forward.
All git init Options
Most tutorials only cover the basic git init. Here are all the options:
git init (basic)
git init
Creates a new repository in the current directory. This is what you use 95% of the time.
git init [directory]
git init my-new-project
Creates a new folder named my-new-project and initializes it as a Git repository in one step. Equivalent to mkdir my-new-project && cd my-new-project && git init.
git init --bare
git init --bare
Creates a "bare" repository — one that has no working directory, only the .git contents. Bare repositories are used as centralized shared repositories on servers. When you push to GitHub, you're pushing to a bare repository on GitHub's servers. You wouldn't work directly in a bare repository; you'd only push to and pull from it.
git init --initial-branch=main
git init --initial-branch=main
Sets the default branch name. Older versions of Git defaulted to master. Modern Git (2.28+) defaults to main (configurable). If your Git version creates master by default and you want main, use this flag.
To set the default globally so every new repository uses main:
git config --global init.defaultBranch main
git init --shared
git init --shared
Sets permissions so a group of users can share the repository. Used for setting up shared servers where multiple team members need write access to the same repository.
Real Project Examples
Example 1: Initialize a Web Project
mkdir portfolio-site
cd portfolio-site
# Create project files
touch index.html style.css script.js
mkdir images
git init
git add .
git commit -m "Initial commit: create project structure"
Example 2: Initialize a Python Project
mkdir data-analysis
cd data-analysis
# Create virtual environment and project files
python3 -m venv venv
touch main.py requirements.txt README.md
# Create .gitignore to exclude virtual environment
echo "venv/" > .gitignore
echo "__pycache__/" >> .gitignore
echo "*.pyc" >> .gitignore
git init
git add .
git commit -m "Initial commit: Python project setup"
Note the .gitignore file: it tells Git which files and folders to ignore. The venv/ folder contains thousands of library files that shouldn't be committed — only requirements.txt (which lists dependencies) needs to be tracked.
Example 3: Initialize a Node.js Project
mkdir my-node-app
cd my-node-app
npm init -y # Creates package.json
# Create .gitignore before adding
echo "node_modules/" > .gitignore
git init
git add .
git commit -m "Initial commit: Node.js project with package.json"
node_modules/ often contains hundreds of megabytes of installed packages. Always .gitignore it and commit only package.json — anyone who clones the project can run npm install to restore the packages.
Example 4: Initialize a React Project
npx create-react-app my-react-app
cd my-react-app
# create-react-app already runs git init automatically
# Verify:
git log --oneline
# Should show: "Initialize project using Create React App"
Many project scaffolding tools (create-react-app, npm create vite@latest, Django, etc.) run git init automatically. Check before running it yourself — running git init inside an existing Git repository is harmless but unnecessary.
Command Comparison Table
| Command | What it does | When to use |
|---|---|---|
git init |
Creates a new local repository | Starting a new project from scratch |
git clone <url> |
Downloads an existing repository | Starting from someone else's project |
git add <file> |
Stages specific file for commit | When you want to commit specific files |
git add . |
Stages all changed files | When you want to commit everything |
git commit -m "msg" |
Saves staged changes as a snapshot | After staging, to record your changes |
git status |
Shows current state of working directory | Any time you want to see what's changed |
git log |
Shows commit history | Reviewing what was changed and when |
git remote add origin <url> |
Links local repo to a remote URL | Before your first push to GitHub |
git push |
Uploads local commits to remote | After committing, to sync to GitHub |
git pull |
Downloads and merges remote changes | Before starting work, to get others' changes |
When NOT to Use git init
Don't run git init if:
-
You cloned the repository.
git clonealready initializes the repository — runninggit initafterward is redundant (though harmless, it reinitializes the existing one). -
The project already has a
.gitfolder. Check withls -a(Mac/Linux) ordir /a(Windows). If.gitis there, Git is already set up. -
You're inside another Git repository. Running
git initin a subdirectory of an existing repo creates a "nested" repository, which causes confusing behavior and is almost never what you want. -
You want to contribute to an existing project. Use
git cloneto download it first, then work in your clone.
How to check if you're already in a Git repository:
git rev-parse --is-inside-work-tree
# Returns: true (you're in a repo) or an error (you're not)
Common Mistakes (And How to Fix Them)
Mistake 1: Forgetting .gitignore before the first commit
If you commit node_modules/, venv/, .env files, or build artifacts, they're in the history. Even deleting them later doesn't remove them from previous commits (someone could still see them by checking out that commit).
Fix: Always create .gitignore before your first git add. GitHub provides template .gitignore files for every major language at github.com/github/gitignore.
Mistake 2: Using the wrong branch name
Older Git defaults to master; modern Git defaults to main. If you initialize with master but GitHub expects main (or vice versa), git push will fail or create an unexpected branch.
Fix: Set the default globally once:
git config --global init.defaultBranch main
Mistake 3: Committing sensitive files
API keys, passwords, and private configuration files (config.py, .env, secrets.json) should never be committed — even in private repositories.
Fix: Add them to .gitignore immediately. If you accidentally committed a secret, it's not enough to delete it in the next commit — it's still in the history. Use git filter-repo (or contact GitHub support for private repos) to fully remove it, and rotate the compromised credential immediately.
Mistake 4: Forgetting git add before git commit
git commit only commits staged files. If you changed a file but didn't run git add, the changes won't be in the commit.
Fix: Check git status before every commit to see what's staged vs. unstaged. Or use git commit -am "message" which stages and commits all tracked (already-added) modified files in one step. Note: -a doesn't add brand-new untracked files — only files Git is already tracking.
Mistake 5: Running git push without setting the remote first
fatal: 'origin' does not appear to be a git repository
Fix: Link to the remote before pushing:
git remote add origin https://github.com/username/repo.git
git push -u origin main
Mistake 6: Initializing in the wrong directory
If you run git init from your home directory by accident, Git will track everything in your home folder.
Fix: Always cd to your specific project folder first, then run git init. Check where you are with pwd (Mac/Linux) or cd alone (Windows).
Frequently Asked Questions
What happens immediately after git init?
Git creates a hidden .git folder in the current directory. Your project files are untouched. The repository is empty — no commits yet, no history. Git is now watching the folder but hasn't recorded anything.
Can I delete the .git folder?
Yes. Deleting .git removes all Git tracking, history, branches, and configuration. Your project files remain. The directory becomes an ordinary folder again. This is how you "un-Git" a project.
Does git init delete or change my existing files?
No. git init only creates the .git folder. It never touches your existing project files.
Do I need to run git init every time I start working on a project?
No — only once per project. After initialization, the .git folder persists and Git keeps tracking the project until you delete it.
What is HEAD in Git? HEAD is a pointer to the current branch you're on. When you make a commit, HEAD (via the branch it points to) updates to point to the new commit. When you switch branches, HEAD updates to point to the new branch. It tells Git "this is where you currently are."
Can I rename the default branch from master to main after init?
Yes:
git branch -m master main
This renames your local branch. If you've already pushed to GitHub, you'll also need to update the remote default branch in GitHub's repository settings.
What is the difference between git init and git clone?
git init creates a new, empty repository locally. git clone downloads an existing repository (with all its history) from a remote URL. Use git init when starting from scratch, git clone when starting from an existing project.
What is a bare repository (git init --bare)?
A bare repository has no working directory — only the .git contents, stored directly in the root folder. You can't edit files in a bare repository; it's only used as a remote that other developers push to and pull from. GitHub stores your repositories as bare repositories on their servers.
Is it safe to run git init in a directory that's already a Git repository?
Yes — it reinitializes the existing repository without deleting any history or data. Git will output "Reinitialized existing Git repository." This is occasionally useful for resetting hooks or configuration.
Why does my terminal show (master) instead of (main) after git init?
Your Git version or configuration defaults to master. Set the global default:
git config --global init.defaultBranch main
Then new repositories will use main. For the current one: git branch -m master main.
Quick Reference Card
# Initialize new repository
git init
# Initialize in a new directory
git init my-project
# Check status
git status
# Stage all files
git add .
# Stage specific file
git add filename.txt
# Make first commit
git commit -m "Initial commit"
# Connect to GitHub
git remote add origin https://github.com/username/repo.git
# Push to GitHub (first time)
git push -u origin main
# Push to GitHub (subsequent times)
git push
Conclusion
git init is one command, but understanding what it does — creating the .git folder, setting up the object store, the HEAD reference, the branch pointer — turns Git from a collection of magic incantations into a coherent system that makes sense.
The workflow after git init is always the same pattern: edit files, stage changes with git add, record a snapshot with git commit, and push to a remote with git push. That loop is the foundation of every Git workflow, from a solo student project to a multi-thousand-developer open source codebase.
Start with a project you're actually working on. Run git init. Make your first commit. Push it to GitHub. The concepts become concrete very quickly once you're doing them for real rather than just reading about them.
For the next steps in your Git journey, see: How to Use git add and git commit, Branching and Merging in Git, How to Work with GitHub Repositories, and the Big Tech Roadmap for CS Students which covers where Git fits in the broader software engineering skill set.
0 Comments