Run git init in your project directory to create a new Git repository. For a bare repository (used on servers), run git init --bare. That's it — you're now tracking changes.
✦ Definition~90s read
What is Git Init?
git init creates a new Git repository by initializing a .git subdirectory with the necessary metadata, objects, and refs. It's the first command you run to start tracking a project with Git.
★
Think of git init as installing a security camera system in your house.
Plain-English First
Think of git init as installing a security camera system in your house. Before you install it, nothing is recorded. After git init, every change you make is watched and can be replayed. The .git folder is the DVR — it stores all the footage. Without it, you have no history, no undo, no blame.
You just deleted a file you worked on for three hours. No undo. No backup. That sinking feeling? That's why Git exists. And it all starts with one command: git init. Most tutorials gloss over it — run the command, done. But get it wrong and you'll be fighting your tool instead of shipping code. Here's what nobody tells you: git init is not just a setup step. It's a decision point that affects how you collaborate, deploy, and recover from disasters. By the end of this, you'll know exactly when to use git init, git init --bare, and how to avoid the footguns that have burned teams I've worked with.
What git init Actually Does Under the Hood
When you run git init, Git creates a .git directory in your project root. This directory is the repository — everything else is just your working tree. Inside .git, you get: objects/ (all your data), refs/ (branches and tags), HEAD (current branch pointer), and a config file. That's it. No magic. No remote. No commits yet. You're just telling Git 'I want you to watch this folder.' The first time you run git add and git commit, Git starts populating the object database. Until then, your repo is empty — a newborn baby with a name but no memories.
explore-git-init.shBASH
1
2
3
4
5
6
7
// io.thecodeforge — DevOps tutorial
mkdir my-project
cd my-project
git init
ls -la .git
# Output shows the skeleton of a Git repository
Output
total 16
drwxr-xr-x 7 user staff 224 Mar 15 10:00 .
drwxr-xr-x 3 user staff 96 Mar 15 10:00 ..
-rw-r--r-- 1 user staff 23 Mar 15 10:00 HEAD
drwxr-xr-x 2 user staff 64 Mar 15 10:00 branches
drwxr-xr-x 4 user staff 128 Mar 15 10:00 config
drwxr-xr-x 2 user staff 64 Mar 15 10:00 description
drwxr-xr-x 14 user staff 448 Mar 15 10:00 hooks
drwxr-xr-x 3 user staff 96 Mar 15 10:00 info
drwxr-xr-x 4 user staff 128 Mar 15 10:00 objects
drwxr-xr-x 4 user staff 128 Mar 15 10:00 refs
Senior Shortcut:
Run git init inside an existing project with files — it won't touch them. Git only starts tracking files after you git add them. So git init is safe to run anytime.
Bare Repos: The Server-Side Secret
If you're setting up a central repository that multiple developers push to — like on a server or GitHub Enterprise — you need a bare repository. A bare repo has no working tree. It only contains the .git directory contents. Why? Because if someone pushes to a non-bare repo, Git would try to update the working tree files, which can cause conflicts and data loss. That's why git push to a non-bare repo is rejected by default. The fix: initialize with git init --bare. The --bare flag tells Git to skip the working tree and create only the database. This is how all remote repos on servers should be set up.
setup-bare-repo.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// io.thecodeforge — DevOps tutorial
# On the server
mkdir /var/git/my-project.git
cd /var/git/my-project.git
git init --bare
# On a client machine
git clone ssh://user@server/var/git/my-project.git
cd my-project
echo "hello" > README.md
git add README.md
git commit -m "first commit"
git push origin main
Output
Cloning into 'my-project'...
warning: You appear to have cloned an empty repository.
Never run git init (without --bare) on a server that you intend to push to. You'll get refusing to update checked out branch errors. I've seen this bring down CI/CD pipelines because the deploy script assumed a bare repo.
Reinitializing an Existing Repo: Safe or Not?
Running git init on an already initialized repo is safe. Git will just reinitialize the .git directory — it won't delete your commits or branches. It's a no-op if the repo already exists. But there's a catch: if you run git init --bare on a non-bare repo, you'll lose your working tree. The command will convert it to bare, but Git will warn you. Don't do it unless you're sure. The safe way to convert a non-bare to bare is to clone it with --bare.
reinit-safe.shBASH
1
2
3
4
5
// io.thecodeforge — DevOps tutorial
cd my-project
git init # safe, even if already a repo
git status # still shows your working tree
Output
Reinitialized existing Git repository in /Users/user/my-project/.git/
On branch main
nothing to commit, working tree clean
Never Do This:
Don't run git init --bare on a repo that has a working tree with uncommitted changes. You'll lose those files. Always commit or stash first.
Customizing Your Initialization with Templates
You can customize what goes into .git when you run git init using a template directory. Templates let you pre-populate hooks, config, or even a default .gitignore. This is useful for enforcing company policies — like a commit-msg hook that checks for ticket numbers. Use git init --template=/path/to/template. Git ships with a default template at /usr/share/git-core/templates/. You can override it globally with git config --global init.templateDir /path/to/template.
Set init.templateDir globally so every new repo gets your hooks. But be careful — hooks are not pushed to remotes. Each developer needs their own setup.
git init vs git clone: When to Use Which
git init creates a new repo from scratch. git clone copies an existing repo. If you're starting a new project, use git init. If you're contributing to an existing project, use git clone. But here's the nuance: you can git init and then add a remote — that's essentially what git clone does internally. git clone is just git init + git remote add + git fetch + git checkout. So if you need fine-grained control (like shallow clone or specific branch), you might git init manually. But 99% of the time, just git clone.
Interviewers love asking 'What's the difference between git init and git clone?' The real answer: git clone is git init plus remote setup and fetch. But git init gives you more control — like --template or --bare.
● Production incidentPOST-MORTEMseverity: high
The Bare Repo That Wasn't
Symptom
Team couldn't push to the central repo. Error: refusing to update checked out branch.
Assumption
Assumed a permissions issue on the server.
Root cause
Someone ran git init (non-bare) on the server and then tried to push to it. Git refuses to push to a non-bare repo because it would overwrite the working tree.
Fix
Re-initialized the server repo with git init --bare. Then reconfigured remotes on all clients.
Key lesson
Always use git init --bare for central/shared repositories.
Non-bare repos are for local work only.
Production debug guideSystematic recovery paths for the failure modes engineers actually hit.3 entries
Symptom · 01
fatal: Not a git repository when running git commands in a directory that should be a repo
→
Fix
1. Check if .git exists: ls -la .git. 2. If missing, run git init. 3. If .git exists but is corrupted, delete it and re-init (but you'll lose local history — better to clone from remote).
Symptom · 02
refusing to update checked out branch on push
→
Fix
1. SSH into the server. 2. Check if the remote repo is bare: ls -la /path/to/repo — if it has a HEAD file at the root, it's non-bare. 3. Convert to bare: git clone --bare /path/to/repo /path/to/repo.git then update remotes.
Symptom · 03
fatal: destination path '.' already exists when running git init in a non-empty directory
→
Fix
1. This is not an error — Git still initializes. 2. Check with git status. 3. If you wanted to clone into this directory, use git clone repo-url . (note the dot).
★ Git Init Triage Cheat SheetFirst-response commands for when things go wrong — copy-paste ready.
`fatal: Not a git repository`−
Immediate action
Check if you're in the right directory
Commands
ls -la .git
git init
Fix now
Run git init in the project root.
`refusing to update checked out branch`+
Immediate action
Check if remote is bare
Commands
ssh server 'ls -la /repo/path'
git remote -v
Fix now
Re-init server repo with git init --bare and update remotes.
`fatal: destination path '.' already exists`+
Immediate action
It's fine — just check status
Commands
git status
Fix now
No fix needed. Git initialized successfully.
Lost working tree after `git init --bare`+
Immediate action
Stop! Do not run any more commands
Commands
git fsck --lost-found
git stash
Fix now
Recover from reflog: git reflog then git checkout <commit>.
Feature
git init
git init --bare
Working tree
Yes
No
Use case
Local development
Central/shared repo
Can push to
No (rejected by default)
Yes
Contains .git
Yes
Yes (contents at root)
Typical location
Project directory
Server directory
⚙ Quick Reference
5 commands from this guide
File
Command / Code
Purpose
explore-git-init.sh
mkdir my-project
What git init Actually Does Under the Hood
setup-bare-repo.sh
mkdir /var/git/my-project.git
Bare Repos
reinit-safe.sh
cd my-project
Reinitializing an Existing Repo
custom-template.sh
mkdir ~/.git-templates
Customizing Your Initialization with Templates
init-vs-clone.sh
git init my-repo
git init vs git clone
Key takeaways
1
git init creates a .git directory
the heart of your repository. Without it, Git doesn't exist.
2
Always use git init --bare for shared/central repositories. Non-bare repos are for local work only.
3
Running git init on an existing repo is safe
it's a no-op. But git init --bare on a non-bare repo can lose your working tree.
4
Templates (--template) let you enforce company policies like commit hooks from the start.
INTERVIEW PREP · PRACTICE MODE
Interview Questions on This Topic
Q01JUNIOR
What happens when you run `git init` on an existing repository?
Q02SENIOR
Why does Git refuse to push to a non-bare repository by default?
Q03SENIOR
How would you set up a Git server from scratch using only `git init`?
Q04SENIOR
What's the difference between `git init` and `git init --template`?
Q05SENIOR
Can you convert a non-bare repo to bare without losing history?
Q06SENIOR
How would you design a Git workflow for a team of 50 developers using on...
Q01 of 06JUNIOR
What happens when you run `git init` on an existing repository?
ANSWER
It's a no-op. Git reinitializes the .git directory but doesn't delete any objects or refs. It's safe to run multiple times.
Q02 of 06SENIOR
Why does Git refuse to push to a non-bare repository by default?
ANSWER
Because pushing to a non-bare repo would update the working tree, potentially overwriting uncommitted changes or causing conflicts. The receive.denyCurrentBranch config controls this. In a bare repo, there's no working tree, so it's safe.
Q03 of 06SENIOR
How would you set up a Git server from scratch using only `git init`?
ANSWER
On the server, create a directory and run git init --bare. Then on clients, clone using SSH or HTTP. For multiple users, set up proper permissions and consider using git-shell for restricted access.
Q04 of 06SENIOR
What's the difference between `git init` and `git init --template`?
ANSWER
--template allows you to specify a directory whose contents are copied into the new .git directory. This is useful for pre-populating hooks, config, or a default .gitignore. Without it, Git uses the default template.
Q05 of 06SENIOR
Can you convert a non-bare repo to bare without losing history?
ANSWER
Yes. The safest way is to clone it with --bare: git clone --bare non-bare-repo bare-repo.git. Alternatively, you can manually move the .git contents and update the config, but cloning is safer.
Q06 of 06SENIOR
How would you design a Git workflow for a team of 50 developers using only `git init`?
ANSWER
Use a central bare repo on a server. Developers clone from it, work on feature branches, and push. Use hooks (pre-receive) to enforce policies. For large teams, consider a Git hosting service like GitHub or GitLab to manage access and code review.
01
What happens when you run `git init` on an existing repository?
JUNIOR
02
Why does Git refuse to push to a non-bare repository by default?
SENIOR
03
How would you set up a Git server from scratch using only `git init`?
SENIOR
04
What's the difference between `git init` and `git init --template`?
SENIOR
05
Can you convert a non-bare repo to bare without losing history?
SENIOR
06
How would you design a Git workflow for a team of 50 developers using only `git init`?
SENIOR
FAQ · 4 QUESTIONS
Frequently Asked Questions
01
What does git init do?
It creates a new Git repository by initializing a .git subdirectory with the necessary metadata. After running git init, you can start tracking changes with git add and git commit.
Was this helpful?
02
What's the difference between git init and git init --bare?
git init creates a repository with a working tree (your project files). git init --bare creates a repository without a working tree — it only contains the Git database. Bare repos are used on servers to accept pushes.
Was this helpful?
03
How do I create a Git repository in an existing project?
Navigate to your project directory and run git init. It won't affect your existing files. Then use git add . to stage all files and git commit to create the first commit.
Was this helpful?
04
Can I undo git init?
Yes, simply delete the `.git` directory:rm -rf .git. This removes all Git history and tracking. Your project files remain untouched.