22
0
Fork 0

Hop, je complète la doc actuelle avec des notes prises ces dernières années.

This commit is contained in:
Gregory Colpart 2016-12-18 00:07:01 +01:00
parent 9e64416d71
commit 23cf0b0e6d
1 changed files with 274 additions and 3 deletions

View File

@ -39,9 +39,10 @@ $ git init
### Cloner un dépôt
Plusieurs méthodes d'accès pour récupérer un dépôt : HTTP(S), Git, file.
Plusieurs méthodes d'accès pour récupérer un dépôt : SSH, HTTP(S), Git, file.
~~~{.bash}
$ git clone ssh://git.example.com/path/projet.git
$ git clone https://git.example.com/path/projet
$ git clone git://git.example.com/path/projet.git
$ git clone file:///path/projet
@ -112,7 +113,7 @@ $ git branch -a
Créer une branche *myfeature* à partir de la branche *master* :
~~~{.bash}
$ git checkout -b myfeature master
$ git checkout myfeature master
~~~
Pour passer d'une branche à une autre dans son dépôt local :
@ -145,6 +146,59 @@ $ git push origin :myfeature
## Commandes avancées
### Afficher l'historique
Affichage de l'historique de différentes façons :
~~~{.bash}
$ git log
$ git log -p
$ git log --stat
$ git log --summary
$ git log --color
$ git log --graph
$ git log --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset'
~~~
On peut notamment combiner toutes ces options dans un alias à mettre dans `.gitconfig` :
~~~
[alias]
log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset'
~~~
On peut aussi utiliser *whatchanged* qui va lister tout ce qui a changé :
~~~{.bash}
$ git whatchanged
$ git whatchanged -p
~~~
Pour voir un commit (par exemple l'avant-dernier) :
~~~{.bash}
$ git show HEAD~1
~~~
Pour voir le fichier *foo/bar* tel qu'il était dans un commit (par exemple l'avant-dernier) :
~~~{.bash}
$ git show HEAD~1:foo/bar
~~~
Pour voir ce qu'il s'est passé entre deux commits :
~~~{.bash}
$ git show HEAD~8..HEAD
$ git show -p HEAD~8..HEAD
~~~
On peut voir graphiquement l'historique avec différents outils :
~~~
# apt install gitk gitg
$ gitk --all
~~~
### Modifier l'historique
/!\\ Les modifications de l'historique ne doivent avoir lieu que si il n'a pas déjà été pushé vers un dépôt partagé !
@ -176,7 +230,7 @@ $ git rebase --continue
*Note* : On peut remonter au Nième commit en utilisant *HEAD~N*
### Piquer un commit dans une autre branche
### Picorer un commit d'une autre branche (cherry-pick)
~~~{.bash}
$ git cherry-pick <SHA1 du commit>
@ -225,6 +279,159 @@ Pour purger le buffer sans l'appliquer :
$ git stash clear
~~~
### git diff
Voir les modifications locales non commitées et non stagées :
~~~{.bash}
$ git diff
~~~
Voir les modifications locales *stagées* (avec *git add*) :
~~~{.bash}
$ git diff --staged
~~~
Voir les modifications entre deux commits, ou entre deux branches :
~~~{.bash}
$ git diff HEAD~8..HEAD^^
$ git diff myfeature..master
~~~
### git fetch/pull
`git pull` est une commande qui effectue un rappatriement des données (`git fetch`) puis l'intégration de ces données via `git rebase` (par défaut) ou `git merge`.
Dans certains cas il est pratique de faire un simple `git fetch`, notamment si l'on veut faire des manipulations complexes ou si l'on veut avoir toutes les données pour travailler hors ligne sans rien changer à l'état actuel de sa *working copy*.
### git push
Pour pousser toutes ses branches d'un coup (déconseillé) :
~~~{.bash}
$ git-push --all origin
~~~
Si l'on a une branche local nommée *foo* et que l'on veut la pousser dans la branche *bar* du dépôt distant :
~~~{.bash}
$ git push origin foo:bar
~~~
/!\\ Attention, il ne faut jamais modifier un historique qui a été pushé vers un dépôt partagé. Néanmoins dans certaines situations exceptionnelles (un mot de passe ou un email qui aurait été mis par erreur) on peut être amené à faire un `push --force` :
~~~{.bash}
$ git push -f origin
~~~
Il faudra ensuite que chaque utilisateur fasse confiance (ou vérifie) les modifications d'historiques puis acceptent d'écraser leur dépôt local :
~~~{.bash}
$ git fetch
$ git reset origin
~~~
### git branch
Pour créer une branche et switcher directement dans cette nouvelle branche, on utilise l'option `-b` :
~~~{.bash}
$ git branch -b myfeature master
~~~
Une branche est en fait la création une déviation, un commit qui a deux *enfants*.
On peut ainsi créer une branche à partir de n'importe quel commit :
~~~{.bash}
$ git branch newbranch e150b8517a694a2d4816cff95ef612086d644f67
~~~
Pour supprimer la branche *foo* sur un dépôt distant non cloné :
~~~{.bash}
$ git push ssh://git.example.com/projet.git :foo
~~~
Pour récupérer une nouvelle branche depuis le dépôt référencé comme distant :
~~~{.bash}
$ git remote update
~~~
### git clean/reset
/!\\ Certaines commandes peuvent provoquer une perte de données !
Pour supprimer toutes les modifications non commitées et les fichiers/répertoires non trackés :
~~~{.bash}
$ git reset --hard
$ git clean -f -d
~~~
On peut aussi `git reset` sur des commits précédents (*HEAD^*,*HEAD~N*,*<SHA1>*).
Ou même sur une branche distante comme *origin/master* par exemple (pratique si l'historique de la branche distante a été modifié).
### git add
Pour ajouter tout un répertoire et son contenu :
~~~{.bash}
$ git add foo/
~~~
Pour choisir ce que l'on veut ajouter pour le prochain commit :
~~~{.bash}
$ git add -p
~~~
### git merge
Un merge consiste à créer un commit qui aura deux parents, et permet ainsi de fusionner deux branches existantes.
Quand un merge est très simple, c'est à dire que cela rajoute simplement des commits sur une branche qui n'a pas bougé entre temps, on n'a même pas besoin de créer un commit pour fusionner, on appelle cela un merge **fast-forward**. Cela se fait automatiquement avec la commande `git merge`. Notons que l'on peut vouloir tout de même avoir un commit pour marquer le coup, et forcer un commit de merge avec l'option `git merge --no-ff`.
Quand un merge n'est pas simple, Git peut adopter plusieurs stratégies (resolve, recursive, ours, theirs, patience, etc.). Il est probable que cela génère des conflits qui devront être résolus manuellement.
### git apply
`git apply` permet d'appliquer un diff.
On peut utiliser une option pour exclure l'application de certain fichier du diff :
~~~{.bash}
$ git apply --exclude=debian/changelog /tmp/foo.diff
~~~
### git blame
Pour voir qui a modifié les lignes d'un fichier *foo/bar* :
~~~{.bash}
$ git blame foo/bar
~~~
### .git/config
La configuration d'un dépôt se trouve dans le fichier `.git/config`
On peut éditer ce fichier ou utiliser des commandes pour le faire.
Pour ajouter un dépôt distant :
~~~{.bash}
$ git remote add origin2 ssh://git.example.com/path/projet.git
~~~
Pour lister les dépôts distants configurés :
~~~{.bash}
$ git remote
~~~
### Echanger des commits sous forme de patchs Git
Pour transmettre ses 3 derniers commits, on peut générer 3 patches qui contiendront les diffs ainsi que les messages de commit :
@ -239,6 +446,25 @@ Si l'on a ces 3 patches, on peut les appliquer sur son dépôt local ainsi :
$ git am 000*.patch
~~~
### hooks
On peut gérer des hooks à différents moments (pre-commit, post-commit, pre-push, post-push, etc.),
par exemple pour générer des emails de notification.
Voir dans le répertoire `.git/hooks/`.
### dépôt "bare"
Un dépôt classique possède un répertoire `.git/` qui contient toutes les données et meta-données, ainsi qu'une *working copy* de la branche courante.
Quand on crée un dépôt ayant vocation à servir de dépôt central, il est préférable de ne pas avoir de *working copy* : il s'agira alors d'un **bare repository** que l'on peut initier avec la commande :
~~~{.bash}
$ mkdir foo
$ cd foo
$ git init --bare
~~~
## Workflow de travail
Il existe plusieurs workflows possibles en travaillant avec Git.
@ -251,6 +477,31 @@ L'idée est de ne jamais toucher à *master*, sauf hotfixes.
Pour le reste on le fait dans *dev*.
Et pour les grosses features on le fait dans une branche, nommée avec le nom de la feature.
## Plomberie
<https://git-scm.com/book/fr/Git-Commands-Plumbing-Commands>
La plomberie de Git consiste à réaliser des commandes bas niveau
manipulant tout ce qui se trouve dans le répertoire `.git/` d'un dépôt.
Les données brutes sont dans le répertoires `.git/objects/` qui contient
de nombreux fichiers : à chaque commit correspond fichier nommé en fonction
de l'empreinte SHA1 du commit et contenant les données compressées.
Les données comprennent notamment la référence au(x) commit(s) *parent*
ce qui permet de d'avoir des liens entre les commits.
Observons `.git/refs/` qui contient des pseudos-pointeurs (fichier contenant un SHA1 ou une autre référence) :
- un tag est simplement un pointeur vers un commit ;
- une branche est également un pointeur vers un commit, la différence est qu'il se déplace à chaque nouveau commit dans la branche ;
Directement dans `.git/` on a également *HEAD* (et *FETCH_HEAD*, *ORIG_HEAD*) qui sont aussi des pseudo-pointeurs, qui changent notamment quand on change de branche ou pendant un *rebase*.
Si l'on veut mettre à jour ces pseudo-pointeurs, il faut utiliser `git update-ref`.
Observons `.git/logs/` qui contient l'historique de ce qui a été fait dans le dépôt.
Cet historique est notamment accessible avec la commande `git reflog`.
## Astuces diverses
### Partager un dépôt avec plusieurs utilisateurs
@ -292,6 +543,14 @@ Lancer la commande suivante :
$ git cvsimport -C repo_git -r cvs -k -vA path/to/authors_file -d user@hostname:/path/to/cvsroot repo
~~~
### Importer un dépôt Arch dans GIT
Lancer la commande suivante :
~~~{.bash}
$ git-archimport -v foo@arch.example.com--branch
~~~
### Convertir un dépôt en utf8
Créer un fichier exécutable dans `/tmp/recode-all-files` :
@ -391,4 +650,16 @@ $ git config hooks.showrev "git show -C %s; echo
$ git config --global http.sslverify "false"
~~~
### Nettoyage d'un dépôt Git
Quand on supprime des commits, ils ne sont pas vraiment supprimés du dépôt.
Cela offre l'avantage de pouvoir les retrouver en cas de besoin.
Si l'on veut gagner de la place, on peut aussi faire un nettoyage :
~~~{.bash}
$ git repack
$ git gc
~~~