Какая польза от репозиториев git bare?
На удаленной машине я создаю пустой репозиторий с помощью следующей команды:
git init --bare $HOME/bare/My-Repo
На моей локальной машине я клонирую репо (но не тот, который я создал на удаленной машине):
git clone ssh://something.com/My-Repo
На моем локальном компьютере в репозитории, который я только что клонировал, я создаю "ссылку" на вышеупомянутый пустой репозиторий, расположенный на удаленном компьютере:
git remote add my_remote ssh://remote.com/${USER}/bare/My-Repo
Я не знаю, относится ли это к моему вопросу, но я также делаю следующие вещи в своем локальном хранилище:
git config remote.my_remote /some/path/git-receive-pack
git config remote.my_remote /some/path/git-upload-pack
Теперь я могу перейти из локального репозитория в пустой репозиторий на удаленной машине:
git push my_remote master
Теперь идея заключается в том, что мы создадим еще один репозиторий на удаленной машине, который должен извлечь некоторый контент из чистого репозитория. Я создаю этот репозиторий, выполняя что-то вроде этого на удаленной машине:
some_script.sh $HOME/bare/My-Repo $HOME/My-Repo
Теперь я делаю некоторые изменения в $HOME/My-Repo
на удаленной машине (обратите внимание, что это не пустой репозиторий), то я git add
а также git commit
и после этого я нажимаю:
git push origin my-dev-branch
В результате я нажимаю на пустой репозиторий (который находится на той же удаленной машине). После этого я иду на свою локальную машину и "беру" изменения с удаленной машины (из чистого репозитория):
git fetch my_remote
git checkout -b my-dev-branch my_remote/my-dev-branch
git fetch origin
git rebase origin/master
Итак, мои вопросы: зачем нам этот голый репозиторий? Почему мы не можем просто иметь один удаленный репозиторий и напрямую обмениваться контентом между локальным и удаленным репозиториями? Или, альтернативно, почему мы не можем просто rsync
(или же scp
) локальный репозиторий на и с удаленной машины?
ADDED
Вот почему я задаю вопрос, а не гуглю. Я погуглил свой вопрос, и первая ссылка здесь: http://www.saintsjd.com/2011/01/what-is-a-bare-git-repository/
Я прочитал там:
Репозитории, созданные с помощью команды git init, называются рабочими каталогами. В папке верхнего уровня репозитория вы найдете две вещи: подпапку.git со всей историей ревизий репозитория, связанной с git, рабочим деревом или извлеченными копиями файлов вашего проекта. Репозитории, созданные с помощью git init --bare, называются открытыми репозиториями. Они структурированы немного иначе, чем рабочие каталоги. Во-первых, они не содержат рабочей или извлеченной копии ваших исходных файлов. И, во-вторых, голые репозитории хранят историю изменений git вашего репозитория в корневой папке вашего репозитория, а не в подпапке.git. Обратите внимание... голые репозитории обычно получают расширение.git.
Итак, теперь, чтобы понять, что мне нужно знать:
- Что такое "история изменений"?
- Что такое "рабочее дерево"?
- Что такое "проверенные копии"?
И это только первый раздел. Я знаю, что ответом будет: пойди и прочитай учебник или введение в git. Ну, я сделал это. Первая проблема с этим состоит в том, что использование терминов является "круглым". Термин A выражается через термин B, а термин B - через термин A . Во-вторых, у меня нет времени читать книгу, чтобы найти ответ на свой вопрос. В-третьих, я на 100% уверен, что ответ на мой вопрос можно выразить простыми словами. Это на самом деле тривиально.
1 ответ
Если я правильно понимаю, ваш главный вопрос сводится к следующему: зачем нам нужен промежуточный пустой репозиторий для синхронизации между двумя репозиториями Git?
В вашем конкретном примере у вас есть локальный репозиторий Git, назовем его X, и два удаленных репозитория, пустой, назовем его B, и не голый, назовем его Y.
На данный момент, я надеюсь, вы видите, что X и Y могут быть где угодно. Оба они могут быть локальными или оба могут быть удаленными, на одном сервере с B. Не важно, где они находятся, важно то, что вы хотите синхронизировать между ними, и для этого вам нужен B, где-нибудь, где угодно, А твой вопрос почему?
Прежде всего, вам не нужен B в середине. Рекомендуется, и поведение по умолчанию поможет вам в этом направлении.
Почему рекомендуется делать репо между репозиториями? Ответ связан с рабочими деревьями. Рабочее дерево - это то место, где у вас есть файлы, с которыми вы работаете. Git-репозиторий рабочего дерева находится внутри .git
подкаталог. Команды Git, которые вы выполняете внутри рабочего дерева, связываются с репозиторием Git, запрашивают его содержимое и сравнивают его с содержимым рабочего дерева. Пустое хранилище похоже на .git
каталог один, без рабочего дерева.
Чтобы демистифицировать голые репозитории, попробуйте это, чтобы увидеть разницу между голым и не голым репо:
$ cd /tmp/
$ git init --bare bare.git
Initialized empty Git repository in /private/tmp/bare.git/
$ git init regular
Initialized empty Git repository in /private/tmp/regular/.git/
$ diff -r bare.git/ regular/.git/
diff -r bare.git/config regular/.git/config
4c4,5
< bare = true
---
> bare = false
> logallrefupdates = true
Технически, разница заключается в нескольких флагах конфигурации. Я мог бы переместить bare.git
каталог в любой каталог в файловой системе, переименуйте его в .git
отредактируйте config
файл и вуаля, я буду преобразовывать обычный репозиторий обычный.
Вернемся к вопросу: почему рекомендуется иметь пустой репозиторий между двумя не голыми репозиториями, которые хотят синхронизировать друг с другом? По умолчанию Git запрещает отправку в не-пустое хранилище. Что если это не так? Если git push
обновит содержание .git
удаленного, что должно произойти с соответствующим рабочим деревом? Многие вопросы будут следовать:
- Какова текущая ветвь рабочего дерева? Если толчок не изменил эту ветку, то все в порядке.
- Что должно произойти, если толчок затронул текущую ветвь рабочего дерева? Должен ли Git обновить рабочее дерево?
- Если рабочее дерево не является чистым, его нельзя безопасно обновить. Незавершенные изменения могут быть потеряны.
- Даже если рабочее дерево чистое, могут возникнуть конфликты, если есть изменения в
.gitignore
или если история ветки была переписана с принудительным нажатием. - Если мы не обновим рабочее дерево, оно будет не синхронизировано с репозиторием, поэтому
git status
сообщит об изменениях, которые не должны быть зафиксированы.
Это звучит сложно и запутанно? Это потому что это так. И это причина, по которой отправка в не-пустой репозиторий по умолчанию не разрешена. Вы можете сделать это, если действительно хотите, это может быть достаточно безопасно, если вы будете постоянно чистить рабочее дерево репо, к которому вы обращаетесь, но оно будет подвержено ошибкам (вы можете забыть), и никому не нужна такая неопределенность и умственная нагрузка, На самом деле лучше всего использовать пустой репозиторий между ними.