Depuis un certain temps, j'utilise subversion pour mes projets personnels.
De plus en plus, j'entends beaucoup de choses sur Git et Mercurial, et DVCS en général.
J'aimerais donner un tourbillon à l'ensemble du DVCS, mais je ne suis pas trop familier avec l'une ou l'autre option.
Quelles sont les différences entre Mercurial et Git?
Remarque: je n'essaie pas de savoir lequel est le "meilleur" ou même avec lequel je devrais commencer. Je recherche principalement des domaines clés où ils sont similaires et où ils sont différents, car je suis intéressé de savoir en quoi ils diffèrent en termes de mise en œuvre et de philosophie.
Réponses:
Avis de non-responsabilité: j'utilise Git, je suis le développement de Git sur la liste de diffusion git, et je contribue même un peu à Git (gitweb principalement). Je connais Mercurial à partir de la documentation et certains de la discussion sur le canal IRC #revctrl sur FreeNode.
Merci à toutes les personnes sur le canal IRC #mercurial qui ont fourni de l'aide sur Mercurial pour cette rédaction
Sommaire
Ici, ce serait bien d'avoir une syntaxe pour la table, quelque chose comme dans PHPMarkdown / MultiMarkdown / Maruku extension de Markdown
.hgtags
fichier versionné avec des règles spéciales pour les balises par référentiel et prend également en charge les balises locales dans.hg/localtags
; dans les balises Git sont des références résidant dans l'refs/tags/
espace de noms, et par défaut sont suivies automatiquement lors de la récupération et nécessitent une poussée explicite.Il y a quelques choses qui diffèrent Mercurial de Git, mais il y a d'autres choses qui les rendent similaires. Les deux projets s'empruntent des idées. Par exemple, la
hg bisect
commande dans Mercurial (anciennement extension bissecte ) a été inspirée par lagit bisect
commande dans Git, tandis que l'idée de agit bundle
été inspirée parhg bundle
.Structure du référentiel, stockage des révisions
Dans Git, il existe quatre types d'objets dans sa base de données d'objets: les objets blob qui contiennent le contenu d'un fichier, les objets arborescents hiérarchiques qui stockent la structure du répertoire, y compris les noms de fichier et les parties pertinentes des autorisations de fichier (autorisation exécutable pour les fichiers, étant un lien symbolique) , un objet commit qui contient des informations sur la paternité, un pointeur vers un instantané de l'état du référentiel à la révision représenté par un commit (via un objet arborescent du répertoire supérieur du projet) et des références à zéro ou plusieurs commit parents, et des objets tag qui référencent d'autres objets et peuvent être signé à l'aide de PGP / GPG.
Git utilise deux façons de stocker des objets: un format lâche , où chaque objet est stocké dans un fichier séparé (ces fichiers sont écrits une fois et jamais modifiés), et un format compressé où de nombreux objets sont stockés delta-compressés dans un seul fichier. L'atomicité des opérations est fournie par le fait que la référence à un nouvel objet est écrite (atomiquement, en utilisant l'astuce create + rename) après avoir écrit un objet.
Les référentiels Git nécessitent une maintenance périodique en utilisant
git gc
(pour réduire l'espace disque et améliorer les performances), bien que Git le fasse automatiquement de nos jours. (Cette méthode offre une meilleure compression des référentiels.)Mercurial (pour autant que je le comprends) stocke l'historique d'un fichier dans un journal de fichiers (ensemble, je pense, avec des métadonnées supplémentaires comme le suivi des renommées et des informations d'assistance); il utilise une structure plate appelée manifeste pour stocker la structure du répertoire et une structure appelée changelog qui stocke des informations sur les changements (révisions), y compris le message de validation et zéro, un ou deux parents.
Mercurial utilise le journal des transactions pour fournir l'atomicité des opérations et s'appuie sur la troncature des fichiers pour le nettoyage après une opération échouée ou interrompue. Les revlogs sont en ajout uniquement.
En regardant la structure du référentiel dans Git par rapport à Mercurial, on peut voir que Git est plus comme une base de données d'objets (ou un système de fichiers adressé par contenu), et Mercurial plus comme une base de données relationnelle traditionnelle à champ fixe.
Différences:
dans Git, les objets arborescents forment une structure hiérarchique ; dans le fichier manifeste Mercurial est une structure plate . Dans Git, l' objet blob stocke une version du contenu d'un fichier; dans Mercurial filelog stocke l' historique complet d'un seul fichier (si nous ne prenons pas en compte ici les complications de renommage). Cela signifie qu'il existe différentes zones d'opérations où Git serait plus rapide que Mercurial, toutes autres choses considérées égales (comme les fusions ou l'affichage de l'historique d'un projet), et des zones où Mercurial serait plus rapide que Git (comme l'application de correctifs ou l'affichage historique d'un seul fichier).Ce problème peut ne pas être important pour l'utilisateur final.
En raison de la structure à enregistrement fixe de la structure du journal des modifications de Mercurial, les validations dans Mercurial ne peuvent avoir que deux parents ; commits dans Git peut avoir plus de deux parents (ce que l'on appelle la «fusion de poulpe»). Bien que vous puissiez (en théorie) remplacer la fusion de poulpe par une série de fusions à deux parents, cela pourrait entraîner des complications lors de la conversion entre les référentiels Mercurial et Git.
Pour autant que je sache, Mercurial n'a pas d'équivalent de balises annotées (objets de balises) de Git. Un cas particulier des balises annotées sont les balises signées (avec signature PGP / GPG); l'équivalent dans Mercurial peut être fait en utilisant GpgExtension , laquelle extension est distribuée avec Mercurial. Vous ne pouvez pas baliser un objet non validé dans Mercurial comme vous le pouvez dans Git, mais ce n'est pas très important, je pense (certains référentiels git utilisent un blob balisé pour distribuer la clé PGP publique à utiliser pour vérifier les balises signées).
Références: branches et balises
Dans Git, les références (branches, branches de suivi à distance et balises) résident en dehors du DAG des validations (comme elles le devraient). Les références dans l'
refs/heads/
espace de noms ( branches locales ) pointent vers des validations et sont généralement mises à jour par "git commit"; ils pointent vers la pointe (tête) de la branche, c'est pourquoi un tel nom. Les références dans l'refs/remotes/<remotename>/
espace de noms ( branches de suivi à distance ) pointent vers la validation, suivent les branches dans le référentiel distant<remotename>
et sont mises à jour par "git fetch" ou équivalent. Les références dans l'refs/tags/
espace de noms ( balises ) pointent généralement vers des validations (balises légères) ou des objets de balise (balises annotées et signées), et ne sont pas censées changer.Mots clés
Dans Mercurial, vous pouvez donner un nom persistant à la révision à l'aide d'une balise ; les balises sont stockées de manière similaire aux modèles d'ignorance. Cela signifie que les balises visibles globalement sont stockées dans un
.hgtags
fichier contrôlé par révision dans votre référentiel. Cela a deux conséquences: premièrement, Mercurial doit utiliser des règles spéciales pour ce fichier pour obtenir la liste actuelle de toutes les balises et mettre à jour ce fichier (par exemple, il lit la dernière révision validée du fichier, pas la version actuellement extraite); deuxièmement, vous devez valider les modifications de ce fichier pour que la nouvelle balise soit visible par les autres utilisateurs / autres référentiels (pour autant que je le comprenne).Mercurial prend également en charge les balises locales , stockées dans
hg/localtags
, qui ne sont pas visibles par les autres (et bien sûr ne sont pas transférables)Dans Git, les balises sont des références nommées fixes (constantes) à d'autres objets (généralement des objets de balise, qui à leur tour pointent vers des validations) stockés dans l'
refs/tags/
espace de noms. Par défaut, lors de la récupération ou de la poussée d'un ensemble de révision, git récupère ou pousse automatiquement les balises qui indiquent que les révisions sont récupérées ou poussées. Néanmoins, vous pouvez contrôler dans une certaine mesure les balises récupérées ou poussées.Git traite les balises légères (pointant directement sur les validations) et les balises annotées (pointant sur les objets de balise, qui contiennent un message de balise qui inclut éventuellement la signature PGP, qui à son tour pointe pour valider) légèrement différemment, par exemple, par défaut, il ne prend en compte que les balises annotées lors de la description valide en utilisant "git describe".
Git n'a pas d'équivalent strict des balises locales dans Mercurial. Néanmoins, les meilleures pratiques de git recommandent de configurer un référentiel nu public séparé, dans lequel vous transférez les modifications prêtes, et à partir duquel d'autres clones et récupèrent. Cela signifie que les balises (et les branches) que vous ne poussez pas sont privées dans votre référentiel. D'autre part, vous pouvez également utiliser un espace de noms autre que
heads
,remotes
outags
, par exemple,local-tags
pour les balises locales.Opinion personnelle: À mon avis, les balises doivent résider en dehors du graphique de révision, car elles lui sont externes (ce sont des pointeurs dans le graphique des révisions). Les balises doivent être sans version, mais transférables. Le choix de Mercurial d'utiliser un mécanisme similaire à celui pour ignorer les fichiers, signifie qu'il doit soit traiter
.hgtags
spécialement (le fichier dans l'arborescence est transférable, mais ordinaire il est versionné), ou avoir des balises qui sont uniquement locales (.hg/localtags
n'est pas versionnée, mais non transférable).Branches
Dans Git, la branche locale (pointe de branche ou tête de branche) est une référence nommée à un commit, où l'on peut développer de nouveaux commits. La branche peut également signifier une ligne de développement active, c'est-à-dire que toutes les validations sont accessibles depuis l'extrémité de la branche. Les branches locales résident dans l'
refs/heads/
espace de noms, par exemple, le nom complet de la branche «maître» est «réfs / têtes / maître».La branche actuelle dans Git (signifiant branche extraite et branche où ira le nouveau commit) est la branche référencée par la référence HEAD. On peut avoir HEAD pointant directement vers un commit, plutôt que d'être une référence symbolique; cette situation d'être sur une branche anonyme sans nom est appelée HEAD détaché ("la branche git" montre que vous êtes sur '(pas de branche)').
Dans Mercurial, il y a des branches anonymes (têtes de branche), et on peut utiliser des signets (via l' extension de signet ). Ces branches de signets sont purement locales et ces noms (jusqu'à la version 1.6) n'étaient pas transférables avec Mercurial. Vous pouvez utiliser rsync ou scp pour copier le
.hg/bookmarks
fichier dans un référentiel distant. Vous pouvez également utiliserhg id -r <bookmark> <url>
pour obtenir l'ID de révision d'une astuce actuelle d'un signet.Depuis 1.6 les signets peuvent être poussés / tirés. La page BookmarksExtension contient une section sur l'utilisation des référentiels distants . Il y a une différence dans le fait que dans Mercurial, les noms de signets sont globaux , tandis que la définition de «distant» dans Git décrit également le mappage des noms de branche à partir des noms du référentiel distant vers les noms des branches locales de suivi à distance; par exemple, le
refs/heads/*:refs/remotes/origin/*
mappage signifie que l'on peut trouver l'état de la branche 'maître' ('refs / heads / master') dans le référentiel distant dans la branche de suivi à distance 'origin / master' ('refs / remotes / origin / master').Mercurial a également ce qu'on appelle des branches nommées , où le nom de la branche est intégré dans un commit (dans un changeset). Ce nom est global (transféré à l'extraction). Ces noms de branche sont enregistrés en permanence dans le cadre des métadonnées de l'ensemble de modifications \ u2019. Avec Mercurial moderne, vous pouvez fermer la "branche nommée" et arrêter l'enregistrement du nom de la branche. Dans ce mécanisme, les pointes de branches sont calculées à la volée.
Les "branches nommées" de Mercurial devraient à mon avis être plutôt appelées labels de commit , car c'est ce qu'elles sont. Il existe des situations où la "branche nommée" peut avoir plusieurs astuces (plusieurs validations sans enfant) et peut également consister en plusieurs parties disjointes du graphique des révisions.
Il n'y a pas d'équivalent de ces "branches intégrées" Mercurial dans Git; de plus, la philosophie de Git est que si l'on peut dire que la branche inclut une validation, cela ne signifie pas qu'une validation appartient à une branche.
Notez que la documentation de Mercurial propose toujours d'utiliser des clones séparés (référentiels séparés) au moins pour les branches à longue durée de vie (branche unique par flux de travail de référentiel), alias branchement par clonage .
Branches en poussant
Mercurial par défaut pousse toutes les têtes . Si vous voulez pousser une seule branche ( tête unique ), vous devez spécifier la révision de pointe de la branche que vous voulez pousser. Vous pouvez spécifier la pointe de branche par son numéro de révision (local vers le référentiel), par l'identifiant de révision, par le nom du signet (local vers le référentiel, non transféré) ou par le nom de la branche incorporée (branche nommée).
Si je comprends bien, si vous poussez une série de révisions qui contiennent des commits marqués comme étant sur une "branche nommée" dans le langage Mercurial, vous aurez cette "branche nommée" dans le référentiel vers lequel vous poussez. Cela signifie que les noms de ces branches incorporées ("branches nommées") sont globaux (en ce qui concerne les clones du référentiel / projet donné).
Par défaut (sous réserve de la
push.default
variable de configuration) "git push" ou "git push < remote >" Git pousserait les branches correspondantes , c'est-à-dire uniquement les branches locales qui ont leur équivalent déjà présent dans le référentiel distant dans lequel vous poussez. Vous pouvez utiliser l'--all
option git-push ("git push --all") pour pousser toutes les branches , vous pouvez utiliser "git push < remote > < branch >" pour pousser une seule branche donnée , et vous pouvez utiliser "git push < remote > HEAD "pour pousser la branche courante .Tout ce qui précède suppose que Git n'est pas configuré sur les branches à pousser via
remote.<remotename>.push
les variables de configuration.Branches à aller chercher
Remarque: ici, j'utilise la terminologie Git où "récupérer" signifie télécharger les modifications à partir du référentiel distant sans intégrer ces modifications au travail local. C'est ce que font "
git fetch
" et "hg pull
".Si je comprends bien, par défaut, Mercurial récupère toutes les têtes du référentiel distant, mais vous pouvez spécifier la branche à récupérer via "
hg pull --rev <rev> <url>
" ou "hg pull <url>#<rev>
" pour obtenir une seule branche . Vous pouvez spécifier <rev> à l'aide de l'identifiant de révision, du nom de la "branche nommée" (branche intégrée dans le journal des modifications) ou du nom du signet. Cependant, le nom du signet (au moins actuellement) n'est pas transféré. Toutes les révisions de "branches nommées" que vous obtenez appartiennent à être transférées. "hg pull" stocke les bouts de branches récupérées comme des têtes anonymes et sans nom.Dans Git par défaut (pour la télécommande 'origin' créée par "git clone" et pour les télécommandes créées en utilisant "git remote add") "
git fetch
" (ou "git fetch <remote>
") obtient toutes les branches du référentiel distant (de l'refs/heads/
espace de noms) et les stocke dansrefs/remotes/
espace de noms. Cela signifie par exemple que la branche nommée 'master' (nom complet: 'refs / heads / master') dans la 'origin' distante serait stockée (enregistrée) en tant que branche de suivi à distance 'origin / master' (nom complet: 'refs / télécommandes / origine / maître ').Vous pouvez récupérer une seule branche dans Git en utilisant
git fetch <remote> <branch>
- Git stockerait les branches demandées dans FETCH_HEAD, ce qui est quelque chose de similaire aux têtes sans nom Mercurial.Ce ne sont que des exemples de cas par défaut de puissante syntaxe refspec Git: avec les refspecs, vous pouvez spécifier et / ou configurer les branches que vous souhaitez récupérer et où les stocker. Par exemple, le cas par défaut "récupérer toutes les branches" est représenté par '+ refs / heads / *: refs / remotes / origin / *' wildcard refspec, et "fetch single branch" est un raccourci pour 'refs / heads / <branch>:' . Les refspecs sont utilisées pour mapper les noms des branches (refs) dans le référentiel distant aux noms des refs locaux. Mais vous n'avez pas besoin d'en savoir (beaucoup) sur les refspecs pour pouvoir travailler efficacement avec Git (grâce principalement à la commande "git remote").
Opinion personnelle: Personnellement, je pense que les "branches nommées" (avec des noms de branche intégrés dans les métadonnées des changements) dans Mercurial sont une conception erronée avec son espace de noms global, en particulier pour un système de contrôle de version distribué . Par exemple, prenons le cas où Alice et Bob ont tous deux "branche nommée" nommée "for-joe" dans leurs référentiels, branches qui n'ont rien en commun. Dans le référentiel de Joe, cependant, ces deux branches seraient traitées comme une seule branche. Vous avez donc en quelque sorte trouvé une convention protégeant contre les conflits de noms de branche. Ce n'est pas un problème avec Git, où dans le référentiel de Joe, la branche 'for-joe' d'Alice serait 'alice / for-joe', et de Bob ce serait 'bob / for-joe'.
Les «succursales de signets» de Mercurial manquent actuellement de mécanisme de distribution interne.
Différences:
Cette zone est l'une des principales différences entre Mercurial et Git, comme James Woodyatt et Steve Losh l'ont dit dans leurs réponses. Mercurial, par défaut, utilise des codelines légères anonymes, qui dans leur terminologie sont appelées "têtes". Git utilise des branches nommées légères, avec un mappage injectif pour mapper les noms des branches du référentiel distant aux noms des branches de suivi à distance. Git vous "force" à nommer des branches (enfin, à l'exception d'une seule branche sans nom, situation appelée HEAD détaché), mais je pense que cela fonctionne mieux avec des flux de travail lourds comme une branche de sujet, ce qui signifie plusieurs branches dans un paradigme de référentiel unique.
Révisions de dénomination
Dans Git, il existe de nombreuses façons de nommer les révisions (décrites par exemple dans la page de manuel git rev-parse ):
^
pour réviser le paramètre signifie le premier parent d'un objet commit,^n
signifie le nième parent d'un commit de fusion. Un suffixe~n
pour le paramètre de révision signifie le n-ième ancêtre d'une validation dans la première ligne directe. Ces suffixes peuvent être combinés pour former un spécificateur de révision suivant le chemin à partir d'une référence symbolique, par exemple «pu ~ 3 ^ 2 ~ 3»Il existe également des spécificateurs de révision impliquant le reflog, non mentionnés ici. Dans Git, chaque objet, que ce soit commit, tag, tree ou blob a son identifiant SHA-1; il existe une syntaxe spéciale comme par exemple 'next: Documentation' ou 'next: README' pour faire référence à l'arborescence (répertoire) ou au blob (contenu du fichier) à la révision spécifiée.
Mercurial a également de nombreuses façons de nommer les changements (décrits par exemple dans la page de manuel hg ):
Différences
Comme vous pouvez le voir en comparant les listes ci-dessus, Mercurial propose des numéros de révision, locaux au référentiel, contrairement à Git. D'autre part, Mercurial propose des décalages relatifs uniquement à partir de `` tip '' (branche actuelle), qui sont locaux au référentiel (au moins sans ParentrevspecExtension ), tandis que Git permet de spécifier n'importe quel commit à la suite de n'importe quelle astuce.
La révision la plus récente est nommée HEAD dans Git et "tip" dans Mercurial; il n'y a pas de révision nulle dans Git. Mercurial et Git peuvent avoir plusieurs racines (peuvent avoir plus d'un commit sans parent; cela est généralement le résultat de la fusion de projets auparavant séparés).
Voir aussi: Beaucoup de différents types d' articles de spécification de révision sur le blog d'Elijah (newren).
Opinion personnelle: Je pense que les numéros de révision sont surévalués (au moins pour le développement distribué et / ou l'histoire non linéaire / branchée). Premièrement, pour un système de contrôle de version distribué, ils doivent être soit locaux au référentiel, soit exiger de traiter certains référentiels de manière spéciale comme une autorité de numérotation centrale. Deuxièmement, les projets plus importants, avec un historique plus long, peuvent avoir un nombre de révisions dans une plage de 5 chiffres, de sorte qu'ils n'offrent qu'un léger avantage par rapport aux identificateurs de révision raccourcis à 6-7 caractères, et impliquent un ordre strict tandis que les révisions ne sont que partiellement ordonnées (je veux dire ici que les révisions n et n + 1 n'ont pas besoin d'être parent et enfant).
Gammes de révision
Dans Git, les plages de révision sont topologiques . La
A..B
syntaxe courante , qui pour l'historique linéaire signifie une plage de révision commençant à A (mais excluant A) et se terminant à B (c'est-à-dire que la plage est ouverte par le bas ), est un raccourci ("sucre syntaxique") pour^A B
lequel, pour les commandes de parcours de l'historique, toutes les commits accessibles depuis B, à l'exclusion de ceux accessibles depuis A. Cela signifie que le comportement de laA..B
plage est entièrement prévisible (et très utile) même si A n'est pas l'ancêtre de B:A..B
signifie alors la plage de révisions de l'ancêtre commun de A et B (fusionner la base ) à la révision B.Dans Mercurial, les plages de révision sont basées sur la plage de numéros de révision . La plage est spécifiée à l'aide de la
A:B
syntaxe et contrairement à Git, la plage agit comme un intervalle fermé . La plage B: A est également la plage A: B dans l'ordre inverse, ce qui n'est pas le cas dans Git (mais voir la note ci-dessous sur laA...B
syntaxe). Mais cette simplicité a un prix: la gamme de révision A: B n'a de sens que si A est l'ancêtre de B ou vice versa, c'est-à-dire avec une histoire linéaire; sinon (je suppose que) la plage est imprévisible et le résultat est local au référentiel (car les numéros de révision sont locaux au référentiel).Ceci est corrigé avec Mercurial 1.6, qui a une nouvelle plage de révision topologique , où 'A..B' (ou 'A :: B') est compris comme l'ensemble de changements qui sont à la fois des descendants de X et des ancêtres de Y. C'est , Je suppose, équivalent à '--ancestry-path A..B' dans Git.
Git a également une notation
A...B
pour la différence symétrique des révisions; cela signifieA B --not $(git merge-base A B)
, ce qui signifie que toutes les validations sont accessibles depuis A ou B, mais en excluant toutes les validations accessibles depuis les deux (accessibles depuis les ancêtres communs).Renomme
Mercurial utilise le suivi des renommées pour gérer les renommages de fichiers. Cela signifie que les informations sur le fait qu'un fichier a été renommé sont enregistrées au moment de la validation; dans Mercurial, ces informations sont enregistrées sous la forme "diff amélioré" dans les métadonnées de fichier journal (fichier revlog). La conséquence de cela est que vous devez utiliser
hg rename
/hg mv
... ou vous devez vous rappeler de courirhg addremove
pour effectuer une détection de renommage basée sur la similitude.Git est unique parmi les systèmes de contrôle de version en ce qu'il utilise la détection de renommage pour gérer les renommages de fichiers. Cela signifie que le fait que le fichier a été renommé est détecté au moment où il est nécessaire: lors d'une fusion ou lors de l'affichage d'un diff (si demandé / configuré). Cela a l'avantage que l'algorithme de détection de renommage peut être amélioré et n'est pas figé au moment de la validation.
Git et Mercurial nécessitent d'utiliser l'
--follow
option pour suivre les renommages lors de l'affichage de l'historique d'un seul fichier. Les deux peuvent suivre des renommages lors de l'affichage de l'historique par ligne d'un fichier dansgit blame
/hg annotate
.Dans Git, la
git blame
commande est capable de suivre le mouvement du code, en déplaçant (ou en copiant) également le code d'un fichier à l'autre, même si le mouvement du code ne fait pas partie d'un renommage de fichier sain. Pour autant que je sache, cette fonctionnalité est unique à Git (au moment de la rédaction, octobre 2009).Protocoles réseau
Mercurial et Git ont tous deux la prise en charge de l'extraction et de la transmission vers des référentiels sur le même système de fichiers, où l'URL du référentiel n'est qu'un chemin d'accès du système de fichiers au référentiel. Les deux prennent également en charge la récupération à partir de fichiers groupés .
Prise en charge de Mercurial récupérant et poussant via SSH et via les protocoles HTTP. Pour SSH, il faut un compte shell accessible sur la machine de destination et une copie de hg installé / disponible. Pour l'accès HTTP, le
hg-serve
script Mercurial CGI en cours d'exécution est requis et Mercurial doit être installé sur la machine serveur.Git prend en charge deux types de protocoles utilisés pour accéder au référentiel distant:
git-daemon
), nécessitent l'installation de git sur le serveur. L'échange dans ces protocoles consiste à négocier client et serveur sur les objets qu'ils ont en commun, puis à générer et à envoyer un packfile. Modern Git inclut la prise en charge du protocole HTTP "intelligent".git update-server-info
(généralement exécutées à partir d'un hook ). L'échange consiste en un client parcourant la chaîne de validation et en téléchargeant les objets et les fichiers pack en vrac selon les besoins. L'inconvénient est qu'il télécharge plus que ce qui est strictement requis (par exemple, dans le cas où il n'y a qu'un seul packfile, il serait téléchargé en entier même en ne récupérant que quelques révisions), et qu'il peut nécessiter de nombreuses connexions pour terminer.Extension: scriptabilité vs extensions (plugins)
Mercurial est implémenté en Python , avec du code de base écrit en C pour les performances. Il fournit une API pour écrire des extensions (plugins) comme moyen d'ajouter des fonctionnalités supplémentaires. Certaines fonctionnalités, comme les «branches de signets» ou les révisions de signature, sont fournies dans les extensions distribuées avec Mercurial et nécessitent d'être activées.
Git est implémenté dans les scripts C , Perl et shell . Git fournit de nombreuses commandes de bas niveau ( plomberie ) utilisables dans les scripts. La manière habituelle d'introduire une nouvelle fonctionnalité est de l'écrire en Perl ou en script shell, et lorsque l'interface utilisateur se stabilise, réécrivez-la en C pour les performances, la portabilité, et dans le cas d'un script shell en évitant les cas d'angle (cette procédure est appelée intégration ).
Git s'appuie et est construit autour des formats [référentiel] et des protocoles [réseau]. Au lieu des liaisons de langage, il y a des réimplémentations (partielles ou complètes) de Git dans d'autres langages (certaines d'entre elles sont partiellement des réimplémentations et enveloppent partiellement les commandes git): JGit (Java, utilisé par EGit, Eclipse Git Plugin), Grit (Ruby) , Dulwich (Python), git # (C #).
TL; DR
la source
Je pense que vous pouvez avoir une idée de ce que ces systèmes sont similaires ou différents en décochant ces deux vidéos:
Linus Torvalds sur Git ( http://www.youtube.com/watch?v=4XpnKHJAok8 )
Bryan O'Sullivan sur Mercurial ( http://www.youtube.com/watch?v=JExtkqzEoHY )
Les deux sont très similaires dans la conception mais très différents dans les implémentations.
J'utilise Mercurial. Pour autant que je comprends Git, une chose importante est différente git, c'est qu'il suit le contenu des fichiers au lieu des fichiers eux-mêmes. Linus dit que si vous déplacez une fonction d'un fichier à un autre, Git vous indiquera l'historique de cette fonction unique tout au long du déplacement.
Ils disent également que git est plus lent sur HTTP mais qu'il a son propre protocole réseau et son propre serveur.
Git fonctionne mieux en tant que client épais SVN que Mercurial. Vous pouvez tirer et pousser contre un serveur SVN. Cette fonctionnalité est toujours en cours de développement dans Mercurial
Mercurial et Git disposent de très belles solutions d'hébergement Web (BitBucket et GitHub), mais Google Code ne prend en charge que Mercurial. Soit dit en passant, ils ont une comparaison très détaillée de Mercurial et Git qu'ils ont faite pour décider lequel prendre en charge ( http://code.google.com/p/support/wiki/DVCSAnalysis ). Il a beaucoup de bonnes informations.
la source
J'ai écrit un article de blog sur les modèles de branchement de Mercurial il y a quelque temps, et j'ai inclus des comparaisons avec le modèle de branchement de git. Vous le trouverez peut-être intéressant: http://stevelosh.com/blog/entry/2009/8/30/a-guide-to-branching-in-mercurial/
la source
J'utilise les deux assez régulièrement. La principale différence fonctionnelle réside dans la façon dont les noms Git et Mercurial se branchent au sein des référentiels. Avec Mercurial, les noms de branche sont clonés et extraits avec leurs changesets. Lorsque vous ajoutez des modifications à une nouvelle branche dans Mercurial et que vous les envoyez à un autre référentiel, le nom de la branche est poussé en même temps. Ainsi, les noms de branche sont plus ou moins globaux dans Mercurial, et vous devez utiliser l'extension Bookmark pour avoir des noms légers uniquement locaux (si vous les souhaitez; Mercurial, par défaut, utilise des codelines légères anonymes, qui dans sa terminologie sont appelés "têtes"). Dans Git, les noms des branches et leur mappage injectif vers les branches distantes sont stockés localement et vous devez les gérer explicitement, ce qui signifie savoir comment faire cela.
Comme d'autres le noteront ici, il y a beaucoup, beaucoup de différences mineures. La chose avec les branches est le grand différenciateur.
la source
Jetez un œil à Git vs Mercurial: Please Relax blog post de Patrick Thomson, où il écrit:
Git est MacGyver , Mercurial est James Bond
Notez que ce billet de blog date du 7 août 2008 et que les deux SCM se sont beaucoup améliorés depuis.
la source
Mercurial est presque entièrement écrit en python. Le noyau de Git est écrit en C (et devrait être plus rapide que Mercurial) et les outils écrits en sh, perl, tcl et utilisent des utilitaires GNU standard. Il doit donc apporter tous ces utilitaires et interprètes avec lui au système qui ne les contient pas (par exemple Windows).
Les deux support fonctionnent avec SVN, bien que le support AFAIK svn soit interrompu pour git sous Windows (peut-être que je suis juste malchanceux / boiteux, qui sait). Il existe également des extensions qui permettent d'interagir entre git et Mercurial.
Mercurial a une belle intégration de Visual Studio . La dernière fois que j'ai vérifié, le plugin pour Git fonctionnait mais était extrêmement lent.
Ces jeux de commandes de base sont très similaires (init, clone, add, status, commit, push, pull etc.). Ainsi, le flux de travail de base sera le même. En outre, il existe un client de type TortoiseSVN pour les deux.
Les extensions pour Mercurial peuvent être écrites en python (sans surprise!) Et pour git, elles peuvent être écrites sous n'importe quelle forme exécutable (binaire exécutable, script shell, etc.). Certaines extensions sont puissamment folles, comme
git bisect
.la source
Si vous avez besoin d'une bonne prise en charge de Windows, vous préférerez peut-être Mercurial. TortoiseHg (plugin Windows Explorer) parvient à offrir une interface graphique simple à utiliser à un outil assez complexe. Comme indiqué ici, vous aurez également un plugin Visual Studio . Cependant, la dernière fois que j'ai essayé, l'interface SVN ne fonctionnait pas aussi bien sous Windows.
Si cela ne vous dérange pas l'interface de ligne de commande, je recommanderais Git. Pas pour des raisons techniques mais pour des raisons stratégiques. Le taux d'adoption de git est beaucoup plus élevé. Il suffit de voir combien de projets open source célèbres passent de cvs / svn à Mercurial et combien passent à Git. Découvrez le nombre de fournisseurs d'hébergement de code / projet que vous pouvez trouver avec le support git par rapport à l'hébergement Mercurial.
la source
Après avoir lu partout que Mercurial est plus facile (ce que je pense toujours, après toute la communauté Internet est de l'avis), quand j'ai commencé à travailler avec Git et Mercurial, j'ai senti que Git était relativement plus simple pour moi de m'adapter (j'ai commencé avec Mercurial avec TortoiseHg) lorsque vous travaillez à partir de la ligne de commande, principalement parce que les commandes git ont été nommées de manière appropriée selon moi et sont moins nombreuses. Mercurial a un nom différent pour chaque commande qui effectue un travail distinct, tandis que les commandes Git peuvent être polyvalentes selon la situation (par exemple,
checkout
). Alors que Git était plus difficile à l'époque, la différence n'est désormais plus substantielle. YMMV .. Avec un bon client GUI comme TortoiseHg, c'est vrai qu'il était beaucoup plus facile de travailler avec Mercurial et je n'avais pas à me souvenir des commandes légèrement déroutantes. Je n'entre pas dans le détail de la façon dont chaque commande pour la même action a varié, mais voici deux listes complètes: 1 sur le propre site de Mercurial et 2 sur les wikiv .Git enregistre un enregistrement de chaque version des fichiers validés en interne, tandis que Hg enregistre uniquement les ensembles de modifications qui peuvent avoir une empreinte plus petite. Git facilite la modification de l'historique par rapport à Hg, mais là encore, c'est une fonction de haine ou d'aimer. J'aime Hg pour l'ancien et Git pour le dernier.
Ce qui me manque dans Hg, c'est la fonctionnalité de sous-module de Git. Hg a des sous-dépôts mais ce n'est pas exactement le sous-module Git.
L'écosystème autour des deux peut également influencer son choix: Git doit être plus populaire (mais c'est trivial), Git a GitHub tandis que Mercurial a BitBucket , Mercurial a TortoiseHg pour lequel je n'ai pas vu d'équivalent aussi bon pour Git.
Chacun a ses avantages et ses inconvénients, vous ne perdrez ni l'un ni l'autre.
la source
Consultez le post de Scott Chacon il y a quelque temps.
Je pense que git a la réputation d'être "plus compliqué", bien que d'après mon expérience ce ne soit pas plus compliqué qu'il ne devrait l'être. OMI, le modèle git est beaucoup plus facile à comprendre (les balises contiennent des commits (et des pointeurs vers zéro ou plusieurs commits parents) contiennent des arbres contiennent des blobs et d'autres arbres ... c'est fait).
Ce n'est pas seulement mon expérience que git n'est pas plus déroutant que mercurial. Je recommanderais à nouveau de lire ce billet de blog de Scott Chacon sur la question.
la source
.hgtags
lorsque vous avez extrait la révision 1.0. Cependant, vous n'avez pas besoin de regarder à l'intérieur.hgtags
et vous constaterez quehg tags
toutes les balises sont répertoriées. En outre, ce comportement est une simple conséquence du stockage de balises dans un fichier contrôlé par version - encore une fois, le modèle est facile à saisir et très prévisible .J'utilise Git depuis un peu plus d'un an dans mon emploi actuel, et avant cela, j'utilisais Mercurial depuis un peu plus d'un an dans mon emploi précédent. Je vais fournir une évaluation du point de vue d'un utilisateur.
Premièrement, les deux sont des systèmes de contrôle de version distribués. Les systèmes de contrôle de version distribués nécessitent un changement de mentalité par rapport aux systèmes de contrôle de version traditionnels, mais fonctionnent en fait beaucoup mieux à bien des égards une fois que l'on les comprend. Pour cette raison, je considère que Git et Mercurial sont bien supérieurs à Subversion, Perforce, etc. La différence entre les systèmes de contrôle de version distribués et les systèmes de contrôle de version traditionnels est beaucoup plus grande que la différence entre Git et Mercurial.
Cependant, il existe également des différences significatives entre Git et Mercurial qui rendent chacun mieux adapté à son propre sous-ensemble de cas d'utilisation.
Mercurial est plus simple à apprendre. J'en suis arrivé au point où je devais rarement me référer à la documentation ou aux notes après quelques semaines d'utilisation de Mercurial; Je dois encore me référer régulièrement à mes notes avec Git, même après l'avoir utilisé pendant un an. Git est considérablement plus compliqué.
C'est en partie parce que Mercurial est tout simplement plus propre. Vous devez rarement créer une branche manuellement dans Mercurial; Mercurial créera automatiquement une branche anonyme pour vous si et quand vous en avez besoin. La nomenclature mercurielle est plus intuitive; vous n'avez pas à vous soucier de la différence entre "chercher" et "tirer" comme vous le faites avec Git. Mercurial est un peu moins buggé. Il existe des problèmes de sensibilité à la casse des noms de fichiers qui causaient des problèmes lors de la transmission de projets sur plusieurs plates-formes avec Git et Mercurial; cela a été corrigé dans Mercurial il y a quelque temps alors qu'ils n'avaient pas été corrigés dans Git la dernière fois que j'ai vérifié. Vous pouvez informer Mercurial des renommages de fichiers; avec Git, s'il ne détecte pas automatiquement le renommage - une proposition très réussie ou manquante dans mon expérience - le renommage ne peut pas être suivi du tout.
L'autre raison de la complication supplémentaire de Git, cependant, est qu'une grande partie est nécessaire pour prendre en charge des fonctionnalités et une puissance supplémentaires. Oui, c'est plus compliqué de gérer les branchements dans Git - mais d'un autre côté, une fois que vous avez les branches, il n'est pas trop difficile de faire des choses avec ces branches qui sont pratiquement impossibles dans Mercurial. Le remodelage des branches est l'une de ces choses: vous pouvez déplacer votre branche de sorte que sa base, au lieu d'être l'état du tronc lorsque vous vous êtes ramifié, soit l'état du tronc maintenant; cela simplifie considérablement l'historique des versions lorsque de nombreuses personnes travaillent sur la même base de code, car chacune des poussées vers le tronc peut être faite pour apparaître séquentielle, plutôt qu'entrelacée. De même, il est beaucoup plus facile de réduire plusieurs validations sur votre branche en une seule validation,
En fin de compte, je pense que le choix entre Mercurial et Git devrait dépendre de la taille de vos projets de contrôle de version, mesurée en termes de nombre de personnes qui y travaillent simultanément. Si vous avez un groupe d'une douzaine ou plus travaillant sur une seule application Web monolithique, par exemple, les outils de gestion de branche plus puissants de Git la rendront bien mieux adaptée à votre projet. D'un autre côté, si votre équipe développe un système distribué hétérogène, avec seulement un ou deux développeurs travaillant sur un composant à la fois, l'utilisation d'un référentiel Mercurial pour chacun des projets de composants permettra au développement de se dérouler plus en douceur avec moins frais généraux de gestion du référentiel.
En bout de ligne: si vous avez une grande équipe développant une seule énorme application, utilisez Git; si vos applications individuelles sont petites, avec une échelle provenant du nombre plutôt que de la taille de ces applications, utilisez Mercurial.
la source
Une différence totalement indépendante des DVCS eux-mêmes:
Git semble être très populaire auprès des développeurs C. Git est le référentiel de facto pour le noyau Linux et cela peut être la raison pour laquelle il est si populaire auprès des développeurs C. Cela est particulièrement vrai pour ceux qui ont le luxe de ne travailler que dans le monde Linux / Unix.
Les développeurs Java semblent préférer Mercurial à Git. Il y a peut-être deux raisons à cela: la première est qu'un certain nombre de très gros projets Java sont hébergés sur Mercurial, y compris le JDK lui-même. Un autre est que la structure et la documentation propre de Mercurial font appel aux personnes venant du camp Java alors que ces personnes trouvent que la dénomination de commande wrt Git est incohérente et manque de documentation. Je ne dis pas que c'est vrai, je dis que les gens se sont habitués à quelque chose de leur habitat habituel et qu'ils ont tendance à choisir DVCS à partir de cela.
Les développeurs Python favorisent presque exclusivement Mercurial, je suppose. Il n'y a en fait aucune raison rationnelle à cela autre que le fait que Mercurial est basé sur Python. (J'utilise aussi Mercurial et je ne comprends vraiment pas pourquoi les gens se moquent du langage d'implémentation du DVCS. Je ne comprends pas un mot de Python et sans le fait qu'il soit répertorié quelque part qu'il est basé sur Python alors je ne l'aurais pas su).
Je ne pense pas que vous puissiez dire qu'un DVCS correspond mieux à une langue qu'une autre, vous ne devriez donc pas choisir parmi cela. Mais en réalité, les gens choisissent (en partie) en fonction du DVCS auquel ils sont le plus exposés dans le cadre de leur communauté.
(non, je n'ai pas de statistiques d'utilisation pour sauvegarder mes affirmations ci-dessus .. tout est basé sur ma propre subjectivité)
la source