Ma motivation pour essayer git-svn est la fusion et la création de branches sans effort. Puis j'ai remarqué que man git-svn (1) dit:
Exécuter git-merge ou git-pull n'est PAS recommandé sur une branche à partir de laquelle vous prévoyez de dcommit. Subversion ne représente pas les fusions de manière raisonnable ou utile; donc les utilisateurs utilisant Subversion ne peuvent pas voir les fusions que vous avez effectuées. De plus, si vous fusionnez ou tirez d'une branche git qui est un miroir d'une branche SVN, dcommit peut s'engager dans la mauvaise branche.
Cela signifie-t-il que je ne peux pas créer une branche locale à partir de svn / trunk (ou une branche), pirater, fusionner à nouveau dans svn / trunk, puis dcommit? Je comprends que les utilisateurs de svn verront le même désordre que celui qui fusionne dans svn pre 1.5.x, mais y a-t-il d'autres inconvénients? Cette dernière phrase m'inquiète aussi. Les gens font-ils régulièrement ce genre de choses?
--mergeinfo=<mergeinfo>
option qui peut être capable de transmettre les informations de fusion au SVN. Je ne sais pas comment il doit être utilisé.Réponses:
En fait, j'ai trouvé un moyen encore meilleur avec l'
--no-ff
option sur git merge. Toute cette technique de squash que j'utilisais auparavant n'est plus nécessaire.Mon nouveau workflow est désormais le suivant:
J'ai une branche « maître » qui est la seule branche que je dcommit à partir et que le dépôt SVN clone (
-s
supposons que vous avez une mise en page standard SVN dans le référentieltrunk/
,branches/
ettags/
):Je travaille sur une branche locale "work" (
-b
crée la branche "work")commit localement dans la branche "work" (
-s
pour valider votre message de commit). Dans la suite, je suppose que vous avez effectué 3 commits locauxVous souhaitez maintenant vous engager sur le serveur SVN
[Finalement] cacher les modifications que vous ne voulez pas voir validées sur le serveur SVN (souvent vous avez commenté du code dans le fichier principal juste parce que vous voulez accélérer la compilation et vous concentrer sur une fonctionnalité donnée)
rebase de la branche maître avec le référentiel SVN (pour mettre à jour depuis le serveur SVN)
revenir à la branche de travail et rebase avec master
Assurez-vous que tout va bien en utilisant, par exemple:
Il est maintenant temps de fusionner les trois commits de la branche "work" dans "master" en utilisant cette merveilleuse
--no-ff
optionVous pouvez remarquer l'état des journaux:
Maintenant, vous voulez probablement éditer (
amend
) le dernier commit pour vos mecs SVN (sinon ils ne verront qu'un seul commit avec le message "Merge branch 'work'"Enfin commit sur le serveur SVN
Revenez au travail et récupérez éventuellement vos fichiers cachés:
la source
--no-ff
option, vous créez explicitement une validation de fusion (une validation avec deux parents) au lieu d'une avance rapide. Pour vous assurer que tous les commits de la branche svn-tracking sont des commits monoparentaux, toutes les fusions doivent être rapides (cela--ff-only
peut vous aider) ou, si le tronc a changé dans votre dos--squash
, non?git svn dcommit
réécrit le commit git que vous lui donnez. Cela signifie que vous perdez son autre parent, et maintenant votre dépôt git n'a aucun enregistrement dans lequel vous avez jamais fusionné cette branchemaster
. Cela peut également laisser votre répertoire de travail dans un état incohérent.git merge --no-ff work -m "commit message"
au lieu d'avoir unegit commit --amend
étape supplémentaireCréer des branches locales est certainement possible avec git-svn. Tant que vous n'utilisez que des branches locales pour vous-même et que vous n'essayez pas d'utiliser git pour fusionner entre les branches svn en amont, tout devrait bien se passer.
J'ai une branche "maître" que j'utilise pour suivre le serveur svn. C'est la seule branche dont je m'engage. Si je travaille, je crée une branche thématique et j'y travaille. Lorsque je veux le valider, je fais ce qui suit:
J'ai aussi une autre situation où je dois maintenir quelques changements locaux (pour le débogage) qui ne devraient jamais être poussés vers svn. Pour cela, j'ai la branche master ci-dessus mais aussi une branche appelée "work" où je travaille normalement. Les branches thématiques sont dérivées du travail. Quand je veux valider le travail là-bas, je vérifie le maître et utilise le choix de cerise pour choisir les commits de la branche de travail que je veux commettre dans svn. C'est parce que je veux éviter de valider les trois commits de changement locaux. Ensuite, je me désengage de la branche master et je rebase tout.
Cela vaut la peine de
git svn dcommit -n
commencer par vous assurer que vous êtes sur le point de valider exactement ce que vous avez l'intention de commettre. Contrairement à git, réécrire l'historique dans svn est difficile!Je pense qu'il doit y avoir un meilleur moyen de fusionner le changement sur une branche de sujet tout en ignorant ces commits de changement local que d'utiliser le choix de la cerise, donc si quelqu'un a des idées, ils seraient les bienvenus.
la source
Solution simple: supprimez la branche 'work' après la fusion
Réponse courte: vous pouvez utiliser git comme vous le souhaitez (voir ci-dessous pour un flux de travail simple), y compris la fusion. Assurez-vous simplement de suivre chaque ' git merge work ' avec ' git branch -d work ' pour supprimer la branche de travail temporaire.
Explication d'arrière-plan: Le problème de merge / dcommit est que chaque fois que vous 'git svn dcommit' une branche, l'historique de fusion de cette branche est 'aplati': git oublie toutes les opérations de fusion qui sont allées dans cette branche: Seul le contenu du fichier est conservé, mais le fait que ce contenu provienne (partiellement) d'une autre branche spécifique est perdu. Voir: Pourquoi git svn dcommit perd-il l'historique des commits de fusion pour les branches locales?
(Remarque: il n'y a pas grand-chose que git-svn puisse faire à ce sujet: svn ne comprend tout simplement pas les fusions git beaucoup plus puissantes. Ainsi, à l'intérieur du dépôt svn, ces informations de fusion ne peuvent être représentées d'aucune façon.)
Mais c'est tout le problème. Si vous supprimez la branche 'work' après avoir été fusionnée dans la 'branche principale', votre dépôt git est 100% propre et ressemble exactement à votre dépôt svn.
Mon workflow: Bien sûr, j'ai d'abord cloné le référentiel svn distant dans un référentiel git local (cela peut prendre un certain temps):
Tout le travail se déroule alors dans le "répertoire local". Chaque fois que j'ai besoin d'obtenir des mises à jour du serveur (comme 'svn update'), je fais:
Je fais tout mon travail de développement dans un `` travail '' de branche distinct qui est créé comme ceci:
Bien sûr, vous pouvez créer autant de branches pour votre travail que vous le souhaitez et fusionner et rebaser entre elles comme vous le souhaitez (supprimez-les simplement lorsque vous en avez terminé avec elles - comme indiqué ci-dessous). Dans mon travail normal, je m'engage très fréquemment:
La prochaine étape (git rebase -i) est facultative --- il s'agit simplement de nettoyer l'historique avant de l'archiver sur svn: Une fois que j'ai atteint un mile stable que je veux partager avec d'autres, je réécris l'histoire de ce `` travail '' branchez et nettoyez les messages de validation (les autres développeurs n'ont pas besoin de voir toutes les petites étapes et erreurs que j'ai faites en cours de route - juste le résultat). Pour cela, je fais
et copiez le hachage sha-1 du dernier commit qui est actif dans le dépôt svn (comme indiqué par un git-svn-id). Alors j'appelle
Collez simplement le hachage sha-1 de notre dernier commit svn au lieu du mien. Vous voudrez peut-être lire la documentation avec 'git help rebase' pour plus de détails. En bref: cette commande ouvre d'abord un éditeur présentant vos commits - changez simplement «pick» en «squash» pour tous les commits que vous voulez écraser avec les commits précédents. Bien sûr, la première ligne doit rester un «choix». De cette manière, vous pouvez condenser vos nombreux petits engagements en une ou plusieurs unités significatives. Enregistrez et quittez l'éditeur. Vous obtiendrez un autre éditeur vous demandant de réécrire les messages du journal de validation.
En bref: après avoir terminé le `` code hacking '', je masse ma branche `` travail '' jusqu'à ce qu'elle ressemble à comment je veux la présenter aux autres programmeurs (ou comment je veux voir le travail dans quelques semaines lorsque je parcours l'historique) .
Afin de pousser les modifications vers le référentiel svn, je fais:
Nous sommes maintenant de retour à l'ancienne branche «master» mise à jour avec tous les changements intervenus entre-temps dans le dépôt svn (vos nouveaux changements sont cachés dans la branche «work»).
S'il y a des changements qui peuvent entrer en conflit avec vos nouveaux changements de «travail», vous devez les résoudre localement avant de pouvoir pousser votre nouveau travail (voir les détails ci-dessous). Ensuite, nous pouvons appliquer nos modifications à svn:
Note 1: La commande 'git branch -d work' est assez sûre: elle vous permet uniquement de supprimer les branches dont vous n'avez plus besoin (car elles sont déjà fusionnées dans votre branche actuelle). Si vous exécutez cette commande par erreur avant de fusionner votre travail avec la branche «master», vous obtenez un message d'erreur.
Remarque 2: assurez-vous de supprimer votre branche avec 'git branch -d work' entre la fusion et dcommit: si vous essayez de supprimer la branche après dcommit, vous obtenez un message d'erreur: lorsque vous faites 'git svn dcommit', git oublie que votre branche a été fusionnée avec «master». Vous devez le supprimer avec 'git branch -D work' qui ne fait pas le contrôle de sécurité.
Maintenant, je crée immédiatement une nouvelle branche 'work' pour éviter de pirater accidentellement la branche 'master':
Intégrer votre 'travail' avec les changements sur svn: Voici ce que je fais quand 'git svn rebase' révèle que d'autres ont changé le dépôt svn pendant que je travaillais sur ma branche 'work':
Des solutions plus puissantes existent: Le flux de travail présenté est simpliste: il utilise les pouvoirs de git uniquement dans chaque cycle de 'update / hack / dcommit' --- mais laisse l'historique du projet à long terme aussi linéaire que le dépôt svn. Ce n'est pas grave si vous voulez simplement commencer à utiliser les fusions git par petites étapes dans un projet svn hérité.
Lorsque vous vous familiariserez avec la fusion git, n'hésitez pas à explorer d'autres flux de travail: si vous savez ce que vous faites, vous pouvez mélanger des fusions git avec des fusions svn (en utilisant git-svn (ou similaire) juste pour aider avec svn merge? )
la source
git merge --squash work
, pourquoi ne pas faire ça? Je peux voir faire des commits squash dans la branche avant de fusionner si vous créez plus d'un 'pick' (disons que vous avez 8 commits et que vous transformez chacun des 4 commits en 1, et fusionnez 2 commits en master). Aussi, lors de la mise à jour de ma branche 'travail', je le faisrebase
, c'est plus simple que de créer une autre branche pour ma branche et de faire des fusions ...La réponse de Greg Hewgill sur le dessus n'est pas sûre! Si de nouveaux commits apparaissent sur le tronc entre les deux "git svn rebase", la fusion ne sera pas en avance rapide.
Cela peut être assuré en utilisant le drapeau "--ff-only" sur git-merge, mais je n'exécute généralement pas "git svn rebase" dans la branche, seulement "git rebase master" dessus (en supposant que ce n'est qu'un local branche). Ensuite, un "git merge thebranch" est garanti d'avance rapide.
la source
Un moyen sûr de fusionner des branches svn dans git est d'utiliser git merge --squash. Cela créera un seul commit et s'arrêtera pour que vous ajoutiez un message.
Disons que vous avez une branche svn de sujet, appelée svn-branch.
à ce stade, vous avez toutes les modifications de la branche svn écrasées en un seul commit en attente dans l'index
la source
Rebase la branche git locale sur la branche git principale puis dcommit et de cette façon, il semble que vous ayez fait tous ces commits dans l'ordre afin que les gens svn puissent le voir linéairement comme ils en sont habitués. Donc, en supposant que vous ayez une branche locale appelée topic, vous pouvez le faire
qui jouera ensuite vos commits sur la branche master, prêt à être décommit
la source