Skip to main content

Introduction

This tutorial will take you from Git basics through advanced workflows. By the end, you’ll understand how to:
  • Manage project history with commits
  • Work with branches for parallel development
  • Collaborate with others using remotes
  • Resolve conflicts when they arise
  • Use Git effectively in real-world scenarios
If you haven’t installed Git yet, check the Installation Guide first.

Setting Up

Before starting, configure your identity:
git config --global user.name "Your Name Comes Here"
git config --global user.email you@yourdomain.example.com
This information is included in every commit you make.

Creating Your First Repository

Let’s import a new project into Git. Assume you have a project directory you want to track:
1

Initialize the Repository

cd project
git init
Git replies:
Initialized empty Git repository in .git/
You’ve now initialized the working directory. A new directory called .git has been created.
2

Stage All Files

Take a snapshot of all files in the current directory:
git add .
This snapshot is now stored in the staging area (also called the “index”).
3

Make Your First Commit

Permanently store the staged content in the repository:
git commit
This prompts you for a commit message. Enter something descriptive like:
Initial import of project files

Starting Git tracking for this project.
You’ve now stored the first version of your project in Git!
Use git commit -m "message" to provide the commit message directly on the command line.

Making Changes

Now let’s modify some files and commit the changes:
1

Edit Files

Make changes to your files using your favorite editor:
# Edit some files
vim file1.txt
vim file2.txt
vim file3.txt
2

Review Changes

Before staging, see what you changed:
# Show changes in working directory
git diff
This displays line-by-line differences.
3

Stage Updated Content

Add the modified files to the staging area:
git add file1.txt file2.txt file3.txt
4

Check Staged Changes

See what’s about to be committed:
git diff --cached
Without --cached, git diff shows unstaged changes.
5

Check Status

Get a summary of the current state:
git status
Output:
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)

    modified:   file1.txt
    modified:   file2.txt
    modified:   file3.txt
6

Commit the Changes

git commit
This prompts for a message describing the change, then records the new version.

Commit Message Best Practices

Though not required, it’s good practice to begin commit messages with a single short line (no more than 50 characters) summarizing the change, followed by a blank line and a more thorough description.
The text up to the first blank line is the commit title, used throughout Git. For example, git format-patch uses the title as the email Subject line. Example:
Add user authentication module

Implements login and logout functionality using JWT tokens.
Includes password hashing with bcrypt and session management.

Automatic Staging

Instead of running git add separately, you can use:
git commit -a
This automatically stages all modified (but not new) files and commits them in one step.
git commit -a only stages modified tracked files. New files must still be added explicitly with git add.

Understanding How Git Tracks Content

Many revision control systems have an add command to start tracking a file. Git’s add command is different:
  • Other systems: add tells the system to start tracking a file
  • Git: add takes a snapshot of the file’s current content and stages it
Git’s add is used for both:
  • New files (start tracking them)
  • Modified files (stage their current content)
In both cases, it captures the exact content at that moment and stages it for the next commit.

Viewing Project History

At any point, view your commit history:
git log

# Shows commits with:
# - Commit hash (SHA-1)
# - Author and email
# - Date and time
# - Commit message
Sample output:
commit c82a22c39cbc32576f64f5c6b3f24b99ea8149c7
Author: Junio C Hamano <junkio@cox.net>
Date:   Tue May 16 17:18:22 2006 -0700

    merge-base: Clarify the comments on post processing.

Managing Branches

Branches are Git’s killer feature. They’re lightweight pointers to commits, making them perfect for experimentation.

Creating and Switching Branches

1

Create a New Branch

git branch experimental
This creates a new branch named experimental pointing to your current commit.
2

List All Branches

git branch
Output:
  experimental
* master
The asterisk marks your current branch.
3

Switch to the New Branch

git switch experimental
Now you’re on the experimental branch.
You can also use git checkout experimental on older Git versions.
4

Make Changes on the Branch

# Edit a file
vim README.md

# Commit the change
git commit -a -m "Experimental feature implementation"
5

Switch Back to Master

git switch master
The file changes from the experimental branch are no longer visible!

Creating and Switching in One Command

# Create and switch to a new branch
git switch -c feature-x

# Older syntax
git checkout -b feature-x

Working with Divergent Branches

Let’s make different changes on different branches:
1

Make Changes on Master

git switch master

# Edit files
vim app.py

# Commit
git commit -a -m "Add logging to main application"
2

View the Divergence

At this point, the two branches have diverged with different changes in each.
# Visualize the history
gitk

# Or use log
git log --oneline --graph --all

Merging Branches

To combine changes from experimental into master:
# Switch to the target branch
git switch master

# Merge the experimental branch
git merge experimental
If there are no conflicts, Git automatically creates a merge commit. Done! If there are conflicts, Git marks them in the files:
<<<<<<< HEAD
print("Hello from master")
=======
print("Hello from experimental")
>>>>>>> experimental
1

View Conflicts

git diff
This shows the conflicting sections.
2

Resolve Conflicts

Edit the files to resolve conflicts, removing the markers:
# Choose what you want to keep
print("Hello from master and experimental")
3

Stage Resolved Files

git add app.py
4

Complete the Merge

git commit -a
Git provides a default merge message.

Deleting Branches

Once a branch is merged, you can delete it:
# Safe delete (only if merged)
git branch -d experimental

# Force delete (even if not merged)
git branch -D crazy-idea
Branches are cheap and easy! Use them freely to try things out. If an experiment doesn’t work, just delete the branch.

Collaboration Basics

Git excels at helping multiple people work on the same project.

Cloning a Repository

Suppose Alice has a repository that Bob wants to contribute to:
# Bob clones Alice's repository
bob$ git clone /home/alice/project myrepo
This creates a new directory myrepo with a complete copy of the project history.

Making and Sharing Changes

1

Bob Makes Changes

bob$ cd myrepo
bob$ vim README.md
bob$ git commit -a -m "Update documentation"
2

Alice Pulls Bob's Changes

alice$ cd /home/alice/project
alice$ git pull /home/bob/myrepo master
This merges changes from Bob’s master branch into Alice’s current branch.

Understanding Pull

The pull command performs two operations:
  1. Fetch: Downloads changes from the remote branch
  2. Merge: Merges them into the current branch
Alice should commit her local changes before pulling. If Bob’s work conflicts with uncommitted changes, Git will refuse to merge.

Inspecting Before Merging

Alice can examine Bob’s changes before merging:
# Fetch without merging
alice$ git fetch /home/bob/myrepo master

# Inspect what Bob did
alice$ git log -p HEAD..FETCH_HEAD
The notation HEAD..FETCH_HEAD means “show everything reachable from FETCH_HEAD but not from HEAD.”

Using Remote Shortcuts

Instead of typing the full path repeatedly, define a remote:
# Add a remote shorthand
alice$ git remote add bob /home/bob/myrepo

# Now fetch from Bob
alice$ git fetch bob

# View changes
alice$ git log -p master..bob/master

# Merge when ready
alice$ git merge bob/master

Automatic Remote Configuration

When Bob cloned Alice’s repository, Git automatically configured a remote:
bob$ git config --get remote.origin.url
/home/alice/project

# Bob can pull updates easily
bob$ git pull
The clone command set up:
  • Remote name: origin
  • Remote URL: Alice’s repository
  • Remote tracking branch: origin/master
# View remote branches
bob$ git branch -r
  origin/master

Remote Protocols

Git supports multiple protocols for accessing remote repositories:
# Clone from a local directory
git clone /home/alice/project myrepo

Exploring History

Commit References

Git provides many ways to refer to commits:
# Use the full SHA-1 hash
git show c82a22c39cbc32576f64f5c6b3f24b99ea8149c7

Merge Commits

Merge commits have multiple parents:
# First parent (usually current branch)
git show HEAD^1

# Second parent (merged branch)
git show HEAD^2

Tagging Commits

Create named references to important commits:
# Create a lightweight tag
git tag v2.5 1b2e1d63ff

# Create an annotated tag (recommended for releases)
git tag -a v2.5 -m "Release version 2.5"

# Now reference the commit by tag
git show v2.5
git diff v2.5 HEAD

Searching History

# Search for a string in a specific version
git grep "hello" v2.5

# Search in current working directory
git grep "hello"

Visualizing History

For projects with frequent merges, gitk provides a better visualization:
# View all history
gitk

# View last 2 weeks of commits affecting drivers/
gitk --since="2 weeks ago" drivers/
Adjust gitk’s fonts by holding Ctrl and pressing ”+” or ”-”.

Undoing Changes

Dangerous Commands

Be careful with git reset --hard! It discards changes permanently. Also, never use git reset on publicly-visible branches that others pull from.
# Reset branch to a previous commit (DANGEROUS!)
git reset --hard HEAD^
This:
  • Removes the last commit from the branch
  • Deletes all working directory changes
  • If this branch is the only one with those commits, they’re lost forever

Safe Alternative: Revert

To undo changes you’ve already pushed:
# Create a new commit that undoes a previous commit
git revert HEAD
This is safe because it doesn’t rewrite history.

Everyday Git Workflows

Individual Developer

Essential commands for solo development:
  • git init - Create a repository
  • git add - Stage changes
  • git commit - Save changes
  • git status - Check current state
  • git diff - View changes
  • git log - View history
  • git branch - Manage branches
  • git switch - Change branches
  • git merge - Combine branches
  • git tag - Mark releases

Team Participant

Additional commands for collaboration:
  • git clone - Copy a repository
  • git pull - Update from remote
  • git push - Share changes
  • git fetch - Download without merging
  • git remote - Manage remotes

Example: Daily Development Workflow

1

Start the Day

# Update your local repository
git pull
2

Create a Feature Branch

git switch -c feature/user-profile
3

Develop and Commit

# Make changes
vim profile.py

# Test and commit
git add profile.py
git commit -m "Add user profile page"

# More changes
vim tests.py
git commit -a -m "Add tests for profile page"
4

Keep Up with Main Branch

# Switch to main and update
git switch main
git pull

# Merge changes into your feature branch
git switch feature/user-profile
git merge main
5

Share Your Work

# Push your branch
git push -u origin feature/user-profile

Next Steps

You now have a solid foundation in Git! Continue learning:

Advanced Branching

Learn rebasing, cherry-picking, and advanced branch workflows

Remote Workflows

Master push, pull, and distributed collaboration

Git Internals

Understand the object database and how Git works

Best Practices

Workflows and conventions for teams

Further Reading

The tutorial has covered the essentials. To fully understand Git’s depth and power, learn about:
The elegant system Git uses to store:
  • Files (blobs)
  • Directories (trees)
  • Commits
  • Tags
See the advanced tutorial: git help tutorial-2
A cache of the directory tree state used to:
  • Create commits
  • Check out working directories
  • Hold trees involved in merges
See: git help tutorial-2
  • git-format-patch and git-am: Convert commits to email patches
  • git-bisect: Binary search through history to find bugs
  • gitworkflows: Recommended workflows
  • giteveryday: Essential commands for daily use
  • User Manual: Comprehensive guide to Git

Getting Help

Git has extensive documentation:
# Command-specific help
git help <command>
man git-<command>

# Tutorials
git help tutorial
git help everyday
git help workflows

# All commands
git help -a
The Git community is helpful! Check the mailing list archives at lore.kernel.org/git/ for solutions to common problems.