705 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			Bash
		
	
	
	
	
	
			
		
		
	
	
			705 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			Bash
		
	
	
	
	
	
| # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
 | |
| ##@cooked nocomments
 | |
| ##@require nulib.sh
 | |
| ##@require base
 | |
| module: git "" "Fonctions pour faciliter l'utilisation de git"
 | |
| require: nulib.sh base
 | |
| 
 | |
| function: git_geturl ""
 | |
| function git_geturl() {
 | |
|     git config --get remote.origin.url
 | |
| }
 | |
| 
 | |
| function: git_have_annex ""
 | |
| function git_have_annex() {
 | |
|     [ -n "$(git config --get annex.uuid)" ]
 | |
| }
 | |
| 
 | |
| NULIB_GIT_FUNCTIONS=(
 | |
|     git_check_gitvcs git_ensure_gitvcs
 | |
|     git_list_branches git_list_rbranches
 | |
|     git_have_branch git_have_rbranch
 | |
|     git_get_branch git_is_branch
 | |
|     git_have_remote git_track_branch
 | |
|     git_check_cleancheckout git_ensure_cleancheckout
 | |
|     git_is_ancestor git_should_ff git_should_push
 | |
|     git_is_merged
 | |
| )
 | |
| NULIB_GIT_FUNCTIONS_MAP=(
 | |
|     cg:git_check_gitvcs eg:git_ensure_gitvcs
 | |
|     lbs:git_list_branches rbs:git_list_rbranches
 | |
|     hlb:git_have_branch hrb:git_have_rbranch
 | |
|     gb:git_get_branch ib:git_is_branch
 | |
|     hr:git_have_remote tb:git_track_branch
 | |
|     cc:git_check_cleancheckout ec:git_ensure_cleancheckout
 | |
|     ia:git_is_ancestor sff:git_should_ff spu:git_should_push
 | |
|     im:git_is_merged
 | |
| )
 | |
| 
 | |
| function: git_check_gitvcs ""
 | |
| function git_check_gitvcs() {
 | |
|     git rev-parse --show-toplevel >&/dev/null
 | |
| }
 | |
| 
 | |
| function: git_ensure_gitvcs ""
 | |
| function git_ensure_gitvcs() {
 | |
|     git_check_gitvcs || edie "Ce n'est pas un dépôt git" || return
 | |
| }
 | |
| 
 | |
| function: git_list_branches ""
 | |
| function git_list_branches() {
 | |
|     git for-each-ref refs/heads/ --format='%(refname:short)' | csort
 | |
| }
 | |
| 
 | |
| function: git_list_rbranches ""
 | |
| function git_list_rbranches() {
 | |
|     git for-each-ref "refs/remotes/${1:-origin}/" --format='%(refname:short)' | csort
 | |
| }
 | |
| 
 | |
| function: git_list_pbranches "lister les branches locales et celles qui existent dans l'origine \$1(=origin) et qui pourraient devenir une branche locale avec la commande git checkout -b"
 | |
| function git_list_pbranches() {
 | |
|     local prefix="${1:-origin}/"
 | |
|     {
 | |
|         git for-each-ref refs/heads/ --format='%(refname:short)'
 | |
|         git for-each-ref "refs/remotes/$prefix" --format='%(refname:short)' | grep -F "$prefix" | cut -c $((${#prefix} + 1))-
 | |
|     } | grep -vF HEAD | csort -u
 | |
| }
 | |
| 
 | |
| function: git_have_branch ""
 | |
| function git_have_branch() {
 | |
|     git_list_branches | grep -qF "$1"
 | |
| }
 | |
| 
 | |
| function: git_have_rbranch ""
 | |
| function git_have_rbranch() {
 | |
|     git_list_rbranches "${2:-origin}" | grep -qF "$1"
 | |
| }
 | |
| 
 | |
| function: git_get_branch ""
 | |
| function git_get_branch() {
 | |
|     git rev-parse --abbrev-ref HEAD 2>/dev/null
 | |
| }
 | |
| 
 | |
| function: git_get_branch_remote ""
 | |
| function git_get_branch_remote() {
 | |
|     local branch="$1"
 | |
|     [ -n "$branch" ] || branch="$(git_get_branch)"
 | |
|     [ -n "$branch" ] || return
 | |
|     git config --get "branch.$branch.remote"
 | |
| }
 | |
| 
 | |
| function: git_get_branch_merge ""
 | |
| function git_get_branch_merge() {
 | |
|     local branch="$1"
 | |
|     [ -n "$branch" ] || branch="$(git_get_branch)"
 | |
|     [ -n "$branch" ] || return
 | |
|     git config --get "branch.$branch.merge"
 | |
| }
 | |
| 
 | |
| function: git_get_branch_rbranch ""
 | |
| function git_get_branch_rbranch() {
 | |
|     local branch="$1" remote="$2" merge
 | |
|     [ -n "$branch" ] || branch="$(git_get_branch)"
 | |
|     [ -n "$branch" ] || return
 | |
|     [ -n "$remote" ] || remote="$(git_get_branch_remote "$branch")"
 | |
|     [ -n "$remote" ] || return
 | |
|     merge="$(git_get_branch_merge "$branch")"
 | |
|     [ -n "$merge" ] || return
 | |
|     echo "refs/remotes/$remote/${merge#refs/heads/}"
 | |
| }
 | |
| 
 | |
| function: git_is_branch ""
 | |
| function git_is_branch() {
 | |
|     [ "$(git_get_branch)" == "${1:-master}" ]
 | |
| }
 | |
| 
 | |
| function: git_have_remote ""
 | |
| function git_have_remote() {
 | |
|     [ -n "$(git config --get remote.${1:-origin}.url)" ]
 | |
| }
 | |
| 
 | |
| function: git_track_branch ""
 | |
| function git_track_branch() {
 | |
|     local branch="$1" origin="${2:-origin}"
 | |
|     [ -n "$branch" ] || return
 | |
|     git_have_remote "$origin" || return
 | |
|     [ "$(git config --get branch.$branch.remote)" == "$origin" ] && return
 | |
|     if git_have_rbranch "$branch" "$origin"; then
 | |
|         if git_have_branch "$branch"; then
 | |
|             git branch -u "$origin/$branch" "$branch"
 | |
|         else
 | |
|             git branch -t "$branch" "$origin/$branch"
 | |
|         fi
 | |
|     elif git_have_branch "$branch"; then
 | |
|         git push -u "$origin" "$branch" || return
 | |
|     fi
 | |
| }
 | |
| 
 | |
| function: git_ensure_branch "
 | |
| @return 0 si la branche a été créée, 1 si elle existait déjà, 2 en cas d'erreur"
 | |
| function git_ensure_branch() {
 | |
|     local branch="$1" source="${2:-master}" origin="${3:-origin}"
 | |
|     [ -n "$branch" ] || return 2
 | |
|     git_have_branch "$branch" && return 1
 | |
|     if git_have_rbranch "$branch" "$origin"; then
 | |
|         # une branche du même nom existe dans l'origine. faire une copie de cette branche
 | |
|         git branch -t "$branch" "$origin/$branch" || return 2
 | |
|     else
 | |
|         # créer une nouvelle branche du nom spécifié
 | |
|         git_have_branch "$source" || return 2
 | |
|         git branch "$branch" "$source" || return 2
 | |
|         if [ -z "$NULIB_GIT_OFFLINE" ]; then
 | |
|             git_have_remote "$origin" && git_track_branch "$branch" "$origin"
 | |
|         fi
 | |
|     fi
 | |
|     return 0
 | |
| }
 | |
| 
 | |
| function: git_check_cleancheckout "vérifier qu'il n'y a pas de modification locales dans le dépôt correspondant au répertoire courant."
 | |
| function git_check_cleancheckout() {
 | |
|     [ -z "$(git status --porcelain 2>/dev/null)" ]
 | |
| }
 | |
| 
 | |
| function: git_ensure_cleancheckout ""
 | |
| function git_ensure_cleancheckout() {
 | |
|     git_check_cleancheckout ||
 | |
|         edie "Vous avez des modifications locales. Enregistrez ces modifications avant de continuer" || return
 | |
| }
 | |
| 
 | |
| function git__init_ff() {
 | |
|     o="${3:-origin}"
 | |
|     b="$1" s="${2:-refs/remotes/$o/$1}"
 | |
|     b="$(git rev-parse --verify --quiet "$b")" || return 1
 | |
|     s="$(git rev-parse --verify --quiet "$s")" || return 1
 | |
|     return 0
 | |
| }
 | |
| function git__can_ff() {
 | |
|     [ "$1" == "$(git merge-base "$1" "$2")" ]
 | |
| }
 | |
| 
 | |
| function: git_is_ancestor "vérifier que la branche \$1 est un ancêtre direct de la branche \$2, qui vaut par défaut refs/remotes/\${3:-origin}/\$1
 | |
| note: cette fonction retourne vrai si \$1 et \$2 identifient le même commit"
 | |
| function git_is_ancestor() {
 | |
|     local o b s; git__init_ff "$@" || return
 | |
|     git__can_ff "$b" "$s"
 | |
| }
 | |
| 
 | |
| function: git_should_ff "vérifier si la branche \$1 devrait être fast-forwardée à partir de la branche d'origine \$2, qui vaut par défaut refs/remotes/\${3:-origin}/\$1
 | |
| note: cette fonction est similaire à git_is_ancestor(), mais retourne false si \$1 et \$2 identifient le même commit"
 | |
| function git_should_ff() {
 | |
|     local o b s; git__init_ff "$@" || return
 | |
|     [ "$b" != "$s" ] || return 1
 | |
|     git__can_ff "$b" "$s"
 | |
| }
 | |
| 
 | |
| function: git_should_push "vérifier si la branche \$1 devrait être poussée vers la branche de même nom dans l'origine \$2(=origin), parce que l'origin peut-être fast-forwardée à partir de cette branche."
 | |
| function git_should_push() {
 | |
|     git_should_ff "refs/remotes/${2:-origin}/$1" "$1"
 | |
| }
 | |
| 
 | |
| function: git_fast_forward "vérifier que la branche courante est bien \$1, puis tester s'il faut la fast-forwarder à partir de la branche d'origine \$2, puis le faire si c'est nécessaire. la branche d'origine \$2 vaut par défaut refs/remotes/origin/\$1"
 | |
| function git_fast_forward() {
 | |
|     local o b s; git__init_ff "$@" || return
 | |
|     [ "$b" != "$s" ] || return 1
 | |
|     local head="$(git rev-parse HEAD)"
 | |
|     [ "$head" == "$b" ] || return 1
 | |
|     git__can_ff "$b" "$s" || return 1
 | |
|     git merge --ff-only "$s"
 | |
| }
 | |
| 
 | |
| function: git_is_merged "vérifier que les branches \$1 et \$2 ont un ancêtre commun, et que la branche \$1 a été complètement fusionnée dans la branche destination \$2"
 | |
| function git_is_merged() {
 | |
|     local b="$1" d="$2"
 | |
|     b="$(git rev-parse --verify --quiet "$b")" || return 1
 | |
|     d="$(git rev-parse --verify --quiet "$d")" || return 1
 | |
|     [ -n "$(git merge-base "$b" "$d")" ] || return 1
 | |
|     [ -z "$(git rev-list "$d..$b")" ]
 | |
| }
 | |
| 
 | |
| ################################################################################
 | |
| # git annex
 | |
| 
 | |
| NULIB_GIT_SSH_WRAPPER=
 | |
| function: git_annex_use_ssh_wrapper ""
 | |
| function git_annex_use_ssh_wrapper() {
 | |
|     [ -n "$NULIB_GIT_SSH_WRAPPER" ] && return
 | |
|     NULIB_GIT_FORCE_PATH="$PATH"
 | |
|     NULIB_GIT_FORCE_SSH="${GIT_SSH:-ssh}"
 | |
|     export NULIB_GIT_FORCE_PATH NULIB_GIT_FORCE_SSH
 | |
|     base_delpath "$NULIBDIR/ssh-wrapper" NULIB_GIT_FORCE_PATH
 | |
|     base_inspath "$NULIBDIR/ssh-wrapper" PATH
 | |
|     NULIB_GIT_SSH_WRAPPER=1
 | |
| }
 | |
| 
 | |
| function: git_annex_initial "sur le dépôt \$1 fraichement cloné, vérifier s'il faut faire git annex init. Si oui, l'initialiser avec le nom d'hôte, et récupérer tous les fichiers annexés
 | |
| @return 1 si une erreur s'est produite"
 | |
| function git_annex_initial() {
 | |
|     local repodir="${1:-.}"
 | |
|     [ -d "$repodir" ] || return 1
 | |
|     repodir="$(abspath "$repodir")"
 | |
| 
 | |
|     local GIT_DIR GIT_WORK_TREE
 | |
|     [ "$(cd "$repodir"; git rev-parse --is-bare-repository)" == false ] || return 0
 | |
|     [ -n "$(GIT_DIR="$repodir/.git" git config --get annex.uuid)" ] && return 0
 | |
| 
 | |
|     # ici, on sait que git annex n'a pas encore été configuré
 | |
|     # vérifier s'il existe des fichiers annexés
 | |
|     local -a links
 | |
|     base_array_splitl links "$(find "$repodir" -type l)"
 | |
|     local link hasannex=
 | |
|     for link in "${links[@]}"; do
 | |
|         link="$(readlink "$link")"
 | |
|         if [ "${link#.git/annex/}" != "$link" ]; then
 | |
|             hasannex=1
 | |
|             break
 | |
|         elif [[ "$link" == */.git/annex/* ]]; then
 | |
|             hasannex=1
 | |
|             break
 | |
|         fi
 | |
|     done
 | |
| 
 | |
|     if [ -n "$hasannex" ]; then
 | |
|         base_in_path git-annex || edie "Vous devez installer git-annex" || return
 | |
|         local cwd; base_push_cwd "$repodir" &&
 | |
|             git annex init "$MYHOSTNAME" &&
 | |
|             git annex get &&
 | |
|             git annex sync &&
 | |
|             base_pop_cwd || base_pop_cwd 1 || return
 | |
|     fi
 | |
| }
 | |
| 
 | |
| ################################################################################
 | |
| # Outils de haut niveau
 | |
| 
 | |
| function: git_commit ""
 | |
| function git_commit() {
 | |
|     local all=auto allnew push=auto nopush args
 | |
|     setyesval nopush "$NULIB_GIT_OFFLINE"
 | |
|     [ -n "$nopush" ] && push=
 | |
|     parse_opts + "${PRETTYOPTS[@]}" \
 | |
|         -a,--all all=1 \
 | |
|         -A,--all-new allnew=1 \
 | |
|         -c,--cached all= \
 | |
|         -p,--push push=1 \
 | |
|         -l,--local push= \
 | |
|         @ args -- "$@" && set -- "${args[@]}" || {
 | |
|         eerror "$args"
 | |
|         return 1
 | |
|     }
 | |
| 
 | |
|     if [ -n "$allnew" ]; then
 | |
|         git add -A
 | |
|         all=
 | |
|     fi
 | |
| 
 | |
|     local message="$1"; shift
 | |
|     local -a cmd
 | |
|     cmd=(git commit)
 | |
|     [ -n "$message" ] && cmd=("${cmd[@]}" -m "$message")
 | |
|     if [ "$all" == "auto" ]; then
 | |
|         # Si des fichiers sont spécifiés, prendre ceux-là.
 | |
|         if [ -z "$*" ]; then
 | |
|             # Sinon, s'il y a des fichiers dans l'index, commiter uniquement ces
 | |
|             # fichiers
 | |
|             # Sinon, committer tous les fichiers modifiés
 | |
|             # le code suivant retourne vrai si l'index contient au moins fichier
 | |
|             git status --porcelain 2>/dev/null | lawk '
 | |
|                 BEGIN { ec = 1 }
 | |
|                 substr($0, 1, 1) ~ /[^ ?]/ { ec = 0; exit }
 | |
|                 END { exit ec }' ||
 | |
|             cmd=("${cmd[@]}" -a)
 | |
|         fi
 | |
|     else
 | |
|         [ -n "$all" ] && cmd=("${cmd[@]}" -a)
 | |
|     fi
 | |
| 
 | |
|     if ! "${cmd[@]}" "$@"; then
 | |
|         [ "$push" == auto ] && return 1
 | |
|     fi
 | |
|     if [ "$push" == auto ]; then
 | |
|         git_push --auto || return
 | |
|     elif [ -n "$push" ]; then
 | |
|         git_push --force || return
 | |
|     fi
 | |
|     return 0
 | |
| }
 | |
| 
 | |
| function: git_update ""
 | |
| function git_update() {
 | |
|     local args autoff=1
 | |
|     parse_opts + "${PRETTYOPTS[@]}" \
 | |
|         -n,--no-autoff autoff= \
 | |
|         @ args -- "$@" && set -- "${args[@]}" || {
 | |
|         eerror "$args"
 | |
|         return 1
 | |
|     }
 | |
| 
 | |
|     if [ -z "$autoff" ]; then
 | |
|         git pull "$@"
 | |
|         return $?
 | |
|     fi
 | |
| 
 | |
|     local branch orig_branch restore_branch remote rbranch pbranch
 | |
|     local -a branches prbranches crbranches dbranches
 | |
| 
 | |
|     base_array_splitl prbranches "$(git_list_rbranches)"
 | |
|     git fetch -p "$@" || return
 | |
|     base_array_splitl crbranches "$(git_list_rbranches)"
 | |
| 
 | |
|     # vérifier s'il n'y a pas des branches distantes qui ont été supprimées
 | |
|     for branch in "${prbranches[@]}"; do
 | |
|         if ! base_array_contains crbranches "$branch"; then
 | |
|             base_array_add dbranches "${branch#*/}"
 | |
|         fi
 | |
|     done
 | |
|     if [ ${#dbranches[*]} -gt 0 ]; then
 | |
|         eimportant "One or more distant branches where deleted"
 | |
|         for branch in "${dbranches[@]}"; do
 | |
|             if git_have_branch "$branch"; then
 | |
|                 if ! ask_yesno "Do you want to delete local branch $branch?" X; then
 | |
|                     base_array_del dbranches "$branch"
 | |
|                 fi
 | |
|             fi
 | |
|         done
 | |
|     fi
 | |
|     if [ ${#dbranches[*]} -gt 0 ]; then
 | |
|         base_array_splitl branches "$(git_list_branches)"
 | |
|         branch="$(git_get_branch)"
 | |
|         if base_array_contains dbranches "$branch"; then
 | |
|             # si la branche courante est l'une des branches à supprimer, il faut
 | |
|             # basculer vers develop ou master
 | |
|             local swto
 | |
|             if [ -z "$swto" ] && base_array_contains branches develop && ! base_array_contains dbranches develop; then
 | |
|                 swto=develop
 | |
|             fi
 | |
|             if [ -z "$swto" ] && base_array_contains branches master && ! base_array_contains dbranches master; then
 | |
|                 swto=master
 | |
|             fi
 | |
|             if ! git_check_cleancheckout; then
 | |
|                 echo "* There are uncommitted local changes. However current branch is slated for removal.
 | |
| Make your verifications then delete the local branches:
 | |
|     ${swto:+$(qvals git checkout "$swto")
 | |
|     }$(qvals git branch -D "${dbranches[@]}")"
 | |
|                 return 1
 | |
|             fi
 | |
|             if [ -n "$swto" ]; then
 | |
|                 git checkout -q "$swto"
 | |
|             else
 | |
|                 echo "* Current branch is slated for removal but I don't know to which branch I should switch first.
 | |
| Make your choice then delete the local branches:
 | |
|     $(qvals git branch -D "${dbranches[@]}")"
 | |
|                 return 1
 | |
|             fi
 | |
|         fi
 | |
|         for branch in "${dbranches[@]}"; do
 | |
|             git branch -D "$branch"
 | |
|         done
 | |
|     fi
 | |
| 
 | |
|     # intégrer les modifications dans les branches locales
 | |
|     if ! git_check_cleancheckout; then
 | |
|         branch="$(git_get_branch)"
 | |
|         remote="$(git_get_branch_remote "$branch")"
 | |
|         rbranch="$(git_get_branch_rbranch "$branch" "$remote")"
 | |
|         pbranch="${rbranch#refs/remotes/}"
 | |
|         if git merge -q --ff-only "$rbranch"; then
 | |
|             echo "* There are uncommitted local changes: only CURRENT branch were updated"
 | |
|         fi
 | |
|         return 0
 | |
|     fi
 | |
| 
 | |
|     orig_branch="$(git_get_branch)"
 | |
|     base_array_splitl branches "$(git_list_branches)"
 | |
|     for branch in "${branches[@]}"; do
 | |
|         remote="$(git_get_branch_remote "$branch")"
 | |
|         rbranch="$(git_get_branch_rbranch "$branch" "$remote")"
 | |
|         pbranch="${rbranch#refs/remotes/}"
 | |
|         [ -n "$remote" -a -n "$rbranch" ] || continue
 | |
|         if git_is_ancestor "$branch" "$rbranch"; then
 | |
|             if git_should_ff "$branch" "$rbranch"; then
 | |
|                 echo "* Fast-forwarding $branch -> $pbranch"
 | |
|                 git checkout -q "$branch"
 | |
|                 git merge -q --ff-only "$rbranch"
 | |
|                 restore_branch=1
 | |
|             fi
 | |
|         else
 | |
|             if [ "$branch" == "$orig_branch" ]; then
 | |
|                 echo "* Cannot fast-forward CURRENT branch $branch from $pbranch
 | |
| Try to merge manually with: git merge $pbranch"
 | |
|             else
 | |
|                 echo "* Cannot fast-forward local branch $branch from $pbranch
 | |
| You can merge manually with: git checkout $branch; git merge $pbranch"
 | |
|             fi
 | |
|         fi
 | |
|     done
 | |
|     [ -n "$restore_branch" ] && git checkout -q "$orig_branch"
 | |
|     return 0
 | |
| }
 | |
| 
 | |
| function: git_push ""
 | |
| function git_push() {
 | |
|     local all all_branches all_tags auto force args no_annex
 | |
|     parse_opts + "${PRETTYOPTS[@]}" \
 | |
|         -a,--all all=1 \
 | |
|         -b,--branches,--all-branches all_branches=1 \
 | |
|         -t,--tags,--all-tags all_tags=1 \
 | |
|         --auto auto=1 \
 | |
|         -f,--force force=1 \
 | |
|         -n,--no-annex no_annex=1 \
 | |
|         @ args -- "$@" && set -- "${args[@]}" || {
 | |
|         eerror "$args"
 | |
|         return 1
 | |
|     }
 | |
| 
 | |
|     if [ -n "$all" ]; then
 | |
|         # On a demandé à pusher toutes les branches et tous les tags
 | |
|         local r
 | |
|         git push --all "$@"; r=$?
 | |
|         if [ $r -eq 0 ]; then
 | |
|             git push --tags "$@"; r=$?
 | |
|         fi
 | |
|         return $r
 | |
|     elif [ -n "$all_branches" ]; then
 | |
|         # On a demandé à pusher toutes les branches
 | |
|         git push --all "$@"
 | |
|         return $?
 | |
|     elif [ -n "$all_tags" ]; then
 | |
|         # On a demandé à pusher tous les tags
 | |
|         git push --tags "$@"
 | |
|         return $?
 | |
|     elif [ $# -gt 0 ]; then
 | |
|         # Sinon, si des arguments sont spécifiés, les passer à git sans
 | |
|         # modification
 | |
|         git push "$@"
 | |
|         return $?
 | |
|     elif git_have_annex; then
 | |
|         # Si une annexe existe dans le dépôt, demander à git-annex de faire la
 | |
|         # synchronisation, sauf si --no-annex est spécifié ou si on est en mode
 | |
|         # automatique
 | |
|         if [ -z "$no_annex" -a -z "$auto" ]; then
 | |
|             git annex sync
 | |
|             return $?
 | |
|         fi
 | |
|     fi
 | |
| 
 | |
|     # sinon on push vers origin. vérifier la présence du remote
 | |
|     [ -n "$(git config --get remote.origin.url)" ] || {
 | |
|         if [ -n "$auto" ]; then
 | |
|             # en mode automatique, ignorer l'absence de remote
 | |
|             return 0
 | |
|         else
 | |
|             eerror "Aucun remote origin n'est défini"
 | |
|             return 1
 | |
|         fi
 | |
|     }
 | |
| 
 | |
|     # puis calculer la branche à pusher
 | |
|     local branch="$(git rev-parse --abbrev-ref HEAD 2>/dev/null)"
 | |
|     local origin="$(git config --get "branch.$branch.remote")"
 | |
|     if [ -n "$branch" -a "$origin" == origin ]; then
 | |
|         if [ -n "$auto" ]; then
 | |
|             # en mode automatique, ne pousser que la branche courante
 | |
|             git push "$origin" "$branch" || return
 | |
|         else
 | |
|             # utiliser la configuration par défaut, qui est sous debian squeeze
 | |
|             # de pousser toutes les branches
 | |
|             git push || return
 | |
|         fi
 | |
|     elif [ -n "$force" ]; then
 | |
|         # utiliser la configuration par défaut, qui est sous debian squeeze de
 | |
|         # pousser toutes les branches
 | |
|         git push || return
 | |
|     fi
 | |
|     return 0
 | |
| }
 | |
| 
 | |
| function git__pclone() {
 | |
|     estep "$1 --> $(ppath "$2")"
 | |
|     mkdirof "$2" || return 1
 | |
|     git clone "$1" "$2" || return 1
 | |
|     if [ -z "$3" ]; then
 | |
|         (
 | |
|             cd "$2"
 | |
|             if git_have_rbranch develop; then
 | |
|                 git checkout develop || exit 1
 | |
|             fi
 | |
|         ) || return 1
 | |
|     fi
 | |
|     git_annex_initial "$2" || return 1
 | |
| }
 | |
| function git__gitolite_info() {
 | |
|     local mode="$1" urlbase="$2" pattern="$3"
 | |
|     case "$mode" in
 | |
|     http) curl -fs "$urlbase/info${pattern:+"?$pattern"}";;
 | |
|     ssh) ssh -q "$urlbase" info ${pattern:+"$pattern"} 2>/dev/null;;
 | |
|     esac
 | |
| }
 | |
| function git__filter_repos() {
 | |
|     lawk -v prefix="$1" '
 | |
| NR <= 2 { next }
 | |
| {
 | |
|   # filtrer les projets qui ne sont pas encore créés
 | |
|   if (substr($0, 5, 2) == " C") next
 | |
|   repo = substr($0, 6)
 | |
|   # filtrer les projets de type wildcard
 | |
|   if (repo ~ /[\[\]\*]/) next
 | |
|   # enlever le prefixe
 | |
|   if (prefix != "" && substr(repo, 1, length(prefix)) != prefix) next
 | |
|   print repo
 | |
| }'
 | |
| }
 | |
| 
 | |
| function: git_clone ""
 | |
| function git_clone() {
 | |
|     no_clone=
 | |
|     update=
 | |
|     nodevelop=
 | |
|     recursive=
 | |
|     parse_opts "${PRETTYOPTS[@]}" \
 | |
|         -n,--no-clone no_clone=1 \
 | |
|         -u,--update update=1 \
 | |
|         -m,--master nodevelop=1 \
 | |
|         -r,--recursive recursive=1 \
 | |
|         @ args -- "$@" && set -- "${args[@]}" || edie "$args" || return
 | |
| 
 | |
|     if [ -n "$recursive" ]; then
 | |
|         repobase="$1"
 | |
|         [ -n "$repobase" ] || edie "Vous devez spécifier l'url de base des dépôts à cloner" || return
 | |
|         if [ "${repobase#http://}" != "$repobase" -o "${repobase#https://}" != "$repobase" ]; then
 | |
|             # accès par http
 | |
|             mode=http
 | |
|             splitfsep "$repobase" :// scheme hostuserpath
 | |
|             splitfsep "$hostuserpath" / host userpath
 | |
|             splitfsep "$userpath" / user basepath
 | |
|             [ -n "$host" -a -n "$user" ] || edie "Vous devez spécifier l'hôte e.g http://host/git/basepath" || return
 | |
|             urlbase="$scheme://$host/$user"
 | |
|         else
 | |
|             # accès par ssh
 | |
|             mode=ssh
 | |
|             splitfsep "$repobase" : userhost basepath
 | |
|             splituserhost "$userhost" user host
 | |
|             [ -n "$user" ] || user=git
 | |
|             [ -n "$host" ] || edie "Vous devez spécifier l'hôte" || return
 | |
|             urlbase="$user@$host"
 | |
|         fi
 | |
|         basepath="${basepath%/}"
 | |
|         destbase="${2:-.}"
 | |
| 
 | |
|         git_annex_use_ssh_wrapper
 | |
|         prefix="${basepath:+$basepath/}"
 | |
|         base_array_splitl repos "$(set -o pipefail; git__gitolite_info "$mode" "$urlbase" "$prefix" | git__filter_repos "$prefix")" || edie || return
 | |
|         for repo in "${repos[@]}"; do
 | |
|             case "$mode" in
 | |
|             http) repourl="$urlbase/$repo";;
 | |
|             ssh) repourl="$urlbase:$repo";;
 | |
|             esac
 | |
|             setx destdir=abspath "$destbase/${repo#$prefix}"
 | |
|             if [ -d "$destdir" ]; then
 | |
|                 if [ -n "$update" ]; then
 | |
|                     (
 | |
|                         ${no_clone:+qvals} cd "$destdir"
 | |
|                         ${no_clone:+qvals} git pull
 | |
|                     ) || edie || return
 | |
|                 else
 | |
|                     estepe "$(ppath2 "$destdir"): répertoire existant"
 | |
|                 fi
 | |
|             elif [ -n "$no_clone" ]; then
 | |
|                 qvals git clone "$repourl" "$destdir"
 | |
|             else
 | |
|                 git__pclone "$repourl" "$destdir" "$nodevelop" || edie || return
 | |
|             fi
 | |
|         done
 | |
| 
 | |
|     else
 | |
|         repourl="${1%.git}"
 | |
|         [ -n "$repourl" ] || edie "Vous devez spécifier l'url du dépôt git" || return
 | |
| 
 | |
|         destdir="$2"
 | |
|         if [ -z "$destdir" ]; then
 | |
|             splitfsep "$repourl" : userhost path
 | |
|             setx destdir=basename -- "$path"
 | |
|             destdir="${destdir%.git}"
 | |
|         fi
 | |
|         setx destdir=abspath "$destdir"
 | |
| 
 | |
|         git_annex_use_ssh_wrapper
 | |
|         if [ -d "$destdir" ]; then
 | |
|             if [ -n "$update" ]; then
 | |
|                 (
 | |
|                     ${no_clone:+qvals} cd "$destdir"
 | |
|                     ${no_clone:+qvals} git pull
 | |
|                 ) || edie || return
 | |
|             else
 | |
|                 estepe "$(ppath2 "$destdir"): répertoire existant"
 | |
|             fi
 | |
|         elif [ -n "$no_clone" ]; then
 | |
|             qvals git clone "$repourl" "$destdir"
 | |
|         else
 | |
|             git__pclone "$repourl" "$destdir" "$nodevelop" || edie || return
 | |
|         fi
 | |
|     fi
 | |
| }
 | |
| 
 | |
| function: git_crone ""
 | |
| function git_crone() {
 | |
|     repourl="${1%.git}"
 | |
|     [ -n "$repourl" ] || edie "Vous devez spécifier l'url du dépôt git" || return
 | |
|     if [ "${repourl#http://}" != "$repourl" -o "${repourl#https://}" != "$repourl" ]; then
 | |
|         # accès par http
 | |
|         mode=http
 | |
|         splitfsep "$repourl" :// scheme hostuserpath
 | |
|         splitfsep "$hostuserpath" / host userpath
 | |
|         splitfsep "$userpath" / user path
 | |
|         [ -n "$host" -a -n "$user" ] || edie "Vous devez spécifier l'hôte e.g http://host/git/repo" || return
 | |
|         hostuser="$scheme://$host/$user"
 | |
|     else
 | |
|         # accès par ssh
 | |
|         mode=ssh
 | |
|         splitfsep "$repourl" : userhost path
 | |
|         splituserhost "$userhost" user host
 | |
|         [ -n "$user" ] || user=git
 | |
|         [ -n "$host" ] || edie "Vous devez spécifier l'hôte" || return
 | |
|         userhost="$user@$host"
 | |
|     fi
 | |
|     [ -n "$path" ] || edie "Vous devez spécifier le chemin du dépôt git" || return
 | |
| 
 | |
|     destdir="$2"
 | |
|     if [ -z "$destdir" ]; then
 | |
|         setx destdir=basename -- "$path"
 | |
|         destdir="${destdir%.git}"
 | |
|     fi
 | |
|     tmpdestdir=
 | |
|     if [ -d "$destdir" ]; then
 | |
|         [ -d "$destdir/.git" ] && edie "$(ppath2 "$destdir"): un dépôt existe déjà" || return
 | |
|         ac_set_tmpdir tmpdestdir
 | |
|     fi
 | |
| 
 | |
|     if [ "$mode" == http ]; then
 | |
|         setx result=curl -fs "$hostuser/create?$path" || edie || return
 | |
|         echo "$result"
 | |
|         [[ "$result" == FATAL:* ]] && edie || return
 | |
|         if [ -n "$tmpdestdir" ]; then
 | |
|             setxx destname=abspath "$destdir" // basename
 | |
|             git clone "$hostuser/$path" "$tmpdestdir/$destname" || edie || return
 | |
|             mv "$tmpdestdir/$destname/.git" "$destdir" || edie || return
 | |
|             ac_clean "$tmpdestdir"
 | |
|         else
 | |
|             git clone "$hostuser/$path" "$destdir" || edie || return
 | |
|         fi
 | |
|     elif [ "$mode" == ssh ]; then
 | |
|         git_annex_use_ssh_wrapper
 | |
|         ssh "$userhost" create "$path" || edie || return
 | |
|         if [ -n "$tmpdestdir" ]; then
 | |
|             setxx destname=abspath "$destdir" // basename
 | |
|             git clone "$userhost:$path" "$tmpdestdir/$destname" || edie || return
 | |
|             mv "$tmpdestdir/$destname/.git" "$destdir" || edie || return
 | |
|             ac_clean "$tmpdestdir"
 | |
|         else
 | |
|             git clone "$userhost:$path" "$destdir" || edie || return
 | |
|         fi
 | |
|     else
 | |
|         edie "$mode: mode non supporté" || return
 | |
|     fi
 | |
|     git_annex_initial "$destdir" || edie || return
 | |
| }
 |