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):
$> git svn clone <svn-repository-url> <local-directory>
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:
$> git checkout master
$> git svn rebase
Je fais tout mon travail de développement dans un `` travail '' de branche distinct qui est créé comme ceci:
$> git checkout -b work
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:
$> git commit -am '-- finished a little piece of work'
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
$> git log
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
$> git rebase -i 74e4068360e34b2ccf0c5869703af458cde0cdcb
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:
$> git checkout master
$> git svn rebase
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:
$> git checkout master
$> git merge work # (1) merge your 'work' into 'master'
$> git branch -d work # (2) remove the work branch immediately after merging
$> git svn dcommit # (3) push your changes to the svn repository
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':
$> git checkout -b work
$> git branch # show my branches:
master
* work
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':
$> git checkout master
$> git svn rebase # 'svn pull' changes
$> git checkout work # go to my work
$> git checkout -b integration # make a copy of the branch
$> git merge master # integrate my changes with theirs
$> ... check/fix/debug ...
$> ... rewrite history with rebase -i if needed
$> git checkout master # try again to push my changes
$> git svn rebase # hopefully no further changes to merge
$> git merge integration # (1) merge your work with theirs
$> git branch -d work # (2) remove branches that are merged
$> git branch -d integration # (2) remove branches that are merged
$> git svn dcommit # (3) push your changes to the svn repository
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? )