Git et Mercurial - Comparer et contraster

520

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.

TM.
la source

Réponses:

451

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

  • Structure du référentiel: Mercurial ne permet pas les fusions de poulpe (avec plus de deux parents), ni le marquage d'objets non validés.
  • Balises: Mercurial utilise un .hgtagsfichier 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.
  • Branches: Dans Mercurial, le flux de travail de base est basé sur des têtes anonymes ; Git utilise des branches nommées légères et possède des types spéciaux de branches ( branches de suivi à distance) qui suivent les branches dans le référentiel distant.
  • Noms et plages de révision : Mercurial fournit des numéros de révision , du local au référentiel, et base les révisions relatives (comptage à partir de la pointe, c'est-à-dire la branche actuelle) et les plages de révision sur cette numérotation locale ; Git fournit un moyen de faire référence à la révision par rapport à la pointe de la branche, et les plages de révision sont topologiques (basées sur le graphique des révisions)
  • Mercurial utilise le suivi des renommées , tandis que Git utilise la détection des renommées pour gérer les renommages de fichiers
  • Réseau: Mercurial prend en charge les protocoles SSH et HTTP «intelligents» et le protocole HTTP statique; Git moderne prend en charge les protocoles "intelligents" SSH, HTTP et GIT et le protocole "stupide" HTTP (S). Les deux prennent en charge les fichiers de bundles pour le transport hors ligne.
  • Mercurial utilise des extensions (plugins) et une API établie; Git a une scriptabilité et des formats établis.

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 bisectcommande dans Mercurial (anciennement extension bissecte ) a été inspirée par la git bisectcommande dans Git, tandis que l'idée de a git bundleété inspirée par hg 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 .hgtagsfichier 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, remotesou tags, par exemple, local-tagspour 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 .hgtagsspécialement (le fichier dans l'arborescence est transférable, mais ordinaire il est versionné), ou avoir des balises qui sont uniquement locales ( .hg/localtagsn'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/bookmarksfichier dans un référentiel distant. Vous pouvez également utiliser hg 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.defaultvariable 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' --alloption 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 dans refs/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 ):

  • Le nom d'objet SHA1 complet (chaîne hexadécimale de 40 octets), ou une sous-chaîne de celui-ci qui est unique dans le référentiel
  • Un nom de référence symbolique, par exemple 'master' (se référant à la branche 'master'), ou 'v1.5.0' (se référant à la balise), ou 'origin / next' (se référant à la branche de suivi à distance)
  • Un suffixe ^pour réviser le paramètre signifie le premier parent d'un objet commit, ^nsignifie le nième parent d'un commit de fusion. Un suffixe ~npour 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»
  • Sortie de "git describe", c'est-à-dire une balise la plus proche, éventuellement suivie d'un tiret et d'un certain nombre de validations, suivie d'un tiret, d'un 'g' et d'un nom d'objet abrégé, par exemple 'v1.6.5.1-75- g5bf8097 ».

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 ):

  • Un entier simple est traité comme un numéro de révision. Il faut se rappeler que les numéros de révision sont locaux pour un référentiel donné ; dans d'autres référentiels, ils peuvent être différents.
  • Les entiers négatifs sont traités comme des décalages séquentiels par rapport à la pointe, -1 indiquant la pointe, -2 indiquant la révision avant la pointe, etc. Ils sont également locaux dans le référentiel.
  • Un identifiant de révision unique (chaîne hexadécimale à 40 chiffres) ou son préfixe unique.
  • Un nom de balise (nom symbolique associé à une révision donnée), ou un nom de signet (avec l'extension: nom symbolique associé à une tête donnée, local au référentiel), ou une "branche nommée" (étiquette de validation; révision donnée par "branche nommée" est astuce (validation sans enfant) de toutes les validations avec une étiquette de validation donnée, avec le plus grand numéro de révision s'il y en a plusieurs)
  • Le nom réservé "tip" est une balise spéciale qui identifie toujours la révision la plus récente.
  • Le nom réservé "null" indique la révision nulle.
  • Le nom réservé "." indique le parent du répertoire de travail.

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..Bsyntaxe 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 Blequel, 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 la A..Bplage est entièrement prévisible (et très utile) même si A n'est pas l'ancêtre de B: A..Bsignifie 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:Bsyntaxe 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 la A...Bsyntaxe). 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...Bpour la différence symétrique des révisions; cela signifie A 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 courir hg addremovepour 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' --followoption 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 dans git blame/ hg annotate.

Dans Git, la git blamecommande 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-servescript 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:

  • Les protocoles "intelligents" , qui incluent l'accès via SSH et via le protocole git: // personnalisé (par 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".
  • Les protocoles "stupides" , qui incluent HTTP et FTP (uniquement pour la récupération) et HTTPS (pour la transmission via WebDAV), ne nécessitent pas l'installation de git sur le serveur, mais ils nécessitent que le référentiel contienne des informations supplémentaires générées par 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

Jakub Narębski
la source
32
Ce qui pourrait être ajouté, c'est que hg essaie très fort de décourager la réécriture de l'historique (cela ne peut être fait qu'avec des extensions: mq, histedit, rebase), tandis que git le fait tout de suite (et il ressemble à une partie de la communauté l'encourage même).
tonfa
80
Je pense que "réécrire l'histoire" a un son inutilement négatif. Ce que j'encourage dans git, c'est que les gens considèrent l'histoire qu'ils publient. D'autres personnes doivent consommer cette histoire. Personne (pas même vous) n'est intéressé par tous vos commits "oups, vous avez oublié un fichier". Personne ne se soucie non plus de la série de fusions entrantes que vous avez subies pendant que vous suiviez une branche en amont tout en travaillant sur une nouvelle fonctionnalité. Ce genre de choses rend l'histoire (et les outils associés) beaucoup plus difficiles à comprendre et n'apporte aucune valeur.
Dustin
5
@Jakub: les branches nommées sont quelque chose qui n'existe pas dans git. C'est simplement un champ dans la description de cset (et cela fait partie de l'historique, donc il est immuable à moins que vous ne changiez les hachages, etc.). Quelque chose comme les branches git sont des signets ("têtes nommées") mais elles ne sont pas actuellement transférables à distance (vous n'importez pas les signets distants lorsque vous tirez). stevelosh.com/blog/entry/2009/8/30/… l' explique très bien.
tonfa
28
"Mercurial ne supportait à l'origine qu'une seule branche par workflow de référentiel, et cela se voit." Euh non. Mercurial ne supportait pas les branches nommées à l' origine, mais vous avez toujours pu avoir autant de branches anonymes que votre cœur le souhaite dans un seul dépôt. Comparez cela avec git, ce qui rend la branche anonyme une énorme douleur. Vous à peu près avoir à penser à un nom pour chaque petite branche si vous voulez obtenir quoi que ce soit fait (et éviter d' avoir vos déchets de travail collectées).
Steve Losh
17
@SteveLosh: vous semblez avoir beaucoup de branches anonymes dans Mercurial est une bonne chose, mais cela me semble horrible. Comment les différenciez-vous tous? Et vous semblez penser que nommer des branches dans Git est une énorme difficulté, mais si vous avez un objectif pour créer la branche, vous avez un nom prêt à l'emploi. Si vous n'avez aucun but, ne branchez pas. Je ne vois pas comment Mercurial offre des avantages ici. Je ne vois que douleur et confusion.
iconoclaste
57

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.

artemb
la source
8
Je recommanderais de lire tous les commentaires sur cette page de codes Google. Les informations semblent quelque peu biaisées et ne correspondent pas bien à mon expérience. Je aime hg, et utilisé largement pour un an. J'utilise git presque exclusivement maintenant. Il y a des choses que j'ai besoin d'accomplir que git rend facile et hg rend presque impossible (bien que certains aiment appeler cela au moyen de "complication".) Git de base est aussi simple que hg de base.
Dustin
11
Dustin, peut-être énumérer certains de ces cas «git easy, hg not so»?
Gregg Lind
1
@knittl non, ce n'est pas le cas. Principalement parce que ce serait pénible pour eux de le déployer car git n'a pas de protocole http intelligent (la plupart des frontaux de Google sont basés sur http).
tonfa
2
@tonfa: Le protocole HTTP intelligent pour Git est en cours de développement (comme dans: il y a des correctifs sur la liste de diffusion git, et ils sont dans 'pu' = branche de mises à jour proposée dans le référentiel git.git).
Jakub Narębski
4
À partir de maintenant, Google Code prend également en charge Git.
Andrej Kirejeŭ
30

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/

Steve Losh
la source
@Steve Losh: Je voulais faire un commentaire sur cette entrée de blog (sur la branche sans nom aka détachée HEAD, et sur git-fetch pour récupérer toutes les branches, pas une), mais j'ai eu 500 erreurs de serveur.
Jakub Narębski
1
@Jakub Narębski Je parie que le problème est le caractère non ASCII de votre nom. Je suis presque sûr d'avoir rencontré le même problème sur un autre site et il s'est avéré que la liaison Python Askimet s'étouffe sur Unicode. Je regarderai.
Steve Losh
@Steve Losh: Merci pour une info, après avoir "décodé" mon nom, j'ai pu poster un commentaire. Très bonne description de la ramification dans Mercurial (mais je pense toujours qu'elle est inférieure ;-))
Jakub Narębski
@SteveLosh Je vous encourage à étendre cette réponse à un examen plus complet de mercurial. À l'heure actuelle, la meilleure réponse est malheureusement en grande partie une annonce pour git car son auteur n'a pas beaucoup utilisé mercurial et ne comprend pas comment l'utiliser efficacement. Ce serait bien qu'une autre réponse fournisse le point de vue mercuriel, pour ainsi dire.
Warren Dew
25

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.

James Woodyatt
la source
2
Voir également ce post pour une bonne explication sur les quatre types de branches dans Mercurial: stevelosh.com/blog/entry/2009/8/30/…
Martin Geisler
19

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.

Jakub Narębski
la source
11

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.

Elder_george
la source
9
Mercurial core est écrit en C trop FYI (mais c'est probablement un noyau plus petit que git).
tonfa
1
J'utilise git-svn sous Windows sans aucun problème. Cela utilise Cygwin (la seule bonne façon d'utiliser git sur Windows si vous me le demandez). Je ne peux pas parler pour msysgit.
Dan Moulding,
@Dan Moulding: Oui, j'ai rencontré des problèmes avec msysgit. Peut-être besoin d'essayer le port cygwin (j'avais une mauvaise expérience de l'utilisation de cygwin plus tôt, donc je l'ai évité). Merci du conseil!
aîné_george
Personnellement, je n'aime pas l'intrusion de cygwin dans le registre pour stocker les données des utilisateurs. C'est un PITA pour le faire fonctionner à partir de la clé USB et garder une copie locale du lecteur c: \ synchronisée pour quand je veux courir plus vite que ma clé USB ne peut aller. : - /
Chris K
1
J'utilise le plugin Git pour Visual Studio mentionné ci-dessus, et les performances de la version actuelle sont bonnes. Il s'exécute sur les outils de ligne de commande pour faire le travail, donc je ne pense pas qu'il perdra considérablement les performances sur les grands projets.
Stuart Ellis
11

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.

Eric Darchis
la source
Il y a aussi TortoiseGit, si vous n'aimez pas utiliser la ligne de commande. (Mais il nécessite l'installation de msysgit.)
Ben James
2
Notre entreprise a fini par choisir git en raison de son excellent support sur Windows - consultez Git Extensions . Je suis biaisé parce que je suis maintenant un contributeur, mais je ne l'étais pas lorsque nous avons commencé à l'utiliser.
Jacob Stanley
11

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               ║                Mercurial                                                                       ║
╠═════════════════════════════╬════════════════════════════════════════════════════════════════════════════════════════════════╣
║ git pull                    ║ hg pull -u                                                                                     ║
║ git fetch                   ║ hg pull                                                                                        ║
║ git reset --hard            ║ hg up -C                                                                                       ║
║ git revert <commit>         ║ hg backout <cset>                                                                              ║
║ git add <new_file>          ║ hg add <new_file> (Only equivalent when <new_file> is not tracked.)                            ║
║ git add <file>              ║ Not necessary in Mercurial.                                                                    ║
║ git add -i                  ║ hg record                                                                                      ║
║ git commit -a               ║ hg commit                                                                                      ║
║ git commit --amend          ║ hg commit --amend                                                                              ║
║ git blame                   ║ hg blame or hg annotate                                                                        ║
║ git blame -C                ║ (closest equivalent): hg grep --all                                                            ║
║ git bisect                  ║ hg bisect                                                                                      ║
║ git rebase --interactive    ║ hg histedit <base cset> (Requires the HisteditExtension.)                                      ║
║ git stash                   ║ hg shelve (Requires the ShelveExtension or the AtticExtension.)                                ║
║ git merge                   ║ hg merge                                                                                       ║
║ git cherry-pick <commit>    ║ hg graft <cset>                                                                                ║
║ git rebase <upstream>       ║ hg rebase -d <cset> (Requires the RebaseExtension.)                                            ║
║ git format-patch <commits>  ║ hg email -r <csets> (Requires the PatchbombExtension.)                                         ║
║   and git send-mail         ║                                                                                                ║
║ git am <mbox>               ║ hg mimport -m <mbox> (Requires the MboxExtension and the MqExtension. Imports patches to mq.)  ║
║ git checkout HEAD           ║ hg update                                                                                      ║
║ git log -n                  ║ hg log --limit n                                                                               ║
║ git push                    ║ hg push                                                                                        ║
╚═════════════════════════════╩════════════════════════════════════════════════════════════════════════════════════════════════╝

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.

nawfal
la source
8

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.

Dustin
la source
1
Le modèle Mercurial est en fait presque identique: le journal des modifications pointe vers le point manifeste pour réviser le fichier / blob ... fait. Si vous compariez le format sur disque, vous ne teniez probablement pas compte du fichier packs qui est plus difficile à expliquer que le format revlog simple de hg.
tonfa
Eh bien, ce modèle simplifié ignore le balisage qui est considérablement plus lourd dans la pratique en hg (bien que je soutienne que git tag est un peu déroutant car il ne crée pas d'objet tag par défaut). Le format sur disque était particulièrement coûteux pour les deux projets qui avaient de nombreux noms de fichiers.
Dustin
1
Je ne pense pas que le modèle ignore le marquage: le marquage est trivial dans Mercurial - comme vous le savez, c'est juste un fichier qui donne des noms aux hachages SHA-1. Il n'y a aucune conjecture sur la façon dont les balises circulent dans le système: elles se déplacent avec des poussées et des tractions. Et s'il y a un conflit de balises, eh bien, il est également trivial de le résoudre: vous le résolvez comme tout autre conflit. Après tout, ce n'est qu'une ligne dans un fichier texte. Je pense que la simplicité de ce modèle est une très belle fonctionnalité.
Martin Geisler
Dustin: Oui, les utilisateurs sont souvent déroutés par le fait que vous ne pouvez pas voir la balise 1.0 .hgtagslorsque vous avez extrait la révision 1.0. Cependant, vous n'avez pas besoin de regarder à l'intérieur .hgtagset vous constaterez que hg tagstoutes 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 .
Martin Geisler
1
Martin Geisler Je dirais que les règles pour les balises dans Mercurial, obligatoires car elles utilisent un fichier contrôlé par version pour le transport, avec une couche sur des règles spéciales pour rendre les balises non versionnées, sont tout sauf faciles à comprendre.
Jakub Narębski
5

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.

Warren Dew
la source
4

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é)

peterh
la source