Разверните проект с помощью Git push
Можно ли развернуть сайт, используя git push
? У меня есть предчувствие, что это как-то связано с использованием git-хуков для выполнения git reset --hard
на стороне сервера, но как мне это сделать?
19 ответов
Я нашел этот скрипт на этом сайте, и он, кажется, работает довольно хорошо.
- Скопируйте каталог.git на свой веб-сервер.
В локальной копии измените файл.git / config и добавьте свой веб-сервер в качестве удаленного:
[remote "production"] url = username@webserver:/path/to/htdocs/.git
На сервере замените этот файл на.git / hooks / post-update (ответ ниже)
Добавить исполняемый доступ к файлу (опять же на сервере):
chmod +x .git/hooks/post-update
Теперь просто локально нажмите на ваш веб-сервер, и он должен автоматически обновить рабочую копию:
git push production
Используя файл пост-обновления ниже:
- Скопируйте ваш каталог.git на ваш веб-сервер
В локальной копии измените файл.git / config и добавьте свой веб-сервер в качестве удаленного:
[remote "production"] url = username@webserver:/path/to/htdocs/.git
На сервере замените.git / hooks / post-update файлом ниже
Добавить исполняемый доступ к файлу (опять же на сервере):
chmod +x .git/hooks/post-update
Теперь просто локально нажмите на ваш веб-сервер, и он должен автоматически обновить рабочую копию:
git push production
#!/bin/sh
#
# This hook does two things:
#
# 1. update the "info" files that allow the list of references to be
# queries over dumb transports such as http
#
# 2. if this repository looks like it is a non-bare repository, and
# the checked-out branch is pushed to, then update the working copy.
# This makes "push" function somewhat similarly to darcs and bzr.
#
# To enable this hook, make this file executable by "chmod +x post-update".
git-update-server-info
is_bare=$(git-config --get --bool core.bare)
if [ -z "$is_bare" ]
then
# for compatibility's sake, guess
git_dir_full=$(cd $GIT_DIR; pwd)
case $git_dir_full in */.git) is_bare=false;; *) is_bare=true;; esac
fi
update_wc() {
ref=$1
echo "Push to checked out branch $ref" >&2
if [ ! -f $GIT_DIR/logs/HEAD ]
then
echo "E:push to non-bare repository requires a HEAD reflog" >&2
exit 1
fi
if (cd $GIT_WORK_TREE; git-diff-files -q --exit-code >/dev/null)
then
wc_dirty=0
else
echo "W:unstaged changes found in working copy" >&2
wc_dirty=1
desc="working copy"
fi
if git diff-index --cached HEAD@{1} >/dev/null
then
index_dirty=0
else
echo "W:uncommitted, staged changes found" >&2
index_dirty=1
if [ -n "$desc" ]
then
desc="$desc and index"
else
desc="index"
fi
fi
if [ "$wc_dirty" -ne 0 -o "$index_dirty" -ne 0 ]
then
new=$(git rev-parse HEAD)
echo "W:stashing dirty $desc - see git-stash(1)" >&2
( trap 'echo trapped $$; git symbolic-ref HEAD "'"$ref"'"' 2 3 13 15 ERR EXIT
git-update-ref --no-deref HEAD HEAD@{1}
cd $GIT_WORK_TREE
git stash save "dirty $desc before update to $new";
git-symbolic-ref HEAD "$ref"
)
fi
# eye candy - show the WC updates :)
echo "Updating working copy" >&2
(cd $GIT_WORK_TREE
git-diff-index -R --name-status HEAD >&2
git-reset --hard HEAD)
}
if [ "$is_bare" = "false" ]
then
active_branch=`git-symbolic-ref HEAD`
export GIT_DIR=$(cd $GIT_DIR; pwd)
GIT_WORK_TREE=${GIT_WORK_TREE-..}
for ref
do
if [ "$ref" = "$active_branch" ]
then
update_wc $ref
fi
done
fi
После многих фальстартов и тупиков, я наконец-то смог развернуть код сайта просто с помощью "git push remote" благодаря этой статье.
Сценарий автора после обновления занимает всего одну строку, и его решение не требует настройки.htaccess, чтобы скрыть репозиторий Git, как это делают некоторые другие.
Пара камней преткновения, если вы развертываете это на экземпляре Amazon EC2;
1) Если вы используете sudo для создания чистого конечного репозитория, вы должны сменить владельца репо на ec2-user, иначе загрузка не удастся. (Попробуйте "chown ec2-user: ec2-user repo.")
2) Push не удастся, если вы предварительно не сконфигурируете расположение вашего amazon-private-ключа.pem, либо в /etc/ssh/ssh_config в качестве параметра IdentityFile, либо в ~/.ssh/config, используя "[[ Host] - HostName - IdentityFile - User"макет описан здесь...
... ОДНАКО, если Host настроен в ~/.ssh/config и отличается от HostName, Git push не удастся. (Это, вероятно, ошибка Git)
Не устанавливайте git на сервер и не копируйте туда папку.git. чтобы обновить сервер из git clone, вы можете использовать следующую команду:
git ls-files -z | rsync --files-from - --copy-links -av0 . user@server.com:/var/www/project
Возможно, вам придется удалить файлы, которые были удалены из проекта.
это копирует все проверенные файлы. rsync использует ssh, который в любом случае установлен на сервере.
чем меньше программного обеспечения установлено на сервере, тем более он безопасен и тем проще управлять его конфигурацией и документировать его. также нет необходимости хранить полный git-клон на сервере. это только усложняет, чтобы защитить все должным образом.
receive.denyCurrentBranch updateInstead, добавленный в Git 2.3, возможен.
Установите его в хранилище сервера, и он также обновляет рабочее дерево, если оно чистое.
Там были дальнейшие улучшения в 2.4 с push-to-checkout
крючок и обработка нерожденных веток.
Пример использования:
git init server
cd server
touch a
git add .
git commit -m 0
git config --local receive.denyCurrentBranch updateInstead
cd ..
git clone server local
cd local
touch b
git add .
git commit -m 1
git push origin master:master
cd ../server
ls
Выход:
a
b
У этого есть следующие недостатки, упомянутые в объявлении GitHub:
- Ваш сервер будет содержать каталог.git, содержащий всю историю вашего проекта. Вы, вероятно, хотите убедиться, что он не может быть предоставлен пользователям!
- Во время развертывания пользователи могут на мгновение встретиться с сайтом в несогласованном состоянии, с некоторыми файлами в старой версии и другими в новой версии, или даже наполовину записанными файлами. Если это проблема для вашего проекта, push-to-deploy, вероятно, не для вас.
- Если ваш проект нуждается в шаге "сборки", то вам придется настроить его явно, возможно, через githooks.
Но все эти моменты выходят за рамки Git и должны решаться внешним кодом. Таким образом, в этом смысле это, вместе с хуками Git, является окончательным решением.
По сути, все, что вам нужно сделать, это следующее:
server = $1
branch = $2
git push $server $branch
ssh <username>@$server "cd /path/to/www; git pull"
У меня есть эти строки в моем приложении как исполняемый файл под названием deploy
,
поэтому, когда я хочу сделать развертывание, я печатаю ./deploy myserver mybranch
,
То, как я это делаю, это то, что у меня есть пустой Git-репозиторий на моем сервере развертывания, где я отправляю изменения. Затем я захожу на сервер развертывания, перехожу на фактический каталог документов веб-сервера и выполняю git pull. Я не использую никаких хуков, чтобы попытаться сделать это автоматически, это кажется большим количеством проблем, чем оно того стоит.
Для сценария развертывания
В нашем сценарии мы храним код в github/bitbucket и хотим развернуть его на живых серверах. В этом случае у нас работает следующая комбинация (это ремикс ответов с большим количеством голосов здесь):
- Скопируйте ваш
.git
каталог на ваш веб-сервер - На вашей локальной копии
git remote add live ssh://user@host:port/folder
- На удаленном:
git config receive.denyCurrentBranch ignore
На удаленном:
nano .git/hooks/post-receive
и добавьте этот контент:#!/bin/sh GIT_WORK_TREE=/var/www/vhosts/example.org git checkout -f
На удаленном:
chmod +x .git/hooks/post-receive
- Теперь вы можете нажать там с
git push live
Заметки
- Это решение работает со старыми версиями git (протестировано с 1.7 и 1.9)
- Вы должны убедиться, что сначала нажали на github/bitbucket, чтобы вы имели постоянное репо в прямом эфире.
Если твой
.git
папка находится в корне документа, убедитесь, что вы скрываете ее снаружи, добавив в.htaccess
( источник):RedirectMatch 404 /\..*$
Обновление: сейчас я использую решение Ллойда Мура с ключевым агентом ssh -A ...
, Выдвижение основного репо, а затем параллельное извлечение со всех ваших машин происходит немного быстрее и требует меньших настроек на этих машинах.
Не видя этого решения здесь. просто нажмите через ssh, если на сервере установлен git.
Вам понадобится следующая запись в вашем локальном.git / config
[remote "amazon"]
url = amazon:/path/to/project.git
fetch = +refs/heads/*:refs/remotes/amazon/*
Но эй, что это с amazon:
? В вашем локальном ~/.ssh/config вам нужно добавить следующую запись:
Host amazon
Hostname <YOUR_IP>
User <USER>
IdentityFile ~/.ssh/amazon-private-key
теперь вы можете позвонить
git push amazon master
ssh <USER>@<YOUR_IP> 'cd /path/to/project && git pull'
(Кстати: /path/to/project.git отличается от фактического рабочего каталога /path/to/project)
Мы используем Capistrano для управления развертыванием. Мы строим capistrano для развертывания на промежуточном сервере, а затем запускаем rsync со всеми нашими серверами.
cap deploy
cap deploy:start_rsync (when the staging is ok)
С Capistrano, мы можем сделать легкий откат в случае ошибки
cap deploy:rollback
cap deploy:start_rsync
Giddyup - это не зависящие от языка git-хуки типа " просто добавь воды", которые автоматизируют развертывание с помощью git push. Это также позволяет вам иметь пользовательские перехватчики запуска / остановки для перезапуска веб-сервера, прогрева кеша и т. Д.
https://github.com/mpalmer/giddyup
Проверьте примеры.
Я использую следующее решение от toroid.org, которое имеет более простой скрипт хука.
на сервере:
$ mkdir website.git && cd website.git
$ git init --bare
Initialized empty Git repository in /home/ams/website.git/
и установите хук на сервере:
$ mkdir /var/www/www.example.org
$ cat > hooks/post-receive
#!/bin/sh
GIT_WORK_TREE=/var/www/www.example.org git checkout -f
GIT_WORK_TREE=/var/www/www git clean -f -d # clean directory from removed files
$ chmod +x hooks/post-receive
на вашем клиенте:
$ mkdir website && cd website
$ git init
Initialized empty Git repository in /home/ams/website/.git/
$ echo 'Hello, world!' > index.html
$ git add index.html
$ git commit -q -m "The humble beginnings of my web site."
$ git remote add web ssh://server.example.org/home/ams/website.git
$ git push web +master:refs/heads/master
затем опубликовать, просто введите
$ git push web
На сайте есть полное описание: http://toroid.org/ams/git-website-howto
Похоже, у вас должно быть две копии на вашем сервере. Чистая копия, из которой вы можете нажать / вытащить, с которой ваши изменения будут проталкиваться, когда вы закончите, а затем вы клонируете это в свой веб-каталог и настраиваете cronjob для обновления git pull из вашего веб-каталога каждый день или так.
Можно предположить, что можно настроить git hook, чтобы, когда говорят, что был сделан коммит, чтобы сказать "стабильную" ветвь, он извлекает изменения и применяет их к сайту PHP. Большим недостатком является то, что у вас не будет большого контроля, если что-то пойдет не так, и это добавит время к вашему тестированию - но вы можете получить представление о том, сколько работы потребуется, когда вы объединитесь, скажем, ваша магистральная ветка с стабильной веткой, чтобы знать сколько конфликтов вы можете столкнуться. Будет важно следить за любыми файлами, относящимися к конкретному сайту (например, файлами конфигурации), если только вы не собираетесь запускать только один сайт.
В качестве альтернативы вы рассматривали возможность изменения сайта?
Для получения информации о git hooks смотрите документацию githooks.
Мой взгляд на решение христиан.
git archive --prefix=deploy/ master | tar -x -C $TMPDIR | rsync $TMPDIR/deploy/ --copy-links -av username@server.com:/home/user/my_app && rm -rf $TMPDIR/deploy
- Архивирует главную ветку в tar
- Распаковывает архив tar в каталог deploy в системную временную папку.
- rsync превращается в сервер
- удалить каталог развертывания из временной папки.
В качестве дополнительного ответа я хотел бы предложить альтернативу. Я использую git-ftp, и он отлично работает.
https://github.com/git-ftp/git-ftp
Простой в использовании, только тип:
git ftp push
и git автоматически загрузит файлы проекта.
С уважением
Я использую два решения для ловушки после получения:
DEPLOY SOLUTION 1
#!/bin/bash
# /git-repo/hooks/post-receive - file content on server (chmod as 755 to be executed)
# DEPLOY SOLUTION 1
export GIT_DIR=/git/repo-bare.git
export GIT_BRANCH1=master
export GIT_TARGET1=/var/www/html
export GIT_BRANCH2=dev
export GIT_TARGET2=/var/www/dev
echo "GIT DIR: $GIT_DIR/"
echo "GIT TARGET1: $GIT_TARGET1/"
echo "GIT BRANCH1: $GIT_BRANCH1/"
echo "GIT TARGET2: $GIT_TARGET2/"
echo "GIT BRANCH2: $GIT_BRANCH2/"
echo ""
cd $GIT_DIR/
while read oldrev newrev refname
do
branch=$(git rev-parse --abbrev-ref $refname)
BRANCH_REGEX='^${GIT_BRANCH1}.*$'
if [[ $branch =~ $BRANCH_REGEX ]] ; then
export GIT_WORK_TREE=$GIT_TARGET1/.
echo "Checking out branch: $branch";
echo "Checking out to workdir: $GIT_WORK_TREE";
git checkout -f $branch
fi
BRANCH_REGEX='^${GIT_BRANCH2}.*$'
if [[ $branch =~ $BRANCH_REGEX ]] ; then
export GIT_WORK_TREE=$GIT_TARGET2/.
echo "Checking out branch: $branch";
echo "Checking out to workdir: $GIT_WORK_TREE";
git checkout -f $branch
fi
done
DEPLOY SOLUTION 2
#!/bin/bash
# /git-repo/hooks/post-receive - file content on server (chmod as 755 to be executed)
# DEPLOY SOLUTION 2
export GIT_DIR=/git/repo-bare.git
export GIT_BRANCH1=master
export GIT_TARGET1=/var/www/html
export GIT_BRANCH2=dev
export GIT_TARGET2=/var/www/dev
export GIT_TEMP_DIR1=/tmp/deploy1
export GIT_TEMP_DIR2=/tmp/deploy2
echo "GIT DIR: $GIT_DIR/"
echo "GIT TARGET1: $GIT_TARGET1/"
echo "GIT BRANCH1: $GIT_BRANCH1/"
echo "GIT TARGET2: $GIT_TARGET2/"
echo "GIT BRANCH2: $GIT_BRANCH2/"
echo "GIT TEMP DIR1: $GIT_TEMP_DIR1/"
echo "GIT TEMP DIR2: $GIT_TEMP_DIR2/"
echo ""
cd $GIT_DIR/
while read oldrev newrev refname
do
branch=$(git rev-parse --abbrev-ref $refname)
BRANCH_REGEX='^${GIT_BRANCH1}.*$'
if [[ $branch =~ $BRANCH_REGEX ]] ; then
export GIT_WORK_TREE=$GIT_TARGET1/.
echo "Checking out branch: $branch";
echo "Checking out to workdir: $GIT_WORK_TREE";
# DEPLOY SOLUTION 2:
cd $GIT_DIR/; mkdir -p $GIT_TEMP_DIR1;
export GIT_WORK_TREE=$GIT_TEMP_DIR1/.
git checkout -f $branch
export GIT_WORK_TREE=$GIT_TARGET1/.
rsync $GIT_TEMP_DIR1/. -v -q --delete --delete-after -av $GIT_TARGET1/.
rm -rf $GIT_TEMP_DIR1
fi
BRANCH_REGEX='^${GIT_BRANCH2}.*$'
if [[ $branch =~ $BRANCH_REGEX ]] ; then
export GIT_WORK_TREE=$GIT_TARGET2/.
echo "Checking out branch: $branch";
echo "Checking out to workdir: $GIT_WORK_TREE";
# DEPLOY SOLUTION 2:
cd $GIT_DIR/; mkdir -p $GIT_TEMP_DIR2;
export GIT_WORK_TREE=$GIT_TEMP_DIR2/.
git checkout -f $branch
export GIT_WORK_TREE=$GIT_TARGET2/.
rsync $GIT_TEMP_DIR2/. -v -q --delete --delete-after -av $GIT_TARGET2/.
rm -rf $GIT_TEMP_DIR2
fi
done
Оба решения основаны на более ранних решениях, доступных в этой теме.
Обратите внимание, BRANCH_REGEX = '^ $ {GIT_BRANCH1}. $ 'фильтрует имена ветвей, совпадающие со строкой "master " или "dev*", и развертывает рабочее дерево, если соответствующая ветвь совпадает. Это позволяет развернуть версию dev и master версию в разных местах.
DEPLOY SOLUTION 1 удаляет только те файлы, которые являются частью репо и были удалены коммитом. Это быстрее, чем Deployment Solution 2.
Преимущество DEPLOY SOLUTION 2 состоит в том, что он удаляет все новые файлы из производственного каталога, который был добавлен на стороне сервера, независимо от того, был ли он добавлен в репозиторий или нет. Это всегда будет чистый дуп из репо. Это медленнее, чем Deployment Solution 1.
Я закончил тем, что создал свой собственный элементарный инструмент развертывания, который будет автоматически извлекать новые обновления из репозитория - https://github.com/jesalg/SlimJim - По сути, он слушает github post-receive-hook и использует прокси для запуска обновить скрипт.
В условиях, когда у нескольких разработчиков есть доступ к одному и тому же репозиторию, могут помочь следующие рекомендации.
Убедитесь, что у вас есть группа Unix, к которой принадлежат все разработчики, и передайте права собственности на репозиторий.git этой группе.
В.git/config хранилища сервера установите sharedrepository = true. (Это говорит git разрешить нескольким пользователям, что необходимо для фиксации и развертывания.
установите umask каждого пользователя в своих файлах bashrc одинаковым - 002 - хорошее начало