↓Перейти к содержанию
  1. Git: руководства и команды/

git init --bare: создание голого репозитория для совместной работы

·9 минут·

Bare репозиторий (голый репозиторий) — Git репозиторий без рабочей директории. Он содержит только содержимое папки .git, но без файлов проекта. Bare репозитории используются как центральные серверы: в них можно делать git push, но нельзя работать напрямую.

Что такое bare репозиторий #

Обычный репозиторий состоит из двух частей:

  • Рабочая директория (файлы проекта, которые вы редактируете)
  • Git хранилище (папка .git со всей историей)

Bare репозиторий — только Git хранилище, без рабочей директории:

Обычный репозиторий:
my-project/
├── .git/         ← Git хранилище
├── src/
├── README.md
└── package.json

Bare репозиторий:
my-project.git/   ← только Git хранилище (без .git папки)
├── HEAD
├── config
├── objects/
└── refs/

Создание bare репозитория #

# Создать новый bare репозиторий
git init --bare my-project.git
# Initialized empty Git repository in /home/user/my-project.git/

# Содержимое bare репозитория
ls my-project.git/
# HEAD  config  description  hooks  info  objects  refs

# Конвертировать существующий репозиторий в bare
git clone --bare /path/to/my-project my-project.git
# Это создаёт bare копию существующего репозитория

# Создать bare с правами для группы (для сервера)
git init --bare --shared=group my-project.git

Push в bare репозиторий #

Главная особенность bare репозитория — в него можно делать git push:

# Настроить remote
git remote add origin /home/git/repos/my-project.git

# Push работает
git push origin main
# Counting objects: 3, done.
# Writing objects: 100% (3/3), 221 bytes | 221.00 KiB/s, done.
# To /home/git/repos/my-project.git
#  * [new branch]      main -> main

# Pull тоже работает
git pull origin main

# В обычный репозиторий с рабочей директорией push не работает
git push         # может привести к ошибке или непредсказуемому поведению

Почему нельзя делать push в обычный репозиторий? Потому что Git не знает что делать с рабочей директорией — у неё могут быть несохранённые изменения, и перезапись HEAD была бы опасна.

Использование как локальный сервер #

# Создать центральный репозиторий
mkdir -p /srv/git
cd /srv/git
git init --bare myapp.git

# Разработчик 1: клонировать
git clone /srv/git/myapp.git ~/myapp
cd ~/myapp
echo "Hello" > README.md
git add README.md
git commit -m "Initial commit"
git push origin main

# Разработчик 2: клонировать и получить изменения
git clone /srv/git/myapp.git ~/myapp2
cd ~/myapp2
git log --oneline
# abc1234 Initial commit  ← видит коммит от разработчика 1

Использование по SSH #

# На сервере (user: git, host: server.example.com)
ssh [email protected]
mkdir -p /home/git/repos
cd /home/git/repos
git init --bare myapp.git
exit

# Локально
git remote add origin [email protected]:/home/git/repos/myapp.git
git push origin main

# Клонировать
git clone [email protected]:/home/git/repos/myapp.git

Конфигурация bare репозитория #

Файл config в bare репозитории:

cat my-project.git/config
[core]
    repositoryformatversion = 0
    filemode = true
    bare = true              ← ключевой флаг
[receive]
    denyCurrentBranch = ignore
# Разрешить push непосредственно в проверяемую ветку
# (для обычных репозиториев, не bare)
git config receive.denyCurrentBranch updateInstead
# Тогда push обновит и рабочую директорию

bare vs mirror #

# --bare: голый репозиторий (для совместной работы)
git clone --bare https://github.com/user/project.git

# --mirror: зеркало (полная копия всех refs для резервного копирования)
git clone --mirror https://github.com/user/project.git
# Включает все ссылки: ветки, теги, refs/pull/, refs/notes/ и т.д.

# Обновить зеркало
cd project.git
git remote update  # или git fetch --all

Проверка что репо является bare #

Как узнать содержит ли репо рабочую директорию:

# Прямая проверка конфига
git rev-parse --is-bare-repository
# true  ← это bare репо
# false ← это обычный репо с рабочей директорией

# Также можно проверить файл config
cat my-project.git/config | grep bare
# bare = true

# Или посмотреть структуру:
ls my-project.git/
# Если есть только: HEAD, config, objects, refs, hooks, info
# и НЕТУ других файлов — это bare репо

ls my-project/
# Если видите: .git/, src/, README.md, package.json
# Это обычный репо

git clone –bare vs git init –bare #

Различие между двумя способами создания bare репо:

# git init --bare — создать пустой bare репо
git init --bare my-project.git
# Создаёт: HEAD, config, objects/, refs/, hooks/, info/
# Ничего больше

# git clone --bare — создать bare копию существующего репо
git clone --bare /path/to/my-project /tmp/my-project.git
# Копирует: всю историю, все ветки, все теги
# Но без рабочей директории

# Результат разный:
# init --bare:    пустой, готов для первого push
# clone --bare:   полная копия с историей

# Обновить bare копию (зеркало)
cd /tmp/my-project.git
git fetch origin
# или
git remote update

Использование bare репо как backup #

Bare репозиторий удобен для резервных копий:

# Способ 1: Прямая копия через clone --bare
git clone --bare /path/to/project /backup/project.git

# Способ 2: Периодическая синхронизация (cron job)
#!/bin/bash
# backup-git.sh
cd /backup/project.git
git fetch origin
git fetch --tags origin

# Добавить в crontab (каждый час)
0 * * * * /scripts/backup-git.sh

# Способ 3: Git как хранилище для CI/CD артефактов
# Использовать bare репо на сервере для хранения:
# - Release artifacts
# - Build outputs
git clone --bare . /ci-artifacts/build-$(date +%Y%m%d).git

# Способ 4: Mirror для full backup (все refs)
git clone --mirror https://github.com/user/project.git
cd project.git
git remote set-url origin https://github.com/user/project.git
git fetch --all  # обновить всё

Post-receive hook для автоматического деплоя #

Автоматизация деплоя при push:

# Создать hook
cat > /srv/git/myapp.git/hooks/post-receive << 'EOF'
#!/bin/bash

# Получить информацию о push
while read oldrev newrev refname; do
    echo "Received push to $refname ($oldrev -> $newrev)"

    # Если push в main ветку
    if [ "$refname" = "refs/heads/main" ]; then
        echo "Deploying main branch..."

        # Checkout в рабочую директорию
        git --work-tree=/var/www/myapp \
            --git-dir=/srv/git/myapp.git \
            checkout -f main

        # Запустить build скрипт
        cd /var/www/myapp
        ./scripts/deploy.sh

        # Отправить уведомление
        echo "Deploy complete!" | \
            mail -s "Deploy successful" [email protected]
    fi
done
EOF

chmod +x /srv/git/myapp.git/hooks/post-receive

Параметры в post-receive hook:

# Получить информацию о пользователе
GIT_COMMITTER_NAME=$GL_USERNAME  # GitLab
REMOTE_USER=$USER                # SSH

# Получить список файлов в push
git diff-tree --no-commit-id -r $newrev

# Получить автора последнего коммита
git log -1 --format=%an $newrev

# Проверить какие файлы изменились
git diff --name-only $oldrev $newrev

# Отправить email со ссылкой на deploy
echo "Deployed: https://example.com/releases/$newrev"

Bare репо для team collaboration #

Настройка для совместной работы нескольких разработчиков:

# На сервере: создать пользователя git
sudo useradd -m git
sudo mkdir -p /home/git/.ssh

# Настроить права доступа
sudo chmod 700 /home/git/.ssh
sudo chown -R git:git /home/git/.ssh

# Добавить публичные ключи разработчиков
# Каждый разработчик генерирует ключ:
ssh-keygen -t ed25519 -f ~/.ssh/git_key -N ""

# Сервер: добавить ключи в authorized_keys
cat developer1-key.pub >> /home/git/.ssh/authorized_keys
cat developer2-key.pub >> /home/git/.ssh/authorized_keys

# Настроить права на директорию репо
sudo mkdir -p /srv/git
sudo chown git:git /srv/git
sudo chmod 770 /srv/git  # git пользователь и группа

# Создать bare репо
cd /srv/git
sudo -u git git init --bare --shared=group myapp.git

# Разработчики подключаются
git clone git@server:/srv/git/myapp.git
cd myapp

# Разработчик 1
git switch -c feature/login
git commit -am "Add login form"
git push origin feature/login

# Разработчик 2
git fetch origin
git switch -b feature/login origin/feature/login
# Или работать в своей ветке
git switch -c feature/auth

Хуки в bare репозитории #

Bare репозитории поддерживают серверные хуки:

# post-receive хук — срабатывает после push
cat > my-project.git/hooks/post-receive << 'EOF'
#!/bin/bash
echo "Received push, deploying..."
git --work-tree=/var/www/myapp --git-dir=/srv/git/myapp.git checkout -f main
echo "Deploy complete"
EOF
chmod +x my-project.git/hooks/post-receive

# Теперь при каждом push на сервер
# автоматически обновляется /var/www/myapp

Работа с bare репозиторием напрямую #

# Просмотр истории в bare репозитории
git --git-dir=/srv/git/myapp.git log --oneline

# Список веток
git --git-dir=/srv/git/myapp.git branch -a

# Просмотр файла из bare репозитория
git --git-dir=/srv/git/myapp.git show HEAD:README.md

# Создать ветку в bare репозитории
git --git-dir=/srv/git/myapp.git branch feature/new-ui main

Различие между –bare и –mirror #

Оба варианта создают репо без рабочей директории, но отличаются:

# git clone --bare
# Копирует: refs/heads/* (ветки)
#          refs/tags/* (теги)
# Игнорирует: refs/pull/* (GitHub pull requests)
#             refs/notes/* (git notes)
git clone --bare https://github.com/user/project.git

# git clone --mirror
# Копирует: ВСЕ refs
#          refs/heads/* (ветки)
#          refs/tags/* (теги)
#          refs/pull/* (pull requests как refs)
#          refs/notes/* (notes)
# Идеально для полного зеркала GitHub
git clone --mirror https://github.com/user/project.git

# Обновить bare репо
cd project.git
git fetch  # только новые ветки/теги

# Обновить mirror репо
cd project.git
git remote update  # всё, включая pull requests

Выбор:

  • --bare для работающего репозитория
  • --mirror для резервной копии или зеркала

Конвертация обычного репо в bare #

Если нужно преобразовать существующий репозиторий:

# Способ 1: Через clone --bare
cd /path/to/my-project
git clone --bare . ../my-project.git

# Способ 2: Вручную скопировать .git и изменить config
# Скопировать содержимое .git
cp -r /path/to/my-project/.git ../my-project.git

# Отредактировать config
cat ../my-project.git/config
# Изменить bare = true

# Или через команду
git config -f ../my-project.git/config core.bare true

# Способ 3: Из обычного репо сделать bare (в сам себе — опасно)
# НЕ ДЕЛАЙТЕ так! Используйте способы 1 или 2
# git --git-dir=.git config core.bare true

Использование bare репо в CI/CD #

Bare репозиторий часто используется в CI/CD пайплайнах:

# Gitlab Runner, GitHub Actions, Jenkins могут
# клонировать из bare репо без лишних затрат

# Пример: использовать как artifact store в CI
# .gitlab-ci.yml
stages:
  - build
  - push_cache

build:
  script:
    - ./build.sh
  artifacts:
    paths:
      - build/

push_cache:
  script:
    # Сохранить результат в bare репо (как cache)
    - git init --bare cache.git
    - git --git-dir=cache.git config receive.denyCurrentBranch ignore
    # Push build артефактов
    - tar czf build.tar.gz build/
    - git add build.tar.gz
    - git commit -m "Build cache"
    - git push cache.git main

Производительность: bare vs обычный репо #

Bare репозитории обычно быстрее для push операций:

Операция              Обычный репо    Bare репо
──────────────────────────────────────────────
git clone             медленнее        быстрее
git fetch             медленнее        быстрее
git push              медленнее        быстрее (нет RW проверок)
git pull              медленнее        недоступно
Локальная работа      ✓ быстро         ✗ невозможно
Размер на диске       +.git/ + files   только .git/
──────────────────────────────────────────────

Рекомендация:

  • Разработка: обычный репо
  • Сервер/backup: bare репо
  • CI/CD artifact: bare репо

Часто задаваемые вопросы #

Зачем соглашение о расширении .git для bare репозиториев? Это просто соглашение (как GitHub и GitLab хранят репозитории), а не требование. git init --bare project работает так же хорошо.

Можно ли клонировать из bare репозитория? Да, git clone /path/to/repo.git работает как с обычными, так и с bare репозиториями.

Почему нельзя редактировать файлы в bare репозитории? Нет рабочей директории — негде делать изменения. Bare репозиторий существует только как точка обмена данными между разработчиками.

Как сконвертировать обычный репозиторий в bare? Скопируйте содержимое .git/ в новую директорию и установите core.bare = true в config: git clone --bare . ../project.git. Исходный репозиторий при этом не изменяется.

Чем отличается bare от зеркала GitHub? git clone --bare копирует ветки и теги. git clone --mirror копирует абсолютно все ссылки, включая служебные (pull requests как refs/pull/*). Mirror используется для полного резервного копирования.

Заключение #

Bare репозиторий — Git хранилище без рабочей директории, предназначенное для центрального сервера. Создаётся через git init --bare. Позволяет делать git push от нескольких разработчиков. Используется при развёртывании собственного Git сервера и в хостинговых платформах (GitHub, GitLab хранят репозитории именно как bare).