6
votes

La branche Git n'affiche pas toutes les branches

Je suis nouveau dans l'utilisation de Git, j'ai cloné une branche depuis GitHub et toutes les branches sont affichées lorsque j'ai tapé git branch . Après avoir terminé mon travail, je l'ai poussé dans une nouvelle succursale avec succès. Après cela, j'ai copié le dossier dans un autre répertoire (parce que je voulais avoir une sauvegarde pour éviter les conflits), je l'ai entré et j'ai tapé git branch . Seulement 3 branches affichées, sachant que j'en ai 4 sur Github.

J'ai essayé de résoudre le problème en clonant la branche dans un nouveau dossier (tapé git clone -b <branch-name> <repo-link-https> ) et maintenant seule la branche que j'ai clonée apparaît.

Des suggestions s'il vous plaît?


2 commentaires

Mais pourquoi ne clonez-vous qu'une seule branche alors que vous avez besoin de toutes les branches ?


Parce que je n'avais besoin que de cette branche spécifique pour travailler avec ... c'est ce que j'ai pensé en premier


3 Réponses :


3
votes

Remarques:

Pour les branches, utilisez git branch -avv pour obtenir une liste de toutes les branches locales et distantes.
Puis réessayez votre copie, et comparez git branch -avv fois terminé dans le nouveau dossier copié: s'il manque une branche distante, une simple git fetch suffira.


0 commentaires

3
votes

Afin de vous assurer que vous avez toutes les informations à jour sur les branches de Github (votre télécommande), vous pouvez faire une git fetch :

git branch -av

Où le drapeau --all récupère les branches de toutes les télécommandes. Si vous souhaitez simplement voir toutes les branches (sur votre machine et sur votre GitHub), vous pouvez faire une git branch :

git fetch --all

-a montre les branches du local et des télécommandes, et -v donne une sortie plus verbeuse.


0 commentaires

5
votes

Lorsque vous clonez un référentiel existant, votre Git crée un référentiel nouveau et différent, et copie dans ce nouveau référentiel tous les 1 des commits et aucune des branches du référentiel d'origine. La dernière étape de git clone consiste à créer une branche. Ce nom de branche est le vôtre , pas le leur; il est simplement orthographié de la même manière que l'un de leurs noms.

Au fur et à mesure que vous travaillez avec votre clone - un référentiel différent - vous pouvez lui ajouter de plus en plus de branches. Si vous y ajoutez toutes les mêmes branches qui se trouvent dans le référentiel d'origine, vous avez maintenant tous leurs commits et tous leurs noms de branches (comme vos propres branches, remarquez). Mais jusque-là, vous avez juste tous leurs engagements . C'est bien, car Git ne concerne pas les branches. Git concerne les commits .


1 La description précise est beaucoup plus compliquée que celle-ci, mais en la considérant comme «copiez tous leurs commits et aucune de leurs branches» vous permettra de démarrer.


J'ai essayé de résoudre le problème en clonant la branche dans un nouveau dossier (tapé git clone -b ) et maintenant seule la branche que j'ai clonée apparaît.

Lorsque vous créez un nouveau clone - qui, encore une fois, est un nouveau dépôt, où vous obtenez tous les commits du dépôt précédent mais aucune de ses branches pour le moment - la dernière étape de la commande git clone est d'exécuter un git checkout ou git switch commande 2 qui crée une branche. L'indicateur -b existe pour que vous puissiez dire à votre Git lequel de ses noms de branche copier, comme dernière étape. Si vous omettez l'indicateur -b , votre Git demande à son référentiel Git - celui que vous clonez - quelle branche il recommande. Mais de toute façon, vous n'obtenez qu'une seule branche.

Vous n'avez en fait besoin d' aucun nom de branche pour travailler dans Git. Cependant, vous avez besoin d' une sorte de nom, et les noms de branche sont le meilleur type de nom ici. C'est pourquoi votre Git fait un nom à la fin du processus de git clone . Chaque nom que vous créez vous donne une autre chose avec laquelle travailler.

Pour comprendre ce qui se passe, lisez la suite. Si vous êtes convaincu que votre question immédiate a été répondue, vous pouvez vous arrêter ici.


2 La commande git switch été ajoutée pour la première fois dans Git version 2.23, pour diviser la git checkout trop compliquée en deux commandes distinctes, git switch et git restore . Le git checkout existant reste; vous pouvez l'utiliser à la place des deux nouvelles commandes plus simples. Les nouvelles commandes simplifiées sont en un sens plus sûres, cependant: la commande git switch essaie d'être très sûre, tout comme la moitié de git checkout qu'elle a copiée. La commande git restore , cependant, est délibérément dangereuse en ce qu'elle détruira irrévocablement le travail; il copie l'autre moitié de git checkout . Donc, si vous utilisez git checkout , vous pouvez accidentellement invoquer la moitié «détruire mon travail» lorsque vous pensez invoquer la moitié «faire des choses en toute sécurité».


Git est une question de commits

Pour comprendre ce que fait Git ici et pourquoi il fait cela comme ça, commencez par le fait que Git lui-même est vraiment une question de commits. Il ne s'agit pas de branches, bien que les noms de branche vous aident (et Git) à trouver des commits. Il ne s'agit pas de fichiers, bien que les commits contiennent des fichiers. C'est vraiment une question de commits: tout ce que fait Git est au service de la conservation et de l'ajout de commits. Les commits sont là où les choses commencent et sont le but de tout le reste.

Cela signifie qu'il est crucial de comprendre ce Commit est, comment vous nommez un particulier commettras, et comment vous faites un commit. Commençons par le nom.

Le vrai nom d'un commit est son ID de hachage

Vous pourriez penser qu'un nom de branche nommerait un commit - et c'est en quelque sorte le cas, mais indirectement. En fait, chaque commit est nommé par son numéro. Chaque commit a un numéro unique. Aucun autre commit ne peut jamais avoir ce numéro: une fois que ce commit est fait, ce numéro est alloué à ce commit. Parce que cette validation prend ce nombre pour toujours, le nombre doit être vraiment grand, et c'est le cas. Actuellement, chaque commit Git obtient un des 2160 nombres possibles. 3 Ce nombre est exprimé en hexadécimal sous la forme d'une grosse chaîne laide comme e31aba42fb12bdeb0f850829e008e1e3f43af500 (il s'agit d'un commit réel dans un référentiel Git pour Git lui-même).

Ce numéro fonctionne toujours: si vous avez ce commit, c'est son numéro, et git show e31aba42fb12bdeb0f850829e008e1e3f43af500 le montrera, par exemple. Vous pouvez généralement abréger le nombre, à aussi peu que les quatre premiers caractères si cela n'est pas ambigu, donc si vous avez un clone du dépôt Git pour Git, git show e31aba42fb12bdeb0f850829e008 presque à coup git show e31aba42fb12bdeb0f850829e008 . Mais git show e31a ne le fait pas car il pourrait être court pour ce commit, ou pour commit e31a17f741... , par exemple. Bien que e31ab fonctionne aujourd'hui, à mesure que de nouveaux commits sont ajoutés, il peut cesser de fonctionner.

Ces chiffres semblent aléatoires, mais ne le sont pas. En fait, chacun est une somme de contrôle cryptographique du contenu complet du commit. 4 Git effectue une double vérification lors de l'extraction de l'un de ses objets internes, y compris les commits, que la somme de contrôle correspond toujours, afin de détecter les échecs de stockage: vous dites à Git de trouver un commit (ou un autre objet) par ID de hachage et il vérifie que l'ID de hachage correspond toujours. Cela signifie donc qu'aucune partie d'un commit - ou de l'un des autres objets internes de Git - ne peut jamais changer non plus. Vous pouvez en créer de nouveaux , chacun obtenant un nouvel identifiant différent, mais cela n'affecte pas les existants, qui restent dans le référentiel.


3 Il est prévu de refaire le système de numérotation pour utiliser 2 256 numéros, avec une sorte de transition laide.

4 En fait, tous les objets internes de Git utilisent ce schéma. Cela signifie que tous les objets enregistrés sont figés pour toujours. C'est ainsi que Git gèle et déduplique le contenu des fichiers, par exemple.


Qu'y a-t-il dans un commit

Maintenant que nous en connaissons une - et la manière la plus profonde, pour ainsi dire - de rechercher un commit, par son ID de hachage, il est temps de regarder ce qu'il y a à l'intérieur de chaque commit. Chaque commit comprend deux parties:

  • Un commit contient un instantané complet de tous vos fichiers. Ce sont les données principales de la plupart des commits (et généralement aussi la majeure partie du référentiel). Chaque fichier est stocké en tant qu'objet blob interne, en utilisant cette même astuce de codage de nom de hachage. Cela déduplique automatiquement les fichiers, de sorte que si vous effectuez une centaine de commits d'affilée qui réutilisent principalement la plupart de leurs fichiers, ils ne prennent pas vraiment d'espace supplémentaire.

  • Chaque commit contient également des métadonnées , ou des informations sur le commit lui-même: qui l'a fait, quand et pourquoi, par exemple. La partie «pourquoi» est votre message de journal: votre propre explication à vous-même et / ou aux autres plus tard. Pourquoi ce commit est- il meilleur que le dernier? Ou du moins, pourquoi c'est différent, si ce n'est pas forcément mieux. Le but de ce commit particulier pourrait être de corriger un bogue, ou d'ajouter une nouvelle fonctionnalité, ou de préparer quelque chose pour ajouter une nouvelle fonctionnalité, ou autre. Le commit lui-même a le code source mis à jour, mais pas nécessairement quoi que ce soit sur le bogue que la mise à jour est censée corriger. C'est votre chance d'expliquer cela.

Il y a une partie des métadonnées que Git génère pour vous, puis utilise plus tard, que vous voyez rarement directement, et c'est la suivante: chaque commit contient l'ID de hachage brut de son prédécesseur immédiat. Cette chaîne s'engage ensemble, à l' envers , dans une chaîne de validations qui se termine par le dernier commit.

Nous pouvons dessiner ceci. Imaginez que nous ayons un référentiel avec seulement trois commits. Au lieu de vrais ID de hachage, nous utiliserons des lettres majuscules uniques pour remplacer les validations. Le tout premier commit sera A , le suivant sera B et le troisième commit sera commit C :

        E   <-- main, origin/main
       /
A--B--C
       \
        D   <-- dev (HEAD), origin/dev

Puisque le commit C est le dernier, il a l'ID de hachage du commit B antérieur dans ses métadonnées. On dit que C pointe vers B De la même manière, engagez B points sur A Puisque A est le tout premier commit jamais effectué, il lui manque cette flèche pointant vers l'arrière: il ne pointe nulle part. Git appelle cela un (ou le) commit racine . C'est là que nous arrêtons de travailler à l'envers.

J'ai mentionné il y a un instant que chaque commit a un instantané complet de chaque fichier. Mais si Git affiche un commit, Git vous montre ce qui a changé . Comment et pourquoi Git fait-il cela?

Le pourquoi est peut-être le plus facile à expliquer. Si vous voulez voir tous les fichiers qui sont dans le commit, vous pouvez simplement vérifier le commit. Git copiera tous ces fichiers hors du commit - où, rappelez-vous, ils sont stockés dans un format Git gelé spécial, dédupliqué (et compressé aussi) - dans des fichiers informatiques ordinaires. Vous avez probablement un tas de visionneuses de fichiers qui sont plus compétentes que Git ne pourrait jamais l'être: elles peuvent vous montrer des images sous forme d' images, ouvrir des documents textuels dans des éditeurs de texte, ouvrir des PDF avec des visionneuses PDF, etc. Mais votre visionneuse de fichiers ne peut probablement pas comparer l'instantané entier avec l'instantané entier précédent. Git peut .

Git peut comparer assez facilement le snapshot C snapshot B , car le commit C contient l'ID de hachage du commit B Donc Git peut simplement extraire les deux commits. De plus, en raison de la façon dont Git déduplique les fichiers, Git peut immédiatement connaître - et même pas prendre la peine de les extraire - les fichiers dupliqués. Git n'a besoin que d'extraire et de comparer les différents fichiers. Git le fera et construira un ensemble de modifications qui transformeront les anciens fichiers en nouveaux. C'est ce que Git va vous montrer: cet ensemble d'instructions.

(Notez que Git crée l'ensemble d'instructions à la demande. Jusqu'à ce que vous demandiez à Git de comparer deux commits, tout ce que Git a sont les deux instantanés. Vous pouvez obtenir différents ensembles d'instructions en fonction des options que vous passez à la commande de comparaison. Par exemple, Git peut faire la vérification des différences en fonction des mots, ou ignorer autrement certains types de changements d'espaces blancs. Les capacités de Git ici ne sont pas toujours aussi bonnes que nous pourrions le souhaiter, mais nous pouvons utiliser quelques astuces. Elles sont hors de portée pour cette réponse particulière, cependant.)

Recherche de commits par nom de branche

Nous savons déjà que si nous mémorisons les gros ID de hachage laids (ou les notons par écrit), nous pouvons les utiliser pour trouver des commits. Mais c'est ridicule. Nous avons un ordinateur . Pourquoi l' ordinateur n'écrit-il pas les identifiants de hachage pour nous?

C'est ce que fait un nom de branche. Mais c'est un peu sournois. Ce qu'un nom de branche fait vraiment, c'est stocker uniquement l'ID de hachage du dernier commit. Dessinons à nouveau ce référentiel à trois commit et ajoutons un nom, main , qui identifie le dernier commit:

git switch dev

Ici, au lieu d'essayer de se souvenir de l' ID de hachage de C , nous savons simplement que le nom main fait pour nous. Donc, git checkout main (pré-2.23 Git) ou git switch main (2.23 et versions ultérieures) nous obtient le dernier commit - actuellement C - quel que soit son ID de hachage.

Nous pouvons maintenant ajouter un nouveau nom qui pointe également vers le commit C :

        E   <-- main (HEAD), origin/main
       /
A--B--C
       \
        D   <-- origin/dev

Maintenant, nous avons besoin d'une dernière chose: lequel de ces noms utilisons-nous? Pour le moment, cela n'a pas beaucoup d'importance, car les deux noms sélectionnent commit C Mais attachons le nom spécial HEAD à l'un des deux noms de branche, comme ceci:

        E   <-- origin/main
       /
A--B--C
       \
        D   <-- origin/dev

Si nous git switch dev , nous attachons à nouveau le nom spécial HEAD au nom dev , comme ceci:

        E
       /
A--B--C
       \
        D

Maintenant, faisons un nouveau commit. Sans nous soucier de la façon dont nous faisons un nouveau commit, supposons simplement que tout est fait. Ce nouveau commit D pointera nécessairement vers le commit C existant, car nous avons créé D partir de C Cela ressemble à ceci:

        E   <-- main (HEAD)
       /
A--B--C
       \
        D   <-- dev

Mais D est maintenant le dernier commit, donc Git doit mettre à jour un nom . Quel nom doit-il mettre à jour? La réponse est claire: il devrait mettre à jour celui auquel HEAD est attaché:

A--B--C   <-- main
       \
        D   <-- dev (HEAD)

Nous avons maintenant deux noms de succursales, et les deux noms spécifions deux différents commits « dernier ». Le dernier commit sur main est C , et le dernier commit sur dev est D Commit D pointe vers le commit C , qui pointe vers B , qui pointe vers A ; donc les quatre commits sont sur branche dev , tandis que trois d'entre eux sont sur main .

Si nous retournons au nom main et y faisons un nouveau commit, nous obtenons:

A--B--C
       \
        D

ce qui signifie que nous avons maintenant trois commits qui sont partagés sur les deux branches, et un commit qui est uniquement sur main et un commit qui est uniquement sur dev . Maintenant, nous avons besoin des deux noms pour trouver les cinq commits; un nom trouvera un commit, qui trouvera les trois commits partagés , mais nous avons besoin de l'autre nom pour trouver le dernier commit restant.

Notez que les noms de branche bougent . En fait, ils se déplacent automatiquement, lorsque nous faisons de nouveaux commits: quel que soit le nom de la branche HEAD est attaché, il se déplace automatiquement pour englober le nouveau commit. Tous les autres noms de branche restent en place à ce stade, mais comme ce sont nos noms de branche, nous en avons le contrôle. Nous pouvons demander à notre Git de déplacer ces noms à tout moment. La seule contrainte est que nous devons avoir un commit pour déplacer le nom.

Le clonage crée des noms de suivi à distance

Lorsque nous clonons le référentiel de quelqu'un d'autre, nous obtenons tous leurs commits et aucune de leurs branches. Comment cela marche-t-il? Eh bien, supposons que nous ayons ce qui précède, avec deux noms de branche réels main et dev sélectionnant respectivement les commits E et D Nous créons maintenant un nouveau référentiel dans lequel nous copions les cinq commits, ce qui nous donne:

A--B--C   <-- main, dev (HEAD)

Nous avons en fait besoin de deux noms pour trouver tous les commits. Mais nous n'avons pas besoin de noms de succursales . L'autre Git, travaillant avec l'autre référentiel, a des noms de branche, car ce sont ses branches qu'il déplacera à mesure qu'il effectuera de nouveaux commits. Donc, ce que fait notre Git, c'est copier leurs noms mais les changer . Nous demandons à notre Git de prendre leurs noms de branche et de créer nos noms de suivi à distance , en ajoutant quelque chose - généralement origin/ - aux noms. 5 Nous obtenons donc:

A--B--C   <-- main (HEAD), dev

Git refusera d'attacher le nom spécial HEAD à l'un de ces noms de suivi à distance. HEAD ne peut être attaché qu'à un nom de branche . Donc, la dernière étape de notre git clone est d'utiliser l'option -b , ou leur recommandation, pour choisir l'un de ces deux noms, et créer un nom de branche à partir de celui-ci, comme ceci:

A--B--C   <-- main, dev

Notez que notre nom de branche sélectionne le même commit que le nom de suivi à distance que notre git clone créé à partir de son nom de branche. Mais nous n'avons maintenant qu'un seul nom de branche, pas deux. Si nous courons:

A--B--C   <-- main

cela utilise une fonctionnalité spéciale fournie par Git, qui trouve leur origin/dev et crée notre propre nouveau nom dev :

A <-B <-C

et maintenant nous avons deux noms de branche. Mais nous ne l'avons pas fait au départ. Notez que nous avons également maintenant vérifié le commit D , plutôt que le commit E , car git switch (ou git checkout , si nous l'utilisons) non seulement change les branches, mais sélectionne également le commit que le nom de la branche identifie, comme le commit qui est à vérifier, et donc à notre disposition pour travailler avec.


5 Techniquement, un nom de suivi à distance se trouve dans un espace de noms distinct. Notre Git ne se contente pas de coller l' origin/ en avant, il remplace les refs/heads/ par des refs/remotes/origin/ . L' origin nom est en fait une télécommande et nous pouvons avoir autant de télécommandes que nous le souhaitons dans notre référentiel Git. Mais c'est un sujet pour une autre question.


1 commentaires

Merci beaucoup! Vous avez tout clarifié et résolu mon problème.