Git
Cette réponse inclut GitHub, car de nombreuses personnes ont également posé des questions à ce sujet.
Référentiels locaux
Git possède (localement) un répertoire ( .git
) dans lequel vous livrez vos fichiers et qui constitue votre "référentiel local". C'est différent des systèmes comme SVN où vous ajoutez et livrez immédiatement vos fichiers au dépôt distant.
Git enregistre chaque version d'un fichier qui change en sauvegardant le fichier entier. Il est également différent de SVN à cet égard, car vous pouvez accéder à n'importe quelle version individuelle sans la "recréer" par des changements delta.
Git ne "verrouille" pas du tout les fichiers et évite ainsi la fonctionnalité de "verrouillage exclusif" pour une modification (les anciens systèmes comme pvcs viennent à l'esprit), de sorte que tous les fichiers peuvent toujours être modifiés, même lorsqu'ils sont hors ligne. Il fait un travail remarquable en fusionnant les modifications de fichiers (dans le même fichier !) pendant les pulls ou les fetches/pushes vers un dépôt distant tel que GitHub. La seule fois où vous devez effectuer des modifications manuelles (en éditant réellement un fichier) est si deux modifications impliquent la ou les mêmes lignes de code.
Branches
Les branches vous permettent de conserver le code principal (la branche "maître"), d'en faire une copie (une nouvelle branche), puis de travailler dans cette nouvelle branche. Si le travail prend un certain temps ou si la branche principale reçoit de nombreuses mises à jour depuis la création de la branche, il faut alors procéder à une fusion ou à un rebasage (souvent préféré pour un meilleur historique et une résolution plus facile des conflits) par rapport à la branche principale. Lorsque vous avez terminé, vous fusionnez les changements effectués dans la branche vers le référentiel maître. De nombreuses organisations utilisent des branches pour chaque élément de travail, qu'il s'agisse d'une fonctionnalité, d'un bogue ou d'un élément de corvée. D'autres organisations n'utilisent les branches que pour les changements majeurs tels que les mises à niveau de version.
Embranchement : Avec une branche, vous contrôlez et gérez la branche, alors qu'avec un embranchement, quelqu'un d'autre contrôle l'acceptation du code en retour.
De manière générale, il existe deux approches principales pour faire des branches. La première consiste à conserver la plupart des changements sur la branche maîtresse, en n'utilisant les branches que pour des choses plus importantes et plus longues, comme les changements de version, où vous voulez avoir deux branches disponibles pour des besoins différents. La seconde consiste à créer une branche pour chaque demande de fonctionnalité, correction de bogue ou corvée, puis à décider manuellement quand fusionner ces branches dans la branche maîtresse principale. Bien que cela semble fastidieux, il s'agit d'une approche courante et c'est celle que j'utilise et recommande actuellement parce que cela permet de garder la branche principale plus propre et c'est la branche principale que nous promouvons en production, donc nous ne voulons que du code complet et testé, via le rebasement et la fusion des branches.
La manière standard d'amener une branche vers master 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".
En gros, l'idée est que vous vous ramifiez à partir d'un certain point (généralement à partir de master). Depuis que vous vous êtes branché, "master" lui-même a évolué à partir 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 toutes les modifications que vous avez faites dans une branche sont comparées à l'état actuel de master avec toutes ses dernières modifications. Le processus est donc le suivant : sauvegarder les modifications, obtenir le "nouveau" master, puis réappliquer (c'est la partie rebase) les modifications par rapport à celui-ci. Sachez que le rebasement, 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 rebasez que si la branche est locale et que vous ne l'avez pas encore poussée vers remote !
Ceci est principalement dû au fait que le rebasement peut modifier l'historique que les autres personnes voient, ce qui peut inclure leurs propres commits.
Suivi des branches
Ce sont les branches qui sont nommées origin/branch_name
(par opposition à branch_name
). Lorsque vous poussez et tirez le code vers/depuis des dépôts 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 va d'abord à origin/building_groups
et ensuite ça va dans le référentiel distant. De même, si vous faites un git fetch building_groups
le fichier récupéré est placé dans le dossier de l'utilisateur. origin/building_groups
branche. Vous pouvez ensuite choisir de fusionner cette branche avec votre copie locale. Notre pratique est de toujours faire une git fetch
et une fusion manuelle plutôt qu'une simple git pull
(qui fait les deux choses ci-dessus en une seule étape).
Récupérer les 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 le serveur distant, il doit y avoir un moyen de "connaître" ces branches et leurs noms afin de pouvoir les récupérer localement. Ceci est fait via un git fetch
qui récupérera toutes les branches nouvelles et modifiées dans le dépôt local en utilisant les branches de suivi (par exemple, origin/
). Une fois que fetch
ed, on peut git branch --remote
pour lister les branches de suivi et git checkout [branch]
pour passer à l'une d'entre elles.
Fusionner
La fusion est le processus qui consiste à combiner des modifications de code provenant de différentes branches, ou de différentes versions de la même branche (par exemple lorsqu'une branche locale et une branche distante ne sont pas synchronisées). Si l'on a développé un travail dans une branche et que ce travail est complet, prêt et testé, on peut alors le fusionner dans la branche master
branche. Pour ce faire, il faut git checkout master
pour passer à la master
branche, alors git merge your_branch
. La fusion permettra de rassembler tous les différents fichiers et même des modifications différentes des mêmes fichiers ensemble. Cela signifie qu'il va réellement modifier le code à l'intérieur des fichiers pour fusionner toutes les modifications.
Lorsque vous faites le checkout
de master
il est également recommandé de faire un git pull origin master
pour obtenir la toute dernière version du master distant fusionnée dans votre master local. Si le master distant a changé, c'est-à-dire, moved forward
vous verrez des informations qui reflètent qu'au cours de cette période. git pull
. Si tel est le cas (le maître a changé), il vous est conseillé de git checkout your_branch
et ensuite rebase
vers master afin que vos modifications soient effectivement "rejouées" sur le "nouveau" master. Vous pouvez ensuite continuer à mettre à jour le master comme indiqué dans le paragraphe suivant.
S'il n'y a pas de conflits, les nouvelles modifications seront ajoutées dans le master. S'il y a des conflits, cela signifie que les mêmes fichiers ont des changements autour de lignes de code similaires qu'il ne peut pas fusionner automatiquement. Dans ce cas git merge new_branch
signalera qu'il y a un ou plusieurs conflits à résoudre. Vous les "résolvez" en éditant les fichiers (qui contiendront les deux modifications), en sélectionnant les modifications que vous voulez, en supprimant littéralement les lignes des modifications que vous ne voulez pas, puis en enregistrant le fichier. Les modifications sont marquées par des séparateurs tels que ========
y <<<<<<<<
.
Une fois que vous aurez résolu tous les conflits, vous pourrez à nouveau git add
y git commit
ces changements pour continuer la fusion (vous recevrez un retour de git pendant 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 choses.
Rebasage interactif et écrasement / réorganisation / suppression de commits
Si vous avez effectué un travail en plusieurs petites étapes, par exemple si vous livrez du code en tant que "travail en cours" tous les jours, vous pouvez vouloir "écraser" ces nombreuses petites livraisons en quelques livraisons plus importantes. Cela peut être particulièrement utile lorsque vous voulez faire des revues de code avec des collègues. Vous ne voulez pas rejouer toutes les "étapes" que vous avez suivies (via les commits), vous voulez juste dire voici l'effet final (diff) de toutes mes modifications pour ce travail en un seul commit.
Le facteur clé à évaluer pour savoir s'il faut le faire est de savoir si les multiples commits concernent le même fichier ou les fichiers plus d'une fois (mieux vaut écraser les commits dans ce cas). Ceci est fait avec l'outil interactif de rebasage. Cet outil vous permet d'écraser des commits, de supprimer des commits, de reformuler des messages, etc. Par exemple, git rebase -i HEAD~10
( note : c'est un ~
et non un -
) donne les résultats suivants :
Soyez toutefois prudent et utilisez cet outil " avec précaution ". Faites un seul écrasement/suppression/réorganisation à la fois, quittez et sauvegardez ce commit, puis relancez l'outil. Si les commits ne sont pas contigus, vous pouvez les réordonner (et ensuite les écraser si nécessaire). Vous pouvez également supprimer des commits ici, mais vous devez vraiment être sûr de ce que vous faites lorsque vous le faites !
Fourchettes
Il existe deux approches principales de la collaboration dans les dépôts Git. La première, décrite ci-dessus, se fait directement via des branches que les gens tirent et poussent de/vers. Ces collaborateurs ont leurs clés SSH enregistrées avec le dépôt distant. Cela leur permettra de pousser directement vers ce dépôt. L'inconvénient est que vous devez maintenir la liste des utilisateurs. L'autre approche - la bifurcation - permet à quiconque de "bifurquer" le dépôt, c'est-à-dire d'en faire une copie locale dans son propre compte de dépôt Git. Il peut alors apporter des modifications et, une fois celles-ci terminées, envoyer une "demande de retrait" (en réalité, il s'agit plutôt d'une "poussée" de sa part et d'une demande de "retrait" pour le responsable actuel du dépôt) pour faire accepter le code.
Cette deuxième méthode, utilisant les fourches, fait no demander à quelqu'un de maintenir une liste d'utilisateurs pour le référentiel.
GitHub
GitHub (un dépôt distant) est une source distante vers laquelle vous poussez et tirez normalement les modifications apportées si vous disposez d'un tel dépôt (ou si vous êtes ajouté à celui-ci). Une autre façon de penser à un dépôt distant est qu'il est un .git
structure de répertoire qui se trouve sur un serveur distant.
Lorsque vous "fork", vous pouvez cliquer sur ce bouton dans l'interface graphique du navigateur web de GitHub. - 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 regarder sous quel dépôt une base de code est listée - soit le propriétaire original, soit "forked from" et vous, par exemple, comme ceci :
Une fois que vous avez la copie locale, vous pouvez apporter des modifications comme vous le souhaitez (en les tirant et en les poussant sur une machine locale). Lorsque vous avez terminé, vous soumettez une "demande de téléchargement" au propriétaire/administrateur du dépôt d'origine (cela peut sembler compliqué, mais en fait, il suffit de cliquer sur ce lien : ) et ils le "tirent" vers l'intérieur.
Pour une équipe travaillant ensemble sur du code, il est plus courant de "cloner" le dépôt (cliquez sur l'icône "copier" sur l'écran principal du dépôt). Ensuite, tapez localement git clone
et coller. Cela vous permettra de vous installer 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 dépôt. Lorsque vous avez un dépôt distant, vous émettez la commande git clone
contre son URL et vous obtenez alors une copie locale, ou clone, du référentiel. Ce clone a tout Il s'agit d'un clone, des fichiers, de la branche principale, des autres branches, de tous les commits existants, de tout le reste. C'est sur ce clone que vous effectuez vos ajouts et vos commits, puis c'est sur le dépôt distant lui-même que vous poussez ces commits. C'est ce concept local/à distance qui fait de Git (et des systèmes similaires comme Mercurial) un DVCS ( Distribué Système de contrôle de version) par opposition aux CVS (systèmes de gestion de version de code) plus traditionnels tels que SVN, PVCS, CVS, etc. où vous livrez directement au dépôt distant.
Visualisation
La visualisation des concepts de base peut être vue à l'adresse suivante
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 changements fonctionnent, vous ne pouvez pas battre l'outil visuel. gitg
( gitx
pour macOS) avec une interface graphique que j'appelle "le plan du métro" (en particulier le métro de Londres), idéal pour montrer qui a fait quoi, comment les choses changent, divergent et fusionnent, etc.
Vous pouvez également l'utiliser pour ajouter, valider et gérer vos modifications !
Bien que gitg/gitx soit assez minimal, le nombre d'outils d'interface graphique continue de croître. De nombreux utilisateurs de Mac utilisent le fork de gitx de brotherbard et pour Linux, une excellente option est smart-git avec une interface intuitive mais puissante :
Notez que même avec un outil GUI, vous ferez probablement beaucoup de commandes à la ligne de commande.
Pour ce faire, j'ai les alias suivants dans mon fichier ~/.bash_aliases
(qui est appelé à partir de mon fichier ~/.bashrc
pour chaque session du 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 git" suivants dans mon fichier ~/.gitconfig
dossier - pourquoi en avoir ?
Ainsi, la complétion des branches (avec la touche TAB) fonctionne !
C'est le cas :
[alias]
co = checkout
cob = checkout -b
Exemple d'utilisation : git co [branch]
<- la complétion de tabulation pour les branches fonctionnera.
Outil d'apprentissage GUI
Vous pouvez trouver https://learngitbranching.js.org/ utile pour apprendre certains des concepts de base. Capture d'écran :
Vidéo : https://youtu.be/23JqqcLPss0
Enfin, 7 clés qui sauvent la vie !
-
Vous faites des changements, les ajoutez et les committez (mais ne poussez pas) et puis oh ! vous réalisez que vous êtes dans master !
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 !
-
Vous avez endommagé des fichiers pendant que vous travailliez dans une branche locale et vous voulez simplement revenir à ce que vous aviez la dernière fois que vous avez fait un git pull
:
git reset --hard origin/master # You will need to be comfortable doing this!
-
Vous commencez à faire des changements localement, vous éditez une demi-douzaine de fichiers et puis, oh merde, vous êtes toujours dans la branche maître (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
-
Vous perturbez un fichier particulier dans votre branche actuelle et vous voulez essentiellement "réinitialiser" ce fichier (perdre les modifications) à la façon dont il était la dernière fois que vous l'avez extrait du référentiel distant :
git checkout your/directories/filename
Cette commande réinitialise en fait le fichier (comme beaucoup de commandes Git, elle n'est pas bien nommée pour ce qu'elle fait ici).
-
Vous effectuez des modifications localement, vous voulez être sûr de ne pas les perdre lorsque vous faites une git reset
ou rebase
: Je fais souvent une copie manuelle de l'ensemble du projet ( cp -r ../my_project ~/
) lorsque je ne suis pas sûr de ne pas faire d'erreur dans Git ou de perdre des modifications importantes.
-
Vous rebasez mais les choses se gâtent :
git rebase --abort # To abandon interactive rebase and merge issues
-
Ajoutez votre branche Git à votre PS1
(voir https://unix.stackexchange.com/a/127800/10043 ), par exemple
La branche est selenium_rspec_conversion
.
21 votes
Pouvez-vous changer la réponse acceptée pour qu'elle soit celle de Michael Durrant ?
11 votes
Il a bien sûr peut mais cela doit être son choix, et franchement la plupart des gens qui arrivent ici (comme moi) veulent quelque chose de plus concis, exactement comme la réponse qu'il a choisie, qui à ce moment-là était celle de vous-même =)