Comprendre la différence de branche entre SVN et Git

44

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

Dans SVN, je commande généralement sur mon ordinateur local un dépôt, qui inclut 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 repo et clone une branche spécifique à l’aide de gitk.

Le dossier de projet ne contient que le contenu de cette branche et je ne peux pas voir 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 comment il est correct ou si quelque chose me manque.

  • Aussi, j'aimerais savoir comment gérer un processus où je dois travailler sur deux branches en même temps au cas où, par exemple, je devrais créer un correctif sur master tout en conservant le contenu d'une autre branche.

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

Radex
la source
8
Intéressant - en général, avec SVN, vous ne vérifiez que le tronc ou la branche sur lequel vous travaillez, mais je comprends ce que vous voulez dire.
HorusKol
20
Le flux de travail dans SVN étant interrompu, vous essayez maintenant de le refléter dans Git (même si un bon flux de travail SVN ne s'applique que partiellement à Git). Meilleure solution - Oubliez toutes les habitudes SVN et commencez à partir de rien avec Git
Lazy Badger
6
git cloneest plus comme svnadmin hotcopyou svnrdump+ svnadmin loadque c'est comme svn checkout. Avec git, vous ne demandez pas des morceaux de la garde; vous copiez l' intégralité du référentiel et l'utilisez localement, en reportant les modifications dans le référentiel "source" quand et si vous le souhaitez. Git et Subversion utilisent deux modèles entièrement différents pour le contrôle de source.
Chepner
1
en ce qui concerne le correctif, envisagez d'utilisergit-flow
Bakuriu
5
@LazyBadger, le flux de travail n'est pas interrompu s'il facilite le développement et apporte de la valeur. Il n'y a pas une seule façon d'utiliser les branches.
dietbuddha

Réponses:

67

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

Bienvenue dans le gang!

Rééducation SVN

En SVN je d'habitude [...]

Attends un instant. Bien que CVS et SVN ainsi que d’autres systèmes de contrôle de version traditionnels (c’est-à-dire centralisés) remplissent (principalement) les mêmes objectifs que les systèmes de contrôle de versions modernes (c.-à-d. Distribués) tels que mercurial et Git, vous serez bien mieux familiarisé avec Git au lieu de essayez de transférer votre flux de travail SVN vers Git.

http://hginit.com ( vue sur archive.org ) par Joel Spolsky ( l' un des fondateurs mêmes de Stack Exchange) est un tutoriel pour Mercurial, Git pas, mais il est zéro e chapitre, « Subversion Rééducation » est utile pour les personnes commutation loin de SVN à tout système de contrôle de version distribué, comme il vous dit quels concepts SVN vous devez (temporairement) un -apprendre (ou stashloin , car les utilisateurs Git pourraient dire) pour pouvoir envelopper votre tête autour de la distribution concepts de système de contrôle de version et les workflows idiomatiques établis pour fonctionner avec eux.

Vous pouvez donc lire ce chapitre au-dessus de zéro et la plupart du temps simplement remplacer le mot "mercurial" par "Git" et ainsi vous préparer correctement ainsi que votre esprit à Git.

Les petits caractères

(Vous pouvez sauter ceci pour le moment.) Bien que mercurial et Git se ressemblent beaucoup plus que SVN, il existe certaines différences conceptuelles entre eux, de sorte que certains des énoncés et conseils de "Subversion Re-education" deviendront techniquement erronés. en remplaçant "mercurial" par "Git":

  • Alors que mercurial suit et stocke en interne les changesets, Git suit et stocke en interne les révisions (c'est-à-dire l'état du contenu d'une arborescence de répertoires), comme le fait Subversion. Mais à part Subversion, Git effectue des fusions en examinant les différences entre chaque branche impliquée et une révision ancestrale commune (une véritable fusion en trois points). Le résultat est donc sensiblement identique à celui de mercurial: la fusion est beaucoup plus simple et moins erronée. -sous que dans SVN.
  • Bien que vous puissiez créer une branche dans Git en clonant le référentiel (comme il est d'usage 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 ne sont que des indicateurs (mobiles) de 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; les workflows mercurial fonctionnent généralement en clonant le référentiel complet en cas de développement divergent.)

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

Mais je t'ai interrompu. Tu disais?

Dans SVN, je commande généralement sur mon ordinateur local un dépôt, qui inclut 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 d'une trunkou à une seule branche, par exemple, dans la structure de référentiel SVN classique, le branchesdossier contenant toutes les branches non liées au réseau), J'ose dire que vous avez probablement mal utilisé SVN (ish) avec SVN, ou du moins que vous avez un peu abusé du fait que le tronc, les branches et les balises sont tous repliés dans un seul espace de noms (bien que hiérarchique) avec des répertoires dans la base de révisions / code.

Même s'il peut être tentant de modifier plusieurs branches de SVN en parallèle, AFAIK ne correspond pas à l'utilisation prévue de SVN. (Bien que je ne sache pas quels inconvénients spécifiques cela pourrait 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 d'origine, y compris toutes les révisions, les branches et les balises. Mais il gardera tout ce que vous voulez: Git le stocke dans une base de données basée sur des fichiers, située dans le sous-dossier caché du dossier racine du référentiel .git/.

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

Lorsque vous êtes git cloneun référentiel, Git fait plusieurs choses. Grossièrement:

  1. Il crée le dossier cible , et dans celui-ci, le .git/sous - dossier 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 d'origine et en crée une copie dans la nouvelle base de données en leur attribuant un nom légèrement modifié qui les désigne comme des références "distantes".
  3. Il transfère toutes les révisions (c.-à-d. États d'arborescence de fichiers) auxquelles ces références font référence, ainsi que toutes les révisions que ces révisions pointent directement ou de manière transitoire (leurs parents et ancêtres) à la nouvelle base de données et les stocke, de sorte que les nouvelles références distantes pointez sur 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 d'origine (généralement master).
  5. Il vérifie cette branche locale.

Cette dernière étape signifie que Git recherche la révision pointée par cette branche et décompresse l'arborescence de fichiers qui y est stockée (la base de données utilise un moyen 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 .gitsous-dossier spécial ) 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 utiliser le référentiel proprement dit (la "base de données" des révisions et références), vous utilisez des gitcommandes.

Voir les branches de Git et interagir avec les branches de Git

Actuellement, je clone un repo et clone une branche spécifique à l’aide de gitk.

La version que gitkj'ai obtenue ne peut pas cloner de référentiels. Il ne peut afficher que l'historique des dépôts, créer des branches et extraire des branches. En outre, 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 repo en utilisant git clone ..., puis en utilisant gitk, vérifiez une branche?

Le dossier de projet ne contient que le contenu de cette branche et je ne peux pas voir 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:

  • Cloner un dépôt en utilisant git clone ...
  • Découvrez la branche sur laquelle vous souhaitez travailler git checkout ...ou en utilisant un outil graphique commegikt

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

  • [...] ou il me manque smt.

Peut être:

  • vous pouvez lister les branches locales avec git branch
  • vous pouvez lister les branches distantes avec git branch -rtoutes les branches avecgit branch -a
  • vous pouvez utiliser gitkpour afficher l'historique complet (toutes les balises de branche, etc. que votre référent local connaît) en l'invoquant avec

    gitk --all
    

Comment travailler avec plusieurs branches en parallèle

  • Aussi, j'aimerais savoir comment gérer un processus où je dois travailler sur deux branches en même temps au cas où, par exemple, je devrais créer un correctif sur master tout en conservant le contenu d'une autre branche.

Il y a différents scénarios ici:

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

Utilisez ce flux de travail:

  1. Créez une nouvelle branche à cpartir 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 une correction de bogue) ou d'une révision qui (avec tous ses ancêtres) est acceptable pour être introduite dans toutes ces branches.
  2. Effectuez et validez le changement sur cette nouvelle branche c.
  3. Pour chaque branche bqui a besoin du changement:

    1. Départ b:

      git checkout b
      
    2. Fusionner cdans b:

      git merge c
      
  4. Supprimer la branche c:

    git branch --delete c
    

Un changement existant est nécessaire sur une autre branche

(... mais sans les autres modifications effectuées sur l'emplacement de ces modifications)

  1. Découvrez la succursale où le changement est nécessaire
  2. Sélectionnez les révisions qui effectuent le changement, dans l'ordre

Sur une branche a, vous voulez changer un ou plusieurs fichiers à l’état exact qu’ils ont sur une autre brancheb

  1. Check-out a
  2. Obtenir le contenu du fichier de la branche b:

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

    ( git checkoutSinon, les chemins demandés ne passeront pas à la branche b, ils obtiendront uniquement le contenu du fichier demandé. Ces fichiers peuvent exister ou ne pas déjà exister a. S'ils le font, ils sont écrasés avec leur contenu 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 utiliser des outils graphiques permettant d'afficher le contenu des révisions non extraites (par exemple, gitkessayez de faire passer les boutons radio de "patch" à "arborescence")
  • ou cloner le référentiel dans un répertoire temporaire et consulter l'autre branche
  • ou utilisez git worktreepour créer un répertoire de travail séparé du même référentiel (c.-à-d. en utilisant également la base de données dans le .git/répertoire de votre référentiel local actuel) où vous pouvez extraire cette autre branche
das-g
la source
Pour le dernier flux de travail, stashc'est idéal.
CAD97
@ CAD97 pas si vous voulez continuer à travailler sur la première branche, tout en cherchant la seconde en parallèle . git stashC'est bien de déplacer les travaux inachevés, par exemple pour changer de branche et revenir plus tard.
das-g
1
"Les workflows mercurial fonctionnent généralement en clonant le référentiel complet pour un développement divergent" - Eh, j'en ai entendu parler, mais la plupart des gens qui veulent des branches Git utilisent simplement des signets au lieu de cloner l'ensemble du repo. C'est beaucoup plus facile.
Kevin
@ Kevin Cela pourrait être. Il y a quelque temps, j'ai utilisé Mercurial pour la dernière fois, alors c'était peut-être différent à l'époque. (Ou peut-être était-ce juste le flux de travail de la communauté dans laquelle je l'ai utilisé qui ressemblait à cela.)
das-g
Peut-être que le texte Hg Init "[...] parce que vous auriez vraiment dû créer une branche de Mercurial, en clonant des référentiels [...]" devrait également être mis à jour à cet égard.
das-g
31

Dans SVN, je commande généralement sur mon ordinateur local un dépôt, qui inclut 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 n'extrayiez le répertoire situé au-dessus du coffre, toutes les branches disponibles dans Subversion ne sont généralement pas disponibles localement. Dans Git, tout le contenu (commits, messages, branches, etc.) est toujours cloné sur chaque copie.

Actuellement, je clone un repo 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 sur un commit.

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

Courez git branch. Par défaut, seules les branches locales sont affichées. Utilisez git branch --remotepour voir les branches distantes.

l0b0
la source
4
Hm. "Par défaut, il ne montre que les branches locales." Cela ressemble à d’autres types de branches qui ne sont pas locales. Mais vous dites aussi "Dans Git, tout le contenu (commits, messages, branches, etc.) est toujours cloné sur chaque copie". . Je trouve cela un peu déroutant, car si toutes les branches sont clonées sur votre copie, quelles sont ces mystérieuses branches non locales? Peut-être que c'est trop compliqué de répondre dans un champ de commentaire.
pipe
2
@pipe Lorsque vous validez des modifications, vous créez un commit local, qui modifie le commit sur lequel pointe la branche. Si vous souhaitez que les autres utilisateurs obtiennent ces modifications, vous devez les transférer dans le référentiel distant. Il en résulte que la branche distante pointe vers ce nouveau commit. Désormais, tout le monde peut extraire ces modifications et ainsi obtenir une copie complète du référentiel
Frozn
9
@pipe Tout d’abord, vous ne pouvez en fait cloner qu’une branche en utilisant --single-branch(même seulement la pointe avec --depth 1). La différence entre les branches locales et distantes connues de git est simplement une sorte d’étiquette. Les branches distantes sont préfixées avec le nom de la source distante (souvent origin). Les branches locales n'ont pas ce préfixe. Mais au final, les données sont disponibles localement (à moins que vous ne l'ayez fait --single-branchou quelque chose de similaire). Lorsque vous utilisez git checkout $branchnameune branche pour laquelle il n’existe pas de branche locale mais une branche distante, git configure automatiquement une branche locale "assurant le suivi" de la télécommande.
Jonas Schäfer
"Sauf si vous consultez le répertoire situé au-dessus de trunk" - Mon expérience est que c'est assez courant, car cela facilite beaucoup la fusion. (Bien que nous utilisions une seule branche "
active
1
@ Izkata "cela facilite beaucoup la fusion", n'est-ce pas?
HorusKol
3

Comme cela est étiqueté avec j'espère que mon manque de connaissances en SVN est négligeable.

Actuellement, je clone un repo et clone une branche spécifique à l’aide de gitk.

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

Le référentiel est mieux imaginé en tant que 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.

Cette fetchcommande permet de maintenir la base de données locale synchronisée avec la base de données 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é.

Disons que vous travaillez sur un référentiel simple, où il n'y a pas de branche en plus master, vous pouvez jeter un coup d'oeil dans le .gitdossier pour dévoiler le "magique":

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

À partir de cette branche git checkout -b mybranch, vous retrouvez exactement le même pointeur dans le fichier cat .git/refs/heads/mybranch.

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

Si vous voulez savoir où vous en êtes HEAD:

cat .git/HEADqui dit, par exemple ref: refs/heads/mybranch, qui pointe ( cat .git/refs/heads/mybranch) à un hachage de commit78a8a6eb6f82eae21b156b68d553dd143c6d3e6f

Les commits réels sont stockés dans le objectsdossier (le comment est un sujet à part).

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

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

Supposons que vous avez différentes branches, votre répertoire de travail est dédié au travail sur cette branche uniquement (bien que vous puissiez placer le travail ailleurs).

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

  • git branch pour les branches locales
  • git branch --remote pour les branches éloignées
  • git branch -a pour les deux

(ou git branch -v)

Puisque git est un système de contrôle de version distribué, il est non seulement possible, mais également conseillé, de créer différentes branches localement / à distance.

Mon flux de travail typique est:

  • branche une branche de fonction
  • branchez une branche WIP (travail en cours) à partir de celle
  • travaillez comme vous le souhaitez - même si vous vous engagez après une seule ligne; ça n'a pas d'importance

Lorsque la fonctionnalité est terminée:

  • squash / retravailler la WIPbranche (avec rebasage interactif) = faire un simple commit à partir de celui-ci
  • fusionnez la WIPbranche dans la branche de fonctionnalités et proposez-la (si vous travaillez avec github, cette offre s'appelle une "demande d'extraction") à intégrer dans la branche stable (principale).

De plus, j'aimerais savoir comment gérer un processus où je dois travailler simultanément sur deux branches au cas où, par exemple, je devrais créer un correctif sur master tout en conservant le contenu d'une autre branche.

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é. 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 principale et pourriez décider de fusionner les deux branches ou de les rebaser (ce qui est une sorte de fusion pour les utilisateurs ayant des besoins avancés, pour ainsi dire).

Ou vous pouvez toujours modifier des branches (par exemple master) et les sélectionner à d’autres branches.

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

C'est à toi de decider.

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

Mais il y a des occasions, quand cela n'est pas voulu:

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

Thomas Junk
la source
2

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

Vous pouvez voir les autres branches utiliser git branchpour voir les branches locales ou git branch -rdistantes, puis git checkoutpour basculer vers une branche existante ou en créer une nouvelle basée sur la branche actuelle.

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

HorusKol
la source
0

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

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

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

Avec svn, vous pouvez si vous souhaitez extraire la racine du référentiel. Cela signifie que chaque branche et étiquette sont extraites en même temps. Afaict ce n'est pas la façon normale d'utiliser svn.

Une branche git n'est pas un répertoire, il n'y a donc pas d'équivalent à "extraire la racine du référentiel". Plusieurs arborescences de travail étant supportées, je suppose que vous pouvez concocter un script pour extraire toutes les branches en même temps si vous le souhaitez vraiment, mais ce serait plutôt inhabituel de le penser.

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

En tant que répertoires et en raison du modèle historique linéaire simple de svn, les branches de 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.

En revanche, les branches de git n'ont pas vraiment d'histoires. Il y a le "refog" mais il est plus destiné à être un mécanisme de reprise après sinistre qu'à un historique à long terme. En particulier, le reflog ne peut pas être lu à distance et est désactivé par défaut pour les pensions nues.

Les commits ont bien sûr des historiques, mais ceux-ci ne suffisent pas pour répondre à la question "ce qui était sur la branche x de la date du jour".

Je ne trouve pas de 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 "branche git".

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

Aussi, j'aimerais savoir comment gérer un processus où je dois travailler sur deux branches en même temps au cas où, par exemple, je devrais créer un correctif sur master tout en conservant le contenu d'une autre branche.

Quelques options.

Vous pouvez valider vos modifications sur «l’autre branche», passer en mode maître, puis revenir en arrière.

Vous pouvez également créer un arbre de travail supplémentaire. Google "git-worktree" pour plus de détails sur la syntaxe.

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

Je ne pense pas qu'il y ait une convention établie. L'extraction de plusieurs arbres de travail à la fois est l'exception et non la règle.

Peter Green
la source
2
cette réponse semble incomplète, pourquoi?
moucher