Git, premiers pas

Créer un dépôt

Créez un répertoire vide et allez dedans :
mkdir git-tests
cd git-tests

Créer un dépôt vide

Si on fait :
git init
git va initialiser un dépôt dans le répertoire courant.

Comme on va travailler avec plusieurs dépôts, on va plutôt créer un dépôt dans un sous-répertoire :
git init repo1
Cette instruction crée un dosssier repo1/ ET initialise un dépôt dans ce dossier.

Mais git refuse de créer un dépôt sans un minimum de configuration (voir paragraphe suivant).
Donc avant de créer un dépôt, faire (en adaptant à vos données) :
git config --global user.name "My name"
git config --global user.email "email@example.org"
Il est maintenant possible de créer le dépôt avec git init repo1.

En listant les fichiers cachés, on voit qu'un répertoire repo1/.git/ a été créé :
ls -a repo1/
.git
Cest dans ce répertoire caché que git va gérer toute l'historique du dépôt.

Cloner un dépôt distant

# Crée un répertoire cours-millau/ et clone le dépôt distant dedans.
git clone https://github.com/tig12/cnam-2isa.git cours-millau

Cloner un dépôt local

Le chemin indiqué à clone peut être une uri distante ou un chemin local, relatif ou absolu.
# en étant toujours dans git-tests :
git clone repo1 clone-repo1

# exactement pareil que
mkdir clone-repo1
cd clone-repo1
git clone ../repo1

.gitignore

git utilise un fichier nommé .gitignore pour exclure du versionnage certains fichiers.
La documentation de référence peut s'obtenir en tapant git help gitignore ; version web de cette doc sur git-scm.com/docs/gitignore.
Il existe de nombreuses pages documentant .gitignore, par exemple help.github.com/articles/ignoring-files/.

Config

git contient 3 niveaux de configuration : Les options system-wide peuvent être overridées par les options user-wide, qui peuvent elles-mêmes être overridées par les options locales.

Les options de configuration de niveau local sont stockées dans .git/config.
L'endroit où sont stockées les autres options dépendent du système d'exploitation.

git config permet de gérer les options de configuration.
# lister les options de git config:
git config --list

# afficher le man complet :
git help config

# Lister la valeur des options :
git config --list

# Lister la valeur des options en précisant où elles sont stockées :
git config --list --show-origin
Exemples de résultat :
git config --list --show-origin

###
### Config pour tous les dépôts git locaux de l'utilisateur (unix ou windows) courant
###
file:/home/user1/.gitconfig	user.name=User1
file:/home/user1/.gitconfig	user.email=user1@example.com
file:/home/user1/.gitconfig	core.editor=vim
file:/home/user1/.gitconfig	core.pager=cat
file:/home/user1/.gitconfig	core.quotepath=false
file:/home/user1/.gitconfig	core.ignorecase=false
file:/home/user1/.gitconfig	merge.tool=meld
file:/home/user1/.gitconfig	color.ui=true
file:/home/user1/.gitconfig	alias.s=status
file:/home/user1/.gitconfig	alias.st=status -uall
file:/home/user1/.gitconfig	alias.ci=commit
file:/home/user1/.gitconfig	alias.cia=commit -am
file:/home/user1/.gitconfig	alias.slog=log -15 --graph --abbrev-commit --decorate --date=iso --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ad)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(bold yellow)%d%C(reset)
' --all
file:/home/user1/.gitconfig	alias.br=branch
file:/home/user1/.gitconfig	alias.bl=show-branch --list
file:/home/user1/.gitconfig	alias.co=checkout
file:/home/user1/.gitconfig	push.default=simple

###
### Config spécifique au dépôt courant
###
file:.git/config	core.repositoryformatversion=0
file:.git/config	core.filemode=true
file:.git/config	core.bare=false
file:.git/config	core.logallrefupdates=true
file:.git/config	remote.origin.url=ssh://user1@my-git-host.org/path/to/repo/repo-name.git
file:.git/config	remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
file:.git/config	branch.main.remote=origin
file:.git/config	branch.main.merge=refs/heads/main
Dans l'exemple précédent, remarquer les alias ; cette syntaxe est parfois utilisée dans la suite.
Remarquer aussi slog.

Modifier la config

On peut modifier la config avec git config :
git config --system     # System-wide
git config --global     # User-wide
git config --local      # Dépôt courant
Par exemple :
git config --global alias.br "branch"
(permet d'utiliser git br au lieu de git branch).

Au lieu d'utiliser la commande git config, on peut directement éditer et modifier le fichier .git/config ou les fichiers contenant les configs global et system.

Alias supplémentaires

Si vous utilisez git toute la journée, certaines commandes se répètent souvent, et il peut être utile d'avoir des raccourcis encore plus court que ce que permet la config de git.
Sous Linux, on peut définir des alias, en général définis dans un fichier .bash_aliases, à la racine du dossier utilisateur.
Voilà quelques exemples, à adapter à vos besoins :
alias ga='git add -A'
alias gic='git commit -m '
alias gid='git diff'
alias gis='git status -uall'

alias gip='git push '
alias gipb='git push beta'
alias gipg='git push github'
alias gipp='git push prod'

alias gl='git tree'
alias gf='git fetch'
alias gr='git remote -v'

Git completion

Pour pouvoir utiliser la touche TAB pour compléter la commande qu'on est en train de taper.
Pré-configuré sous Windows ; sous bash, voir cette page.

Display current branch in console

Pour afficher sur la console le nom de la branche courante, lorsqu'on est dans un répertoire versionné par git.
Pré-configuré sous Windows ; sous bash, voir cette page.

Premier commit, git diff, git add, git status, git log

Aller dans le dépôt vide :
cd repo1
git status permet de voir ce qui a été modifié depuis le dernier commit.
On peut vérifier que rien n'a été modifié :
git status
Sur la branche main
rien à valider, la copie de travail est propre
Créer un premier fichier test1.txt dans lequel on écrit "Une première ligne" :
echo 'Une première ligne' > test1.txt
Maintenant, git status indique quelque chose :
git status
Sur la branche main

Aucun commit

Fichiers non suivis:
  (utilisez "git add <fichier>..." pour inclure dans ce qui sera validé)

	test1.txt

aucune modification ajoutée à la validation mais des fichiers non suivis sont présents (utilisez "git add" pour les suivre)
test1.txt ne fait pas partie des fichiers versionnés. Pour indiquer à git qu'on veut suivre ce fichier, on fait :
git add test1.txt
Si on a plusieurs fichiers à versionner, on peut tous les ajouter en faisant
git add -A
Maintenant, git status donne un résultat différent :
git status
Sur la branche main

Aucun commit

Modifications qui seront validées :
  (utilisez "git rm --cached <fichier>..." pour désindexer)

	nouveau fichier : test1.txt
git indique que test1.txt est bien pris en compte et que ses modifications seront enregistrées au prochain commit.

On peut maintenant faire un premier commit :
git commit -m "Création de test1.txt"
[main (commit racine) 2eb9fa0] Création de test1.txt
 1 file changed, 1 insertion(+)
 create mode 100644 test1.txt
git slog montre que ce commit a bien été pris en compte :
git slog
* 2eb9fa0 - (2019-01-19 12:35:48 +0100) Création de test1.txt - Thierry (HEAD -> main)

Importance des messages de commit

Git n'impose pas de formatter les messages des commits mais il est fortement conseillé de respecter certaines règles.
Voir par exemple cette page.

Les 3 états d'un fichier

Pour un fichier donné, git connaît trois états différents. Si on fait git status, on voit que rien n'a été modifié.

Le fichier test1.txt est dans l'état committed : son état courant est enregistré par git.
On ajoute une seconde ligne à test1.txt
echo "Une seconde ligne" >> test1.txt
On peut voir l'état des modifications avec git diff et git status.
git status
Sur la branche main
Modifications qui ne seront pas validées :
  (utilisez "git add <fichier>..." pour mettre à jour ce qui sera validé)
  (utilisez "git checkout -- <fichier>..." pour annuler les modifications dans la copie de travail)

	modifié :         test1.txt

aucune modification n'a été ajoutée à la validation (utilisez "git add" ou "git commit -a")
Le fichier test1.txt est maintenant dans l'état modified : des modifications ont été faites mais elles ne seront pas prises en compte au prochain commit.

On indique à git que ces modifications seront à inclure dans le prochain commit en faisant :
git add test1.txt
git status donne maintenant :
git status
Sur la branche main
Modifications qui seront validées :
  (utilisez "git reset HEAD <fichier>..." pour désindexer)

	modifié :         test1.txt
Le fichier test1.txt est maintenant dans l'état staged : il a été modifié depuis le dernier commit, ces modifications ont été signalées à git et seront prises en compte lors du prochain commit. On dit que test1.txt est dans la staging area ou dans l'index (la liste des modifications à prendre en compte au prochain commit se trouve dans .git/index).

Si on fait un commit, les modifications faites sur test1.txt seront donc enregistrées dans git.

Mais on peut très bien continuer à modifier test1.txt ; on ajoute une troisième ligne :
echo "Une troisième ligne" >> test1.txt
test1.txt se trouve maintenant à la fois dans l'état modified et staged, comme l'indique git status :
git status
Sur la branche main
Modifications qui seront validées :
  (utilisez "git reset HEAD <fichier>..." pour désindexer)

	modifié :         test1.txt

Modifications qui ne seront pas validées :
  (utilisez "git add <fichier>..." pour mettre à jour ce qui sera validé)
  (utilisez "git checkout -- <fichier>..." pour annuler les modifications dans la copie de travail)

	modifié :         test1.txt
Si on fait un commit maintenant, seules les modifications enregistrées dans l'index seront enregistrées :
git commit -m "Ajout d'une seconde ligne dans test1.txt"
git status permet de voir que test1.txt reste dans l'état modified. On peut enregistrer ces modifications en faisant :
git add test1.txt
git commit -m "Ajout d'une troisième ligne dans test1.txt"
Ou de manière plus courte :
git commit -am "Ajout d'une troisième ligne dans test1.txt"
Le "a" indique qu'on fait un add juste avant de faire le commit.
Mais attention : ce "a" ne va concerner que les fichiers déjà gérés par git. Si vous voulez ajouter un fichier qui n'a jamais été versionné, il faut faire explicitement git add.

Pour résumer :
Etat d'un fichierSignification
Non versionné Inconnu de git
Ne fait pas partie des 3 états officiellement reconnus.
Un git add est nécessaire pour qu'il devienne versionné.
Modified Le fichier a été modifié depuis le dernier commit.
Les modifications ne seront pas prises en compte lors du prochain commit.
Pour le faire passer en état staged, il faut faire git add ou utiliser l'option a de git commit.
Staged Des modifications on été faites sur le fichier depuis le dernier commit, et seront enregistrées au prochain commit.
Commited L'état du fichier est conforme à la base de données de git.

Remotes, pull

Chaque dépôt git peut être connecté à des dépôts distants (remote repository en anglais), que l'on peut lister avec git remote.
Si on fait git remote depuis repo1, git n'affiche rien car il a été créé de manière autonome et on ne lui a rien indiqué.
Mais si on va dans le dépôt clone-repo1 (créé dans le paragraphe "Cloner un dépôt local"), git affiche quelque chose :
cd ../clone-repo1

# on est dans git-tests/clone-repo1

git remote 
origin
Lorsqu'on a cloné le dépot repo1, git a automatiquement créé un remote qu'il a appelé "origin".
Cette information est stockée dans .git/config :
[remote "origin"]
	url = /path/to/git-test/repo1/
	fetch = +refs/heads/*:refs/remotes/origin/*
[branch "main"]
	remote = origin
	merge = refs/heads/main
Si on fait git slog, git ne renvoie rien car on a créé clone-repo1 alors que repo1 ne contenait aucun commit.

On peut récupérer les commits de repo1 en faisant :
git pull origin
remote: Décompte des objets: 9, fait.
remote: Compression des objets: 100% (4/4), fait.
remote: Total 9 (delta 0), reused 0 (delta 0)
Dépaquetage des objets: 100% (9/9), fait.
Depuis /home/thierry/dev/jobs/cnam/git-repos/git-test/repo1
 * [nouvelle branche] main     -> origin/main
On peut constater deux effets de git pull :