How to convert Git repo to bare repo

Converting Git repository to bare repository creates server-side storage without working directory for central repository and backup purposes. With over 25 years of software development experience and as the creator of CoreUI, I’ve set up numerous bare repositories for team collaboration. Bare repositories contain only Git metadata and history without checked-out files, ideal for remote repositories and backup storage. This approach enables proper central repository setup for teams and efficient backup strategies without workspace overhead.

Use git clone –bare to create bare repository or convert existing repository by removing working directory configuration.

Convert existing repository to bare:

# Method 1: Clone as bare repository
cd /path/to/original-repo
git clone --bare . /path/to/bare-repo.git

# Verify it's bare
cd /path/to/bare-repo.git
git config --get core.bare
# Output: true

# Method 2: In-place conversion
cd /path/to/repo
mv .git ../repo.git
cd ../repo.git
git config --bool core.bare true
rm -rf ../repo  # Remove old working directory

Create bare repository from scratch:

# Initialize bare repository
git init --bare my-project.git

# Clone from existing repository
git clone --bare https://github.com/user/repo.git repo.git

Set up as central repository:

# On server
cd /var/git
git clone --bare /path/to/local/repo.git project.git

# Set proper permissions
sudo chown -R git:git project.git
sudo chmod -R 755 project.git

# On client machines
git clone git@server:/var/git/project.git

# Set up origin
cd project
git remote add origin git@server:/var/git/project.git
git push -u origin main

Bare repository structure:

# Regular repository
repo/
├── .git/           # Git metadata
├── src/            # Working files
├── README.md
└── package.json

# Bare repository
repo.git/
├── branches/
├── config
├── description
├── HEAD
├── hooks/
├── info/
├── objects/
└── refs/

Mirror existing repository:

# Create bare mirror
git clone --mirror https://github.com/user/repo.git repo.git

# Mirror includes all refs (branches, tags, notes)
cd repo.git
ls refs/
# Output: heads/ tags/ remotes/

# Push mirror to new location
git push --mirror https://github.com/user/new-repo.git

Convert bare back to regular:

# Clone bare repository as regular
git clone /path/to/bare-repo.git regular-repo

# Or convert in place
cd bare-repo.git
git config --bool core.bare false
git checkout main  # Restore working directory

Backup strategy with bare:

#!/bin/bash
# backup-repositories.sh

REPOS_DIR="/var/git"
BACKUP_DIR="/backups/git"
DATE=$(date +%Y%m%d)

mkdir -p "$BACKUP_DIR/$DATE"

# Backup all bare repositories
for repo in "$REPOS_DIR"/*.git; do
  repo_name=$(basename "$repo")
  echo "Backing up $repo_name..."

  # Clone as bare
  git clone --bare "$repo" "$BACKUP_DIR/$DATE/$repo_name"

  # Or create tarball
  tar -czf "$BACKUP_DIR/$DATE/$repo_name.tar.gz" -C "$REPOS_DIR" "$repo_name"
done

echo "Backup completed: $BACKUP_DIR/$DATE"

Shared bare repository setup:

# Initialize shared repository
git init --bare --shared=group project.git

# This sets core.sharedRepository to group
cd project.git
git config --get core.sharedRepository
# Output: group

# Set group ownership
sudo chown -R :developers project.git
sudo chmod -R g+rw project.git

# Find proper permission mode
find . -type d -exec chmod g+s {} \;

Git hooks in bare repository:

# Bare repositories are ideal for server-side hooks
cd bare-repo.git/hooks

# Create post-receive hook for deployment
cat > post-receive <<'EOF'
#!/bin/bash
# Deploy on push

TARGET="/var/www/html"
GIT_DIR="/var/git/project.git"

while read oldrev newrev ref
do
  if [ "$ref" = "refs/heads/main" ]; then
    echo "Deploying main branch..."
    git --work-tree="$TARGET" --git-dir="$GIT_DIR" checkout -f main
    echo "Deployment complete"
  fi
done
EOF

chmod +x post-receive

Update bare repository:

# Fetch updates in bare repository
cd bare-repo.git
git fetch origin '+refs/heads/*:refs/heads/*' --prune

# Or use mirror option
git remote update --prune

Multiple remotes with bare:

# Bare repository can be central hub
cd project.git

# Add multiple remotes
git remote add github https://github.com/user/repo.git
git remote add gitlab https://gitlab.com/user/repo.git
git remote add bitbucket https://bitbucket.org/user/repo.git

# Sync to all remotes
git push --mirror github
git push --mirror gitlab
git push --mirror bitbucket

Verify bare repository:

# Check if repository is bare
git config --get core.bare
# Should return: true

# List all branches
git branch -a

# List all tags
git tag -l

# View repository info
git show-ref

# Check repository size
du -sh .

Clone specific branch from bare:

# Clone only main branch
git clone --single-branch --branch main /path/to/bare-repo.git

# Clone with specific depth
git clone --depth 1 /path/to/bare-repo.git

Maintenance on bare repository:

# Run garbage collection
cd bare-repo.git
git gc --aggressive --prune=now

# Verify integrity
git fsck --full

# Optimize repository
git repack -a -d -f --depth=250 --window=250

# Show repository statistics
git count-objects -v

Access control for bare repository:

# On server with SSH access
# Create git user
sudo adduser git

# Set up SSH keys
sudo su - git
mkdir ~/.ssh
chmod 700 ~/.ssh
touch ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

# Add developer SSH keys
cat dev1.pub >> ~/.ssh/authorized_keys
cat dev2.pub >> ~/.ssh/authorized_keys

# Create repositories directory
mkdir -p ~/repositories
cd ~/repositories

# Initialize bare repository
git init --bare project.git

Automated sync script:

#!/bin/bash
# sync-bare-repo.sh

BARE_REPO="/var/git/project.git"
UPSTREAM="https://github.com/upstream/project.git"

cd "$BARE_REPO"

echo "Fetching from upstream..."
git fetch "$UPSTREAM" '+refs/heads/*:refs/heads/*' --prune

echo "Updating all branches..."
git branch -a | grep -v HEAD | sed 's/remotes\/origin\///' | while read branch; do
  echo "Updating $branch"
  git update-ref "refs/heads/$branch" "refs/remotes/origin/$branch"
done

echo "Sync complete"

Documentation and usage:

# Create README for bare repository
cat > description <<EOF
Project Name Repository
Bare repository for team collaboration
Clone with: git clone git@server:/var/git/project.git
EOF

# View description
cat description

Best Practice Note

Use git clone –bare to create bare repositories for server storage. Bare repositories have no working directory and contain only Git metadata. Use .git extension for bare repository directory names by convention. Set core.sharedRepository for team access. Configure server-side hooks in bare repositories. Use bare repositories for central team repository and backups. Run maintenance commands regularly on bare repositories. Never directly modify files in bare repository. This is how we manage bare repositories for CoreUI projects—central repository setup with proper permissions, automated backups, and server-side hooks for deployment workflows.


Speed up your responsive apps and websites with fully-featured, ready-to-use open-source admin panel templates—free to use and built for efficiency.


About the Author