Every developer uses Git. It does not matter if you write Python, JavaScript, Rust, or Kotlin. Git tracks your code changes, lets you go back to any previous version, and helps you work with other developers.

In this tutorial, you will install Git, create your first repository, and make your first commit. By the end, you will understand how Git tracks changes.

What Is Git?

Git is a version control system. It saves snapshots of your project over time. Each snapshot is called a commit.

Think of it like this: every time you save a document, you can only go back to the last save. Git lets you go back to any save you ever made.

Git is:

  • Free and open source
  • Fast — it works locally on your computer
  • Distributed — every developer has a full copy of the project history

Installing Git

macOS

git --version

If Git is not installed, macOS will ask you to install the Command Line Tools. Click “Install” and wait.

You can also install it with Homebrew:

brew install git

Linux (Ubuntu/Debian)

sudo apt update
sudo apt install git

Windows

Download the installer from git-scm.com. Run it and keep the default options. After installation, open “Git Bash” from the Start menu.

Verify Installation

git --version
git version 2.47.1

If you see a version number, Git is ready.

Configuring Git

Before you use Git, tell it who you are. This information appears in every commit you make.

git config --global user.name "Alex"
git config --global user.email "alex@example.com"

Set the default branch name to main:

git config --global init.defaultBranch main

Check your settings:

git config --list
user.name=Alex
user.email=alex@example.com
init.defaultbranch=main

The --global flag means these settings apply to all repositories on your computer. You can override them per project by running the same commands without --global inside a project folder.

Creating Your First Repository

A repository (or “repo”) is a folder that Git tracks. Let’s create one.

mkdir my-project
cd my-project
git init
Initialized empty Git repository in /home/alex/my-project/.git/

Git creates a hidden .git folder inside your project. This folder contains all the history and configuration. Do not delete it.

The Git Workflow

Git has three areas where your files can be:

Working Directory → Staging Area → Repository
     (edit)          (git add)     (git commit)
  1. Working Directory — the files you see and edit
  2. Staging Area — files you marked as “ready to commit”
  3. Repository — the saved snapshots (commits)

This might seem complicated at first. Why not just save directly? The staging area lets you choose which changes to include in a commit. You might have changed 5 files but only want to commit 2 of them.

Your First Commit

Let’s create a file and commit it.

echo "Hello, Git!" > hello.txt

Check what Git sees:

git status
On branch main

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        hello.txt

nothing added to commit but untracked files present (use "git add" to track)

Git sees the file but is not tracking it yet. The file is untracked.

Stage the File

git add hello.txt

Check the status again:

git status
On branch main

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
        new file:   hello.txt

The file is now in the staging area. It is ready to commit.

Commit the File

git commit -m "Add hello.txt"
[main (root-commit) a1b2c3d] Add hello.txt
 1 file changed, 1 insertion(+)
 create mode 100644 hello.txt

The -m flag lets you write a commit message inline. Every commit needs a message that explains what you changed.

Stage All Files

If you want to stage all changed files at once:

git add .

The . means “everything in the current directory.” This is useful but be careful — it stages everything, including files you might not want to commit.

Checking Status with git status

You already used git status. Here is what each section means:

# After editing hello.txt and creating notes.txt
git status
On branch main
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes)
        modified:   hello.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        notes.txt

no changes added to commit (use "git add" and/or "git commit -a")
  • Modified — a tracked file that changed but is not staged yet
  • Untracked — a new file that Git does not know about
  • Staged — a file in the staging area, ready to commit

Run git status often. It tells you exactly where things stand.

Viewing History with git log

git log
commit a1b2c3d4e5f6g7h8i9j0 (HEAD -> main)
Author: Alex <alex@example.com>
Date:   Mon May 25 09:00:00 2026 +0000

    Add hello.txt

Each commit has:

  • A hash (the long string of letters and numbers) — a unique ID for this commit
  • The author — who made the commit
  • The date — when the commit was made
  • The message — what the commit is about

For a shorter view:

git log --oneline
a1b2c3d Add hello.txt

This shows just the short hash and the message. Much easier to scan when you have many commits.

Seeing Changes with git diff

Let’s edit our file and see what changed.

echo "This is my first Git project." >> hello.txt

Now see the difference:

git diff
diff --git a/hello.txt b/hello.txt
index 8d0e412..b5a7e43 100644
--- a/hello.txt
+++ b/hello.txt
@@ -1 +1,2 @@
 Hello, Git!
+This is my first Git project.

Lines starting with + are added. Lines starting with - are removed. This shows you exactly what changed before you commit.

To see changes that are already staged:

git diff --staged

This is useful when you staged some files and want to review them before committing.

Ignoring Files with .gitignore

Some files should not be in Git. Log files, compiled code, API keys, and IDE settings do not belong in your repository.

Create a .gitignore file in the root of your project:

cat > .gitignore << 'EOF'
# Compiled files
*.class
*.o
build/

# IDE files
.idea/
.vscode/

# OS files
.DS_Store
Thumbs.db

# Environment files
.env
.env.local

# Dependencies
node_modules/
EOF

Each line is a pattern. Git will ignore any file or folder that matches.

Common patterns:

  • *.log — ignore all files ending in .log
  • build/ — ignore the entire build folder
  • .env — ignore a specific file
  • !important.log — do NOT ignore this file (exception)

Add and commit the .gitignore file:

git add .gitignore
git commit -m "Add .gitignore"

Always create .gitignore early in your project. If you add a file to Git and then add it to .gitignore later, Git will keep tracking it. You would need to remove it from tracking first with git rm --cached <file>.

Removing and Moving Files

Git has its own commands for removing and renaming files.

Remove a File

git rm old-file.txt
git commit -m "Remove old-file.txt"

This removes the file from both your working directory and Git’s tracking. If you only want to stop tracking the file but keep it on disk:

git rm --cached secret.txt

This is useful when you forgot to add a file to .gitignore and already committed it.

Rename or Move a File

git mv old-name.txt new-name.txt
git commit -m "Rename old-name to new-name"

This is the same as renaming the file manually and running git add on both the old and new names. But git mv does it in one step.

Multiple Commits — Building History

Let’s make a few more commits to see how history builds up:

echo "Project started on May 2026" >> hello.txt
git add hello.txt
git commit -m "Add project start date"

echo "## My Notes" > notes.txt
echo "- Learn Git basics" >> notes.txt
echo "- Practice daily" >> notes.txt
git add notes.txt
git commit -m "Add learning notes"

echo "- Read documentation" >> notes.txt
git add notes.txt
git commit -m "Add documentation reminder to notes"

Now check the history:

git log --oneline
f7g8h9i Add documentation reminder to notes
e6f7g8h Add learning notes
d5e6f7g Add project start date
c4d5e6f Add .gitignore
b3c4d5e Add hello.txt

Each line is a snapshot. You can see exactly what changed and when. This is the power of Git — a complete history of your project.

Putting It All Together

Here is a typical workflow:

# Create or edit files
echo "My notes" > notes.txt

# Check what changed
git status

# See the actual changes
git diff

# Stage the files you want to commit
git add notes.txt

# Commit with a clear message
git commit -m "Add notes file"

# Check the history
git log --oneline
b2c3d4e Add notes file
a1b2c3d Add hello.txt

Each commit is a snapshot. You can always go back to any of them.

Good Commit Messages

Write commit messages that explain what you changed and why:

# Good
git commit -m "Add user login validation"
git commit -m "Fix crash when email is empty"
git commit -m "Remove unused database helper"

# Bad
git commit -m "update"
git commit -m "fix"
git commit -m "asdfgh"

A good commit message helps you (and your team) understand what happened when you read the history months later.

Some teams follow conventions like starting with a verb in the present tense:

git commit -m "Add search feature"     # not "Added search feature"
git commit -m "Fix memory leak"         # not "Fixed memory leak"
git commit -m "Update dependencies"     # not "Updated dependencies"

This is not a strict rule, but being consistent helps everyone on the team.

Checking What Will Be Committed

Before committing, it is a good habit to review your staged changes:

git diff --staged

This shows exactly what will go into the next commit. If you see something unexpected, unstage it:

git restore --staged <file>

Another useful command is git status -s for a compact view:

git status -s
M  hello.txt
A  notes.txt
?? temp.txt
  • M — modified and staged
  • A — new file, staged
  • ?? — untracked

Common Mistakes

  1. Forgetting to stage files — Running git commit without git add first does nothing. Git only commits what is in the staging area. Use git status to check before committing.

  2. Committing sensitive files — API keys, passwords, and .env files should never be in Git. Create .gitignore at the start of every project. If you already committed a secret, changing .gitignore does not remove it from history.

  3. Writing vague commit messages — Messages like “fix” or “update” are useless when you read the history later. Take 5 seconds to write something meaningful like “Fix login crash on empty email.”

What’s Next?

In the next tutorial, we will learn about branches — how to work on multiple features at the same time without breaking your main code.

Git Tutorial #2: Branching — Work on Multiple Things at Once

For a quick reference of all Git commands, check the Git Commands Cheat Sheet.


This is part 1 of the DevTools Tutorial series.