web-dev-qa-db-fra.com

Comprendre la différence de branche entre SVN et Git

Je suis un utilisateur de SVN et maintenant j'apprends Git.

Dans SVN, je récupère généralement sur ma machine locale un dépôt, qui comprend toutes les branches de mon projet et je sélectionnais le dossier de ma branche qui m'intéresse et j'y travaille.

Je vois une différence en utilisant Git.

Actuellement, je clone un dépôt et clone une branche spécifique à l'aide de gitk.

Le dossier du projet ne contient que le contenu de cette branche et je ne vois pas toutes les branches comme dans SVN, ce qui est un peu déroutant pour moi.

Je ne trouve pas de moyen facile de voir toutes les branches de mon référentiel local à l'aide de Git.

  • Je voudrais savoir si le processus Git que j'ai décrit est "standard" et certains comment correct ou je manque quelque chose.

  • J'aimerais aussi savoir comment gérer un processus où je dois travailler sur deux branches en même temps au cas où, par exemple, je devrais faire un hotfix sur master mais garder le contenu d'une autre branche aussi.

  • Qu'est-ce qu'une convention de nom recommandée pour créer les dossiers qui incluent la branche clonée à partir du référentiel dans Git, exemple myproject-branchname?

47
Radex

Je suis un utilisateur de SVN et maintenant j'apprends GIT.

Bienvenue dans le gang!

Rééducation SVN

Dans SVN, je [...]

Attends un instant. Alors que CVS et SVN et d'autres systèmes de contrôle de version traditionnels (c.-à-d. Centralisés) remplissent (principalement) le même objectif que les systèmes de contrôle de versions modernes (c.-à-d. Distribués) comme Mercurial et Git, vous ferez beaucoup mieux d'apprendre Git à partir de zéro au lieu de essayer de transférer votre flux de travail SVN vers Git.

http://hginit.com ( voir sur archive.org ) par Joel Spolsky (l'un des fondateurs de Stack Exchange) est un tutoriel pour Mercurial, pas Git, mais c'est le chapitre zéro, "" Subversion Re-education " est utile pour les gens qui passent de SVN à any système de contrôle de version distribué, car il vous indique quel SVN concepts que vous devez (temporairement) un - apprendre (ou stash away , comme les utilisateurs de Git pourraient disons) pour pouvoir envelopper votre tête autour des concepts du système de contrôle de version distribué et des workflows idiomatiques établis pour travailler avec eux.

Vous pouvez donc lire ce chapitre zéro et surtout remplacer simplement le mot "Mercurial" par "Git" et ainsi vous préparer correctement et votre esprit pour Git.

Les petits caractères

(Vous pouvez ignorer ceci pour l'instant.) Alors que Mercurial et Git sont beaucoup plus similaires l'un à l'autre qu'à SVN, il y a sont quelques différences conceptuelles entre eux, donc certaines des déclarations et des conseils de "Subversion Re-education" deviendront techniquement erronés lors du remplacement de "Mercurial" par "Git":

  • Alors que Mercurial suit et stocke en interne les changements, Git suit et stocke en interne les révisions (c'est-à-dire les états du contenu d'une arborescence de répertoires), tout comme Subversion. Mais autre que Subversion Git effectue des fusions en examinant respectivement les différences entre chaque branche impliquée et une révision d'ancêtre commune ( une vraie fusion en 3 points), donc le résultat est à peu près le même que pour Mercurial: la fusion est beaucoup plus facile et moins sujette aux erreurs que dans SVN.
  • Alors que vous pouvez branchez dans Git en clonant le référentiel (comme c'est la coutume dans Mercurial), il est beaucoup plus courant de créer une nouvelle branche dans un référentiel Git. (C'est parce que les branches Git sont simplement des pointeurs vers les révisions, alors que les branches Mercurial sont des étiquettes permanentes appliquées à chaque révision. Ces étiquettes permanentes sont généralement indésirables, donc les workflows Mercurial fonctionnent généralement en clonant le référentiel complet pour des développements divergents.)

Dans SVN, tout est un répertoire (mais vous ne devez pas nécessairement le traiter comme tel)

Mais je vous ai interrompu. Tu disais?

Dans SVN, je récupère généralement sur ma machine locale un dépôt, qui comprend toutes les branches de mon projet et je sélectionnais le dossier de ma branche qui m'intéresse et j'y travaille.

Si, par là, vous voulez dire que vous avez extrait le dossier racine du référentiel SVN (ou tout autre dossier correspondant à plus de trunk ou à une seule branche, par exemple dans la disposition de dépôt SVN conventionnelle, le branches dossier contenant toutes les branches non-trunk) alors j'ose dire que vous avez probablement mal utilisé SVN (ish), ou du moins abusé un peu du fait que trunk, branches et tags sont tous pliés en un seul (bien que hiérarchique) espace de noms avec les répertoires dedans les révisions/base de code.

Bien qu'il puisse être tentant de changer plusieurs branches SVN en parallèle, c'est AFAIK pas comment SVN est destiné à être utilisé. (Bien que je ne sois pas sûr de ce que certains inconvénients spécifiques pourraient avoir.)

Dans Git, seuls les répertoires sont des répertoires

Chaque clone d'un référentiel Git est lui-même un référentiel Git: par défaut, il obtient une copie complète de l'historique du référentiel Origin, y compris toutes les révisions, branches et balises. Mais cela gardera tout ce que vous voulez: Git le stocke dans une sorte de base de données basée sur des fichiers, située dans le sous-dossier caché .git/ Du dossier racine du référentiel.

Mais quels sont les fichiers non masqués que vous voyez dans le dossier du référentiel?

Lorsque vous git clone Un référentiel, Git fait plusieurs choses. Grossièrement:

  1. Il crée le dossier cible , et dans celui-ci, le sous-dossier .git/ Avec la "base de données"
  2. Il transfère les références (balises, branches, etc.) de la base de données du référentiel Origin et en fait une copie dans la nouvelle base de données, leur donnant une légère modification nom qui les marque comme références "distantes".
  3. Il transfère toutes les révisions (c'est-à-dire les états de l'arborescence des fichiers) vers lesquelles ces références pointent, ainsi que toutes les révisions vers lesquelles ces révisions pointent directement ou transitivement (leurs parents et ancêtres) dans la nouvelle base de données et les stocke, de sorte que les nouvelles références distantes pointent réellement vers quelque chose qui est disponible dans le nouveau référentiel.
  4. Il crée une branche locale qui suit la révision à distance correspondant à la branche par défaut du référentiel Origin (généralement master).
  5. Il vérifie cette branche locale.

Cette dernière étape signifie que Git recherche la révision vers laquelle pointe cette branche et décompresse l'arborescence de fichiers qui y est stockée (la base de données utilise des moyens de compression et de déduplication) dans le dossier racine du référentiel. Ce dossier racine et tous ses sous-dossiers (à l'exception du sous-dossier spécial .git) Sont appelés "copie de travail" de votre référentiel. C'est là que vous interagissez avec le contenu de la révision/branche actuellement extraite. Ce ne sont que des dossiers et des fichiers normaux. Cependant, pour interagir avec le référentiel en soi (la "base de données" des révisions et des références), vous utilisez les commandes git.

Voir les branches Git et interagir avec les branches Git

Actuellement, je clone un dépôt et clone une branche spécifique à l'aide de gitk.

La version de gitk que j'ai obtenue ne peut pas cloner les référentiels. Il peut uniquement afficher l'historique des dépôts et créer des branches et extraire des branches. De plus, il n'y a pas de "clonage" d'une branche. Vous pouvez uniquement cloner des référentiels.

Voulez-vous dire que vous clonez un dépôt en utilisant git clone ... puis en utilisant gitk, check out une branche?

Le dossier du projet ne contient que le contenu de cette branche et je ne vois pas toutes les branches comme dans SVN, ce qui est un peu déroutant pour moi.

[...]

  • Je voudrais savoir si le processus git que j'ai décrit est "standard" et certains comment correct [...]

Oui, c'est assez standard:

  • Clonez un référentiel en utilisant git clone ...
  • Découvrez la branche sur laquelle vous souhaitez travailler git checkout ... ou en utilisant un outil graphique comme gikt

Je ne trouve pas de moyen facile de voir toutes les branches de mon référentiel local à l'aide de GIT.

  • [...] ou je manque smt.

Peut être:

  • vous pouvez lister les succursales locales avec git branch
  • vous pouvez lister les branches distantes avec git branch -r ou toutes les branches avec git branch -a
  • vous pouvez utiliser gitk pour afficher l'historique complet (toutes les balises de branches, etc. que votre référentiel local connaît) en l'invoquant avec

    gitk --all
    

Comment travailler avec plusieurs branches en parallèle

  • J'aimerais aussi savoir comment gérer un processus où je dois travailler sur deux branches en même temps au cas où, par exemple, je devrais faire un hotfix sur master mais garder le contenu d'une autre branche aussi.

Il y a différents scénarios ici:

Un nouveau changement (encore à créer) doit être appliqué à plusieurs branches

Utilisez ce workflow:

  1. Créez une nouvelle branche c à partir d'une révision qui est déjà dans l'ascendance de toutes ces branches (par exemple la révision qui a introduit le bogue lorsque le changement sera un bugfix) ou à partir d'une révision qui (y compris tous ses ancêtres) est acceptable pour être introduit dans toutes ces branches.
  2. Effectuez et validez la modification sur cette nouvelle branche c.
  3. Pour chaque branche b qui a besoin du changement:

    1. Découvrez b:

      git checkout b
      
    2. Fusionnez c en b:

      git merge c
      
  4. Supprimer la branche c:

    git branch --delete c
    

Un changement existant est nécessaire sur une branche différente

(... mais sans les autres modifications apportées sur l'endroit où réside cette modification)

  1. Découvrez la succursale où le changement est nécessaire
  2. Cherry-pick la (les) révision (s) apportant le changement, afin

Sur une branche a, vous voulez changer un ou certains fichiers à l'état exact qu'ils ont sur une autre branche b

  1. Découvrez a
  2. Obtenez le contenu du fichier à partir de la branche b:

    git checkout b -- path/to/a/file.txt path/to/another/file.cpp or/even/a/complete/directory/ ...
    

    (Autre que git checkout Sans passer par des chemins, ceci ne le sera pas basculez vers la branche b, obtenez seulement le contenu du fichier demandé à partir de là. Ces fichiers peuvent ou non exister déjà sur a. S'ils le font, ils sont remplacés par leur contenu sur b.)

Tout en travaillant sur une branche, vous voulez voir comment les choses se passent sur une autre branche

Découvrez la branche sur laquelle vous souhaitez travailler.

Ensuite, pour regarder l'autre branche,

  • soit utilisez des outils graphiques qui vous permettent d'afficher le contenu des révisions non actuellement extraites (par exemple dans gitk essayez de basculer les boutons radio de "patch" à "tree")
  • ou clonez le référentiel dans un répertoire temporaire et consultez l'autre branche
  • ou utilisez git worktree pour créer un répertoire de travail séparé du même référentiel (c'est-à-dire également en utilisant la base de données dans le répertoire .git/ de votre référentiel local actuel) où vous pouvez vérifier cette autre branche
69
das-g

Dans SVN, je récupère généralement sur ma machine locale un dépôt, qui comprend toutes les branches de mon projet et je sélectionnais le dossier de ma branche qui m'intéresse et j'y travaille.

À moins que vous ne consultiez le répertoire ci-dessus, dans Subversion, vous avez généralement pas toutes les branches disponibles localement. Dans Git, tout le contenu (commits, messages, branches, etc.) est toujours cloné sur chaque copie.

Actuellement, je clone un dépôt et clone une branche spécifique à l'aide de gitk.

Pas possible, voir ci-dessus. Vous pouvez git checkout branch-name, mais vous ne pouvez pas git clone something branch-name. Dans Subversion, les branches sont des dossiers. Dans Git, les branches sont des pointeurs vers une validation.

Je ne trouve pas de moyen facile de voir toutes les branches de mon référentiel local à l'aide de GIT.

Courir git branch. Par défaut, il n'affiche que les succursales locales. Utilisation git branch --remote pour voir les branches distantes.

31
l0b0

Comme ceci est tagué avec git j'espère que mon manque de connaissance SVN est négligeable.

Actuellement, je clone un dépôt et clone une branche spécifique à l'aide de gitk.

Vous clonez l'ensemble du référentiel distant non seulement une branche spécifique.

Le référentiel est mieux conçu comme une base de données, vous créez donc un clone de l'état actuel de la base de données distante. Mais après cela, vous travaillez sur votre propre copie de cette base de données; si vous vous engagez, vous modifiez votre base de données locale.

La commande fetch est utilisée pour synchroniser la base de données locale avec la base distante.

Généralement, à partir de cette base de données locale, vous extrayez une branche sur laquelle travailler. Ce n'est rien d'autre qu'un marqueur interne pour git, où votre travail actuel a commencé.

Supposons que vous travaillez sur un référentiel simple, où il n'y a pas de branche à part master, vous pouvez jeter un œil dans le .git dossier pour dévoiler la "magie":

Supposons que votre dernier commit (sur master) était 182e8220b404437b9e43eb78149d31af79040c66, vous trouverez exactement cela sous cat .git/refs/heads/master.

De là, vous dérivez une nouvelle branche git checkout -b mybranch, vous trouverez exactement le même pointeur dans le fichier cat .git/refs/heads/mybranch.

Les succursales ne sont rien de plus que des "pointeurs". Le marqueur "de travail" est appelé HEAD.

Si vous voulez savoir où se trouve votre HEAD:

cat .git/HEAD qui dit par exemple ref: refs/heads/mybranch, qui à son tour pointe (cat .git/refs/heads/mybranch) à un hachage de validation 78a8a6eb6f82eae21b156b68d553dd143c6d3e6f

Les validations réelles sont stockées dans le dossier objects (le comment est un sujet qui lui est propre).

Le dossier du projet ne contient que le contenu de cette branche et je ne vois pas toutes les branches comme dans SVN, ce qui est un peu déroutant pour moi.

Ne confondez pas le working directory avec la "base de données git" dans son ensemble. Comme je l'ai dit ci-dessus, votre répertoire de travail n'est qu'un instantané (peut-être) d'un sous-ensemble.

Supposons que vous ayez différentes branches, votre répertoire de travail est dédié à travailler uniquement sur cette branche (bien que vous puissiez mettre le travail à partir de là ailleurs).

Habituellement, si vous voulez voir quelles branches sont définies pour le projet, vous avez la possibilité de

  • git branch pour les succursales locales
  • git branch --remote pour les succursales distantes
  • git branch -a pour les deux

(ou git branch -v)

Étant donné que git est un système de contrôle de version distribué, il est non seulement possible, mais encouragé, de créer différentes branches localement/à distance.

Mon flux de travail typique est:

  • dériver une dérivation de fonction
  • branchez une branche WIP (work in progress)
  • travaillez comme vous le souhaitez - même si vous vous engagez après une seule ligne; ça n'a pas d'importance

Une fois la fonctionnalité terminée:

  • écraser/retravailler la branche WIP (avec rebasage interactif) = faire un seul commit à partir de cette
  • fusionnez la branche WIP dans la branche de fonctionnalité et proposez-la (si vous travaillez avec github, cette offre sera appelée "pull request") à intégrer dans la branche stable (master).

Je voudrais également savoir comment gérer un processus où j'ai besoin de wprl sur deux branches en même temps au cas où, par exemple, je devrais faire un hotfix sur master mais garder le contenu d'une autre branche aussi.

Cela dépend de la structure de votre projet:

Disons que vous avez un maître stable. Et les fonctionnalités ne sont développées qu'à partir de cette branche stable - elle se trouve donc généralement derrière une branche de fonctionnalités. Ensuite, vous auriez un dernier commit sur master qui serait la racine de la branche de fonctionnalité.

Ensuite, vous feriez un commit sur la branche master et pourriez décider, si fusionner les deux branches ensemble ou rebaser (qui est une sorte de fusion pour les utilisateurs ayant des besoins avancés pour ainsi dire).

Ou vous pouvez toujours apporter des modifications aux branches (par exemple master) et les sélectionner sur d'autres branches.

Qu'est-ce qu'une convention de nom recommandée pour créer les dossiers qui incluent la branche clonée à partir du référentiel dans GIT, exemple myproject-branchname

C'est comme tu veux.

En règle générale, vous vous retrouvez avec le nom des référentiels.

Mais il y a des occasions où cela n'est pas souhaité:

par exemple. vous clonez oh-my-zsh avec git clone git://github.com/robbyrussell/oh-my-zsh.git ~/.oh-my-zsh Ici .oh-my-zsh est explicitement nommé comme cible.

3
Thomas Junk

Git clone clone en fait tout le référentiel, mais définit votre répertoire de travail par défaut (généralement master).

Vous pouvez voir d'autres branches en utilisant git branch pour voir les succursales locales ou git branch -r pour voir les télécommandes puis git checkout pour basculer vers une branche existante ou en créer une nouvelle en fonction de la branche actuelle.

Vous devriez lire la documentation de git pour plus de détails, et Atlassian a aussi de bons articles dessus.

2
HorusKol

Les branches dans git et svn sont des choses fondamentalement différentes.

Dans svn, une branche (ou une balise) est un répertoire du référentiel.

Dans git, une branche (ou une balise) est un pointeur vers une validation.

Avec svn, vous pouvez, si vous le souhaitez, extraire la racine du dépôt. Cela signifie que chaque branche et chaque étiquette sont extraites en même temps. Afaict ce n'est pas la manière normale d'utiliser svn.

Une branche git n'est pas un répertoire, il n'y a donc pas d'équivalent à "vérifier la racine du dépôt". Il existe un certain support pour plusieurs arborescences de travail, donc je suppose que vous pouvez concocter un script pour vérifier chaque branche en même temps si vous le vouliez vraiment, mais ce serait une pensée plutôt inhabituelle.

De plus, avec SVN, il n'y a qu'un seul dépôt. Avec git, chaque développeur a son propre référentiel. Cela signifie que les développeurs peuvent travailler hors ligne, mais cela signifie également que différents développeurs peuvent avoir une idée différente de ce qui se trouve sur chaque branche.

En raison d'être des répertoires et en vertu du modèle d'histoire linéaire simple de svn, les branches svn ont des historiques robustes. Si vous voulez savoir ce qui était sur la branche x à la date y, vous pouvez facilement poser cette question.

Les branches Git, en revanche, n'ont pas vraiment d'historique. Il y a le "reflog", mais il se veut plus un mécanisme de reprise après sinistre qu'une histoire à long terme. En particulier, le reflog ne peut pas être lu à distance et est désactivé par défaut pour les référentiels nus.

Les commits ont bien sûr des historiques mais ces historiques ne sont pas suffisants pour répondre à la question "ce qui était sur la branche x du repo y à la date z".

Je ne peux pas trouver un moyen facile de voir toutes les branches de mon référentiel local à l'aide de Git.

Vous pouvez lister toutes les branches locales en tapant "git branch".

Vous pouvez lister toutes les branches locales et distantes en utilisant "git branch -a"

J'aimerais aussi savoir comment gérer un processus où je dois travailler sur deux branches en même temps au cas où, par exemple, je devrais faire un hotfix sur master mais garder le contenu d'une autre branche aussi.

Quelques options.

Vous pouvez valider vos modifications sur l '"autre branche", passer à master pour y faire votre travail puis revenir en arrière.

Vous pouvez également créer une arborescence de travail supplémentaire. Google "git-worktree" pour les détails sur la syntaxe.

Quelles sont les conventions de noms recommandées pour créer les dossiers qui incluent la branche clonée à partir du référentiel dans Git, par exemple myproject-branchname?

Je ne pense pas qu'il existe une convention établie. L'extraction simultanée de plusieurs arbres de travail est l'exception et non la règle.

0
Peter Green