Git is a free, open-source distributed version control system that records the history of a project as a series of snapshots, each identified by a cryptographic hash. Every developer holds a complete copy of the repository, including its full history, so most operations such as committing, branching, comparing and viewing the log run locally without a server.
Linus Torvalds created Git in 2005 to manage the Linux kernel source code. Among development tools in programming, it is now the de facto standard for source control: hosting platforms such as GitHub build on it, and workflows like the pull request, code review and continuous integration all assume a Git repository underneath.
How Git stores history
Git is at its core a content-addressable object store. Each piece of data is saved under a name derived from a hash of its content, traditionally SHA-1 with 40 hexadecimal characters. Identical content always gets the same name, so Git stores it only once, and any corruption or tampering changes the hash and becomes detectable.
The repository contains four object types, which together form a directed acyclic graph of history.
| Object | What it contains | Role in history |
|---|---|---|
| Blob | The raw contents of one file | File data, without its name |
| Tree | Names, modes and hashes of blobs and subtrees | One directory snapshot |
| Commit | Root tree, parent commits, author, date, message | One point in history |
| Annotated tag | Target object, tagger, message, optional signature | Named, permanent marker such as a release |
Because each commit records the hash of its parents, changing any past commit changes every hash after it. This chaining makes history tamper-evident. Git stores whole snapshots conceptually, but in practice it compresses objects with zlib and packs similar objects into packfiles with delta compression, so repositories stay compact. Newer versions also support SHA-256 repositories, although SHA-1 remains the common default.
The working tree, the staging area and the repository
Git separates a change into three locations, and understanding them explains most commands. Files are edited in the working tree, selected for the next commit in the staging area (also called the index), and recorded permanently in the repository when committed.
| Command | What it does | Area affected |
|---|---|---|
| git add | Copies changes into the staging area | Working tree to index |
| git commit | Records the staged snapshot as a commit | Index to repository |
| git switch | Moves to another branch | HEAD and working tree |
| git restore | Discards or unstages changes in files | Working tree or index |
| git fetch | Downloads new commits without merging | Remote-tracking branches |
| git pull | Fetches and then merges or rebases | Current branch |
| git push | Uploads local commits to a remote | Remote repository |
The staging area is a deliberate design choice. It lets a developer build small, focused commits from a larger set of edits, for example committing a bug fix separately from an unrelated formatting change in the same file.
Branches, merging and rebasing
A branch in Git is only a movable pointer to a commit, stored as a small reference file. Creating one is instant and costs almost no space, which is why Git workflows create a branch for every feature or fix. The special reference HEAD points to the branch currently checked out.
Diverged branches can be combined in two ways, and choosing between them is a frequent team decision. The table compares them.
| Aspect | Merge | Rebase |
|---|---|---|
| Resulting history | Keeps both lines, adds a merge commit | Linear, as if work started later |
| Commit hashes | Existing commits unchanged | Rewritten commits get new hashes |
| Safety on shared branches | Safe | Unsafe once others built on the commits |
| Conflict handling | Resolved once in the merge commit | May recur for each replayed commit |
| Best fit | Integrating shared or long-lived branches | Tidying local work before review |
When both sides change the same lines, Git stops with a merge conflict and marks the competing versions in the file for manual resolution. Git never guesses in such cases, which protects correctness but requires human judgment.
Git compared with other version control systems
Git belongs to the distributed family of version control systems, in contrast to centralized systems in which a single server holds the authoritative history and most commands need a connection.
| System | Model | Typical strength |
|---|---|---|
| Git | Distributed | Fast branching, huge ecosystem |
| Mercurial | Distributed | Simpler, more consistent command set |
| Subversion (SVN) | Centralized | Path-level permissions, simple linear model |
| Perforce Helix Core | Centralized | Very large binary assets and monorepos |
Git is weak at very large binary files, because every clone downloads every version of every file. Extensions such as Git LFS store large assets outside the main object store, and features like partial clone and sparse checkout help with very large repositories.
Common mistakes and how to avoid them
Most Git accidents come from rewriting shared history or committing the wrong content. The following practices prevent the frequent ones.
- Never force-push to a shared branch; if a rewrite is unavoidable, prefer
--force-with-lease, which refuses to overwrite commits that were not fetched first. - Never commit secrets such as passwords or API keys; deleting them in a later commit leaves them in history, so they must be rotated.
- Use a .gitignore file to keep build outputs, dependencies and local configuration out of the repository.
- Write meaningful commit messages with a short summary line, so the log explains why a change was made.
- Recover lost commits with the reflog, which records where HEAD and branches pointed recently, typically for 90 days by default.
The idea in brief
Git is like a detailed photo album of a project. Every time a developer saves progress, Git takes a picture of all the files and labels it with who made it, when and why. Any earlier picture can be brought back at any time.
Each team member keeps a full copy of the album, and Git helps combine everyone’s new pictures into one shared story, pointing out the places where two people changed the same thing.
A practical scenario
A five-person team maintains a web shop in one Git repository. A developer fixing a checkout bug creates a branch called fix-coupon-rounding, makes three commits and pushes the branch. A colleague reviews the change in a pull request, the automated tests run, and the branch is merged into the main branch.
Two days later, customers report that discounts are wrong again. With git bisect, the team runs a binary search across the 64 commits made since the last good release. Because each step halves the range, Git needs about six test runs to identify the faulty commit, since 2 to the power of 6 equals 64. The team reverts that single commit with git revert, which adds a new commit that undoes it, so shared history stays intact and the fix is live within an hour.