Vérifiez si la traction est nécessaire dans Git

623

Comment vérifier si le référentiel distant a changé et que je dois tirer?

Maintenant, j'utilise ce script simple:

git pull --dry-run | grep -q -v 'Already up-to-date.' && changed=1

Mais c'est plutôt lourd.

Y a-t-il une meilleure façon? La solution idéale consisterait à vérifier toutes les branches distantes et à renvoyer les noms des branches modifiées et le nombre de nouvelles validations dans chacune.

takhin
la source
14
Veuillez noter: "git pull --dry-run" ne fonctionne pas comme prévu. Il semble que git pull passe directement des options inconnues à git fetch. Le résultat est celui d'un git pull normal.
27
"pull" est juste un moyen court de faire "fetch" et "merge" à la fois, si vous avez besoin de vérifier l'état du dépôt à distance, vous simulez vraiment un "fetch". C'est git fetch -v --dry-runce dont vous avez besoin.
Claudio Floreani

Réponses:

859

Première utilisation git remote update, pour mettre à jour vos références de télécommande. Ensuite, vous pouvez effectuer plusieurs opérations, telles que:

  1. git status -unovous dira si la branche que vous suivez est devant, derrière ou a divergé. S'il ne dit rien, le local et le distant sont les mêmes.

  2. git show-branch *mastervous montrera les commits dans toutes les branches dont les noms se terminent par «master» (par exemple master et origin / master ).

Si vous utilisez -vavec git remote update( git remote -v update), vous pouvez voir quelles branches ont été mises à jour, vous n'avez donc pas vraiment besoin d'autres commandes.

Cependant, il semble que vous souhaitiez le faire dans un script ou un programme et vous retrouver avec une valeur vraie / fausse. Dans l'affirmative, il existe des moyens de vérifier la relation entre votre validation HEAD actuelle et le chef de la branche que vous suivez, bien qu'il existe quatre résultats possibles, vous ne pouvez pas la réduire à une réponse oui / non. Cependant, si vous êtes prêt à le faire, pull --rebasevous pouvez traiter "local is behind" et "local has diverged" comme "need to pull", et les deux autres comme "don't need to pull".

Vous pouvez obtenir l'ID de validation de n'importe quelle référence en utilisant git rev-parse <ref>, vous pouvez donc le faire pour master et origin / master et les comparer. S'ils sont égaux, les branches sont les mêmes. S'ils sont inégaux, vous voulez savoir ce qui est en avance sur l'autre. L'utilisation git merge-base master origin/mastervous indiquera l'ancêtre commun des deux branches, et si elles n'ont pas divergé, ce sera la même chose que l'une ou l'autre. Si vous obtenez trois identifiants différents, les branches ont divergé.

Pour le faire correctement, par exemple dans un script, vous devez être en mesure de vous référer à la branche actuelle et à la branche distante qu'elle suit. La fonction de configuration d'invite bash dans /etc/bash_completion.dcontient du code utile pour obtenir les noms de branche. Cependant, vous n'avez probablement pas besoin d'obtenir les noms. Git a quelques raccourcis pour faire référence aux branches et commits (comme documenté dans git rev-parse --help). En particulier, vous pouvez utiliser @pour la branche actuelle (en supposant que vous n'êtes pas dans un état de tête détachée) et @{u}pour sa branche en amont (par exemple origin/master). Ainsi git merge-base @ @{u}retournera le (hachage du) commit auquel la branche courante et son amont divergent et git rev-parse @et git rev-parse @{u}vous donnera les hachages des deux astuces. Cela peut être résumé dans le script suivant:

#!/bin/sh

UPSTREAM=${1:-'@{u}'}
LOCAL=$(git rev-parse @)
REMOTE=$(git rev-parse "$UPSTREAM")
BASE=$(git merge-base @ "$UPSTREAM")

if [ $LOCAL = $REMOTE ]; then
    echo "Up-to-date"
elif [ $LOCAL = $BASE ]; then
    echo "Need to pull"
elif [ $REMOTE = $BASE ]; then
    echo "Need to push"
else
    echo "Diverged"
fi

Remarque: les anciennes versions de git ne le permettaient pas @, vous devrez donc peut-être utiliser à la @{0}place.

La ligne UPSTREAM=${1:-'@{u}'}vous permet éventuellement de passer explicitement une branche en amont, au cas où vous voudriez comparer avec une branche distante différente de celle configurée pour la branche actuelle. Il s'agit généralement de la forme nom distant / nom de branche . Si aucun paramètre n'est donné, la valeur par défaut est @{u}.

Le script suppose que vous avez fait une git fetchou une git remote updatepremière pour mettre à jour les branches de suivi. Je n'ai pas intégré cela dans le script car il est plus flexible de pouvoir faire la récupération et la comparaison en tant qu'opérations distinctes, par exemple si vous voulez comparer sans récupérer car vous avez déjà récupéré récemment.

Neil Mayhew
la source
4
@takeshin Je suppose que vous pouvez combiner git ls-remote origin -h refs / heads / master comme suggéré par @brool avec git rev-list --max-count = 1 origin / master. S'ils renvoient le même hachage, la branche distante n'a pas changé depuis la dernière mise à jour de vos références distantes (avec pull, fetch, mise à jour à distance, etc.) Cela aurait l'avantage que vous n'auriez pas à retirer le contenu de tous les commits tout de suite, mais pourraient laisser cela pour un moment plus pratique. Cependant, comme la mise à jour à distance n'est pas destructrice, vous pourriez tout aussi bien le faire.
Neil Mayhew
2
Vous pouvez également essayer git status -s -u no, ce qui donne une sortie plus courte que git status -u no.
Phillip Cloud
2
@mhulse, git remote -v update. Regardez la sortie de git remote --helppour une explication plus complète.
Neil Mayhew
1
@ChrisMaes Bon point. La syntaxe plus explicite est nécessaire avec les anciennes versions de git. J'ai expérimenté les différents systèmes que j'ai et j'ai trouvé que cela @{u}fonctionne avec git 1.8.3.2 mais @pas. Fonctionne cependant @avec 1.8.5.4. Morale de l'histoire: git continue de s'améliorer et cela vaut la peine d'avoir la version la plus récente possible.
Neil Mayhew
1
Un spécificateur est désormais requis pour @. Vous pouvez utiliser @ {0} au lieu de @.
Ben Davis
132

Si vous avez une succursale en amont

git fetch <remote>
git status

Si vous n'avez pas de succursale en amont

Comparez les deux branches:

git fetch <remote>
git log <local_branch_name>..<remote_branch_name> --oneline

Par exemple:

git fetch origin

# See if there are any incoming changes
git log HEAD..origin/master --oneline

(Je suppose que origin/masterc'est votre branche de suivi à distance)

Si des validations sont répertoriées dans la sortie ci-dessus, vous avez des modifications entrantes - vous devez fusionner. Si aucun commit n'est répertorié par, git logil n'y a rien à fusionner.

Notez que cela fonctionnera même si vous êtes sur une branche de fonctionnalité - qui n'a pas de télécommande de suivi, car si elle fait explicitement référence au origin/masterlieu d'utiliser implicitement la branche en amont mémorisée par Git.

PlagueHammer
la source
2
Même une notation plus courte git fetch; git log HEAD.. --onelinepeut être utilisée s'il existe une branche distante par défaut pour une branche locale.
phil pirozhkov
@philpirozhkov Si vous avez une branche distante par défaut, un simple "état git" devrait faire je pense. Ma réponse était générique pour deux branches, où l'une peut ou non suivre l'autre.
PlagueHammer
55
git rev-list HEAD...origin/master --countvous donnera le nombre total de commits "différents" entre les deux.
Jake Berger
1
court et simple. Ma solution préférée qui montre juste les nouveaux commits (pouce levé deux fois)
spankmaster79
Comment puis-je l'utiliser dans un fichier batch (Ubuntu), afin de pouvoir exécuter d'autres commandes au cas où cette commande montre qu'un pull est nécessaire?
Ulysses Alves
69

S'il s'agit d'un script, vous pouvez utiliser:

git fetch
$(git rev-parse HEAD) == $(git rev-parse @{u})

(Remarque: l'avantage de cette réponse par rapport aux réponses précédentes est que vous n'avez pas besoin d'une commande distincte pour obtenir le nom de la branche actuelle. "HEAD" et "@ {u}" (la branche actuelle en amont) s'en occupent. Voir "git rev-parse --help" pour plus de détails.)

Stephen Haberman
la source
J'ai découvert @ {u} indépendamment et j'avais mis à jour ma réponse avant de voir la vôtre.
Neil Mayhew
1
Affiche en git rev-parse @{u}fait le dernier commit sans un git fetch?
Kyle Strand
3
C'était le ticket! Cependant, votre logique utilise ==ce qui signifie "s'il n'y a AUCUN changement depuis l'amont". J'avais l'habitude !=de vérifier "s'il y a des changements en amont" pour mon application. N'oubliez pas de git fetchcommencer!
ChrisPrime
1
J'ai ajouté git fetch, car il est vraiment nécessaire de répondre à la question d'origine. @est l'abréviation de HEADbtw.
user1338062
Les utilisateurs de Windows auront besoin de guillemets simples par @{u}exemplegit rev-parse '@{u}'
spuder
36

La commande

git ls-remote origin -h refs/heads/master

affichera la tête actuelle sur la télécommande - vous pouvez la comparer à une valeur précédente ou voir si vous avez le SHA dans votre référentiel local.

brool
la source
1
Un exemple de script pour comparer ces valeurs?
prend le
18
git rev-list HEAD...origin/master --countvous donnera le nombre total de commits "différents" entre les deux.
Jake Berger
3
@jberger pour clarifier, cela ne montrera que le nombre de validations que vous êtes derrière (pas devant et derrière) et cela ne fonctionne que si vous git fetchou d' git remote updateabord. git statusmontre également un décompte, btw.
Dennis
1
@Dennis Je pensais que c'était .."commits en origine / master, en soustrayant HEAD" (ie nombre de commits derrière). Considérant que, ...est la différence symétrique (c'est-à-dire devant et derrière)
Jake Berger
3
Excellent. Pour autant que je sache, c'est la seule solution qui vérifie l'origine des mises à jour mais ne le fait pas implicitement fetch.
Kyle Strand
35

Voici un one-liner Bash qui compare le hachage de validation HEAD de la branche actuelle à sa branche en amont distante, sans lourdeur git fetchni git pull --dry-runopération requise:

[ $(git rev-parse HEAD) = $(git ls-remote $(git rev-parse --abbrev-ref @{u} | \
sed 's/\// /g') | cut -f1) ] && echo up to date || echo not up to date

Voici comment cette ligne quelque peu dense est décomposée:

  • Les commandes sont regroupées et imbriquées à l'aide de la substitution de commandes$(x) Bash syntaxe de .
  • git rev-parse --abbrev-ref @{u}renvoie une référence abrégée en amont (par exemple origin/master), qui est ensuite convertie en champs séparés par des espaces par la sedcommande canalisée , par exemple origin master.
  • Cette chaîne est introduite dans git ls-remote laquelle renvoie le commit de tête de la branche distante. Cette commande communiquera avec le référentiel distant. La cutcommande canalisée extrait uniquement le premier champ (le hachage de validation), supprimant la chaîne de référence séparée par des tabulations.
  • git rev-parse HEAD renvoie le hachage de validation local.
  • La syntaxe Bash [ a = b ] && x || ycomplète le one-liner: il s'agit d'une comparaison de chaînes Bash =dans une construction de test [ test ], suivie de constructions and-list et or-list && true || false.
wjordan
la source
2
Je n'utiliserais pas / g sur le sed si vous utilisez des barres obliques dans les noms de branche. Il s'agit uniquement de "sed / \ // /".
Martyn Davis
@wjordan Votre solution échoue lorsque le référentiel distant n'est pas accessible (ou en cours de maintenance) et se déclenchera "à jour"
image
20

Je vous suggère d'aller voir le script https://github.com/badele/gitcheck . J'ai codé ce script pour archiver en un seul passage tous vos référentiels Git, et il montre qui n'a pas commis et qui n'a pas poussé / tiré.

Voici un exemple de résultat:

Entrez la description de l'image ici

Bruno Adelé
la source
6
soigné, en pensant à le réécrire en pure coque
Olivier Refalo
1
Maintenant, vous pouvez également utiliser gitcheck directement à partir d'un conteneur docker (avec vos fichiers dans votre hôte) Pour plus d'informations, voir le projet gitcheck github
Bruno Adelé
Un outil similaire dans bash git-multi-repo-tooling . git mrepo -ccela affichera toutes les validations en attente.
Greg
11

J'ai basé cette solution sur les commentaires de @jberger.

if git checkout master &&
    git fetch origin master &&
    [ `git rev-list HEAD...origin/master --count` != 0 ] &&
    git merge origin/master
then
    echo 'Updated!'
else
    echo 'Not updated.'
fi
ma11hew28
la source
se référant à votre commentaire précédent , à ce stade, je ne peux pas vous donner une réponse définitive. Au moment où j'ai fait ces commentaires, je plongeais dans les profondeurs de Git et en particulier des télécommandes et des diffs. Cela fait quelques mois depuis et une grande partie de cette connaissance est enfouie dans mon cerveau. ;) Si vous recherchez le nombre de commits «différents» entre les deux, cela ...semble être une partie valide de votre solution.
Jake Berger
1
Merci. C'était propre.
Shobhit Puri
10

Il existe déjà de nombreuses réponses très riches et ingénieuses. Pour apporter un peu de contraste, je pourrais me contenter d'une ligne très simple.

# Check return value to see if there are incoming updates.
if ! git diff --quiet remotes/origin/HEAD; then
 # pull or whatever you want to do
fi
thuovila
la source
2
La réponse originale manquait '!' dans l'if. La valeur de retour de git diff est zéro, lorsqu'il n'y a aucun changement.
thuovila
IMO meilleure solution là-bas, même si je dois remplacer "télécommandes / origine / HEAD" par "origine / maître" ou autre révision
Matthias Michael Engh
9

Je pense que la meilleure façon de procéder serait:

git diff remotes/origin/HEAD

En supposant que vous avez enregistré cette refspec. Vous devriez, si vous avez cloné le référentiel, sinon (c'est-à-dire si le référentiel a été créé de novo localement et poussé sur la télécommande), vous devez ajouter explicitement la refspec.

Jeet
la source
9

Le script ci-dessous fonctionne parfaitement.

changed=0
git remote update && git status -uno | grep -q 'Your branch is behind' && changed=1
if [ $changed = 1 ]; then
    git pull
    echo "Updated successfully";
else
    echo "Up-to-date"
fi
Harikrishna
la source
6

Je ferais la manière suggérée par brool. Le script d'une ligne suivant prend le SHA1 de votre dernière version validée et le compare à celui de l'origine distante, et ne récupère les modifications que si elles diffèrent. Et c'est encore plus léger des solutions basées sur git pullou git fetch.

[ `git log --pretty=%H ...refs/heads/master^` != `git ls-remote origin
-h refs/heads/master |cut -f1` ] && git pull
Claudio Floreani
la source
Cette commande échoue si le référentiel git est cloné avec "--depth 1" (pour limiter la taille du téléchargement). Savez-vous s'il existe un moyen de le réparer?
Adam Ryczkowski
Le journal git ceci renvoie de nombreuses lignes, et donne une erreur "bash: [: trop d'arguments" je passerais àgit rev-parse --verify HEAD
Drew Pierce
1
Il s'agit d'une simple comparaison de chaînes effectuée par bash. Si quelque chose échoue, je vous suggère de vérifier votre syntaxe (c'est-à-dire que vous l'avez mal tapé). Exécutez d'abord git log --pretty=%H ...refs/heads/master^ pour obtenir le SHA1 de votre dernière version validée, puis exécutez git ls-remote origin -h refs/heads/master |cut -f1 pour obtenir le SHA1 de l'origine distante. Ces deux sont des commandes git et n'ont rien à voir avec bash. Ce que bash fait à l'intérieur des crochets est de comparer la sortie de la première commande avec la seconde, et si elles sont égales, elle retourne vrai et s'exécute git pull.
Claudio Floreani
"et s'ils sont égaux, il retourne vrai et s'exécute git pull". Je sais que je suis nerveux, mais juste pour éviter la confusion de quelqu'un, cela devrait être "et s'ils ne sont pas égaux". De plus, pour une raison quelconque, la première commande git ne fonctionne pas pour moi. (Je suis sur git 2.4.1.) Donc j'utilise juste à la git log --pretty=%H master | head -n1place. Mais je ne sais pas si c'est exactement la même chose.
xd1le
6

Si vous exécutez ce script, il testera si la branche actuelle a besoin d'un git pull:

#!/bin/bash

git fetch -v --dry-run 2>&1 |
    grep -qE "\[up\s+to\s+date\]\s+$(
        git branch 2>/dev/null |
           sed -n '/^\*/s/^\* //p' |
                sed -r 's:(\+|\*|\$):\\\1:g'
    )\s+" || {
        echo >&2 "Current branch need a 'git pull' before commit"
        exit 1
}

Il est très pratique de le mettre en pré-commit du hook Git pour éviter

Merge branch 'foobar' of url:/path/to/git/foobar into foobar

quand tu commitavantpulling .

Pour utiliser ce code comme hook, copiez / collez simplement le script dans

.git/hooks/pre-commit

et

chmod +x .git/hooks/pre-commit
Gilles Quenot
la source
6

Je veux juste poster ceci comme un message réel car il est facile de manquer cela dans les commentaires.

La réponse correcte et la meilleure pour cette question a été donnée par @Jake Berger, Merci beaucoup mec, tout le monde en a besoin et tout le monde le manque dans les commentaires. Donc, pour tous ceux qui luttent avec cela, voici la bonne réponse, utilisez simplement la sortie de cette commande pour savoir si vous avez besoin de faire un git pull. si la sortie est 0, il n'y a évidemment rien à mettre à jour.

@stackoverflow, donnez à ce gars une cloche. Merci @ Jake Berger

git rev-list HEAD...origin/master --count will give you the total number of "different" commits between the two.  Jake Berger Feb 5 '13 at 19:23
diegeelvis_SA
la source
4

Exécutez git fetch (remote)pour mettre à jour vos références distantes, il vous montrera les nouveautés. Ensuite, lorsque vous passez à la caisse de votre succursale locale, elle vous indique si elle est en amont.

che
la source
Je pense qu'il a déjà vérifié la succursale locale, il a donc besoin d'autre chose pour montrer s'il est derrière, etc. Il peut le faire avec le statut git.
Neil Mayhew
Certes, après avoir récupéré les télécommandes, git statuscela le montrera également.
che
1
C'est quelque chose dans l'humeur git pull --dry-run, mais je pense que c'est trop lourd pour un script cron exécuté chaque minute.
takehin
@takeshin: Vous ne pouvez pas vérifier les référentiels distants sans aller sur le réseau. S'il n'y a rien de nouveau fetch, cela ne va pas faire beaucoup plus que de vérifier le statut. Si vous avez besoin d'une réaction très rapide et légère sur les mises à jour à distance, vous voudrez peut-être envisager de connecter une sorte de notifications au référentiel distant.
che
@takeshin: si vous voulez vérifier le repo à distance toutes les minutes, je pense que vous avez raté l'intérêt du DVCS. L'idée est de pouvoir se développer de façon indépendante pendant un certain temps, puis de tout assembler en douceur plus tard. Ce n'est pas comme cvs, svn, p4 etc. où vous devez toujours travailler au-dessus de ce qui est le plus récent dans le référentiel. Si vous avez vraiment besoin de quelque chose sur lequel quelqu'un d'autre travaille, alors vous devriez utiliser un mécanisme de communication différent, comme le courrier électronique, pour vous dire quand il est prêt à tirer.
Neil Mayhew
4

Toutes ces suggestions complexes alors que la solution est si courte et si simple:

#!/bin/bash

BRANCH="<your branch name>"
LAST_UPDATE=`git show --no-notes --format=format:"%H" $BRANCH | head -n 1`
LAST_COMMIT=`git show --no-notes --format=format:"%H" origin/$BRANCH | head -n 1`

git remote update
if [ $LAST_COMMIT != $LAST_UPDATE ]; then
        echo "Updating your branch $BRANCH"
        git pull --no-edit
else
        echo "No updates available"
fi
Humain numérique
la source
LAST_COMMIT et LAST_UPDATE sont toujours égaux même s'il y a des changements
canbax
Cette solution est bonne et simple, il faut qu'elle ait été git remote updateexécutée avant votre code, pour obtenir les dernières informations de validation d'origine
ak93
Ne devrait git remote updatepas s'ajouter avant les git showcommandes?
Setop
2

Voici ma version d'un script Bash qui vérifie tous les référentiels dans un dossier prédéfini:

https://gist.github.com/henryiii/5841984

Il peut faire la différence entre des situations courantes, comme la traction nécessaire et la poussée nécessaire, et il est multithread, de sorte que la récupération se produit en même temps. Il a plusieurs commandes, comme pull et status.

Mettez un lien symbolique (ou le script) dans un dossier de votre chemin, puis cela fonctionne comme git all status(, etc.). Il ne prend en charge que l'origine / master, mais il peut être modifié ou combiné avec une autre méthode.

Henry Schreiner
la source
1
git ls-remote | cut -f1 | git cat-file --batch-check >&-

répertorie tout ce qui est référencé dans toute télécommande qui n'est pas dans votre référentiel. Pour attraper les changements de référence à distance sur des choses que vous aviez déjà (par exemple, réinitialise les validations précédentes) prend un peu plus:

git pack-refs --all
mine=`mktemp`
sed '/^#/d;/^^/{G;s/.\(.*\)\n.* \(.*\)/\1 \2^{}/;};h' .git/packed-refs | sort -k2 >$mine
for r in `git remote`; do 
    echo Checking $r ...
    git ls-remote $r | sort -k2 | diff -b - $mine | grep ^\<
done
jthill
la source
1

Peut-être cela, si vous souhaitez ajouter une tâche en tant que crontab:

#!/bin/bash
dir="/path/to/root"
lock=/tmp/update.lock
msglog="/var/log/update.log"

log()
{
        echo "$(date) ${1:-missing}" >> $msglog
}

if [ -f $lock ]; then
        log "Already run, exiting..."
else
        > $lock
        git -C ~/$dir remote update &> /dev/null
        checkgit=`git -C ~/$dir status`
        if [[ ! "$checkgit" =~ "Your branch is up-to-date" ]]; then
                log "-------------- Update ---------------"
                git -C ~/$dir pull &>> $msglog
                log "-------------------------------------"
        fi
        rm $lock

fi
exit 0
Altzone
la source
1

Utilisation d'une expression rationnelle simple:

str=$(git status) 
if [[ $str =~ .*Your\ branch\ is\ behind.*by.*commits,\ and\ can\ be\ fast-forwarded ]]; then
    echo `date "+%Y-%m-%d %H:%M:%S"` "Needs pull"
else
    echo "Code is up to date"
fi
Tomas Kukis
la source
Cela ne fonctionnera pas. git status n'est qu'un contrôle local, et il ne vous dirait donc que si votre branche est en retard si vous avez déjà mis à jour vos paramètres distants.
minhaz1
0

J'utilise une version d'un script basé sur la réponse de Stephen Haberman:

if [ -n "$1" ]; then
    gitbin="git -C $1"
else
    gitbin="git"
fi

# Fetches from all the remotes, although --all can be replaced with origin
$gitbin fetch --all
if [ $($gitbin rev-parse HEAD) != $($gitbin rev-parse @{u}) ]; then
    $gitbin rebase @{u} --preserve-merges
fi

En supposant que ce script est appelé git-fetch-and-rebase, il peut être invoqué avec un argument facultatifdirectory name du référentiel Git local pour effectuer l'opération. Si le script est appelé sans arguments, il suppose que le répertoire courant fait partie du référentiel Git.

Exemples:

# Operates on /abc/def/my-git-repo-dir
git-fetch-and-rebase /abc/def/my-git-repo-dir

# Operates on the Git repository which the current working directory is part of
git-fetch-and-rebase

Il est également disponible ici .

Tuxdude
la source
0

Après avoir lu de nombreuses réponses et plusieurs articles, et passé une demi-journée à essayer différentes permutations, voici ce que j'ai trouvé.

Si vous êtes sous Windows, vous pouvez exécuter ce script dans Windows en utilisant Git Bash fourni par Git pour Windows (installation ou portable).

Ce script nécessite des arguments

- chemin local par exemple / d / source / project1
- URL Git, par exemple https: //[email protected]/username/project1.git
- mot de passe

si un mot de passe ne doit pas être entré sur la ligne de commande en texte brut,
puis modifiez le script pour vérifier si GITPASS est vide; ne pas
remplacer et laisser Git demander un mot de passe

Le script

- Find the current branch
- Get the SHA1 of the remote on that branch
- Get the SHA1 of the local on that branch
- Compare them.

S'il y a un changement tel qu'imprimé par le script, vous pouvez alors procéder à la récupération ou à l'extraction. Le script n'est peut-être pas efficace, mais il fait le travail pour moi.

Mise à jour - 30/10/2015: stderr dev dev null pour empêcher l'impression de l'URL avec le mot de passe sur la console.

#!/bin/bash

# Shell script to check if a Git pull is required.

LOCALPATH=$1
GITURL=$2
GITPASS=$3

cd $LOCALPATH
BRANCH="$(git rev-parse --abbrev-ref HEAD)"

echo
echo git url = $GITURL
echo branch = $BRANCH

# Bash replace - replace @ with :password@ in the GIT URL
GITURL2="${GITURL/@/:$GITPASS@}"
FOO="$(git ls-remote $GITURL2 -h $BRANCH 2> /dev/null)"
if [ "$?" != "0" ]; then
  echo cannot get remote status
  exit 2
fi
FOO_ARRAY=($FOO)
BAR=${FOO_ARRAY[0]}
echo [$BAR]

LOCALBAR="$(git rev-parse HEAD)"
echo [$LOCALBAR]
echo

if [ "$BAR" == "$LOCALBAR" ]; then
  #read -t10 -n1 -r -p 'Press any key in the next ten seconds...' key
  echo No changes
  exit 0
else
  #read -t10 -n1 -r -p 'Press any key in the next ten seconds...' key
  #echo pressed $key
  echo There are changes between local and remote repositories.
  exit 1
fi
RuntimeException
la source
0

Pour les utilisateurs de Windows qui se retrouvent sur cette question à la recherche de cela, j'ai modifié une partie de la réponse en un script PowerShell. Ajustez si nécessaire, enregistrez dans un .ps1fichier et exécutez à la demande ou planifié si vous le souhaitez.

cd C:\<path to repo>
git remote update                           #update remote
$msg = git remote show origin               #capture status
$update = $msg -like '*local out of date*'
if($update.length -gt 0){                   #if local needs update
    Write-Host ('needs update')
    git pull
    git reset --hard origin/master
    Write-Host ('local updated')
} else {
    Write-Host ('no update needed')
}
Andrew Grothe
la source
0

Parce que la réponse de Neils m'a tellement aidé, voici une traduction Python sans dépendances:

import os
import logging
import subprocess

def check_for_updates(directory:str) -> None:
    """Check git repo state in respect to remote"""
    git_cmd = lambda cmd: subprocess.run(
        ["git"] + cmd,
        cwd=directory,
        stdout=subprocess.PIPE,
        check=True,
        universal_newlines=True).stdout.rstrip("\n")

    origin = git_cmd(["config", "--get", "remote.origin.url"])
    logging.debug("Git repo origin: %r", origin)
    for line in git_cmd(["fetch"]):
        logging.debug(line)
    local_sha = git_cmd(["rev-parse", "@"])
    remote_sha = git_cmd(["rev-parse", "@{u}"])
    base_sha = git_cmd(["merge-base", "@", "@{u}"])
    if local_sha == remote_sha:
        logging.info("Repo is up to date")
    elif local_sha == base_sha:
        logging.info("You need to pull")
    elif remote_sha == base_sha:
        logging.info("You need to push")
    else:
        logging.info("Diverged")

check_for_updates(os.path.dirname(__file__))

hth

frans
la source
-5

Vous pouvez également trouver un script Phing qui le fait maintenant.

J'avais besoin d'une solution pour mettre à jour automatiquement mes environnements de production et nous sommes très heureux grâce à ce script que je partage.

Le script est écrit en XML et nécessite Phing .

Pol Dellaiera
la source
Peut-être que ce n'est pas une bonne idée de copier coller le script ici, je le mets toujours à jour ...
Pol Dellaiera