git
version control
git init
bare repository
programming

What is the difference between git init and git init --bare?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

git init creates a working repository where you edit files and make commits. git init --bare creates a bare repository that stores only Git's internal data (commits, branches, objects) without a working directory. Bare repositories are used as shared remote servers (like GitHub). You push to them and pull from them but never edit files directly in them. Working repositories are where you do your actual development.

git init (Working Repository)

bash
1mkdir my-project
2cd my-project
3git init
4# Initialized empty Git repository in /path/my-project/.git/

This creates:

 
1my-project/
2├── .git/           # Git metadata (hidden)
3│   ├── HEAD
4│   ├── config
5│   ├── objects/
6│   ├── refs/
7│   └── ...
8├── src/            # Your working files
9├── README.md       # Your working files
10└── ...

You work directly in my-project/, editing files, staging with git add, and committing with git commit. The .git/ subdirectory stores all version history.

git init --bare (Bare Repository)

bash
1mkdir my-project.git
2cd my-project.git
3git init --bare
4# Initialized empty Git repository in /path/my-project.git/

This creates:

 
1my-project.git/
2├── HEAD
3├── config
4├── objects/
5├── refs/
6└── ...

No working directory, no .git/ subdirectory. The Git data lives at the top level. By convention, bare repositories are named with a .git suffix.

Key Differences

Featuregit initgit init --bare
Working directoryYes (edit files)No
.git/ subdirectoryYesNo (Git data is at root)
Can git add/git commitYesNo
Accepts git pushNot recommendedYes (designed for this)
Use caseDevelopmentShared remote/server
Conventionmy-project/my-project.git/

Why Not Push to a Non-Bare Repository?

bash
1# On a working repository, push updates the branch but NOT the working files
2# This creates a confusing mismatch
3
4# Server (non-bare)
5cd /server/my-project
6git init
7echo "hello" > file.txt
8git add . && git commit -m "Initial"
9
10# Developer
11git clone /server/my-project dev-copy
12cd dev-copy
13echo "updated" > file.txt
14git add . && git commit -m "Update"
15git push origin main
16
17# Back on server:
18cat file.txt
19# hello  ← Still shows old content!
20# The branch moved forward but the working directory is out of sync

Git warns you about this:

 
remote: error: refusing to update checked out branch: refs/heads/main

Bare repositories avoid this problem by having no working directory to get out of sync.

Setting Up a Shared Repository

bash
1# Create bare repo on server
2ssh server
3mkdir /srv/git/my-project.git
4cd /srv/git/my-project.git
5git init --bare
6
7# Developer 1: push existing project
8cd my-project
9git remote add origin server:/srv/git/my-project.git
10git push -u origin main
11
12# Developer 2: clone
13git clone server:/srv/git/my-project.git

This is exactly what GitHub, GitLab, and Bitbucket do. They host bare repositories.

Converting Between Types

bash
1# Working → Bare
2cd my-project
3git clone --bare . /path/my-project.git
4
5# Bare → Working
6git clone /path/my-project.git my-project

You cannot directly convert a working repo to bare by deleting the working files. Use git clone --bare to create a proper bare copy.

Bare Repository Configuration

bash
1# Check if a repo is bare
2git config --get core.bare
3# true (bare) or false (working)
4
5# Bare repos often have additional config
6cd my-project.git
7cat config
8# [core]
9#     repositoryformatversion = 0
10#     filemode = true
11#     bare = true

Hooks in Bare Repositories

Bare repos support server-side hooks:

bash
1# my-project.git/hooks/post-receive
2#!/bin/bash
3# Deploy on push
4while read oldrev newrev ref; do
5    if [ "$ref" = "refs/heads/main" ]; then
6        echo "Deploying main branch..."
7        GIT_WORK_TREE=/var/www/app git checkout -f main
8    fi
9done
bash
chmod +x hooks/post-receive

post-receive runs after a push is accepted. This is how many deployment pipelines work.

Mirror Repository

bash
1# Create a mirror (bare repo that tracks all refs)
2git clone --mirror https://github.com/user/repo.git
3
4# Update the mirror
5cd repo.git
6git fetch --all
7
8# Push mirror to another remote
9git push --mirror https://other-server.com/repo.git

--mirror creates a bare clone that includes all refs (branches, tags, notes). Used for backups and migrations.

Multiple Remotes Workflow

bash
1# Bare repo as central hub
2git init --bare /srv/git/project.git
3
4# Developer A
5git clone /srv/git/project.git project-a
6cd project-a
7# work, commit, push
8
9# Developer B
10git clone /srv/git/project.git project-b
11cd project-b
12git pull  # Gets Developer A's changes

Common Pitfalls

  • Pushing to non-bare repos: Git refuses pushes to the currently checked-out branch of a working repository. Use a bare repo as the remote, or configure receive.denyCurrentBranch (not recommended).
  • Editing files in bare repos: There are no working files to edit. To change content, clone the bare repo, edit in the clone, and push back.
  • Forgetting the .git suffix: Convention is to name bare repos with .git (e.g., project.git). This is not required but helps distinguish bare from working repos.
  • Permissions: On shared servers, set git init --bare --shared=group to allow multiple users to push. Without --shared, filesystem permissions may block other users.
  • Shallow clones from bare repos: git clone --depth 1 from a bare repo works but the bare repo must have the full history. You cannot create a "shallow bare" repo.

Summary

  • git init creates a working repository for development (edit, add, commit)
  • git init --bare creates a server repository for sharing (push, pull, no working files)
  • Bare repos have no working directory. Git data lives at the top level
  • Never push to a non-bare repository's checked-out branch
  • Use bare repos for shared remotes, CI/CD, and deployment hooks
  • GitHub/GitLab/Bitbucket all host bare repositories internally

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.