Skip to main content

Git Fundamentals: How Git Works and First Setup

How Git stores your work in snapshots, the working tree, staging area and repository, how to install Git 2.56, and the settings to configure first.

Git is a distributed version control system: it records the history of a set of files, lets several people change them at the same time, and merges their work back together. Linus Torvalds wrote it in 2005 for the Linux kernel. Today almost every software project uses it, along with infrastructure code, documentation and configuration, and services such as GitHub, GitLab and Bitbucket are built around it.

Most Git problems come from a wrong mental model, not from a forgotten command. This part explains how Git stores your work, so that the commands in the rest of the guide make sense. Then you install a current Git and set it up properly once.

Prerequisites

  • A computer with Linux, macOS or Windows, and permission to install software.
  • Basic use of a terminal: cd, ls and running commands. The Linux command line part of the Linux guide covers it.

What Git Gives You

Without version control, you copy folders (site-final, site-final-2), email patches and lose track of who changed what. Git replaces that with a repository: a project folder plus a hidden database (.git) that holds every saved version.

  • Full history. Every saved version (a commit) records who made it, when and why. You can compare any two versions and go back to any of them.
  • Distributed. A clone is a complete copy of the repository with its whole history (unless you ask for a shallow or partial clone). You commit, branch and read history offline, and share work when you are ready. Every full clone is also a backup.
  • Cheap branches. A branch is a 41-byte file, so you can start one for every change, try things and throw them away.
  • Integrity. Every file, directory and commit is named by a hash of its content. If a byte changes on disk or on the way over the network, Git notices.

How Git Stores Your Work

Snapshots, not differences

Many older systems store a list of changes per file. Git stores snapshots: each commit records the full state of every file in the project at that moment, plus a pointer to the commit before it (its parent).

That would be wasteful if Git copied every file each time, so it does not. Each piece of content is stored once and named by its hash. If a file did not change, the new snapshot points to the same stored content as the previous one. A commit that changes one file in a project of 10,000 files stores one new file version and a few small directory listings.

Each commit points back to its parent, so the history is a chain (or, once you merge, a graph). A branch is only a name that points to one commit and moves forward when you commit. Part 4 shows this on disk, and Part 10 looks at the objects themselves.

Git names objects with SHA-1 hashes today: 40 hexadecimal characters such as 46b8da18e4efd0f6a8d3356b8006254f4ac46b45 (the first commit you make in Part 2), usually shortened to the first 7, 46b8da1. Git can also create repositories that use SHA-256, which will be the default for new repositories in Git 3.0 (more on that below).

The three areas

When you work with Git, your files live in three places:

  • The working tree is the normal folder you edit with any editor.
  • The staging area, also called the index, is a draft of the next commit. git add copies a file's current content into it.
  • The repository is the .git directory. git commit turns the staging area into a new commit there.

The staging area is what lets you commit some changes and keep others for later: you can edit five files and commit two of them, or even part of one file (Part 3). Commands such as git restore and git switch copy content the other way, from the repository back into the staging area and the working tree.

From Git's point of view, each file in the working tree is in one of these states:

State Meaning Typical next command
Untracked Git has never stored this file git add, or .gitignore
Unmodified Same as in the last commit none
Modified Changed since the last commit, change not staged yet git add or git restore
Staged The change is in the staging area git commit

Install Git

The current release is Git 2.56.0 (28 September 2026). Any version from the last few years runs the commands in this guide; the few newer features are marked with the version that added them. Distributions with long-term support ship older versions with security fixes backported, so an older version number is not a problem by itself.

Where Git version in October 2026
Ubuntu 24.04 LTS 2.43.0
Ubuntu 26.04 LTS 2.53.0
Ubuntu, ppa:git-core/ppa 2.56.0
Debian 13 2.47.3
Fedora 44 2.56.0
Homebrew (macOS) 2.56.0
Git for Windows 2.56.0 (2.56.0.windows.3)

On Windows, the installer asks several questions. The defaults are fine. Two worth reading: the default editor (pick one you know, such as VS Code or Notepad++) and line endings ("Checkout Windows-style, commit Unix-style" is the usual choice; the project in this guide adds a .gitattributes file in Part 2 that keeps its shell scripts on LF line endings anyway, and Part 9 explains how that makes line endings independent of each person's settings).

Check that it works:

The examples in this guide come from Git 2.56.0 on Linux, run as a user called dev on a machine called devbox. Your hashes and dates will differ; everything else should match.

First-Time Setup

Git stores settings with git config. You set a few of them once per computer, with --global, and they apply to every repository you use.

Your name and email

Every commit records an author name and email. Set them before your first commit:

git config --global user.name "Dev"
git config --global user.email "dev@example.com"

Use the email address of your GitHub, GitLab or Bitbucket account, so that the platform links your commits to your profile. To keep your address private, GitHub gives every account a noreply address (ID+username@users.noreply.github.com) under Settings, Emails.

The default branch name

New repositories still start with a branch called master, and Git prints a hint about it. This is what git init says if you have not set anything:

GitHub, GitLab and Bitbucket all name the first branch main, and Git 3.0 will do the same. Set it now, so that local and hosted repositories match:

Your editor

Git opens an editor when it needs a longer text from you: a commit message without -m, a merge commit message, an interactive rebase. Without a setting, Git uses $VISUAL or $EDITOR, and falls back to vi (Debian and Ubuntu builds fall back to the system's editor command, usually nano). Pick an editor you know:

How to set the Git editor for commit messages covers more editors and the GIT_EDITOR variable.

See what is set, and where

git config list shows every setting that applies, and the two options below show where each one comes from:

Git reads settings from several files. A later level overrides an earlier one:

Scope File Option Applies to
system /etc/gitconfig --system every user on the computer
global ~/.gitconfig or ~/.config/git/config --global all your repositories
local .git/config in the repository --local one repository (the default)
worktree config.worktree in the worktree's Git directory --worktree one worktree of a repository (only with extensions.worktreeConfig enabled; otherwise it acts like --local)

You can also pass a setting for a single command with git -c name=value <command>.

Git 2.46 added subcommands for git config that read more clearly. The older forms still work, and you will see both in documentation:

Task Newer form (Git 2.46+) Older form
Set a value git config set --global user.name Dev git config --global user.name Dev
Read a value git config get user.name git config user.name
List all git config list git config --list
Remove a value git config unset --global core.editor git config --global --unset core.editor

A different email for work repositories

If you use one computer for personal and work projects, a conditional include picks the right identity by folder. Put your work settings in a separate file, ~/.gitconfig-work:

[user]
	email = dev@work.example.com

Then tell your global config to include it for every repository under ~/work/ (the trailing slash matters):

git config get --show-origin user.email tells you which file a value came from when you are not sure.

Getting Help

Every command has a manual page and a short summary of its options:

git help commit      # the full manual page (git commit --help does the same)
git commit -h        # a short list of options in the terminal
git help -g          # guides, such as "git help everyday" and "git help workflows"

What Changes in Git 3.0

Git 3.0 is the first release since Git 2.0 (2014) that is allowed to break backward compatibility. The Git project keeps the list in its BreakingChanges document. The plan agreed at the Git Contributor Summit (part of Git Merge 2026) is to skip from 2.56 to 2.98 in December 2026, then release 2.99 as a long-term support version together with 3.0 in spring 2027 (GitLab's Git 2.56 article, LWN). Until it ships, treat the dates as a plan.

Change in Git 3.0 What it means for you
New repositories use main Nothing, if you set init.defaultBranch as above
New repositories use SHA-256 object names Existing SHA-1 repositories keep working; SHA-1 is not being removed. Hosting support for SHA-256 is still limited (Part 10)
New repositories store refs in the reftable format Invisible to Git users; tools that read .git/refs files directly may need updates
Rust is required to build Git Matters if you build Git yourself or use a platform without a Rust compiler
safe.bareRepository defaults to explicit Git stops using bare repositories it finds by walking up from your current directory, which closes a hook-based attack
Old commands removed (git whatchanged, git pack-redundant, grafts) Use git log --raw instead of git whatchanged

git checkout is not going away: the project decided to keep it next to git switch and git restore, which this guide uses.

Common Mistakes

  • Committing before setting your name and email. Git stops with "Author identity unknown" when it cannot work out an email address. On a machine whose host name includes a domain, it builds one from your user and host name instead and only prints a warning, and those commits are not linked to your account. Set the identity and, if the commits are not shared yet, see how to change the author of a commit.
  • An editor that returns at once. Graphical editors need a "wait" flag (code --wait); otherwise Git sees an empty message and aborts the commit.
  • Using sudo git. Files created as root in your project lead to permission errors later. Git never needs root for your own repositories.
  • Assuming the history is in the cloud. Commits live in your .git until you push them (Part 6).

Summary

  • Git stores snapshots of your whole project; unchanged content is stored once and named by its hash.
  • Your files move between the working tree, the staging area (git add) and the repository (git commit).
  • Install a current Git from your package manager, Homebrew or Git for Windows; 2.56.0 is the current release.
  • Set user.name, user.email, init.defaultBranch main and core.editor once with --global.
  • Git 3.0 (planned for spring 2027) changes defaults for new repositories; existing repositories keep working.

Next: Creating and Managing Repositories, where you start the project that the rest of the guide builds on.

Keep Learning

Updated:

Tags

GitVersion ControlGitHubBranchingCollaborationDevOps

Found an issue?