web-dev-qa-db-fra.com

Quelles sont les différences entre git branch, fork, fetch, fusion, rebase et clone?

Je veux comprendre la différence entre une branche, une fourchette et un clone dans Git?

De même, qu'est-ce que cela signifie quand je fais un git fetch par opposition à un git pull?

Aussi, que signifie rebase par rapport à merge?

Comment puis-je écraser les individus s’engagent ensemble?

Comment sont-ils utilisés, pourquoi sont-ils utilisés et que représentent-ils?

Comment GitHub figure-t-il?

489
jackiekazil

Un clone est simplement une copie d'un référentiel. En apparence, son résultat est équivalent à svn checkout, où vous téléchargez le code source à partir d'un autre référentiel. La différence entre les VCS centralisés comme Subversion et les DVCS comme Git est que, dans Git, lorsque vous clonez, vous copiez en réalité l'intégralité du référentiel source, y compris l'historique et les branches. Vous avez maintenant un nouveau référentiel sur votre machine et tous les commits que vous faites vont dans ce référentiel. Personne ne verra de modifications tant que vous n'aurez pas transféré ces commits vers un autre référentiel (ou le référentiel d'origine), ni jusqu'à ce que quelqu'un les extrait de votre référentiel, s'il est accessible au public.

Une branche est quelque chose qui se trouve dans un référentiel. Conceptuellement, cela représente un fil de développement. Vous avez généralement une branche master, mais vous pouvez également avoir une branche sur laquelle vous travaillez sur une fonctionnalité xyz et une autre pour corriger le bogue abc. Lorsque vous avez extrait une branche, les commits que vous avez effectués resteront sur cette branche et ne seront pas partagés avec d'autres branches jusqu'à ce que vous les fusionniez avec ou que vous les rebasonniez sur la branche en question. Bien sûr, Git semble un peu bizarre en ce qui concerne les branches jusqu'à ce que vous examiniez le modèle sous-jacent de la façon dont les branches sont mises en œuvre. Plutôt que de l'expliquer moi-même (j'en ai déjà trop dit, il me semble), je vais vous renvoyer à l'explication "informatique" de la façon dont Git modélise les branches et les commits, tirées du site Web de Git:

http://eagain.net/articles/git-for-computer-scientists/

Une fourchette n'est pas vraiment un concept Git, c'est plutôt une idée politique/sociale. Autrement dit, si certaines personnes ne sont pas satisfaites de la progression d'un projet, elles peuvent utiliser le code source et le travailler eux-mêmes, en dehors des développeurs d'origine. Cela serait considéré comme une fourchette. Git facilite les échanges car tout le monde a déjà sa propre copie "maîtresse" du code source. Il est donc simple de couper les liens avec les développeurs du projet original et n'exige pas l'exportation de l'historique depuis un référentiel partagé, comme ce que vous pourriez avoir à faire avec SVN. .

EDIT: comme je ne connaissais pas la définition moderne de "fork" utilisée par des sites tels que GitHub, jetez un œil aux commentaires et aussi réponse de Michael Durrant au-dessous du mien pour plus d'informations.

361
siride

Git

Cette réponse inclut GitHub car de nombreuses personnes ont également posé des questions à ce sujet.

Dépôts locaux

Git (localement) a un répertoire (.git) dans lequel vous validez vos fichiers. Il s'agit de votre 'référentiel local'. Cela diffère des systèmes tels que SVN où vous ajoutez et validez immédiatement dans le référentiel distant.

Git stocke chaque version d'un fichier qui change en enregistrant l'intégralité du fichier. Il est également différent de SVN à cet égard, car vous pouvez utiliser une version individuelle sans la "recréer" via des modifications delta.

Git ne "verrouille" pas du tout les fichiers et évite ainsi la fonctionnalité de "verrouillage exclusif" d'une édition (des systèmes plus anciens comme les systèmes en PVC, par exemple), de sorte que tous les fichiers peuvent toujours être édités, même hors ligne. Il fait un travail incroyable en fusionnant les modifications de fichiers (dans le même fichier!) Lors de l'extraction ou de l'extraction/de l'extraction dans un référentiel distant tel que GitHub. La seule fois où vous devez effectuer des modifications manuelles (en réalité, éditer un fichier), c'est si deux modifications impliquent la même ligne de code.


Branches

Les branches vous permettent de conserver le code principal (la branche "principale"), de faire une copie (une nouvelle branche), puis de travailler dans cette nouvelle branche. Si le travail prend un certain temps ou si le maître obtient de nombreuses mises à jour depuis la création de la branche, il convient de procéder à la fusion ou à la refonte (souvent préférable pour un meilleur historique et pour résoudre les conflits) avec la branche principale. Lorsque vous avez terminé, vous fusionnez les modifications apportées dans la branche dans le référentiel principal. De nombreuses organisations utilisent des branches pour chaque travail, qu’il s’agisse d’une fonctionnalité, d’un bogue ou d’une tâche. D'autres organisations n'utilisent que des branches pour les modifications majeures telles que les mises à niveau de version.

Fork: avec une branche, vous contrôlez et gérez la branche, alors qu'avec une branche, quelqu'un d'autre contrôle l'acceptation du code.

De manière générale, il existe deux approches principales pour faire des branches. La première consiste à conserver la plupart des modifications sur la branche principale, en n'utilisant que des branches pour des tâches plus volumineuses et plus longues, telles que les modifications de version, lorsque vous souhaitez disposer de deux branches pour des besoins différents. La seconde consiste à créer une branche pour chaque demande de fonctionnalité, correctif de bogue ou tâche, puis à décider manuellement du moment de la fusion de ces branches dans la branche principale principale. Bien que cela paraisse fastidieux, c’est une approche courante que j’utilise et que je recommande actuellement, car elle garde la branche principale plus propre et c’est le maître que nous promouvons en production. Nous ne voulons donc que du code complet et testé, via le fusion de branches.

La méthode standard pour amener une branche 'à' maîtriser est de faire un merge. Les branches peuvent également être "rebasées" pour "nettoyer" l'historique. Cela n'affecte pas l'état actuel et est fait pour donner un historique 'plus propre'.

Fondamentalement, l’idée est que vous avez créé une branche à partir d’un certain point (généralement à partir du maître). Depuis que vous avez créé une branche, le mot "maître" lui-même est passé de ce point de branchement. Il sera plus propre (plus facile de résoudre les problèmes et l’historique sera plus facile à comprendre) si tous les changements que vous avez effectués dans une branche sont appliqués à l’état actuel du maître avec tous ses derniers changements. Le processus est donc le suivant: enregistrez les modifications; récupérez le 'nouveau' maître, puis réappliquez (c'est la partie rebase) les modifications à nouveau. Sachez que la refonte, tout comme la fusion, peut entraîner des conflits que vous devez résoudre manuellement (c'est-à-dire modifier et corriger).

Une ligne directrice à noter:
Ne rebase que si la branche est locale et que vous ne l'avez pas encore poussée à distance!
Ceci est principalement dû au fait que le changement de base peut modifier l’historique que les autres utilisateurs voient, ce qui peut inclure leurs propres commits.

Branches de suivi

Ce sont les branches nommées Origin/branch_name (par opposition à branch_name). Lorsque vous poussez et extrayez le code vers/depuis des référentiels distants, c'est en fait le mécanisme par lequel cela se produit. Par exemple, lorsque vous git Push une branche appelée building_groups, votre branche passe d'abord à Origin/building_groups, puis au référentiel distant. De même, si vous faites un git fetch building_groups, le fichier récupéré est placé dans votre branche Origin/building_groups. Vous pouvez ensuite choisir de fusionner cette branche dans votre copie locale. Notre pratique est de toujours faire un git fetch et une fusion manuelle plutôt que simplement un git pull (qui effectue les deux opérations ci-dessus en une seule étape).

Aller chercher de nouvelles branches.

Obtenir de nouvelles branches: Au point initial d'un clone, vous aurez toutes les branches. Cependant, si d'autres développeurs ajoutent des branches et les poussent vers la télécommande, il doit exister un moyen de "connaître" ces branches et leurs noms afin de pouvoir les supprimer localement. Cette opération est effectuée via un git fetch, qui récupère toutes les branches nouvelles et modifiées dans le référentiel local à l'aide des branches de suivi (par exemple, Origin/). Une fois que fetched, on peut git branch --remote pour répertorier les branches de suivi et git checkout [branch] pour passer à l’une quelconque.

Fusionner

La fusion est le processus consistant à combiner des modifications de code provenant de différentes branches ou de différentes versions d'une même branche (par exemple, lorsqu'une branche locale et distante sont désynchronisées). Si vous avez développé un travail dans une branche et que le travail est terminé, prêt et testé, vous pouvez le fusionner dans la branche master. Ceci est effectué par git checkout master pour passer à la branche master, puis git merge your_branch. La fusion rassemblera tous les différents fichiers et même des modifications différentes apportées aux mêmes fichiers. Cela signifie qu’il va réellement changer le code dans les fichiers pour fusionner toutes les modifications.

Lorsque vous utilisez la checkout de master, il est également recommandé de faire un git pull Origin master pour obtenir la dernière version du maître distant fusionnée dans votre maître local. Si le maître distant a changé, c'est-à-dire moved forward, vous verrez des informations reflétant ces informations au cours de ce git pull. Si tel est le cas (maître modifié), il vous est conseillé de git checkout your_branch, puis rebase de le maîtriser afin que vos modifications soient réellement "répétées" par-dessus le "nouveau" maître. Ensuite, vous continuerez à mettre le maître à jour, comme indiqué dans le paragraphe suivant.

S'il n'y a pas de conflits, les nouvelles modifications sont ajoutées au maître. S'il y a des conflits, cela signifie que les mêmes fichiers ont des modifications autour de lignes de code similaires qu'il ne peut pas fusionner automatiquement. Dans ce cas, git merge new_branch signalera qu'il existe des conflits à résoudre. Vous les "résolvez" en modifiant les fichiers (qui contiennent les deux modifications), en sélectionnant les modifications souhaitées, en supprimant littéralement les lignes des modifications non souhaitées, puis en enregistrant le fichier. Les modifications sont marquées par des séparateurs tels que ======== et <<<<<<<<.

Une fois que vous avez résolu tous les conflits, vous devrez à nouveau git add et git commit ces modifications pour poursuivre la fusion (vous obtiendrez les informations de git au cours de ce processus pour vous guider).

Lorsque le processus ne fonctionne pas bien, vous constaterez que git merge --abort est très pratique pour réinitialiser les éléments.

Rebasement interactif et écrasement/réordonnancement/suppression des commits

Si vous avez effectué un grand nombre de petites étapes, par exemple, si vous commettez du code en tant que "travail en cours" tous les jours, vous pouvez "écraser" ces nombreux petits commits en un plus grand nombre. Cela peut être particulièrement utile lorsque vous souhaitez réviser le code avec des collègues. Vous ne voulez pas rejouer toutes les 'étapes' que vous avez effectuées (via les commits), vous voulez simplement dire que voici l'effet final (diff) de toutes mes modifications pour ce travail dans un même commit.

Le facteur clé à évaluer pour déterminer s’il convient de le faire est de déterminer si les validations multiples sont appliquées plusieurs fois sur le même fichier ou sur plusieurs fichiers (il est préférable d’écraser les validations dans ce cas). Ceci est fait avec l'outil de rebasage interactif. Cet outil vous permet d'écraser, de supprimer, de reformuler des messages, etc. Par exemple, git rebase -i HEAD~10 (note: c'est un ~, pas un -) ce qui suit:

interactive rebasing in Git

Soyez prudent et utilisez cet outil avec précaution. Effectuez une compression/suppression/réorganisation à la fois, quittez et enregistrez cette validation, puis entrez à nouveau dans l'outil. Si les commits ne sont pas contigus, vous pouvez les réorganiser (puis écraser au besoin). Vous pouvez réellement supprimer les commits ici aussi, mais vous devez vraiment être sûr de ce que vous faites quand vous le faites!

Fourches

Il existe deux approches principales de la collaboration dans les référentiels Git. La première, détaillée ci-dessus, est directement via les branches que les gens tirent et Push de/vers. Ces collaborateurs ont leurs clés SSH enregistrées avec le référentiel distant. Cela leur permettra de pousser directement vers ce référentiel. L'inconvénient est que vous devez gérer la liste des utilisateurs. L’autre approche, le forking, permet à n’importe qui de "fourchir" le référentiel, en créant essentiellement une copie locale dans son propre compte de référentiel Git. Ils peuvent ensuite apporter des modifications et, une fois l'opération terminée, envoyer une "demande d'extraction" (il s'agit en réalité d'une "transmission" émanant d'eux et d'une demande d'extraction pour le responsable du référentiel) afin que le code soit accepté.

Cette seconde méthode, utilisant des forks, nécessite not ​​obliger quelqu'un à maintenir une liste d'utilisateurs pour le référentiel.


GitHub

GitHub (un référentiel distant) est une source distante vers laquelle vous poussez et extrayez normalement les modifications validées si vous avez (ou avez été ajouté) un tel référentiel, de sorte que local et distant sont en réalité assez distincts. Une autre façon de penser à un référentiel distant est qu’il s’agit d’une structure de répertoires .git qui réside sur un serveur distant.

Lorsque vous "branchez" - dans l'interface graphique du navigateur Web GitHub, vous pouvez cliquer sur ce bouton Image of fork button - vous créez une copie ('clone') du code dans votre compte GitHub. Cela peut être un peu subtil la première fois que vous le faites, alors assurez-vous de bien regarder dans le référentiel dans lequel une base de code est répertoriée - soit le propriétaire d'origine, soit "à partir de" et vous, par exemple, comme ceci:

Image of name of forked repository

Une fois que vous avez la copie locale, vous pouvez apporter les modifications souhaitées (en les tirant et en les poussant sur une machine locale). Une fois que vous avez terminé, vous soumettez une 'demande d'extraction' au propriétaire/administrateur du référentiel d'origine (cela vous semble intéressant, mais en réalité, il vous suffit de cliquer sur ceci: Image of pull request button) et ils "tirent" dedans.

Le plus souvent, pour une équipe travaillant ensemble sur du code, il est de "cloner" le référentiel (cliquez sur l'icône "Copier" dans l'écran principal du référentiel). Ensuite, tapez localement git clone et collez-le. Cela vous installera localement et vous pourrez également pousser et tirer vers l'emplacement (partagé) de GitHub.

Clones

Comme indiqué dans la section sur GitHub, un clone est une copie d'un référentiel. Lorsque vous avez un référentiel distant, vous émettez la commande git clone contre son URL et vous vous retrouvez avec une copie locale, ou un clone, du référentiel. Ce clone a tout , les fichiers, la branche master, les autres branches, tous les commits existants, tout le Shebang. C’est à ce clone que vous faites vos ajouts et commets, puis le référentiel distant lui-même correspond à ce que vous transmettez à ces commits. C’est ce concept local/distant qui fait de Git (et de systèmes similaires, tels que Mercurial) un système de contrôle de version DVCS ( distribué ). CVS traditionnels (systèmes de version de code) tels que SVN, PVCS, CVS, etc. dans lesquels vous vous engagez directement dans le référentiel distant.

Visualisation

La visualisation des concepts de base peut être vue à
http://marklodato.github.com/visual-git-guide/index-en.html et
http://ndpsoftware.com/git-cheatsheet.html#loc=index

Si vous voulez un affichage visuel de la façon dont les modifications fonctionnent, vous ne pouvez pas battre l'outil visuel gitg (gitx pour macOS) avec une interface graphique que j'appelle "la carte du métro" (en particulier Londres. Underground), idéal pour montrer qui a fait quoi, comment les choses ont changé, divergé et fusionné, etc.

Vous pouvez également l'utiliser pour ajouter, valider et gérer vos modifications!

Image of gitg/gitx interface

Bien que gitg/gitx soit relativement minime, le nombre d'outils d'interface graphique continue de croître. De nombreux utilisateurs de Mac utilisent Brother's fork de gitx et pour Linux, une excellente option est smart-git avec une interface à la fois intuitive et puissante:

Image of smart-git GUI

Notez que même avec un outil graphique, vous ferez probablement beaucoup de commandes en ligne de commande.

Pour cela, j'ai les alias suivants dans mon fichier ~/.bash_aliases (appelé à partir de mon fichier ~/.bashrc pour chaque session de terminal):

# git
alias g='git status'
alias gcob='git checkout -b '
alias gcom='git checkout master'
alias Gd='git diff'
alias gf='git fetch'
alias gfrm='git fetch; git reset --hard Origin/master'
alias gg='git grep '
alias gits='alias | grep "^alias g.*git.*$"'
alias gl='git log'
alias gl1='git log --oneline'
alias glf='git log --name-status'
alias glp='git log -p'
alias gpull='git pull '
alias gpush='git Push '

ET j'ai les "alias de git" suivants dans mon fichier ~/.gitconfig, pourquoi les avoir?
Ainsi, l'achèvement de la branche (avec la touche TAB) fonctionne!

Donc ce sont:

[alias]
  co = checkout
  cob = checkout -b

Exemple d'utilisation: git co [branch] <- l'achèvement de la tabulation pour les branches fonctionnera.

Outil d'apprentissage graphique

Vous pouvez trouver https://learngitbranching.js.org/ utile pour apprendre certains des concepts de base. Capture d'écran: enter image description here
Vidéo: https://youtu.be/23JqqcLPss

Enfin, 7 sauveteurs clés!

  1. Vous apportez des modifications, les ajoutez et les commettez (mais ne poussez pas), puis oh! vous réalisez que vous êtes en maître!

    git reset [filename(s)]
    git checkout -b [name_for_a_new_branch]
    git add [file(s)]
    git commit -m "A useful message"
    
    Voila!  You've moved that 'master' commit to its own branch !
    
  2. Vous gâchez des fichiers lorsque vous travaillez dans une branche locale et vous souhaitez simplement revenir à ce que vous aviez la dernière fois que vous avez effectué un git pull:

    git reset --hard Origin/master  # You will need to be comfortable doing this!
    
  3. Vous commencez à apporter des modifications localement, vous éditez une demi-douzaine de fichiers, puis, oh merde, vous êtes toujours dans la branche principale (ou une autre):

    git checkout -b new_branch_name  # just create a new branch
    git add .                      # add the changes files
    git commit -m"your message"    # and commit them
    
  4. Vous bousillez un fichier en particulier dans votre branche actuelle et vous souhaitez essentiellement le "réinitialiser" (perdre les modifications) pour qu'il redevienne comme avant la dernière fois que vous l'avez extrait du référentiel distant:

    git checkout your/directories/filename
    

    Cela réinitialise le fichier (comme beaucoup de commandes Git, il n’est pas bien nommé pour ce qu’il fait ici).

  5. Vous apportez des modifications localement, vous voulez vous assurer de ne pas les perdre pendant que vous effectuez un git reset ou rebase: Je fais souvent une copie manuelle du projet entier (cp -r ../my_project ~/) quand je ne suis pas sûr de pouvoir gâcher Git ou de perdre des modifications importantes.

  6. Vous rebassez mais les choses se gâchent:

    git rebase --abort # To abandon interactive rebase and merge issues
    
  7. Ajoutez votre branche Git à votre invite PS1 (voir https://unix.stackexchange.com/a/127800/1004 ), par exemple.

    Image of Prompt

    La branche est Selenium_rspec_conversion.

520
Michael Durrant

Voici l'image d'Oliver Steele sur la manière dont tout cela s'emboîte:

enter image description here

142
Contango

Fork vs. Clone - deux mots qui signifient tous deux copie

Veuillez voir ceci diagramme. (À l'origine de http://www.dataschool.io/content/images/2014/Mar/github1.png ).

.-------------------------.     1. Fork     .-------------------------.
| Your GitHub repo        | <-------------- | Joe's GitHub repo       |
| github.com/you/coolgame |                 | github.com/joe/coolgame |
| ----------------------- | 7. Pull Request | ----------------------- |
| master -> c224ff7       | --------------> | master -> c224ff7 (c)   |
| anidea -> 884faa1 (a)   |                 | anidea -> 884faa1 (b)   |
'-------------------------'                 '-------------------------'
    |                 ^
    | 2. Clone        |
    |                 |
    |                 |
    |                 |
    |                 |
    |                 | 6. Push (anidea => Origin/anidea)
    v                 |
.-------------------------.
| Your computer           |  3. Create branch 'anidea'
| $HOME/coolgame          |
| ----------------------- |  4. Update a file
| master -> c224ff7       |
| anidea -> 884faa1       |  5. Commit (to 'anidea')
'-------------------------'

(a) - after you have pushed it
(b) - after Joe has accepted it
(c) - eventually Joe might merge 'anidea' (make 'master -> 884faa1')

Fork

  • Une copie sur votre référentiel distant (cloud) qui la relie à Joe's
  • Une copie que vous pouvez ensuite cloner sur votre dépôt local et F *% $ - up
  • Lorsque vous avez terminé, vous pouvez repousser votre télécommande
  • Vous pouvez ensuite demander à Joe s'il veut l'utiliser dans son projet en cliquant sur pull-request

Cloner

  • une copie sur votre dépôt local (disque dur)
7

Juste pour ajouter aux autres, une note spécifique à la fourche.

Il est bon de se rendre compte que techniquement, cloner le dépôt et le bricoler sont la même chose. Faire:

git clone $some_other_repo

et vous pouvez vous taper sur le dos - vous venez de fourrer un autre repo.

Git, en tant que VCS, est en fait tout à propos de clonage forking. En plus de "naviguer simplement" en utilisant une interface utilisateur distante telle que cgit, il y a très peu à voir avec le repo git qui n'implique pas bifurquer cloner le repo à un moment donné.

Cependant,

  • quand quelqu'un dit j'ai brouillé le repo X, ils veulent dire qu'ils ont créé un clone du repo quelque part avec l'intention de exposer par exemple, pour montrer des expériences ou appliquer un mécanisme de contrôle d'accès différent (par exemple, pour permettre aux personnes sans accès Github mais avec un compte interne de la société de collaborer).

    Les faits: le référentiel est probablement créé avec une commande autre que git clone, qu'il est probablement hébergé quelque part sur un serveur plutôt que sur l'ordinateur portable de quelqu'un, et a probablement un format légèrement différent (c'est un "référentiel nu", c'est-à-dire . sans arbre de travail) ne sont que des détails techniques.

    Le fait qu'il contienne très probablement un ensemble différent de branches, de balises ou de commits est probablement la raison pour laquelle ils l'ont fait en premier lieu.

    (Ce que Github fait quand vous cliquez sur "fork", c'est juste du clonage avec du sucre ajouté: il clone le repo pour vous, le met sous votre compte, enregistre le "fork de" quelque part, ajoute le nom distant "upstream", et plus important encore, joue l'animation de Nice.)

  • Quand quelqu'un dit j'ai cloné le référentiel X, ils veulent dire qu'ils ont créé un clone du référentiel localement sur leur ordinateur portable ou leur ordinateur de bureau avec l'intention de l'étudier, de jouer avec, de contribuer ou de construire quelque chose à partir des sources code dedans.

La beauté de Git, c’est que tout est parfaitement coordonné: toutes ces pensions partagent le point commun de bloquer Commutez la chaîne de sorte qu'il soit possible en toute sécurité (voir la note ci-dessous) de fusionner les modifications entre toutes ces pensions à votre guise.


Remarque: "en toute sécurité" tant que vous ne réécrivez pas la partie commune de la chaîne et que les modifications ne sont pas en conflit.

6
Alois Mahdal