web-dev-qa-db-fra.com

Déployer un projet en utilisant Git push

Est-il possible de déployer un site Web en utilisant git Push? J'ai l'impression que cela a quelque chose à voir avec l'utilisation de git hooks pour exécuter un git reset --hard sur le serveur, mais comment pourrais-je y parvenir?

409
Kyle Cronin

J'ai trouvé ce script sur ce site et il semble fonctionner assez bien.

  1. Copiez votre répertoire .git sur votre serveur Web
  2. Sur votre copie locale, modifiez votre fichier .git/config et ajoutez votre serveur Web en tant que télécommande:

    [remote "production"]
        url = username@webserver:/path/to/htdocs/.git
    
  3. Sur le serveur, remplacez .git/hooks/post-update par ce fichier (dans la réponse ci-dessous)

  4. Ajoutez un accès en exécution au fichier (à nouveau, sur le serveur):

    chmod +x .git/hooks/post-update
    
  5. Désormais, il suffit d'appuyer localement sur votre serveur Web pour qu'il mette automatiquement à jour la copie de travail:

    git Push production
    
287
Kyle Cronin

En utilisant le fichier post-update ci-dessous:

  1. Copiez votre répertoire .git sur votre serveur Web
  2. Sur votre copie locale, modifiez votre fichier .git/config et ajoutez votre serveur Web en tant que télécommande:

    [remote "production"]
        url = username@webserver:/path/to/htdocs/.git
    
  3. Sur le serveur, remplacez .git/hooks/post-update par le fichier ci-dessous

  4. Ajoutez un accès en exécution au fichier (à nouveau, sur le serveur):

    chmod +x .git/hooks/post-update
    
  5. Désormais, il suffit d'appuyer localement sur votre serveur Web pour qu'il mette automatiquement à jour la copie de travail:

    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
77

Après de nombreux faux départs et impasses, je peux enfin déployer le code de site Web avec juste "git Push à distance " grâce à cet article .

Le script post-mise à jour de l'auteur ne comporte qu'une ligne et sa solution ne nécessite pas de configuration .htaccess pour masquer le dépôt Git, contrairement à d'autres.

Quelques obstacles si vous déployez cela sur une instance Amazon EC2;

1) Si vous utilisez Sudo pour créer le référentiel de destination nue, vous devez changer le propriétaire du référentiel en ec2-user, sans quoi le push échouera. (Essayez "chown ec2-user: ec2-user repo .")

2) Le Push échouera si vous ne préconfigurez pas l'emplacement de votre clé privée Amazon . Pem, soit dans/etc/ssh./ssh_config en tant que paramètre IdentityFile ou dans ~/.ssh/config à l'aide de la présentation "[Host] - HostName - IdentityFile - User" décrite ici ...

Cependant, si l'hôte est configuré dans ~/.ssh/config et différent de HostName, Git Push échouera. (C'est probablement un bug de Git)

59
Earl Zedd

ne pas installer git sur un serveur ou copier le dossier .git. pour mettre à jour un serveur depuis un clone git, vous pouvez utiliser la commande suivante:

git ls-files -z | rsync --files-from - --copy-links -av0 . [email protected]:/var/www/project

vous devrez peut-être supprimer les fichiers supprimés du projet.

cela copie tous les fichiers archivés. rsync utilise de toute façon ssh qui est installé sur un serveur.

moins vous avez installé de logiciel sur un serveur, plus il est sécurisé et plus il est facile de gérer sa configuration et de la documenter. Il n'est pas non plus nécessaire de conserver un clone complet de git sur le serveur. cela ne fait que rendre plus complexe la sécurisation correcte de tout.

21
Christian

En substance, tout ce que vous devez faire sont les suivants:

server = $1
branch = $2
git Push $server $branch
ssh <username>@$server "cd /path/to/www; git pull"

J'ai ces lignes dans mon application en tant qu'exécutable appelé deploy.

donc quand je veux faire un déploiement, je tape ./deploy myserver mybranch.

12
Lloyd Moore

Comme je le fais, j’ai un référentiel Git nu sur mon serveur de déploiement où les modifications Push. Ensuite, je me connecte au serveur de déploiement, je modifie le répertoire de documents du serveur Web et effectue une extraction git. Je n'utilise pas de crochets pour essayer de le faire automatiquement, cela semble être plus de problèmes que ça n'en vaut la peine.

9
Greg Hewgill

receive.denyCurrentBranch updateInstead ajouté dans Git 2.3 est une possibilité.

Définissez-le sur le référentiel du serveur et il met également à jour l'arborescence de travail si elle est propre.

La version 2.4 a été améliorée avec le crochet Push-to-checkout et le traitement des branches non encore nées .

Exemple d'utilisation:

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

Sortie:

a
b

Cela a les défauts suivants mentionnés sur l'annonce de GitHub :

  • Votre serveur contiendra un répertoire .git contenant l'historique complet de votre projet. Vous voulez probablement vous assurer que cela ne puisse pas être servi aux utilisateurs!
  • Lors des déploiements, les utilisateurs pourront rencontrer momentanément le site dans un état incohérent, avec certains fichiers de l'ancienne version et d'autres de la nouvelle version, voire des fichiers semi-écrits. Si cela pose un problème pour votre projet, le déploiement instantané n’est probablement pas pour vous.
  • Si votre projet nécessite une étape de "construction", vous devrez alors le configurer explicitement, peut-être via githooks.

Mais tous ces points sont hors de la portée de Git et doivent être gérés par un code externe. Donc, dans ce sens, ceci, avec les crochets Git, constitue la solution ultime.

Pour le scénario de déploiement

Dans notre scénario, nous stockons le code sur github/bitbucket et souhaitons le déployer sur des serveurs en direct. Dans ce cas, la combinaison suivante fonctionne pour nous (c'est un remix des réponses les plus votées ici) :

  1. Copiez votre répertoire .git sur votre serveur Web.
  2. Sur votre copie locale git remote add live ssh://user@Host:port/folder
  3. Sur la télécommande: git config receive.denyCurrentBranch ignore
  4. Sur la télécommande: nano .git/hooks/post-receive et ajoutez ce contenu:

    #!/bin/sh GIT_WORK_TREE=/var/www/vhosts/example.org git checkout -f

  5. Sur la télécommande: chmod +x .git/hooks/post-receive

  6. Maintenant, vous pouvez y appuyer avec git Push live

Remarques

  • Cette solution fonctionne avec les anciennes versions de git (testées avec 1.7 et 1.9)
  • Vous devez vous assurer d’abord d’appuyer sur github/bitbucket pour obtenir un dépôt cohérent en direct.
  • Si votre dossier .git se trouve dans la racine du document, assurez-vous de le masquer de l'extérieur en ajoutant à .htaccess ( source ):

    RedirectMatch 404 /\..*$

5
Attila Fulop

Mise à jour: J'utilise maintenant Lloyd Moore solution avec l'agent de clé ssh -A .... Pousser vers un dépôt principal puis le sortir en parallèle de toutes vos machines est un peu plus rapide et nécessite moins de configuration sur ces machines.


Ne pas voir cette solution ici. Appuyez simplement sur ssh si git est installé sur le serveur.

Vous aurez besoin de l’entrée suivante dans votre .git/config local

[remote "Amazon"]
    url = Amazon:/path/to/project.git
    fetch = +refs/heads/*:refs/remotes/Amazon/*

Mais hé, qu'est-ce que c'est avec Amazon:? Dans votre ~/.ssh/config local, vous devez ajouter l'entrée suivante:

Host Amazon
    Hostname <YOUR_IP>
    User <USER>
    IdentityFile ~/.ssh/Amazon-private-key

maintenant tu peux appeler

git Push Amazon master
ssh <USER>@<YOUR_IP> 'cd /path/to/project && git pull'

(BTW: /path/to/project.git est différent du répertoire de travail actuel/path/to/project)

5
Karussell

Nous utilisons capistrano pour gérer déployer. Nous construisons capistrano pour le déploiement sur un serveur intermédiaire, puis pour exécuter un rsync avec l’ensemble de nos serveurs.

cap deploy
cap deploy:start_rsync (when the staging is ok)

Avec capistrano, on peut facilement revenir en arrière en cas de problème

cap deploy:rollback
cap deploy:start_rsync
4
Supernini

Giddyup sont indépendants de la langue juste-ajouter-eau pour automatiser le déploiement via git Push. Il vous permet également d'avoir des points d'ancrage personnalisés pour démarrer/arrêter le serveur Web, réchauffer le cache, etc.

https://github.com/mpalmer/giddyup

Départ exemples .

2
Artur Bodera

On dirait que vous devriez avoir deux copies sur votre serveur. Une copie nue, à partir de laquelle vous pouvez appuyer/extraire, à partir de laquelle vous souhaitez appliquer vos modifications lorsque vous avez terminé, puis cloner cette information dans votre répertoire Web et configurer un travail cron pour mettre à jour git pull à partir de votre répertoire Web tous les jours ou alors.

1
Flame

J'utilise la solution suivante de toroid.org , qui a un script de hook plus simple.

sur le serveur:

$ mkdir website.git && cd website.git
$ git init --bare
Initialized empty Git repository in /home/ams/website.git/

et installez le hook sur le serveur:

$ 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

sur votre client:

$ 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

puis pour publier, il suffit de taper

$ git Push web

Il y a une description complète sur le site: http://toroid.org/ams/git-website-howto

1
Synox

Comme réponse complémentaire, j'aimerais proposer une alternative. J'utilise git-ftp et cela fonctionne bien.

https://github.com/git-ftp/git-ftp

Facile à utiliser, seul le type:

git ftp Push

et git téléchargera automatiquement les fichiers du projet.

Cordialement

1
manuelbcd

Mon point de vue sur chrétiens solution.

git archive --prefix=deploy/  master | tar -x -C $TMPDIR | rsync $TMPDIR/deploy/ --copy-links -av [email protected]:/home/user/my_app && rm -rf $TMPDIR/deploy
  • Archive la branche maîtresse dans tar
  • Extrait les archives tar dans le répertoire deploy du dossier temporaire du système.
  • rsync se transforme en serveur
  • supprimer le répertoire de déploiement du dossier temporaire.
1
Priit

Vous pourriez éventuellement configurer un crochet git qui, lorsqu'un script est engagé, indique les branches "stables", il extrait les modifications et les applique au site PHP. Le gros inconvénient est que vous n’aurez pas beaucoup de contrôle en cas de problème, ce qui vous donnera plus de temps pour vos tests - mais vous pouvez avoir une idée de l’ampleur du travail que vous devrez effectuer lorsque vous fusionnerez, dites à votre branche de coffre dans la branche stable de savoir combien de conflits vous pouvez rencontrer. Il sera important de garder un œil sur tous les fichiers propres au site (par exemple, les fichiers de configuration), à moins que vous ne souhaitiez uniquement exécuter le site en question.

Sinon, avez-vous envisagé de modifier le site à la place?

Pour plus d'informations sur les crochets git, voir la documentation githooks .

1
Chealion

Dans un environnement où plusieurs développeurs accèdent au même référentiel, les instructions suivantes peuvent vous aider.

Assurez-vous que vous avez un groupe unix auquel tous les développeurs appartiennent et donnez la propriété du référentiel .git à ce groupe.

  1. Dans le fichier .git/config du référentiel du serveur, sharedrepository = true. (Cela indique à git d'autoriser plusieurs utilisateurs, ce qui est nécessaire pour les validations et le déploiement.

  2. définissez le umask de chaque utilisateur dans ses fichiers bashrc pour qu'il soit identique - 002 est un bon début

0
Lloyd Moore

J'ai fini par créer mon propre outil de déploiement rudimentaire qui extrairait automatiquement les nouvelles mises à jour du référentiel - https://github.com/jesalg/SlimJim - En gros, il écoute le github post-receive-hook et utilise un proxy pour déclencher un script de mise à jour.

0
jesal

J'utilise deux solutions pour le hook post-réception:

DÉPLOYER LA 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

Les deux solutions sont basées sur des solutions antérieures disponibles dans ce fil.

Notez que les filtres BRANCH_REGEX = '^ $ {GIT_BRANCH1}. $' pour les noms de branche correspondant à la chaîne "master " ou "dev *" et sont déployés. l'arbre de travail, si la branche poussée correspond. Cela permet de déployer une version dev et une version maître à différents endroits.

DEPLOY SOLUTION 1 ne supprime que les fichiers qui font partie du référentiel et a été supprimé par un commit. C'est plus rapide que la solution de déploiement 2.

DEPLOY SOLUTION 2 présente l’avantage de supprimer tous les nouveaux fichiers du répertoire de production ajouté sur le serveur, qu’il ait été ajouté au référentiel ou non. Ce sera toujours dupe propre du repo. Il est plus lent que la solution de déploiement 1.

0
klor