Использование чистого репо (через SSH) - хорошее решение, при условии, что у вас есть правильный хук pre / post-receive, который будет извлекать ваши файлы в не-пустом хранилище.
- pre-receive hook, чтобы проверить, что в вашем удаленном репозитории не было никаких изменений / новых коммитов (в этом случае вы сначала извлечете его, выполните локальное слияние, а затем добавите в пустой репозиторий)
- hook после получения:чтобы извлекать содержимое, которое вы отправляете в репозиторий non-bare, делая файлы видимыми.
Значение: на удаленном сервере вы создаете два репозитория:
- onenon-bare (для работы непосредственно на сервере)
- one bare (для отправки с локального компьютера)
То есть:
ssh remoteUser@remoteServer
git init newRepo
cd newRepo
git init --bare bare
Затем нана вашем локальном компьютере вы клонируете пустой новый (не пустой) репозиторий, , но вы изменяете push-URL для ссылки на пустой репозиторий (newRepo/bare
)
git clone remoteUser@remoteServer:~/newRepo
cd newRepo
git config --add remote.origin.pushurl remoteUser@remoteServer:~/newRepo/bare
на удаленномсервер, в ~ / newRepo / bare / hooks добавьте ловушку предварительного получения:
#!/bin/bash
DIR="$( cd "$( dirname "$(readlink "${BASH_SOURCE[0]}")" )" && pwd )"
git fetch
# Read stdin for ref information
while read -r oldref newref refname; do
case "${refname}" in
*/master) branch="master"
;;
refs/tags/*)
ok "Pushing tag: proceed"
exit 0
;;
*) echo "invalid branch '${refname}'"
exit 1
;;
esac
if [[ "${newref}" == "0000000000000000000000000000000000000000" ]]; then
ok "Deletion of oldref '${oldref}': pre-receive proceed"
exit 0
fi
localsha1=${newref}
if [[ "master" == "${branch}" ]]; then
originsha1=$(git rev-parse origin/master)
force="false"
# shellcheck disable=SC2086
if [[ "$(git rev-list ${oldref} ^${newref})" != "" ]]; then force="true"; fi
cmd="git merge-base --is-ancestor ${originsha1} ${localsha1}"
if ! eval "${cmd}"; then
if [[ "${force}" == true ]]; then
info "force push master"
else
fatal "Git push of '${refname}' refused because repo locally ($(hostname)) modified\nDo a git pull first" 1
exit 1
fi
fi
if git rev-parse --quiet --verify from_prod >/dev/null && ! git merge-base --is-ancestor from_prod "${localsha1}"; then
error "Git push of '${refname}' refused because from_prod is not an ancestor"
error "Meaning: prod has evolved, fetch and rebase on top of from_prod first, then push again"
exit 1
fi
ok "Push to master will proceed"
fi
done
И хук после получения:
#!/bin/bash
DIR="$( cd "$( dirname "$(readlink "${BASH_SOURCE[0]}")" )" && pwd )"
while read -r oldrev newrev refname
do
case "${refname}" in
*/master) branch="master"
;;
refs/tags/*)
ok "Pushing tag: proceed post-receive"
exit 0
;;
*) fatal "invalid branch '${refname}' in post-receive (oldrev:'${oldrev}')" 1
;;
esac
if [[ "${newrev}" == "0000000000000000000000000000000000000000" ]]; then
ok "Deletion of oldrev '${oldrev}': post-receive proceed"
unset GIT_DIR
cd ..
git --work-tree=. --git-dir=.git fetch --prune
if [ "${branch}" != "" ]; then git --work-tree=. --git-dir=.git branch -d "${branch}"; fi
cd ./bare || fatal "Unable to go into bare of '$(pwd)'" 8
git --git-dir=. fetch --prune
exit 0
fi
info "post-receive for branch '${branch}'"
if [ "master" == "$branch" ]; then
info "pull from non-bare repo"
unset GIT_DIR
cd ..
git --work-tree=. --git-dir=.git fetch
git --work-tree=. --git-dir=.git fetch --tags
if ! git --work-tree=. --git-dir=.git merge-base --is-ancestor master origin/master; then
info "Reset non-bare master to bare master (forced update)"
git --work-tree=. --git-dir=.git reset --hard origin/master
else
info "Update non-bare master with merge from origin/master"
git --work-tree=. --git-dir=.git pull --no-rebase origin master
fi
fi
done
Таким образом, вы можете работать как непосредственно на сервере, в своем обычном репозитории ~ / newRepo, так и без него, совершая коммиты.
Но вы также можете работать на своем компьютере и выполнять push-уведомления, не опасаясь переопределения удаленной фиксации, выполняемой одновременно на сервере: ловушка предварительного получения блокирует push-запрос.
Примечания:
- заменить "
ok
", "info
" и "fatal
" на простые "echo
" в скриптах). - Добавить
bare/
в .gitignore
,для вашего обычного репозитория, чтобы игнорировать его вложенное голое хранилище.