A02

Git — The Basics

Shell

Introduction

Git is a version control system. In simple terms, it keeps a complete history of every change you make to your code. Every time you "save" (we say commit), git takes a snapshot of the state of all your files at that moment. You can go back to any snapshot at any time.

Why it's essential:

  • Safety: your code is saved on a remote server. If your hard drive dies, if you run a bad rm -rf, your code is safe.
  • History: you can see exactly what you changed, when, and why. If a change breaks something, you roll back.
  • Collaboration: multiple people can work on the same project in parallel. Git handles merging changes.
  • Traceability: at 42, the Moulinette checks that your code is properly pushed to the Vogsphere. No push, no correction. Git is mandatory.

Git was created in 2005 by Linus Torvalds (the creator of Linux) because he needed a fast and reliable tool to manage the Linux kernel's code, which has millions of lines and thousands of contributors.

Git is distributed

Most people picture a centralized system: a single server that stores the code, and everyone connects to it. Git doesn't work like that.

With git, every person has a complete copy of the project, including the full history. You can work, commit, create branches, roll back -- all of that without an internet connection, locally on your machine.

The remote server (GitHub, GitLab, 42's Vogsphere) is just a synchronization point. You send your changes when you're ready, and you pull others' changes. But the server isn't needed to work -- it's needed to share.

+----------------+     git push     +----------------+
|  Your machine  | ---------------> |    Server      |
|  (local)       |                  |    (remote)    |
|                | <--------------- |                |
|  complete      |     git pull     |  complete      |
|  copy          |                  |  copy          |
+----------------+                  +----------------+

The three zones of git

Git organizes your work into three zones. Understanding these three zones is understanding git:

Working directory  --git add-->  Staging area  --git commit-->  Repository
   (your files)                    (index)                      (history)
       |                              |                            |
   You edit here             You choose here              Commits live here

This three-step system might seem complicated at first, but it gives you total control. You can modify 10 files but only commit 3. You can check exactly what's going to be committed before doing it.

Configuring git

Identity

Before you can commit, git needs to know who you are. Every commit carries a name and email -- that's what shows up in the history.

Terminal
git config --global user.name "isoulima"
git config --global user.email "isoulima@student.42lausanne.ch"

A flag (or option) is a parameter that starts with - or -- and modifies a command's behavior. The --global flag applies the configuration to your entire system (all your projects). Without --global, the configuration only applies to the current project.

To verify:

Terminal
git config --list
user.name=isoulima
user.email=isoulima@student.42lausanne.ch

Default editor

Some git commands open a text editor (to write a commit message, for example). The default is often vim. If you prefer nano:

Terminal
git config --global core.editor "nano"

Where is the config stored?

  • --global -> ~/.gitconfig
  • Without flag -> .git/config in the project
Terminal
cat ~/.gitconfig
[user]
name = isoulima
email = isoulima@student.42lausanne.ch

Creating a repository

Two ways to get started:

git init -- Create a new repository

Terminal
mkdir my_project
cd my_project
git init
Initialized empty Git repository in /home/isoulima/my_project/.git/
Terminal
ls -la .git/
total 32
drwxr-xr-x 7 isoulima 42staff 4096 Apr 5 10:00 .
drwxr-xr-x 3 isoulima 42staff 4096 Apr 5 10:00 ..
-rw-r--r-- 1 isoulima 42staff 23 Apr 5 10:00 HEAD
drwxr-xr-x 2 isoulima 42staff 4096 Apr 5 10:00 branches
-rw-r--r-- 1 isoulima 42staff 92 Apr 5 10:00 config
drwxr-xr-x 2 isoulima 42staff 4096 Apr 5 10:00 hooks
drwxr-xr-x 2 isoulima 42staff 4096 Apr 5 10:00 objects
drwxr-xr-x 4 isoulima 42staff 4096 Apr 5 10:00 refs

git clone -- Copy an existing repository

Terminal
git clone git@vogsphere.42lausanne.ch:vogsphere/intra-uuid-abc123
Cloning into 'intra-uuid-abc123'...

The difference between clone and simply copying a folder: clone automatically establishes the connection to the remote server (the "remote"). You'll be able to git push and git pull without additional configuration.

Terminal
cd intra-uuid-abc123
git remote -v
origin git@vogsphere.42lausanne.ch:vogsphere/intra-uuid-abc123 (fetch)
origin git@vogsphere.42lausanne.ch:vogsphere/intra-uuid-abc123 (push)

The basic cycle: status, add, commit, push

This is the workflow you'll repeat hundreds of times:

1. You modify your files
2. git status      -> you check what changed
3. git add         -> you stage files for the commit
4. git commit      -> you create a snapshot
5. git push        -> you send to the server

git status -- Where do I stand?

Terminal
touch main.c Makefile
git status
On branch master
 
No commits yet
 
Untracked files:
(use "git add <file>..." to include in what will be committed)
 
main.c
Makefile
 
nothing added to commit but untracked files present

After modifying a tracked file:

Terminal
git status
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
 
modified: main.c

After git add:

Terminal
git status
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
 
new file: main.c
new file: Makefile

After git commit:

Terminal
git status
On branch master
nothing to commit, working tree clean

Make a habit of running git status before every add and before every commit. It's your GPS.

git add -- Stage files

Terminal
git add main.c
Terminal
git add main.c Makefile ft_putchar.c
Terminal
git add .

The . means "everything in the current directory and its subdirectories". It's convenient but dangerous -- you might add files you didn't want (compiled files, temporary files). Always run git status first to check.

Terminal
git restore --staged main.c

The file stays modified but is no longer staged.

git commit -- Create a snapshot

Terminal
git commit -m "add ft_putchar function"
[master 1a2b3c4] add ft_putchar function
1 file changed, 7 insertions(+)
create mode 100644 ft_putchar.c

The -m flag lets you write the message directly. Without -m, git opens a text editor for you to write the message.

  • Describes what you did, not what you're going to do
  • Is short and specific (one line, ideally 50 characters max)
  • Starts with an action verb: "add", "fix", "update", "remove"

Good messages:

add ft_putchar function
fix segfault in ft_split with empty string
update Makefile to include bonus rule
remove unused variable in ft_strlen

Bad messages:

update            <- too vague, update what?
fix               <- fix what?
wip               <- nobody will know what you were doing
asdfgh            <- seriously
done              <- done with what?

git push -- Send to the server

Terminal
git push origin master
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Writing objects: 100% (3/3), 312 bytes | 312.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To vogsphere.42lausanne.ch:vogsphere/intra-uuid-abc123
m0n1o2p..1a2b3c4 master -> master

After the push, your code is safe on the server. Others (and the Moulinette) can access it.

Terminal
git push origin master
! [rejected] master -> master (non-fast-forward)
error: failed to push some refs
hint: Updates were rejected because the remote contains work that you do not have locally.

This means the server has commits you don't have. You need to git pull first to fetch the changes, then push again.

git pull -- Fetch from the server

Terminal
git pull origin master
  1. Downloads new commits from the server
  2. Merges the server's changes with yours

If you're working alone, it happens automatically without conflicts. In a team, it's different -- but branches and conflict resolution are more advanced topics.

Viewing the history

git log -- The commit history

Terminal
git log
commit 1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b (HEAD -> master)
Author: isoulima <isoulima@student.42lausanne.ch>
Date: Sat Apr 5 10:30:00 2026 +0200
 
add ft_putchar function
 
commit m0n1o2pd5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b
Author: isoulima <isoulima@student.42lausanne.ch>
Date: Sat Apr 5 10:00:00 2026 +0200
 
initial commit

Each commit shows:

  • The unique identifier: a long string of letters and numbers (40 characters). It's the commit's serial number -- no other commit will ever have the same one.
  • HEAD -> master: indicates this is the most recent commit on the master branch.
  • The author and date.
  • The message.
Terminal
git log --oneline
1a2b3c4 add ft_putchar function
m0n1o2p initial commit

One commit per line, with the short hash (7 characters) and the message.

Terminal
git log -p
Terminal
git log -5 # The last 5
git log --oneline -10

git diff -- View changes

Terminal
git diff
diff --git a/ft_putchar.c b/ft_putchar.c
--- a/ft_putchar.c
+++ b/ft_putchar.c
@@ -1,5 +1,7 @@
#include <unistd.h>
 
+#include "libft.h"
+
void ft_putchar(char c)
{
write(1, &c, 1);

Lines with + are added (green in the terminal). Lines with - are removed (red). Lines without a sign are context.

Terminal
git diff --staged
Terminal
git diff m0n1o2p 1a2b3c4

Ignoring files -- .gitignore

Some files should never be versioned:

  • Compiled files (.o, .a, a.out) -- they're regenerated at each compilation
  • Editor temporary files (.swp, ~)
  • OS-specific files (.DS_Store on macOS)
  • Files containing secrets (API keys, passwords)

The .gitignore file at the project root lists the patterns to ignore:

Terminal
cat .gitignore
# Compiled files
*.o
*.a
a.out
 
# Temporary files
*~
*.swp
.DS_Store
 
# Directories
.vscode/

Once in the .gitignore, files no longer appear in git status and are no longer added by git add ..

Terminal
git rm --cached file.o
git commit -m "remove tracked .o file"

Typical .gitignore at 42

# Compiled files
*.o
*.a
*.so
*.dylib
a.out

# Editor files
*~
*.swp
.vscode/
.idea/

# OS files
.DS_Store
Thumbs.db

# Debug
*.dSYM/

Put this .gitignore in every project from the very first commit. It's a good habit.

The SSH key

Why SSH?

To communicate with a git server (GitHub, Vogsphere), you need to prove your identity. Two options:

  • HTTPS: you provide your login + password on every push. Convenient but tedious.
  • SSH: you set up a key pair once, and then authentication is automatic.

At 42 we use SSH.

How it works

SSH uses a system of two linked keys: a private key (that you keep secret) and a public key (that you give to the server). It's like a mailbox: anyone can drop in mail (public key = the slot), but only you can open it (private key = the box key). The server verifies you're the owner of the public key by asking a challenge that only someone with the private key can solve.

  • The private key stays on your machine, in ~/.ssh/. Never share it ever. It's the equivalent of your password.
  • The public key is given to the server (GitHub, Vogsphere). It allows the server to verify it's really you.

Generate an SSH key

Terminal
ssh-keygen -t ed25519 -C "isoulima@student.42lausanne.ch"
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/isoulima/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/isoulima/.ssh/id_ed25519
Your public key has been saved in /home/isoulima/.ssh/id_ed25519.pub
  • -t ed25519: ed25519 is the recommended key type. It's the most recent and most secure. If it doesn't work on your system, use -t rsa -b 4096 instead.
  • -C: a comment to identify the key (convention: your email).
  • Passphrase: a password that protects your private key. You can leave it empty for convenience, but it's less secure.

Two files are created:

  • ~/.ssh/id_ed25519 -- the private key (NEVER share it)
  • ~/.ssh/id_ed25519.pub -- the public key (this is the one you give out)

Add the key to the server

Terminal
cat ~/.ssh/id_ed25519.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHx7... isoulima@student.42lausanne.ch

Copy everything (from ssh-ed25519 to the end).

Terminal
ssh -T git@github.com
Hi isoulima! You've successfully authenticated, but GitHub does not provide shell access.

This message means it works. The "does not provide shell access" is normal -- GitHub is not a shell server, it's a git server.

Key permissions

The private key must have 600 permissions (only you can read it). Otherwise SSH refuses to use it:

Terminal
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub

If you see the error "UNPROTECTED PRIVATE KEY FILE", the permissions are too open.

ssh-agent -- Avoid retyping the passphrase

If you set a passphrase on your key, SSH asks for it every time. To avoid that:

Terminal
eval "$(ssh-agent -s)"
Agent pid 12345
ssh-add ~/.ssh/id_ed25519
Enter passphrase for /home/isoulima/.ssh/id_ed25519:
Identity added: /home/isoulima/.ssh/id_ed25519

The SSH agent remembers your passphrase until you close the terminal.

Undoing mistakes

Undo changes to a file (before add)

Terminal
git restore main.c

The file goes back to its state at the last commit. Warning: uncommitted changes are lost permanently.

Undo an add (unstage)

Terminal
git restore --staged main.c

The file leaves the staging area but your changes are preserved.

Modify the last commit

You forgot a file, or you want to fix the message:

Terminal
git add forgotten_file.c
git commit --amend -m "add ft_putchar with header"

Go back to a previous commit (to look around)

Terminal
git checkout a1b2c3d

You're in "detached HEAD" mode. You can look at the code at that point in history. To come back to the present:

Terminal
git checkout master

git reset -- Go back in time (with or without loss)

Terminal
git reset --soft HEAD~1 # Undo last commit, keep files staged
git reset --mixed HEAD~1 # Undo last commit, keep files modified
git reset --hard HEAD~1 # Undo last commit, DELETE changes

Useful commands

git show -- View a commit's contents

Terminal
git show 1a2b3c4

Shows the message and changes of the commit.

git blame -- Who wrote this line?

Terminal
git blame main.c
1a2b3c4d (isoulima 2026-04-05 10:30:00 +0200 1) #include <unistd.h>
1a2b3c4d (isoulima 2026-04-05 10:30:00 +0200 2)
m0n1o2pd (isoulima 2026-04-05 10:00:00 +0200 3) int main(void)

For each line: which commit introduced it, by whom, and when. Useful for understanding a file's history.

git stash -- Temporarily set aside changes

You have changes in progress but need to switch context (a hotfix, another exercise):

Terminal
git stash # Set aside changes
git stash list # View stashes
git stash pop # Retrieve changes

It's like a stack of drafts.

Best practices

The daily cycle

The git workflow you'll repeat every day:

  1. Code / modify your files
  2. git status to check what changed
  3. git add to stage the files
  4. git commit -m "clear message" to save
  5. git push to send to the server

Commit often, in small logical increments. One commit per feature or fix. Not one giant commit with 10 different changes.

Before submitting a project

Checklist:

  1. git status -- is everything committed? Nothing in red?
  2. git log -- does the last commit have the right content?
  3. git push -- is everything pushed?
  4. Check on the web interface that the correct commit is visible
  5. Read the subject one last time to make sure you haven't forgotten anything

Quiz

Test your knowledge — select the correct answer for each question

1What's the difference between git add and git commit?
2You run git status and see a file in red under "Changes not staged for commit". What does that mean?
3You've already committed a file a.out and you now add it to .gitignore. What happens?
4Which command undoes a git add (removes a file from the staging area) without losing changes?
5You just made a commit and realize you forgot to add a file. What do you do?
6What does the .git/ folder contain?
7You run git push and get the error "rejected (non-fast-forward)". Why?
8What's the difference between git clone and git init?
9You want to see only the files you've modified, not the details of the changes. Which command?
10Why must the SSH private key (~/.ssh/id_ed25519) have 600 permissions?