Skip to content

Repository Lifecycle Governance

Lesson 9 of 10Advanced15 min readGit at Scale & Enterprise Engineering · Enterprise GovernanceVerified: GitHub Enterprise Cloud documentation, September 2026

Every enterprise has repositories nobody owns. The number is always larger than anybody guesses, and it grows every quarter.

That is not a hygiene problem — it is a governance problem, because a repository with no owner cannot be classified, cannot be reviewed, cannot be patched, and cannot be retired. It is a permanent gap in every control you build.

A repository has four lifecycle stages: creation, active ownership, decline, and retirement. Governance means each one has a defined state and a transition.

The decisive stage is creation. Metadata set at creation is correct; metadata requested later mostly never arrives. Everything downstream depends on this.

Ownership is the property that decays fastest, because teams reorganise and repositories do not.

Retirement is the stage nobody runs, which is why estates only grow.

The mechanisms are: a governed creation path, required custom properties, a periodic ownership reconciliation, and an archival process with a default.

Everything you want to know about a repository is cheapest to collect when it is created. The person creating it knows why. Six months later, they may not be there.

What to collect:

  • Owning team — not a person. People leave; teams persist longer, and a team can be reassigned.
  • Tier or criticality — drives which rulesets apply.
  • Data classification — drives visibility and access review scope.
  • Expected lifespan, where it is knowable. An experiment declared as an experiment can be archived on a schedule without an argument.

Collect it as custom properties, so policy can target it.

Require the ones that matter. GitHub documents an option requiring explicit user-specified values, so a repository cannot be created without them. That converts the metadata from a hope into a guarantee — verify current behaviour, since repository policies are documented as being in public preview.

Apply the template at the same time. A repository created from a template arrives with a README, a CODEOWNERS, a licence, a .gitignore and the standard workflows. See repository templates.

Two related but distinct questions, and conflating them is why ownership data is usually wrong.

Operational ownership: who reviews changes? This is CODEOWNERS, it lives in the repository, it changes with the code, and it is enforced by required reviews.

Accountable ownership: who is responsible for this repository existing? This is a custom property, it changes with the organisation, and it is what an access review, a security alert or an archival notice is addressed to.

They are frequently different. A shared library may be reviewed by several teams and owned by one. A repository may have no CODEOWNERS at all and still need an accountable owner.

Both decay, differently. CODEOWNERS decays when it names individuals or dissolved teams, and it fails loudly — a pull request cannot get its required review. The property decays quietly and fails only when somebody needs it.

Keeping the accountable owner current is the harder problem, because it fights organisational change and nothing breaks when it is wrong.

Own by team, not by person. A personal owner is wrong the day they change roles. A team is wrong less often and is fixable by one edit.

Use CODEOWNERS as the operational owner — who reviews changes — and a custom property as the accountable owner — who is responsible for the repository existing. They are frequently different and both are needed.

Reconcile against the team list. An owning-team property naming a team that no longer exists is a confident wrong answer, which is worse than a blank. A scheduled job comparing property values against actual teams finds these.

Derive where possible. If a service catalogue knows who owns a service, derive the repository property from it rather than maintaining both.

Handle reorganisations explicitly. When a team is dissolved, its repositories need reassigning, and that should be part of the reorganisation rather than discovered a year later. This is a process question, not a tooling one.

The unowned list is a permanent artifact. Publish it, give it an owner, and treat a growing number as an escalation. It will never be zero, and it should be small and shrinking.

The tension at the heart of lifecycle governance: metadata is essential and collecting it adds friction to the thing you most want to be frictionless.

Restricting who may create repositories is the blunt answer. It works — every repository goes through a person who collects the metadata — and it creates a queue. Queues get bypassed, and the bypass is somebody creating the repository in a personal account or a different organisation.

Self-service with guardrails is the answer that lasts. Anybody may create a repository, through a path that collects the metadata as part of the flow rather than as a subsequent request.

Three ways to build it, in increasing order of effort:

Required custom properties. The lightest option: mark the essential properties as requiring explicit user-specified values, and GitHub’s own creation flow collects them. No engineering, and it works for repositories created through the interface. Verify current behaviour, since repository policies are documented as public preview.

A template repository with the properties pre-set. Creation from a template inherits the template’s contents; combined with required properties this covers most cases.

An internal creation tool. A form, a workflow, or a command in your internal CLI that asks the questions, creates the repository through the API, sets the properties, applies the template, assigns the team and records the request. More work, and it is the version that also handles the things GitHub’s flow cannot — registering in a service catalogue, provisioning a deployment target, notifying an owner.

Whichever you build, make it faster than the ungoverned path. This is the whole trick. If creating a repository properly takes ninety seconds and creating one improperly takes thirty, people will use the proper path when it also does something for them — sets up CI, registers the service, creates the on-call entry. Governance that gives something back is governance people use.

Repositories do not announce that they are finished. These are the observable signals.

No commits in twelve months. The blunt instrument, and reasonably reliable. Note that a stable library may legitimately have no commits and still be depended upon.

No open or recently closed pull requests. Combined with the above, a strong signal.

Failing CI that nobody has fixed. A repository whose pipeline has been red for three months has no active maintainer, whatever the ownership property says.

Open dependency alerts, unaddressed. The clearest signal that nobody is watching, and the one with the most direct security consequence.

No dependents. If nothing in the estate references it, and no deployment consumes it, its purpose may have ended.

An owning team that no longer exists. Definitive.

Combine signals rather than acting on one. A repository with no commits, no dependents and a dissolved owning team is finished. One with no commits but two hundred dependents is a stable library and must not be archived.

The step that makes archival safe, and the one most likely to be skipped because it is the only hard part.

Start with the dependency graph. GitHub’s dependency graph knows which repositories declare a dependency on a package, which covers anything published to a registry. It does not cover repositories consumed by direct Git reference, which in an enterprise is a substantial fraction.

Search the fleet for references. Code search across the organisation for the repository’s name, its clone URL, and its package name. This catches workflow files that check it out, scripts that clone it, and documentation that points at it.

Check reusable workflow references. A repository providing a reusable workflow is consumed by every workflow file that calls it, and archiving it breaks all of them. These references are easy to find by search and easy to miss otherwise.

Check for it as a template. Archiving a template repository stops new repositories being created from it.

Look at traffic. Clone and view counts over the last fortnight tell you whether anything is still pulling it, including systems nobody remembers.

Check package downloads, if it publishes. A library with no commits and steady downloads is stable, not dead.

Then ask. Post the candidate list somewhere engineers see it. Somebody always knows about a consumer no query found.

None of these is complete on its own, and that is the point of the objection window: the checks narrow the risk, and the window catches what they missed.

The process almost nobody has, and the reason estates only grow.

Archiving is the right default end state. An archived repository is read-only: history preserved, code readable, nothing changeable. It satisfies “we might need it” without carrying the maintenance obligation.

Deleting is rarely correct. It destroys the history, the issue record and the pull request approvals — which may be the evidence for a control. And it leaves forks behind.

The transition should be defaulted, not requested. A process that asks teams to volunteer repositories for archival produces nothing. A process that says “these repositories meet the decline criteria and will be archived in 30 days unless you object” produces action.

  1. Identify candidates from the decline signals, monthly.

  2. Notify the owner, or the organisation owner if there is none, with the reason and the date.

  3. Wait a stated period. Thirty days is enough for somebody to notice and object.

  4. Check for dependents before proceeding. A repository consumed by a pipeline must not be archived just because nobody commits to it.

  5. Archive. Not delete.

  6. Record it. What was archived, when, and on what basis.

  7. Leave a route back. Unarchiving is possible, and a team that needs it should not need a ticket to a team that no longer remembers the process.

Worth being precise about, because teams resist archiving based on assumptions that are wrong.

The repository becomes read-only. No pushes, no new issues, no new pull requests, no editing of existing ones.

Everything remains visible. Code, history, issues, pull requests, releases, and the review record. Nothing is deleted and nothing is hidden.

It can be cloned. Read access is unchanged, so anybody who could clone it still can.

Existing releases and packages remain available. A consumer downloading a release asset is unaffected.

Workflows stop. Scheduled workflows do not run on an archived repository, which is frequently a benefit — an unowned repository running a nightly job against production is a real thing that exists.

It can be unarchived. By somebody with the right permission, at any time, restoring full function.

It still counts toward the organisation’s repository count, and its content still counts toward storage.

Saying all of this in the archival notification removes most objections. The fear is that archiving destroys something. It does not — it removes the ability to change, which for a repository nobody is changing costs nothing.

The one genuine loss: somebody cannot open a pull request to fix a bug. For a widely-consumed library that matters, which is why the dependents check is not optional.

Expressing it as a property makes it queryable and enforceable.

StateMeaningGovernance
activeMaintained, changingFull ruleset set applies
maintenanceStable, security fixes onlyReduced expectations, still owned
deprecatedReplacement exists, being migrated awayAnnounced, dated, no new consumers
pending-archiveCandidate, objection window openNotified owner
archivedRead-onlyNo expectations

Each transition has a trigger and a notification. A repository does not become deprecated because somebody feels it is; it becomes deprecated because an owner declares it, with a replacement named and a date.

The value of the explicit states is that they answer the questions people actually ask: is this maintained, should I use it, who do I ask, what replaces it. A README that says “deprecated, use X” is worth more than any policy, and the state property is what makes it findable at fleet scale.

Why unowned repositories are a security problem

Section titled “Why unowned repositories are a security problem”

The case worth making explicitly, because lifecycle governance is otherwise funded as tidiness and tidiness never gets funded.

An unowned repository does not get patched. A dependency alert arrives, nobody is notified, nothing happens. It sits open for years.

It does not get reviewed. Access reviews ask owners to confirm who should have access. With no owner, either the review skips it or somebody guesses.

It is not classified. Which means no targeted ruleset applies, no data-handling requirement is known, and it is invisible to every property-based control.

It still runs. Unowned repositories frequently still have working CI, live deploy keys, valid tokens and active workflows. Nobody watching does not mean nothing happening.

Its credentials still work. Deploy keys, Actions secrets and app installations attached to an unowned repository remain valid indefinitely, and they are exactly what nobody rotates.

And it is still in scope. If an auditor asks for the population of repositories subject to a control, unowned repositories are in that population whether or not anybody can answer for them.

Which reframes the ask. “Let us tidy up the repository list” is a hygiene request. “We have 340 repositories with live credentials, no owner and no patching” is a risk finding, and it gets attention.

Produce the number before asking for the work. The unowned count, with the subset that has open security alerts, is the strongest argument available for lifecycle governance and it takes an afternoon to produce.

Every lifecycle programme reaches a set of repositories that resist classification, and how you handle them determines whether the programme finishes.

The categories are predictable:

Owned by a team that no longer exists, with no obvious successor. Escalate to the organisation owner, and if that fails, to whoever owns the budget the team was in. Somebody inherited the work.

Nobody will claim it, but everybody uses it. The shared library that predates the current team structure. This needs an owner assigned rather than volunteered, and the assignment is a management decision.

Genuinely nobody’s and genuinely unused. Archive it. This is the easy case and it is usually the largest.

Contains something nobody wants to be responsible for. Old credentials, personal data, a licence question. These need actual investigation, and they are the ones worth doing first because they carry real risk.

Somebody’s personal project in a company organisation. More common than expected. Ask, and either archive or move it.

Set a deadline and a default. “Unclaimed repositories will be archived on this date” resolves more of the residue than any amount of asking, because it converts an optional task into a deadline. And archiving is reversible, which is what makes the default defensible.

Requesting metadata after creation. It mostly never arrives.

Owning by person. Wrong the day they change roles.

No unowned-repository report. The gap grows invisibly.

Deleting instead of archiving. Destroys the record, leaves the forks.

Archiving on a single signal. Stable libraries have no commits.

Asking teams to volunteer repositories for archival. Nobody volunteers.

No objection window. Somebody will be surprised, and they will be right.

No documented route back. Teams resist a process they cannot reverse.

Treating lifecycle as a cleanup project. It is a continuous process; a one-off sweep is undone within two years.

The difference between a lifecycle programme that works and a cleanup project that gets undone.

Monthly, not annually. A monthly cadence keeps the working set small — a few dozen candidates rather than a few thousand — and it keeps the process familiar. An annual sweep is a project every time.

Automate the identification, not the decision. A scheduled job that produces the candidate list, checks dependents, and drafts notifications. A human decides, and the decision is cheap because the analysis is done.

Send notifications to owners, not to a central queue. The owner knows whether the repository is finished. A central team does not, and a central team making that call will be wrong publicly and lose authority.

Track three numbers over time: total repositories, unowned repositories, and archived-this-month. The first tells you whether the estate is growing; the second is the governance gap; the third is whether the process is running at all.

Publish them. A dashboard that an engineering leader sees monthly is what keeps this funded, and it is what turns a good month into a visible one.

Expect the archive rate to be lumpy. A reorganisation produces a wave; a quiet quarter produces almost nothing. What matters is that the process runs, not that the numbers are steady.

And expect to be wrong occasionally. A repository will be archived that somebody needed. If unarchiving is quick and blameless, that is a minor inconvenience. If it requires an escalation, the whole programme becomes something people obstruct.

Every repository should have an owner and an expected end state from the day it is created. Governance that starts after creation is retrofitting, and retrofitting has a completion rate near zero. Build the creation path, publish the unowned list, and default the archival transition — those three things do more than any policy.

  • The four lifecycle stages are creation, active ownership, decline and retirement
  • Creation is the only cheap moment to collect metadata, and requiring explicit values is what guarantees it
  • Own by team rather than by person, with CODEOWNERS for operational ownership and a property for accountability
  • Ownership decays with reorganisations; reconciliation against the team list finds the stale values
  • Decline signals should be combined, never acted on individually — a stable library has no commits and many dependents
  • Archiving preserves history and the review record; deletion destroys both and leaves forks
  • Archival must be defaulted with an objection window, not requested
  • Expressing lifecycle state as a property makes it queryable and answers the questions people actually ask
  • The unowned-repository list is a permanent artifact with a permanent owner

Use an organisation you administer.

  1. Count repositories with no commits in twelve months. Predict: what fraction of the total?

  2. For ten of them, check whether anything in the estate depends on them.

  3. List repositories with no owning team recorded. Predict: how many?

  4. Cross-check owning-team values against the actual team list. How many name a team that no longer exists?

  5. Find the oldest repository with an open dependency alert. How long has it been open?

  6. Design your decline criteria: which signals, in what combination.

  7. Write the notification you would send to a repository owner announcing a 30-day archival window.

  8. Describe the repository creation path you would build, and what it would collect.

Engineering Team Onboarding SystemA 30-day Git and GitHub programme with standards templates, assessments and governance checklists.