Pour développer la réponse de Ben Jackson , ce qui est bien, regardons de près la question initiale. (Voir sa réponse pour savoir pourquoi taper des questions; c'est plus sur ce qui se passe .)
Je suis nouveau dans le contrôle de version et je comprends que «commettre» consiste essentiellement à créer une sauvegarde tout en mettant à jour la nouvelle version «actuelle» de ce sur quoi vous travaillez.
Ce n'est pas tout à fait vrai. Les sauvegardes et le contrôle de version sont certainement liés - la mesure exacte dépend exactement de certaines choses qui sont dans une certaine mesure une question d'opinion - mais il existe certainement des différences, ne serait-ce que dans l'intention: les sauvegardes sont généralement conçues pour la reprise après sinistre (la machine tombe en panne, le feu détruit bâtiment entier, y compris tous les supports de stockage, etc.). Le contrôle de version est généralement conçu pour des interactions plus fines et offre des fonctionnalités que les sauvegardes ne font pas. Les sauvegardes sont généralement stockées pendant un certain temps, puis jetées comme «trop anciennes»: une sauvegarde plus récente est tout ce qui compte. Le contrôle de version enregistre normalement pour toujours chaque version validée.
Ce que je ne comprends pas, c'est à quoi sert la mise en scène d'un point de vue pratique. La mise en scène est-elle quelque chose qui n'existe que de nom ou sert-elle un objectif? Quand vous vous engagez, ça va tout commettre de toute façon, non?
Oui et non. La conception de Git ici est quelque peu particulière. Il existe des systèmes de contrôle de version qui ne nécessitent pas d'étape de préparation distincte. Par exemple, Mercurial, qui ressemble beaucoup à Git en termes d'utilisation, ne nécessite pas d' hg add
étape distincte , au-delà de la toute première qui introduit un tout nouveau fichier. Avec Mercurial, vous utilisez la hg
commande qui sélectionne un commit, puis vous faites votre travail, puis vous exécutez hg commit
et vous avez terminé. Avec Git, vous utilisez git checkout
, 1 puis vous faites votre travail, puis vous exécutez git add
, et puis git commit
. Pourquoi le plusgit add
étape ?
Le secret ici est ce que Git appelle, diversement, l' index , ou la zone de transit , ou parfois - rarement de nos jours - le cache . Ce sont tous des noms pour la même chose.
Edit: Je pense que je peux confondre la terminologie. Un fichier «intermédiaire» est-il la même chose qu'un fichier «suivi»?
Non, mais ceux-ci sont liés. Un fichier suivi est celui qui existe dans l'index de Git. Pour bien comprendre l'index, il est bon de commencer par comprendre les commits.
Depuis la version 2.23 de Git, vous pouvez utiliser à la git switch
place de git checkout
. Dans ce cas particulier, ces deux commandes font exactement la même chose. La nouvelle commande existe parce qu'elle a git checkout
été surchargée de trop de choses; ils ont été divisés en deux commandes distinctes, git switch
et git restore
pour rendre l'utilisation de Git plus facile et plus sûre.
S'engage
Dans Git, un commit enregistre un instantané complet de chaque fichier que Git connaît. (Quels fichiers Git connaît-il? Nous le verrons dans la section suivante.) Ces instantanés sont stockés sous une forme spéciale, en lecture seule, Git seule, compressée et dédupliquée, qu'en général seul Git lui-même peut lire . (Il y a plus de choses dans chaque commit que juste cet instantané, mais c'est tout ce que nous allons couvrir ici.)
La déduplication aide à gagner de l'espace: nous ne modifions normalement que quelques fichiers, puis nous faisons un nouveau commit. Alors plupart des fichiers d'un commit sont pour la plupart les mêmes que les fichiers du commit précédent. En réutilisant simplement ces fichiers directement, Git économise beaucoup d'espace: si nous n'avons touché qu'un seul fichier, le nouveau commit ne prend de l'espace que pour une nouvelle copie. Même dans ce cas, il est compressé - parfois très compressé, bien que cela se produise en fait plus tard - de sorte qu'un .git
répertoire peut en fait être plus petit que les fichiers qu'il contient, une fois qu'ils sont développés en fichiers ordinaires de tous les jours. La déduplication est sûre car les fichiers validés sont figés pour toujours. Personne ne peut en changer un, il est donc sûr que les commits dépendent des copies des uns et des autres.
Cependant, étant donné que les fichiers stockés sont dans ce format spécial, figé pour toujours, uniquement Git, Git doit développer chaque fichier en une copie ordinaire de tous les jours. Cette copie ordinaire n'est pas celle de Git copie : c'est votre copie, à faire comme vous voudrez. Git écrira simplement à ceux-ci lorsque vous lui direz de le faire, afin que vous ayez vos copies avec lesquelles travailler. Ces copies utilisables se trouvent dans votre arbre de travail ou votre arbre de travail .
Cela signifie que lorsque vous extrayez un commit particulier, il y a automatiquement deux copies de chaque fichier:
Git a une copie figée pour toujours, Git-ified dans le commit actuel . Vous ne pouvez pas modifier cette copie (bien que vous puissiez bien sûr sélectionner un autre commit, ou faire un nouveau commit).
Vous avez, dans votre arbre de travail, une copie au format normal. Vous pouvez faire tout ce que vous voulez, en utilisant l'une des commandes de votre ordinateur.
D'autres systèmes de contrôle de version (dont Mercurial comme mentionné ci-dessus) s'arrêtent ici, avec ces deux exemplaires. Vous venez de modifier la copie de votre arbre de travail, puis de vous engager. Git ... pas.
L'index
Entre ces deux copies, Git stocke une troisième copie 2 de chaque fichier. Cette troisième copie est au format figé , mais contrairement à la copie figée du commit, vous pouvez la modifier. Pour le changer, vous utilisezgit add
.
La git add
commande signifie que la copie d'index du fichier correspond à la copie de l'arbre de travail . Autrement dit, vous dites à Git: Remplacez la copie dédupliquée au format gelé qui se trouve dans l'index maintenant, en compressant ma copie mise à jour de l'arbre de travail, en la dédupliquant et en la préparant à être gelée dans un nouveau commit. Si vous n'utilisezgit add
, l'index contient toujours la copie au format gelé de la validation actuelle.
Lorsque vous exécutez git commit
, Git compile tout ce qui se trouve dans l'index à ce moment-là à utiliser comme nouvel instantané. Comme il est déjà au format figé et pré-dédupliqué, Git n'a pas à faire beaucoup de travail supplémentaire.
Cela explique également ce que sont les fichiers non suivis . Un fichier non suivi est un fichier qui se trouve dans votre arbre de travail mais qui n'est pas dans l'index de Git pour le moment . Peu importe comment le dossier s'est terminé dans cet état. Peut-être que vous l'avez copié d'un autre endroit sur votre ordinateur, dans votre arbre de travail. Peut-être que vous l'avez créé ici. Il y avait peut- être une copie dans l'index de Git, mais vous avez supprimé cette copie avec git rm --cached
. D'une manière ou d'une autre, il y a une copie ici dans votre arbre de travail, mais il n'y en a pas de copie dans l'index de Git. Si vous effectuez un nouveau commit maintenant, ce fichier ne sera pas dans le nouveau commit.
Notez que remplitgit checkout
initialement l'index de Git à partir du commit que vous extrayez. Ainsi, l'index commence par correspondre au commit. Git remplit également votre arbre de travail à partir de cette même source. Donc, au départ, les trois correspondent. Lorsque vous modifiez des fichiers dans votre arbre de travail et eux, eh bien, maintenant l'index et votre arbre de travail correspondent. Alors tu coursgit add
git commit
et Git effectue un nouveau commit à partir de l'index, et maintenant les trois correspondent à nouveau.
Étant donné que Git effectue de nouveaux commits à partir de l'index, nous pouvons mettre les choses de cette façon: l'index de Git contient le prochain commit que vous prévoyez de faire. Cela ignore le rôle étendu que l'index de Git assume lors d'une fusion en conflit, mais nous aimerions quand même l'ignorer pour le moment. :-)
C'est tout ce qu'il y a à faire - mais c'est quand même assez compliqué! C'est particulièrement délicat car il n'y a pas de moyen facile de voir exactement ce qu'il y a dans l'index de Git. 3 Mais il existe une commande Git qui vous dit ce qui se passe, d'une manière assez utile, et cette commande l'est git status
.
2 Techniquement, ce n'est pas du tout une copie . Au lieu de cela, c'est une référence au fichier Git-ified, pré-dédupliqué et tout. Il y a également d'autres éléments ici, tels que le mode, le nom du fichier, un numéro de transfert et des données de cache pour accélérer Git. Mais à moins que vous ne vous mettiez à travailler avec certaines des commandes de bas niveau de Git - git ls-files --stage
et git update-index
en particulier - vous pouvez le considérer comme une copie.
3 La git ls-files --stage
commande vous montrera les noms et les numéros de transfert de chaque fichier dans l'index de Git, mais ce n'est généralement pas très utile de toute façon.
git status
La git status
commande fonctionne en fait en exécutant deux git diff
commandes distinctes pour vous (et en faisant également d'autres choses utiles, telles que vous dire sur quelle branche vous vous trouvez).
Le premier git diff
compare le commit actuel - qui, rappelez-vous, est figé pour toujours - à ce qui se trouve dans l'index de Git. Pour les fichiers identiques , Git ne dira rien du tout. Pour les fichiers différents , Git vous indiquera que ce fichier est préparé pour la validation . Cela inclut tous les nouveaux fichiers, si la validation n'a pas sub.py
en elle, mais l'indice n'avoir en elle, ce fichier est ajouté et tous les fichiers supprimés, qui étaient (et sont) dans la commettras mais ne sont pas en l'index plus (sub.py
git rm
, peut-être).
Le second git diff
compare tous les fichiers de l'index de Git aux fichiers de votre arbre de travail. Pour les fichiers identiques , Git ne dit rien du tout. Pour les fichiers différents , Git vous indiquera que ce fichier n'est pas préparé pour la validation . Contrairement à la première différence, cette liste particulière n'inclut pas les fichiers qui sont tout nouveaux: si le fichier untracked
existe dans votre arbre de travail, mais pas dans l'index de Git, Git l'ajoute simplement à la liste des fichiers non suivis . 4
À la fin, après avoir accumulé ces fichiers non suivis dans une liste, les noms de ces fichiers git status
seront également annoncés , mais il y a une exception spéciale: si le nom d'un fichier est répertorié dans un fichier, cela supprime cette dernière liste. Notez que lister un fichier suivi - celui qui est dans l'index de Git - dans un n'a aucun effet ici : le fichier est dans l'index, donc il est comparé et est validé, même s'il est répertorié dans . Le fichier ignorer ne supprime que les plaintes de "fichier non suivi". 5.gitignore
.gitignore
.gitignore
4 Lorsque vous utilisez la version courte de git status
- git status -s
, les fichiers non suivis ne sont pas aussi séparés, mais le principe est le même. Accumuler les fichiers comme celui-ci permet également de git status
résumer un tas de noms de fichiers non suivis en imprimant simplement un nom de répertoire, parfois. Pour obtenir la liste complète, utilisez git status -uall
ou git status -u
.
5 Lister un fichier permet également d' ajouter en masse de nombreuses opérations sur les fichiers comme git add .
ou de git add *
sauter le fichier non suivi. Cette partie devient un peu plus compliquée, car vous pouvez l'utiliser git add --force
pour ajouter un fichier qui serait normalement ignoré. Il existe d'autres cas spéciaux normalement mineurs, qui s'ajoutent tous à ceci: le fichier .gitignore
peut être appelé plus correctement .git-do-not-complain-about-these-untracked-files-and-do-not-auto-add-them
ou quelque chose d'aussi peu maniable. Mais c'est trop ridicule, donc .gitignore
ça l'est.
git add -u
, git commit -a
, Etc.
Il y a plusieurs raccourcis pratiques à connaître ici:
git add .
ajoutera tous les fichiers mis à jour dans le répertoire courant et tout sous-répertoire. Cela respecte .gitignore
, donc si un fichier actuellement non suivi n'est pas critiqué par git status
, il ne sera pas ajouté automatiquement.
git add -u
ajoutera automatiquement tous les fichiers mis à jour n'importe où dans votre arbre de travail . 6 Cela affecte uniquement les fichiers suivis . Notez que si vous avez supprimé la copie de l'arborescence de travail, cela supprimera également la copie d'index ( git add
cela fait-il partie de faire correspondre l'index à l'arborescence de travail ).
git add -A
est comme courir à git add .
partir du niveau supérieur de votre arbre de travail (mais voir la note de bas de page 6).
En plus de cela, vous pouvez exécuter git commit -a
, ce qui équivaut à peu près à 7 à courir git add -u
et ensuite git commit
. Autrement dit, cela vous donne le même comportement qui est pratique dans Mercurial.
Je déconseille généralement le git commit -a
modèle: je trouve qu'il vaut mieux l'utiliser git status
souvent, regardez attentivement la sortie , et si le statut n'est pas celui que vous attendiez, découvrez pourquoi c'est le cas. En utilisant git commit -a
, il est trop facile de modifier accidentellement un fichier et de valider une modification que vous n'aviez pas l'intention de valider. Mais c'est surtout une question de goût / d'opinion.
6 Si votre version de Git est antérieure à Git 2.0, soyez prudent ici: git add -u
ne fonctionne que sur le répertoire et les sous-répertoires actuels, vous devez donc d'abord monter au niveau supérieur de votre arbre de travail. L' git add -A
option a un problème similaire.
7 Je dis à peu près équivalent car git commit -a
fonctionne en fait en créant un index supplémentaire et en utilisant cet autre index pour faire le commit. Si le commit fonctionne , vous obtenez le même effet que doing git add -u && git commit
. Si le commit ne fonctionne pas - si vous obligez Git à ignorer le commit de l'une des nombreuses façons dont vous pouvez le faire - alors aucun fichier n'est git add
-ed par la suite, car Git jette l'index supplémentaire temporaire et revient à utiliser l'index principal .
Il y a des complications supplémentaires qui entrent en jeu si vous utilisez git commit --only
ici. Dans ce cas, Git crée un troisième index, et les choses deviennent très délicates, surtout si vous utilisez des hooks pré-commit. C'est une autre raison d'utiliser des git add
opérations distinctes .