Add HowtoGit
This commit is contained in:
parent
5f0e625e59
commit
3f45af4f29
394
HowtoGit.md
Normal file
394
HowtoGit.md
Normal file
|
@ -0,0 +1,394 @@
|
|||
---
|
||||
categories: git
|
||||
title: Howto Git
|
||||
...
|
||||
|
||||
* Documentation: <https://git-scm.com/doc>
|
||||
* À lire : <https://progit.org/>
|
||||
* À voir : <https://youtu.be/4XpnKHJAok8>
|
||||
|
||||
Git est un logiciel de gestion de code source, créé en 2005 par Linux Torvalds.
|
||||
|
||||
## Installation
|
||||
|
||||
~~~
|
||||
# apt install git
|
||||
~~~
|
||||
|
||||
Configuration minimum via `~/.gitconfig` :
|
||||
|
||||
~~~
|
||||
[user]
|
||||
name = Prenom Nom
|
||||
email = jdoe+git@example.com
|
||||
[pull]
|
||||
rebase = true
|
||||
[push]
|
||||
default = simple
|
||||
~~~
|
||||
|
||||
## Commandes de base
|
||||
|
||||
### Créer un dépôt
|
||||
|
||||
~~~{.bash}
|
||||
$ mkdir foo
|
||||
$ cd foo
|
||||
$ 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.
|
||||
|
||||
~~~{.bash}
|
||||
$ git clone https://git.example.com/path/projet
|
||||
$ git clone git://git.example.com/path/projet.git
|
||||
$ git clone file:///path/projet
|
||||
~~~
|
||||
|
||||
### Travailler sur un dépôt local
|
||||
|
||||
Ajouter un nouveau fichier :
|
||||
|
||||
~~~{.bash}
|
||||
$ touch main.c
|
||||
$ git add main.c
|
||||
$ git commit -v
|
||||
~~~
|
||||
|
||||
Modification d'un fichier existant :
|
||||
|
||||
~~~{.bash}
|
||||
$ vi main.c
|
||||
$ git add main.c
|
||||
$ git commit -v
|
||||
~~~
|
||||
|
||||
*Note* : on peut éviter de faire `git add` et faire uniquement `git commit -a` si l'on est sûr qu'aucun autre fichier n'a été modifié (mais c'est une mauvaise habitude que l'on déconseille).
|
||||
|
||||
Voir l'état du dépôt local (fichiers non commités, etc.) :
|
||||
|
||||
~~~{.bash}
|
||||
$ git status
|
||||
~~~
|
||||
|
||||
Voir les derniers commits du dépôt local :
|
||||
|
||||
~~~{.bash}
|
||||
$ git log
|
||||
~~~
|
||||
|
||||
### pull/pusher avec un dépôt distant
|
||||
|
||||
Si l'on a cloné un dépôt existant, un lien est automatiquement créé entre le dépôt local créé et le dépôt distant (référencé comme *origin*).
|
||||
|
||||
Pour récupérer en local les derniers changements du dépôt distant :
|
||||
|
||||
~~~{.bash}
|
||||
$ git pull --rebase origin
|
||||
~~~
|
||||
|
||||
*Note* : l'option `--rebase` est désormais le défaut mais par pédagogie on conseille de la mettre explicitement.
|
||||
|
||||
Pour envoyer ses modifications locales vers le dépôt référencé comme distant :
|
||||
|
||||
~~~{.bash}
|
||||
$ git push origin
|
||||
~~~
|
||||
|
||||
### Gestion des branches
|
||||
|
||||
Par défaut, certains outils utilisent une branche nommée *master*.
|
||||
Cette branche existe donc souvent au sein d'un dépôt, mais il faut
|
||||
garder en tête que c'est une convention, rien n'oblige en avoir une.
|
||||
|
||||
Lister les branches existantes et connaître sa branche courante :
|
||||
|
||||
~~~{.bash}
|
||||
$ git branch -a
|
||||
~~~
|
||||
|
||||
Créer une branche *myfeature* à partir de la branche *master* :
|
||||
|
||||
~~~{.bash}
|
||||
$ git checkout -b myfeature master
|
||||
~~~
|
||||
|
||||
Pour passer d'une branche à une autre dans son dépôt local :
|
||||
|
||||
~~~{.bash}
|
||||
$ git checkout myfeature
|
||||
$ git checkout master
|
||||
~~~
|
||||
|
||||
Travailler sur la branche *myfeature* puis merger son travail dans *master* :
|
||||
|
||||
~~~{.bash}
|
||||
$ git checkout master
|
||||
$ git merge --no-ff myfeature
|
||||
~~~
|
||||
|
||||
Pousser une branche locale vers le dépôt référencé comme distant :
|
||||
|
||||
~~~{.bash}
|
||||
$ git push origin myfeature
|
||||
~~~
|
||||
|
||||
Supprimer une branche locale et distante :
|
||||
|
||||
~~~{.bash}
|
||||
$ git branch -d myfeature
|
||||
$ git push origin :myfeature
|
||||
~~~
|
||||
|
||||
|
||||
## Commandes avancées
|
||||
|
||||
### 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é !
|
||||
|
||||
Modifier son dernier message de commit :
|
||||
|
||||
~~~{.bash}
|
||||
$ git commit --amend
|
||||
~~~
|
||||
|
||||
Modifier son dernier commit :
|
||||
|
||||
~~~{.bash}
|
||||
$ vi main.c
|
||||
$ git add main.c
|
||||
$ git commit --amend
|
||||
~~~
|
||||
|
||||
Modifier son avant-dernier commit :
|
||||
|
||||
~~~{.bash}
|
||||
$ git rebase -i HEAD^^
|
||||
… remplacer "pick" par "edit" pour le commit à modifier
|
||||
$ vi main.c
|
||||
$ git add main.c
|
||||
$ git commit --amend
|
||||
$ git rebase --continue
|
||||
~~~
|
||||
|
||||
*Note* : On peut remonter au Nième commit en utilisant *HEAD~N*
|
||||
|
||||
### Piquer un commit dans une autre branche
|
||||
|
||||
~~~{.bash}
|
||||
$ git cherry-pick <SHA1 du commit>
|
||||
~~~
|
||||
|
||||
### gitignore
|
||||
|
||||
Créer un fichier `.gitignore` à la racine pour ignorer certains fichiers/chemins :
|
||||
|
||||
~~~
|
||||
$ cat .gitignore
|
||||
|
||||
test.php
|
||||
htdocs/foo/bar
|
||||
toto/titi*
|
||||
~~~
|
||||
|
||||
*Note* : le fichier .gitignore se commit dans le dépôt
|
||||
|
||||
### Ranger temporairement son travail (git stash)
|
||||
|
||||
Cela permet d'avoir un buffer pour mettre "en pause" des modifications non commitées :
|
||||
|
||||
~~~{.bash}
|
||||
…hack…hack…
|
||||
$ git stash save
|
||||
~~~
|
||||
|
||||
On peut lister ce buffer :
|
||||
|
||||
~~~{.bash}
|
||||
$ git stash list
|
||||
stash@{0}: WIP on dev: fb1fa70… m
|
||||
stash@{1}: WIP on dev: fb1fa70… m
|
||||
~~~
|
||||
|
||||
Et ré-appliquer les modifications stockées :
|
||||
|
||||
~~~{.bash}
|
||||
$ git stash apply stash@{0}
|
||||
~~~
|
||||
|
||||
Pour purger le buffer sans l'appliquer :
|
||||
|
||||
~~~{.bash}
|
||||
$ git stash clear
|
||||
~~~
|
||||
|
||||
### 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 :
|
||||
|
||||
~~~{.bash}
|
||||
$ git format-patch -3
|
||||
~~~
|
||||
|
||||
Si l'on a ces 3 patches, on peut les appliquer sur son dépôt local ainsi :
|
||||
|
||||
~~~{.bash}
|
||||
$ git am 000*.patch
|
||||
~~~
|
||||
|
||||
## Workflow de travail
|
||||
|
||||
Il existe plusieurs workflows possibles en travaillant avec Git.
|
||||
|
||||
### Le modèle Git branching
|
||||
|
||||
Voir <http://nvie.com/posts/a-successful-git-branching-model/>
|
||||
|
||||
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.
|
||||
|
||||
## Astuces diverses
|
||||
|
||||
### Partager un dépôt avec plusieurs utilisateurs
|
||||
|
||||
Avec un dépôt *foo* existant, on autorisera les utilisateurs que si ils appartiennent au groupe *git* :
|
||||
|
||||
~~~
|
||||
# cd foo
|
||||
# git config core.sharedRepository group
|
||||
# addgroup git
|
||||
# chgrp -R git .
|
||||
# chmod g=rwXs,o= -R .
|
||||
# chmod g=rwX -R . # astuce pour garder le +s sur les répertoires
|
||||
~~~
|
||||
|
||||
### Importer un dépôt SVN dans GIT
|
||||
|
||||
Ce script permet de récupérer la liste des auteurs SVN, modifiez la comme voulu.
|
||||
|
||||
~~~{.bash}
|
||||
#!/usr/bin/env bash
|
||||
authors=$(svn log -q | grep -e '^r' | awk 'BEGIN { FS = "|" } ; { print $2 }' | sort | uniq)
|
||||
for author in ${authors}; do
|
||||
echo "${author} = Prenom Nom <jdoe@example.com>";
|
||||
done
|
||||
~~~
|
||||
|
||||
On lance ensuite la commande suivante :
|
||||
|
||||
~~~{.bash}
|
||||
$ git svn --authors-file=path/to/authors_file clone svn+ssh://svn.example.com/path/to/repo
|
||||
~~~
|
||||
|
||||
### Importer un dépôt CVS dans GIT
|
||||
|
||||
Lancer la commande suivante :
|
||||
|
||||
~~~{.bash}
|
||||
$ git cvsimport -C repo_git -r cvs -k -vA path/to/authors_file -d user@hostname:/path/to/cvsroot repo
|
||||
~~~
|
||||
|
||||
### Convertir un dépôt en utf8
|
||||
|
||||
Créer un fichier exécutable dans `/tmp/recode-all-files` :
|
||||
|
||||
~~~{.bash}
|
||||
#!/bin/sh
|
||||
find . -type f -print | while read f; do
|
||||
mv -i "$f" "$f.recode.$$"
|
||||
iconv -f iso-8859-1 -t utf-8 < "$f.recode.$$" > "$f"
|
||||
rm -f "$f.recode.$$"
|
||||
done
|
||||
~~~
|
||||
|
||||
Puis exécuter la commande suivante dans votre dépôt :
|
||||
|
||||
~~~{.bash}
|
||||
$ git filter-branch --tree-filter /tmp/recode-all-files HEAD
|
||||
~~~
|
||||
|
||||
Exécuter ensuite la commande suivante pour convertir les messages de commit :
|
||||
|
||||
~~~{.bash}
|
||||
$ git filter-branch --msg-filter 'iconv -f iso-8859-1 -t utf-8' -- --all
|
||||
~~~
|
||||
|
||||
### Push vers un non-bare repository
|
||||
|
||||
Ceci est évidemment déconseillé, car cela mettra aussi à jour les fichiers, ce qui nécessite
|
||||
de faire un `git reset --hard`. Mais si l'on veut tout de même le forcer :
|
||||
|
||||
~~~
|
||||
$ git push
|
||||
Counting objects: 7, done.
|
||||
Delta compression using up to 4 threads.
|
||||
Compressing objects: 100% (4/4), done.
|
||||
Writing objects: 100% (4/4), 618 bytes, done.
|
||||
Total 4 (delta 3), reused 0 (delta 0)
|
||||
Unpacking objects: 100% (4/4), done.
|
||||
remote: error: refusing to update checked out branch: refs/heads/master
|
||||
remote: error: By default, updating the current branch in a non-bare repository
|
||||
remote: error: is denied, because it will make the index and work tree inconsistent
|
||||
remote: error: with what you pushed, and will require 'git reset --hard' to match
|
||||
remote: error: the work tree to HEAD.
|
||||
remote: error:
|
||||
remote: error: You can set 'receive.denyCurrentBranch' configuration variable to
|
||||
remote: error: 'ignore' or 'warn' in the remote repository to allow pushing into
|
||||
remote: error: its current branch; however, this is not recommended unless you
|
||||
remote: error: arranged to update its work tree to match what you pushed in some
|
||||
remote: error: other way.
|
||||
remote: error:
|
||||
remote: error: To squelch this message and still keep the default behaviour, set
|
||||
remote: error: 'receive.denyCurrentBranch' configuration variable to 'refuse'.
|
||||
! [remote rejected] master -> master (branch is currently checked out)
|
||||
~~~
|
||||
|
||||
Il faut ajouter dans la config du repository "distant" :
|
||||
|
||||
~~~
|
||||
[receive]
|
||||
denyCurrentBranch = warn
|
||||
~~~
|
||||
|
||||
### Transformer un non-bare repository en bare repository
|
||||
|
||||
Il suffit de supprimer tous les fichiers sauf le .git, par exemple :
|
||||
|
||||
~~~{.bash}
|
||||
$ rm -rf *
|
||||
~~~
|
||||
|
||||
Puis d'indiquer dans la config du repository :
|
||||
|
||||
~~~
|
||||
bare = true
|
||||
~~~
|
||||
|
||||
### Mettre en place des notifications de push
|
||||
|
||||
Sous Debian, pour envoyer des notifications par email à git@example.com :
|
||||
|
||||
~~~
|
||||
# chmod a+x /usr/share/doc/git-core/contrib/hooks/post-receive-email
|
||||
$ cd /path/path/to/your/repository.git
|
||||
$ ln -sf /usr/share/doc/git-core/contrib/hooks/post-receive-email hooks/post-receive
|
||||
$ git hooks.mailinglist git@example.com
|
||||
~~~
|
||||
|
||||
Pour recevoir les patches :
|
||||
|
||||
~~~{.bash}
|
||||
$ git config hooks.showrev "git show -C %s; echo
|
||||
~~~
|
||||
|
||||
### Ignorer les vérifications SSL
|
||||
|
||||
~~~{.basb}
|
||||
$ git config --global http.sslverify "false"
|
||||
~~~
|
||||
|
||||
|
Loading…
Reference in a new issue