Chapter 03Lesson 04~165 minutes

Projects, Repository Settings, Visibility, Forks, Protected Resources, and Project Templates: Diagnostics, Failure Modes, Security, and Performance

Diagnose project-scope mistakes, visibility exposure, unrelated histories, stale paths after rename or transfer, and unsafe archive/delete choices with an evidence-first, least-destructive workflow.

DiagnosticsUnrelated historiesTransfersArchiveDeletionRecovery

Learning objectives

  • Apply a repeatable evidence-first diagnostic sequence to project, namespace, path, visibility, and repository-history failures.
  • Diagnose authentication/authorization/availability errors separately from wrong-target and wrong-offering problems.
  • Explain why server initialization can create unrelated histories and repair the workflow without hiding the original cause.
  • Analyze rename/transfer blast radius across remotes, webhooks, packages, CI, registries, badges, and deployment references.
  • Choose archive, unarchive, pending deletion/restoration, or configuration rollback according to reversibility rather than convenience.
Availability baseline (verified 2026-08-21). Project creation, blank projects, forks, private/public visibility, basic protected branches/tags, archiving, and the Projects API are available across Free, Premium, and Ultimate on GitLab.com, Self-Managed, and Dedicated. Internal visibility is not available for new GitLab.com projects; it remains available on Self-Managed and Dedicated. Group custom project templates are Premium/Ultimate. Project topics are currently documented as Beta. Exact UI labels and administrator restrictions can vary by GitLab version and instance policy.

1. The diagnostic sequence: preserve → scope → inspect → minimally correct → verify

When project operations fail, resist the urge to delete and recreate the project. That can destroy the most useful evidence and introduce new paths, IDs, histories, and permissions. Use the same sequence every time:

  1. Preserve evidence: command, stderr/HTTP status, project path/ID, current remote URL, local HEAD, visible settings.
  2. Scope: host/offering → namespace → project → repository/ref → policy/role.
  3. Inspect: UI, glab repo view -F json, Projects API, git remote -v, git ls-remote, protected-ref APIs.
  4. Choose the least destructive correction: fix target/path/permission/configuration before transfer, history rewrite, or deletion.
  5. Verify independently: compare expected state through a second interface.

2. Failure mode: right project name, wrong namespace

api can exist under your user, platform/api, and payments/api. A short name is insufficient in automation. The wrong namespace can change ownership, inherited access, subscription context, registry/package coordinates, and visibility defaults even though the repository content looks correct.

# Prefer explicit path-with-namespace in scripts.
FULL_PATH="payments/api"
glab repo view "$FULL_PATH" -F json   --jq '{id,path_with_namespace,namespace,visibility,web_url}'

git remote -v
# Compare the exact hosted path with the Git remote before any mutation.

Repair: if the resource is disposable and empty, recreating at the correct namespace may be simplest. If it already has history/integrations, evaluate a transfer. A transfer is high-impact: it changes namespace/path and can change inherited access. Do not perform it as a casual fix.

3. Failure mode: visibility exposes more than the repository

A learner changes Private → Public to “make cloning easier.” The Git repository is now publicly reachable, but so can other project surfaces depending on feature visibility and pipeline settings. If the project ever contained confidential source/history or hosted metadata, revert visibility first and assess exposure; do not spend time polishing the README while data remains exposed.

Containment order: restore the intended visibility/access boundary first; preserve evidence; assess what was reachable; rotate any exposed credential separately. Changing visibility back does not revoke a credential that was copied while the project was public.

4. Intentionally broken example: two independent first commits

Cause: the GitLab project was initialized with a README, while a developer independently ran git init and committed locally. Both histories have different root commits.

# Synthetic reproduction in local temporary directories — no hosted project required.
TMP="$(mktemp -d)"
git init --bare "$TMP/remote.git"

git clone "$TMP/remote.git" "$TMP/server-side"
cd "$TMP/server-side"
git switch -c main
echo server > README.md
git add README.md && git commit -m "server root"
git push -u origin main

mkdir "$TMP/local-side" && cd "$TMP/local-side"
git init -b main
echo local > README.md
git add README.md && git commit -m "local root"
git remote add origin "$TMP/remote.git"

# Intentionally fails because origin/main is not an ancestor of local main.
git push -u origin main || true

git fetch origin
git log --oneline --graph --decorate --all --boundary

# Cleanup after inspection.
cd /
rm -rf -- "$TMP"

The useful evidence is the two roots in the graph. Do not immediately use --force or --allow-unrelated-histories. First decide which history is authoritative. For a brand-new disposable project, recreate the remote empty or clone the hosted history and reapply the intended local change. For valuable history, plan a deliberate merge or migration with review.

5. Failure mode: rename or transfer breaks consumers even though redirects exist

GitLab documents redirects after project path changes/transfers, but redirects are a migration aid, not permission to leave dependencies stale. Current transfer guidance explicitly tells operators to update local remotes, verify member access, update package configurations, test CI/CD/integrations, and review security policies.

Consumer What can embed the old path Verification after change
Developer Git origin/upstream URLs git remote -v, fetch and push test.
CI/CD Includes, project triggers, badges, API paths Pipeline lint/run and explicit project IDs/paths.
Package/Container Registry Image/package coordinates Resolve/pull/publish test using intended new path.
Webhooks / integrations Callback configuration or project URL references Delivery/test event and receiver logs.
Deployments / docs Manifests, links, badges, runbooks Search configuration repos and execute smoke checks.
Permissions Destination group inheritance Recompute effective members/roles; do not assume transfer preserved intended access model.

6. Failure mode: using deletion when archive or rollback is safer

Archiving makes most project features read-only and preserves project data, but it is not inert: current GitLab behavior removes fork relationships, closes open merge requests from forks, removes deployed Pages, stops scheduled pipelines, and stops pull mirroring. Unarchive reverses the read-only state and resumes schedules/mirroring, but Pages requires a rerun.

Deletion is more destructive. Current GitLab defaults first deletion to a pending deletion state across tiers, and Free gained delayed deletion/restoration behavior in GitLab 18.0. Retention and instance policy can vary, so do not hard-code a number of days into an operational runbook. Restore while the project is still pending if deletion was a mistake.

Never practice delete/restore on a valuable project. The chapter’s mandatory lab uses archive or configuration rollback. Immediate/permanent deletion is not required.

7. Failure mode: “the setting is missing, so I need Owner”

A missing control can have at least five causes: wrong offering, wrong tier, wrong GitLab version/feature status, administrator/group policy, or insufficient role. Example: Internal visibility is unavailable for new GitLab.com projects regardless of your project role. Group custom project templates require Premium/Ultimate. Granular protected-branch options can also be tier-dependent.

Evidence Interpretation
Docs say feature not offered on GitLab.com Do not escalate role; choose supported design.
Docs say Premium/Ultimate Free lab uses fixture/alternative; do not request billing merely for course completion.
API returns 403 Identity is known but action is forbidden; inspect role/policy/scope.
API returns 404 Could be wrong path/ID or intentionally hidden inaccessible resource; verify host/target and auth context.
UI differs but API field exists UI may have moved; prefer current docs and machine-readable inspection before assuming removal.

8. Low-risk broken example: wrong Git remote target

This exercise breaks only the local remote URL, not the hosted project.

ORIGINAL="$(git remote get-url origin)"
printf 'original=%s\n' "$ORIGINAL"

git remote set-url origin "git@gitlab.com:synthetic-does-not-exist/ch03.git"
# Preserve the failure message/exit status; do not hide it.
git ls-remote origin; STATUS=$?
printf 'exit_status=%s\n' "$STATUS"

# Least destructive repair: restore the exact prior URL.
git remote set-url origin "$ORIGINAL"
git ls-remote --heads origin

If SSH authentication succeeds but GitLab reports the project cannot be found or you lack permission, the problem may be target path or authorization—not SSH itself. Chapter 02’s authentication model and this chapter’s project-scope model meet here.

9. Project incident runbook

  1. Freeze high-impact mutations: no transfer, delete, visibility widening, force-push, or protection bypass while diagnosis is incomplete.
  2. Capture project ID/path/namespace/visibility/default branch/archive state and local remote/HEAD.
  3. Identify whether the problem is Git history, hosted configuration, authorization, tier/offering, or a downstream dependency.
  4. Correct the narrowest state: remote URL, description/setting, membership, supported visibility, or workflow reference.
  5. For path changes, run a consumer inventory and update each dependency deliberately.
  6. For accidental visibility exposure, contain access first and rotate any exposed credential.
  7. Verify through at least two independent surfaces and record what changed.

Knowledge check

A project is missing after a transfer, but the old URL redirects. Can automation keep the old path indefinitely?

Why is git push --force a poor first response to unrelated histories?

A GitLab.com Owner cannot select Internal visibility. What diagnostic branch wins?

A retired project should remain available as evidence but should stop normal writes. Archive or delete?

Summary

Most project incidents become worse when operators jump straight to transfer, force-push, visibility widening, or deletion. Preserve evidence, scope host/namespace/project/ref, separate Git state from hosted policy, identify tier/offering/role constraints, make the narrowest correction, and independently verify it. Reversibility is a production feature.

Official references

Next lesson

Integrate the whole project-governance model

Lesson 5 starts from a known local Git source state, predicts remote/default-branch behavior before the first push, proves every transition, compares creation strategies, and closes with a production handoff.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this address.