# Repository

## What it is

A repository, nearly always shortened to repo in conversation, is where a
version control system keeps the full record of a project: every recorded state
of every file, who made each change and why, and the names that lead into that
history. The working files you edit are one view of it; the repository is
everything behind that view.

Git defines the word in its own glossary with some precision: “A collection of
refs together with an object database containing all objects which are reachable
from the refs”. Both halves are worth unpacking. The object database holds the
content. Each version of a file, each directory listing and each commit is
stored as an object and named by a hash of its contents, which the Git book
describes as a content-addressable filesystem: a key-value store where the key
is computed from the value. Two identical files are one object, and any change,
however small, produces a new name. The refs are the human side: branches and
tags, short names that each point at one commit and give people a way in.

Most repositories people work in come with a working tree attached. The files
you open in an editor sit in the project directory, and the repository itself
lives beside them in a hidden `.git` directory. A bare repository has no working
tree at all. Its directory name conventionally ends in `.git`, it holds only the
history, and it is the form a server keeps, because nobody edits files there;
people push to it and fetch from it. Git’s glossary says as much: publishers of
public repositories usually make bare ones available. The Git book shows how to
make one from an existing project with
`git clone --bare my_project my_project.git`.

Cloning is where Git’s design shows. A clone receives nearly all the data the
server has: by default, every version of every file for the whole history of the
project comes down with it. Every clone is therefore a complete repository, able
to stand in for the server if the server is lost. The exceptions are small but
matter, and the Git book names them: server-side hooks and similar settings stay
behind.

Two variations come up often. A shallow repository, created by cloning with
`--depth`, keeps only recent commits; the glossary says the older parents are
“cauterized away”, and the history can be deepened later with a fetch. A
submodule is a repository held inside another one, with its own history, pinned
by the outer repository to one exact commit.

## Why it matters

A repository is a project’s memory. When a line of code looks wrong, its history
says when it arrived, in which commit, and with what explanation. That is only
as good as the commits people write, which is why teams that care about their
history put rules on commit messages and enforce them with hooks rather than
goodwill.

It is also the unit that most tooling works on. Access is granted per
repository, hooks run per repository, and continuous integration usually starts
from one. Draw the boundary of a repository and you have drawn the boundary of
what one review, one check and one permission covers.

Repositories keep what they are given. A commit that deletes a file adds a new
state; it leaves every earlier state where it was, in every clone that already
holds it. That permanence is the point of version control, and it cuts both
ways: an old version is always recoverable, and so is a password that someone
committed by mistake.

Finally, a repository can hold far more than application code. Infrastructure
definitions, documentation and configuration all gain the same things from it: a
history, a review step and a way to rebuild a known state. A server whose setup
lives in a repository can be rebuilt by someone who has never seen it.

## What it looks like in practice

[Four repositories built over eighteen months by one person](/portfolio/held-five-repositories-to-one-history-standard-165/)
share one commit standard: a conventional prefix naming the kind of change, a
scope, a subject under a fixed length, no emojis and no attribution trailers. A
commit-message hook in every repository that carries work rejects anything that
breaks it, which makes the standard a property of the repository rather than of
whoever is committing. The history then shows what the work was. On the largest
repository it reads 156 feature commits, 133 fixes, 128 documentation, 81
chores, 26 refactors, 20 style, 5 performance and 3 test. The hook stops short
of quality: the format is checked and the content is not.

For the company’s own estate, a web presence, a git forge, a database, backups,
mail transport and DNS, the brief was to have it
[described in a repository rather than in a head](/portfolio/built-the-companys-infrastructure-as-code-108/).
The repository that resulted holds 12,065 lines of YAML, split into 19 playbooks
and 34 roles, and the estate can be reproduced from it: a host sits in a tier
group whose variables declare the roles it runs, and a converged host reports
zero changes. Each change takes longer than an edit made directly on the
server, and a preflight play was later added in front of the converge.

A repository also keeps what it was given while attention was elsewhere.
[Work for a different company rode along through a repository restructure](/portfolio/wrote-a-scope-rule-after-a-credential-leak-124/),
including a scratch log holding live plaintext credentials that sat in the tree
past every guard for most of the repository’s history. None of it ran, and that
is exactly why it survived. The answer was a scope rule at the top of the
repository’s instructions, one company’s infrastructure and only that, plus a
quarantine instead of a deletion, so the history stays legible while the secret
scanner, the vault guard and the emoji check still read the quarantined files.

## Where it goes wrong

- **A secret committed once outlives its deletion.** Removing the file in the
  next commit leaves it in the previous one and in every clone made since. Treat
  the credential as public: rotate it first, then decide whether rewriting
  history is worth the disruption to everyone who has a copy.
- **A push meets a checked-out branch.** Pushing into a non-bare repository
  whose current branch is the one being updated would leave its working tree out
  of step with its history, so Git refuses such a push by default through
  `receive.denyCurrentBranch`. A repository that people push to should be bare.
- **A shallow clone answers history questions from part of the history.** A
  clone made with `--depth` carries only recent commits, so `git log`,
  `git blame` and any script that derives a version from the last tag see only
  that slice. Build and release jobs that need the past should fetch the full
  history.
- **A local hook stops at the next clone.** Client-side hooks live in
  `.git/hooks`, and the Git book is explicit that a clone does not copy them. A
  policy enforced only there ends the day someone clones afresh. Keep the hook
  scripts tracked in the repository and point `core.hooksPath` at them, or
  enforce the rule on the server side with `pre-receive`.
- **Large binaries swell every clone forever.** Because a clone carries every
  version of every file, each replaced copy of a large binary stays in the
  history and every new clone downloads all of them.
- **Files that nothing runs go unread.** A disabled task, a stale inventory or a
  scratch log still sits in every clone, yet no test, build or deploy touches
  it, so it escapes review. The repository’s contents should match what the
  project is responsible for, and anything else should be removed or set apart
  where the guards can still see it.

## Further reading

- [gitglossary: repository](https://git-scm.com/docs/gitglossary#def_repository)
  — Git’s own definition, next to bare repository, worktree, shallow repository
  and submodule.
- [Getting a Git Repository](https://git-scm.com/book/en/v2/Git-Basics-Getting-a-Git-Repository)
  — the two ways to get one, starting fresh in a directory or cloning, and what
  a clone brings down.
- [Git Objects](https://git-scm.com/book/en/v2/Git-Internals-Git-Objects) — how
  the object database stores content under a hash of that content.
- [gitrepository-layout](https://git-scm.com/docs/gitrepository-layout) — what
  each file and directory inside a repository is for.
- [Getting Git on a Server](https://git-scm.com/book/en/v2/Git-on-the-Server-Getting-Git-on-a-Server)
  — turning an existing repository into a bare one and sharing it.
- [Git Hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks) —
  client-side and server-side hooks, and why a clone leaves the client-side ones
  behind.

<https://engineer.company/glossary/repository/>
