web-dev-qa-db-fra.com

Subversion rebase?

Je trouve ce moyen plus facile de fusionner des branches et moins de conflits:

Copiez le tronc dans une nouvelle branche, fusionnez-le avec la/les branche (s). Une fois les opérations terminées, fusionnez la nouvelle branche dans le coffre. Cette technique est tout à fait comme le Mercurial et le rebasement génial. 

J'avais l'habitude de fusionner tous les changements de tronc en fonction de branche. Mais plus tard, lorsque j'ai fusionné la branche de fonctions dans le coffre, certains éléments du coffre étaient à nouveau fusionnés, ce qui a provoqué de nombreux conflits. Il existe un choix de fusion de réintégration, mais cela ne semblait pas fonctionner pour moi. 

Est-ce que quelqu'un fait un rebasage similaire de Subversion? Je viens juste de commencer à le faire récemment et je n’ai observé aucun effet secondaire. Cela causerait-il des problèmes imprévus? 

37
bo bo

En règle générale, le rebasement consiste à incorporer les modifications en amont dans une branche de fonctionnalité, avant de fusionner la branche de fonctionnalité dans la branche en amont.

Dans git, le processus est encore plus sophistiqué, car les modifications apportées depuis la création de la branche sont d'abord supprimées et mises en mémoire tampon, les modifications en amont sont appliquées, puis les modifications mises en mémoire tampon sont appliquées. Ce qu’il faut retenir ici, c’est que fusionner le tronc dans une branche d’entités n’est pas un rebase en termes génitaux, c’est plus que ça. L’approche git présente un certain nombre d’avantages, mais elle ne peut pas être implémentée de manière très propre dans svn car toutes les commits doivent être stockés sur le serveur (svn n’est pas distribué), mais il peut être dans svn.

Un 'svn rebase' (à la manière de git) pourrait ressembler à quelque chose comme ça

  1. svn cp trunk feature
  2. s'engage à présenter et trunk
  3. svn cp trunk feature-rebase
  4. svn co feature-rebase
  5. cd feature-rebase
  6. svn merge feature
  7. svn commit
  8. svn rm feature
  9. svn mv feature-rebase feature
  10. (retour sur le WC de la fonction de base) svn switch feature

Puis, éventuellement, sur une copie de travail du coffre, svn merge --reintegrate feature

Vous voyez la différence de simplement fusionner le tronc avec la branche de fonctionnalité? Dans cet exemple, vous commencez par la dernière ligne en amont, tronc, puis fusionnez les modifications apportées à une fonctionnalité.

Imaginez que certains des commits sur le tronc puissent provenir de la fusion d’une autre branche d’objet avec le tronc; je ne préconise donc pas du tout l’engagement direct dans le tronc.

26
quickshiftin

J'aimerais avoir une astuce astucieuse pour vous expliquer comment obtenir un changement de base dans SVN, mais j'ai toujours évité le rafraîchissement manuel d'une branche avec des changements de tronc dans SVN, principalement à cause des complications nécessitant une sélection manuelle comme mentionné par jdehaan. 

Ce que je fais généralement à la place, c’est plutôt de fusionner les modifications d’une branche vers une ligne, de supprimer la branche, puis de recréer la branche à partir de la ligne. Cela me permet d'actualiser/rebaser ma branche de fonctionnalité, mais avec l'effet secondaire parfois malheureux que toutes les modifications antérieures de cette branche font maintenant partie du tronc. Pour cette raison, je ne pratique cette pratique que lorsqu'une branche de fonctionnalité est à un point stable et utilisable, mais je souhaite néanmoins continuer à travailler sur cette fonctionnalité afin de poursuivre un objectif plus ambitieux.

Ce que je préférerais, c'est que l'actualisation d'une branche en fusionnant les modifications de joncteur réseau en branche ne provoque pas de fusions de réintégration ultérieures à partir de cette branche pour extraire les révisions basées sur des bases modifiées au cours du processus. Il devrait être possible de le faire en fonction des propriétés de fusion-info, mais selon ce que dit Jdehaan et ce que j’ai craint, c’est que cela exige toujours une cueillette sélective.

Notez qu'une bonne implémentation de rebasage devrait également pouvoir prendre en compte des exemples de cas de marche d'escalier dans lesquels une branche est créée à partir d'une autre branche.

Mise à jour: Selon la documentation de Subversion, il apparaît que, si vous utilisez l'option --reintegrate , Subversion devrait pouvoir réintégrer correctement le travail effectué dans une branche de manière à éviter tout problème. les fusions d’actualisation possibles qui ont pu être effectuées pour apporter des modifications de base à la branche. Bien sûr, c’est techniquement un peu différent du changement de base, mais je pense que son utilisation est suffisamment similaire pour qu’on puisse parler de refonte.

7
jpierson

Dans mon entreprise, nous utilisons l'approche suivante:

  1. pour chaque tâche NK- $ X dans le suivi des problèmes, nous avons une branche distincte/NK- $ X
  2. nous commençons à travailler sur une tâche par svn cp tronc branches/NK- $ X 
  3. nous ne commettons jamais de modifications directement dans le coffre. Pour chaque mise à jour planifiée UPDNK- $ X, nous avons une branche distincte/UPDNK- $ X. Nous le créons avec les branches de tronc svn cp/UPDNK- $ X juste avant la mise à jour.
  4. lorsque la tâche NK- $ X est planifiée pour une mise à jour UPDNK- $ Y, nous fusionnons les branches/NK- $ X inot UPDNK- $ Y. C'est cd UPDNK- $ Y; svn merge -r start: branches HEAD/NK- $ X
  5. une fois que UPDNK- $ Y est prêt, nous le fusionnons dans le tronc. Cd trunk; svn merge -r start: HEAD branches/UPDNK- $ Y

Si cela se produit, la tâche NK- $ X dure plus d'un cycle d'itération et a donc besoin d'être rafraîchie. Nous ne fusionnons jamais, JAMAIS, le tronc avec NK- $ X. Nous avons pour règle que vous n'engagez dans votre branche que les choses que vous avez écrites vous-même, ce qui simplifie les choses. Au lieu de cela nous faisons:

cd NK-$X
svn log
//let L = the number of the last changeset to this branch changeset
//let F = the number of the first changeset to this branch
svn rm branches/NK-$X 
svn cp trunk branches/NK-$X 
svn up
svn merge -r F:L branches/NK-$X@L 
svn ci -m 'refereshed'

De cette façon, chaque fois que vous consultez le journal des modifications de branches/NK- $ X, vous ne voyez que les modifications réellement effectuées par le développeur.

Mise à jour: Le flux de travail ci-dessus pouvant être automatisé, j'ai démarré un projet sur github: svn rebase .

4
qbolec

J'utilise un script qui fait un git comme rebase pour svn:

#!/bin/bash

set_safe()
{
    set -eo pipefail
}

validate_number()
(
    if (! [ "$1" -eq "$1" ] 2>/dev/null ) then
    {
        echo "$1 is not a number"
        return 1
    }
    fi
)

get_line()
(
    set_safe
    #head -n "$1" | tail -n 1
    sed -n "${1}p;$(($1+1))q"
)

split_trim()
(
    set_safe
    tr "$1" '\n' | sed -e 's/^\s*//;' -e 's/\s*$//'
)

run_svn()
(
    set +x
    #echo "svn $*" 1>&2
    svn --non-interactive --password "$svn_password" "$@"
)

rebase()
(
    set_safe

    url="$1"
    cur="$2"
    end="$3"

    validate_number "$cur"
    if ([ -z "$end" ] || [ "$end" = "HEAD" ]) then
    {
        end="$(run_svn info "$url" | grep "Last Changed Rev" | cut -d' ' -f4)"
        echo "end: $end"
    }
    else
    {
        validate_number "$end";
    }
    fi

    while (true) do
    {
        log="$(run_svn log "$url" -l1 -r "$cur:HEAD")"
        meta="$(echo -n "$log" | get_line 2 | split_trim '|')"
        next="$(echo -n "$meta" | get_line 1 | tail -c +2)"
        author="$(echo -n "$meta" | get_line 2)"
        date="$(echo -n "$meta" | get_line 3 | awk '{print $1, $2, $3}')"
        msg="$(echo -n "$log" | tail -n +4 | head -n -1)"
        cur=$next

        if ([ -z $cur ] || [ $cur -gt $end ]) then { break; } fi

        echo "$msg" > .msg

        echo "Merging revision $cur:"
        echo "========"
        cat .msg
        echo "========"

        run_svn merge "$url" -c $cur
        run_svn commit -F .msg
        rm -f .msg
        run_svn update

        echo "Success"
        echo

        cur=$(($cur + 1))
    }
    done
)

if ([ -z "$1" ]) then
{
    echo "Usage:"
    echo "    svn-rebase.sh <url> <begin revision> [end revision]"
    exit
}
fi

echo -n "svn password: "
read -s svn_password
echo

rebase "$1" "$2" "$3"
err=$?
if ([ $err -ne 0 ]) then { echo "rebase failed: $err"; } fi
exit $err

Il fusionne une à une les révisions d’autres branches.

0
anton_rh

J'utilise cette approche:

Avec le changement de base, vous devez prendre soin de ne pas prendre les révisions modifiées lorsque vous fusionnez à nouveau. Lorsqu’il s’agit de fusionner, effectuez une sélection judicieuse: sélectionnez uniquement les révisions de la branche qui implémentent quelque chose de nouveau, et non les ensembles de modifications redéfinis. Alors ça devrait marcher. COMMENTAIRE: Je ne me souviens jamais avoir utilisé la branche de réintégration pour quelque chose. Je pense qu'il est destiné à des cas d'utilisation très simples uniquement.

Dans votre nouvelle approche, la description n’indique pas clairement comment vous gérez le rebase depuis le tronc jusqu’à vos branches d’entités si vous en avez besoin. Voulez-vous interdire complètement le rebasement? Comme la création de branches dans svn est une opération peu coûteuse, cela pourrait également être une option.

0
jdehaan