Git commit

On this page 7

A Git commit is an immutable snapshot of all tracked files in a repository, stored together with metadata such as the author, committer, timestamp and message, and with links to one or more parent commits. Among version control and development tools, the commit is the basic unit of history in Git: every branch, tag, merge and pull request ultimately points to commits.

Each commit is identified by a cryptographic hash of its content, traditionally a 40-character SHA-1 value and, in repositories using the newer object format, a 64-character SHA-256 value. Because the hash covers the snapshot and the parent links, changing any past commit changes every hash after it, which makes Git history tamper-evident.

What a Git commit contains

Despite how tools display it, a commit does not store a diff. It is a small object in Git’s content-addressed database that points to a tree object, which records the full directory structure; trees in turn point to blob objects holding file contents. Unchanged files are shared between commits through identical hashes, so snapshots are cheap, and Git later compresses similar objects into packfiles using delta encoding.

FieldContentPurpose
treeHash of the root treeDefines the complete project snapshot
parentZero, one or several commit hashesLinks the commit into history
authorName, email, timestamp, time zoneWho wrote the change and when
committerName, email, timestamp, time zoneWho applied it to this history
gpgsig (optional)Signature blockProves who created the commit
messageFree text, subject line and bodyExplains why the change was made
Fields stored in a commit object

The author and committer can differ: when a maintainer applies a contributor’s patch or a developer rebases someone else’s work, the author stays the original writer while the committer becomes the person who created the new commit object.

How a commit is created

Creating a commit is a two-stage process. The developer first selects changes with git add, which copies file contents into the staging area, also called the index. Running git commit then turns the index into a tree, writes a commit object that points to it and to the current HEAD commit as parent, and moves the current branch reference to the new commit.

The staging area allows a developer to commit only part of the work in progress, down to individual lines with git add -p. This is how a messy working session becomes a series of focused commits. Hooks such as pre-commit and commit-msg run at this moment and are commonly used to call a linter, formatter or message checker before the commit is accepted.

CommandEffectRewrites existing history
git commitRecords a new commit on the current branchNo
git commit –amendReplaces the latest commit with a new oneYes, the last commit
git mergeMay create a commit with two or more parentsNo
git rebaseReplays commits onto a new baseYes, all replayed commits
git cherry-pickCopies a commit onto another branchNo, creates a new commit
git revertAdds a commit that undoes an earlier oneNo
Commands that create or rewrite commits

Commits, branches and merges

Commits form a directed acyclic graph. A normal commit has one parent, the first commit in a repository has none, and a merge commit has two or more. A Git branch is nothing more than a movable pointer to one commit, and a tag is a pointer that normally does not move. Deleting a branch therefore does not delete commits immediately; unreachable commits remain recoverable through the reflog until garbage collection removes them, by default after about 30 to 90 days.

When two branches change the same lines differently, Git cannot build the merge snapshot automatically and stops with a merge conflict. The developer resolves the files and then records the result as the merge commit. On hosting platforms such as GitHub and GitLab, a pull request is a proposal to bring a set of commits into another branch after code review.

Writing good commits

A good commit is atomic: it contains one logical change that builds and passes tests on its own. Atomic commits make git bisect, which binary-searches history for the commit that introduced a bug, far more effective, and they allow a single change to be reverted cleanly without collateral damage.

The commit message is documentation that travels with the code. The widely followed convention is a subject line of about 50 characters in the imperative mood, such as “Fix rounding in invoice totals”, a blank line, and a body wrapped at about 72 characters that explains why the change was needed, since the diff already shows what changed. Some teams adopt Conventional Commits, with prefixes such as feat: and fix:, so that changelogs and version numbers can be generated automatically.

PracticeBenefitRisk if ignored
One logical change per commitEasy review, bisect and revertUnrelated changes are tangled
Message explains the reasonFuture readers understand intentContext is lost when authors leave
Each commit builds and passes testsReliable bisect and rollbackBroken intermediate states
Signed commitsVerifiable authorshipCommits can be forged by name
No secrets or large binariesSmall, safe repositoryLeaks persist in every clone
Commit practices and their effects

Common mistakes and how to recover

  • Rewriting shared history: amending or rebasing commits that others have already pulled forces them to reconcile diverged histories; use git revert on shared branches instead.
  • Committing a secret: removing it in a later commit does not help, because the earlier snapshot still contains it; the credential must be rotated immediately, and history rewriting only reduces further exposure.
  • Committing to the wrong branch: create a branch at the current commit, then reset the original branch; nothing is lost while a reference points to the commits.
  • Huge mixed commits: split them with an interactive rebase before sharing, or with partial staging before committing.

A detail that often surprises developers is that the author email is not verified by Git itself. Anyone can set any name and email in their configuration, which is why projects with strict provenance requirements use GPG or SSH commit signing and reject unsigned commits on protected branches.

The simple explanation

A Git commit is like a dated photograph of an entire project folder. It comes with a short note that says what changed and why. Each photograph also remembers the one taken before it. Together they form a complete album of the project’s history.

Suppose something breaks later. The team can flip back through the album and find the exact photograph where the problem appeared. They can then return to any earlier state without losing anything.

How it is used in practice

A developer on a web shop team is asked to add a discount code field to checkout. While working, she also notices a typo in an unrelated error message and a missing test for tax rounding. Instead of one large commit, she stages and commits the work as three separate commits: “Fix typo in payment error message”, “Add test for tax rounding on discounted items” and “Add discount code field to checkout”, each with a short body explaining the reason.

Two weeks after release, totals are wrong for some orders. A colleague runs git bisect between the last good release tag and the current branch; after about seven test runs across roughly a hundred commits, Git points to the discount commit. Because that commit contains only the discount feature, the team reverts it with a single git revert, ships the fix the same day, and later reintroduces the corrected feature in a new commit.