É possível implantar um site usando git push
? Eu tenho um palpite de que tem algo a ver com o uso de ganchos git para executar um git reset --hard
no lado do servidor, mas como eu iria conseguir isso?
É possível implantar um site usando git push
? Eu tenho um palpite de que tem algo a ver com o uso de ganchos git para executar um git reset --hard
no lado do servidor, mas como eu iria conseguir isso?
Respostas:
Eu encontrei este script em este site e parece funcionar muito bem.
Na sua cópia local, modifique seu arquivo .git / config e adicione seu servidor web como um controle remoto:
[remote "production"]
url = username@webserver:/path/to/htdocs/.git
No servidor, substitua .git / hooks / pós-atualização por este arquivo (na resposta abaixo)
Adicione acesso de execução ao arquivo (novamente, no servidor):
chmod +x .git/hooks/post-update
Agora, basta enviar localmente para o servidor da Web e ele deve atualizar automaticamente a cópia de trabalho:
git push production
Usando o arquivo pós-atualização abaixo:
Na sua cópia local, modifique seu arquivo .git / config e adicione seu servidor web como um controle remoto:
[remote "production"]
url = username@webserver:/path/to/htdocs/.git
No servidor, substitua .git / hooks / post-update pelo arquivo abaixo
Adicione acesso de execução ao arquivo (novamente, no servidor):
chmod +x .git/hooks/post-update
Agora, basta enviar localmente para o servidor da Web e ele deve atualizar automaticamente a cópia de trabalho:
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
Depois de muitas partidas e becos sem saída, finalmente consegui implantar o código do site com apenas "git push remote ", graças a este artigo .
O script pós-atualização do autor tem apenas uma linha e sua solução não requer a configuração .htaccess para ocultar o repositório Git, como alguns outros.
Alguns obstáculos se você estiver implantando isso em uma instância do Amazon EC2;
1) Se você usar o sudo para criar o repositório de destino vazio, precisará alterar o proprietário do repositório para ec2-user ou o envio falhará. (Tente "chown ec2-user: ec2-user repo .")
2) O envio falhará se você não pré-configurar o local do seu .pem da amazon-private-key , em / etc / ssh / ssh_config como um parâmetro IdentityFile ou em ~ / .ssh / config usando o "[ Host] - Nome do host - IdentityFile - Usuário "layout descrito aqui ...
... NO ENTANTO, se o Host estiver configurado em ~ / .ssh / config e diferente de HostName, o push do Git falhará. (Isso provavelmente é um bug do Git)
não instale o git em um servidor ou copie a pasta .git lá. para atualizar um servidor a partir de um clone git, você pode usar o seguinte comando:
git ls-files -z | rsync --files-from - --copy-links -av0 . user@server.com:/var/www/project
pode ser necessário excluir arquivos que foram removidos do projeto.
isso copia todos os arquivos registrados. O rsync usa o ssh, que é instalado em um servidor de qualquer maneira.
quanto menos software você instalou em um servidor, mais seguro ele é e mais fácil é gerenciar sua configuração e documentá-la. também não há necessidade de manter um clone git completo no servidor. apenas torna mais complexo proteger tudo corretamente.
Em essência, tudo o que você precisa fazer é o seguinte:
server = $1
branch = $2
git push $server $branch
ssh <username>@$server "cd /path/to/www; git pull"
Eu tenho essas linhas no meu aplicativo como um executável chamado deploy
.
então, quando eu quero fazer uma implantação, digito ./deploy myserver mybranch
.
ssh -A ...
git pull
deve ser evitado para implantações automatizadas porque a parte de mesclagem pode exigir limpeza manual se houver algum conflito.
A maneira como faço isso é ter um repositório Git vazio no meu servidor de implantação, onde envio as alterações. Depois, efetuo login no servidor de implantação, mudo para o diretório real de documentos do servidor web e faço um git pull. Não uso ganchos para tentar fazer isso automaticamente, isso parece mais problemas do que vale a pena.
git reset
as alterações mais recentes (todas as confirmações, não apenas toda a solicitação). Se você precisar reverter algo específico que não seja o commit mais recente, poderá usá-lo, git revert
mas provavelmente deve ser usado apenas em emergências ( git revert
cria um novo commit que desfaz o efeito de algum commit anterior).
git config --local receive.denyCurrentBranch updateInstead
Adicionado no Git 2.3, essa pode ser uma boa possibilidade: https://github.com/git/git/blob/v2.3.0/Documentation/config.txt#L2155
Você o define no repositório do servidor e também atualiza a árvore de trabalho, se estiver limpa.
Houve mais melhorias no 2.4 com o push-to-checkout
gancho e manuseio de galhos não nascidos .
Uso da amostra:
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
Resultado:
a
b
Isso tem as seguintes deficiências mencionadas no anúncio do GitHub :
Mas todos esses pontos estão fora do escopo do Git e devem ser resolvidos por código externo. Portanto, nesse sentido, isso, juntamente com os ganchos Git, são a solução definitiva.
Atualização: agora estou usando a solução Lloyd Moore com o agente principal ssh -A ...
. Empurrar para um repositório principal e depois retirá-lo em paralelo de todas as suas máquinas é um pouco mais rápido e requer menos configuração nessas máquinas.
Não está vendo esta solução aqui. basta pressionar via ssh se o git estiver instalado no servidor.
Você precisará da seguinte entrada no seu .git / config local
[remote "amazon"]
url = amazon:/path/to/project.git
fetch = +refs/heads/*:refs/remotes/amazon/*
Mas ei, o que é isso amazon:
? No seu local ~ / .ssh / config, você precisará adicionar a seguinte entrada:
Host amazon
Hostname <YOUR_IP>
User <USER>
IdentityFile ~/.ssh/amazon-private-key
agora você pode ligar
git push amazon master
ssh <USER>@<YOUR_IP> 'cd /path/to/project && git pull'
(BTW: /path/to/project.git é diferente do diretório de trabalho real / caminho / para / projeto)
Em nosso cenário, estamos armazenando o código no github / bitbucket e queremos implantar em servidores ativos. Nesse caso, a seguinte combinação funciona para nós (que é um remix das respostas altamente votadas aqui) :
.git
diretório para o servidor da webgit remote add live ssh://user@host:port/folder
git config receive.denyCurrentBranch ignore
No controle remoto: nano .git/hooks/post-receive
e adicione este conteúdo:
#!/bin/sh
GIT_WORK_TREE=/var/www/vhosts/example.org git checkout -f
No controle remoto: chmod +x .git/hooks/post-receive
git push live
Se sua .git
pasta estiver na raiz do documento, oculte-a do lado de fora adicionando a .htaccess
( fonte ):
RedirectMatch 404 /\..*$
Usamos o capistrano para gerenciar a implantação. Criamos o capistrano para implantar em um servidor intermediário e, em seguida, executamos um rsync com todo o nosso servidor.
cap deploy
cap deploy:start_rsync (when the staging is ok)
Com o capistrano, podemos facilitar a reversão em caso de erro
cap deploy:rollback
cap deploy:start_rsync
Giddyup são ganchos git de adição de água, independentes do idioma, para automatizar a implantação via git push. Também permite que você tenha ganchos de início / parada personalizados para reiniciar o servidor da Web, aquecer o cache etc.
https://github.com/mpalmer/giddyup
Confira exemplos .
Parece que você deve ter duas cópias no seu servidor. Uma cópia simples, da qual você pode enviar / enviar, que enviaria suas alterações quando terminar e, em seguida, clonaria isso no diretório da web e configuraria um cronjob para atualizar o git pull do diretório da web todos os dias ou tão.
Você pode configurar um gancho git que, quando se diz que um commit é feito para dizer o ramo "stable", ele puxa as alterações e as aplica no site PHP. A grande desvantagem é que você não terá muito controle se algo der errado e isso adicionará tempo aos seus testes - mas você pode ter uma idéia de quanto trabalho será envolvido quando você mesclar, diga o seu ramo de tronco no ramo estável para saber quantos conflitos você pode encontrar. Será importante ficar de olho em todos os arquivos específicos do site (por exemplo, arquivos de configuração), a menos que você pretenda executar apenas o site.
Como alternativa, você já tentou fazer a alteração no site?
Para obter informações sobre git hooks, consulte a documentação do githooks .
Minha opinião sobre a solução dos cristãos .
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
Estou usando a seguinte solução do toroid.org , que possui um script de gancho mais simples.
no servidor:
$ mkdir website.git && cd website.git
$ git init --bare
Initialized empty Git repository in /home/ams/website.git/
e instale o gancho no servidor:
$ 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
no seu cliente:
$ 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
para publicar, basta digitar
$ git push web
Há uma descrição completa no site: http://toroid.org/ams/git-website-howto
git push web +master:refs/heads/master
invés de apenas git push web master
?
Como resposta complementar, gostaria de oferecer uma alternativa. Estou usando o git-ftp e funciona bem.
https://github.com/git-ftp/git-ftp
Fácil de usar, apenas digite:
git ftp push
e o git fará o upload automático dos arquivos do projeto.
Saudações
Dado um ambiente em que você tem vários desenvolvedores acessando o mesmo repositório, as seguintes diretrizes podem ajudar.
Verifique se você possui um grupo unix ao qual todos os desenvolvedores pertencem e dê a propriedade do repositório .git a esse grupo.
No .git / config do repositório do servidor, configure sharedrepository = true. (Isso diz ao git para permitir vários usuários, necessários para confirmações e implantação.
defina o umask de cada usuário em seus arquivos bashrc para ser o mesmo - 002 é um bom começo
Acabei criando minha própria ferramenta rudimentar de implantação, que retiraria automaticamente novas atualizações do repositório - https://github.com/jesalg/SlimJim - Basicamente, ele escuta o github pós-recebimento-gancho e usa um proxy para acionar um script de atualização.
Eu uso duas soluções para gancho pós-recebimento:
SOLUÇÃO DE IMPLANTAÇÃO 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
SOLUÇÃO DE IMPLANTAÇÃO 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
Ambas as soluções são baseadas em soluções anteriores disponíveis neste segmento.
Observe que o BRANCH_REGEX = '^ $ {GIT_BRANCH1}. Filtros $ 'para os nomes das filiais correspondentes a "mestre sequência " ou "dev *" e implementa a árvore de trabalho, se a ramificação enviada corresponder. Isso possibilita implantar uma versão dev e uma versão master em diferentes locais.
A IMPLANTAÇÃO SOLUÇÃO 1 remove apenas os arquivos que fazem parte do repositório e foi removida por uma confirmação. É mais rápido que o Deployment Solution 2.
A IMPLANTAÇÃO SOLUÇÃO 2 tem a vantagem de remover todos os novos arquivos do diretório de produção, que foram adicionados no servidor, independentemente de terem sido adicionados ao repositório ou não. Será sempre uma limpeza do repositório. É mais lento que a Solução de Implantação 1.