Projects, Repository Settings, Visibility, Forks, Protected Resources, and Project Templates: Concepts, Architecture, and Mental Model
Build a precise mental model of GitLab projects as namespace-scoped hosted containers around Git repositories, and separate repository state from visibility, templates, forks, protected refs, and project lifecycle policy.
Learning objectives
- Explain why a GitLab project is broader than a Git repository and identify which state belongs to Git versus GitLab.
- Relate namespace, project path, repository, default branch, visibility, feature toggles, forks, templates, and protected refs without collapsing them into one concept.
- Explain how initialization, README/license/template choices create Git history and therefore affect later local-repository integration.
- Distinguish archive, rename, transfer, export/import, deletion, and restoration by reversibility and downstream impact.
- Inspect a project read-only through the UI, Git, glab, and REST API before changing project configuration.
1. A project is a governance boundary, not just a remote repository
After Chapters 01 and 02, you know where GitLab runs and how identities authenticate. The next production question is: what exactly are you creating when you click New project? A Git repository stores commits, trees, blobs, tags, and refs. A GitLab project wraps a repository in hosted state: a namespace path, visibility policy, members and inherited access, issues/work items, merge requests, CI/CD configuration and history, registries, security features, webhooks, deployment metadata, and project settings.
This distinction prevents a common beginner error. Running
git clone copies repository history and refs; it does
not clone GitLab membership, issue state, protected-branch policy,
CI variables, webhooks, container images, or billing/namespace
ownership. Conversely, changing a project description or visibility
does not create a Git commit.
2. Namespace → project → repository → refs: the core mental model
flowchart LR NS[Namespace personal/group] --> P[GitLab project path + policy + hosted features] P --> R[Git repository objects + refs] R --> B[branches/tags] P --> H[hosted metadata issues/MRs/settings] P --> C[CI/CD + registries] POL[visibility + roles + protected-ref policy] --> P F[fork project separate namespace/project] -. fork relationship .-> P
The namespace determines the project address and an important ownership/inheritance boundary. The project owns hosted configuration. The repository inside it owns Git history. Branch and tag protection are GitLab policy around refs; they are not new Git object types. A fork is another GitLab project with its own namespace and settings plus a recorded relationship to an upstream project.
3. Project identity: name, slug, path, ID, and namespace
| Field | What it means | Why DevOps cares |
|---|---|---|
| Name | Human-facing project name. | May change without being the stable machine identifier you should rely on. |
| Slug / path | URL-safe segment under the namespace. | Appears in web, clone, package, registry, webhook, and integration addresses. |
| Path with namespace | For example team/payment-api. |
Makes the target unambiguous across groups and users. |
| Project ID | Numeric GitLab identity. | Useful for APIs because it survives many display-name changes. |
| Namespace | Personal namespace or group/subgroup that contains the project. | Controls ownership context, inheritance, transfer destination, and often governance. |
4. Visibility is hosted authorization, not Git cryptography
Visibility determines who can discover and access a project through GitLab. It does not encrypt Git objects. On GitLab.com, new projects are effectively chosen between Private and Public; the Internal level is documented for Self-Managed and Dedicated, where authenticated non-external users can access internal resources subject to policy.
| Visibility | Who can generally see/clone | Offering note |
|---|---|---|
| Private | Members with sufficient repository access. | All offerings. |
| Internal | Authenticated internal users, except external users, subject to instance policy. | Self-Managed and Dedicated; not available for new GitLab.com projects. |
| Public | Anyone, including unauthenticated users, unless an administrator restricts public access. | All offerings; use deliberately because code and hosted metadata can become internet-visible. |
5. Initialization choices can create the first Git history
A blank project with no repository commit is different from a project initialized with a README, license, or template. Selecting Initialize repository with a README creates the default branch and a first commit on the server. If you already have an unrelated local repository with its own first commit, pushing or pulling without planning can produce a non-fast-forward rejection or an unrelated-histories situation.
The safest production pattern is to declare the source of truth before project creation: either start hosted-first and clone that history, or create an empty GitLab project and push the existing local history. Do not independently initialize both sides and hope Git will infer that they belong together.
6. Forks, copies, imports, and templates preserve different relationships
| Mechanism | Repository/history result | Hosted relationship / copied state |
|---|---|---|
| Fork | Copies upstream repository, optionally all branches or only default branch. | GitLab records an upstream fork relationship; issues/MRs/wiki are not simply cloned as part of the fork. |
| Built-in project template | Starts from template content/history provided by GitLab. | Creates an independent project; useful for scaffolding, not continuous upstream synchronization. |
| Group custom project template | Copies exportable project state from a template project. | Premium/Ultimate; copied permissions/sensitive objects depend on creator permissions. |
| Import/export | Migrates supported project data/history. | Migration operation, not a live synchronization relationship. |
| Independent Git copy | You can clone and push repository history elsewhere. | No GitLab fork relationship or automatic hosted-state transfer. |
7. Protected branches and tags are policy around refs
A protected branch is still an ordinary Git branch ref. GitLab evaluates hosted authorization before accepting certain pushes, deletes, force-pushes, or merges. Protected tags similarly control who may create protected tag names and help prevent accidental update/deletion. Basic protected branches and protected tags are available on Free; finer-grained user/group and Code Owner controls are tier-dependent.
Current GitLab documentation exposes protected-branch configuration through Settings → Repository → Branch rules; the older dedicated Protected branches settings are being removed. That is exactly why the course teaches the policy model before memorizing a menu path.
8. Project lifecycle operations have different blast radii
| Operation | Reversibility / effect | Production question |
|---|---|---|
| Rename path | Redirects may help temporarily, but remotes and integrations can still need updates. | Which scripts, webhooks, packages, badges, registries, deploy references, and docs embed the old path? |
| Transfer | Moves the project to another namespace; access/inheritance and paths may change. | Does destination ownership and membership match the intended governance model? |
| Archive | Makes most project features read-only, removes fork relationships, stops scheduled pipelines and pull mirroring. | Is preservation/read-only state sufficient instead of deletion? |
| Delete / pending deletion | Schedules destructive removal; restoration is possible while pending under current behavior. | Have you exported evidence and verified there is no valuable data? |
| Export/import | Copies supported project data for migration/backup-like workflows. | What is excluded and how will identity/permissions be verified after import? |
9. Read-only inspection before configuration
Use several surfaces because each proves something different. The
web UI is useful for human-readable settings;
glab gives structured command output; Git proves
local/remote ref state; the REST API exposes machine-readable
project metadata.
# Replace with a project you can safely inspect.
FULL_PATH="your-namespace/your-project"
# Hosted project metadata through glab.
glab repo view "$FULL_PATH" -F json --jq '{id,path_with_namespace,visibility,default_branch,archived,topics}'
# Find the numeric project ID once, then make the target explicit.
PROJECT_ID="$(glab repo view "$FULL_PATH" -F json --jq .id)"
glab api "projects/$PROJECT_ID" --jq '{id,path_with_namespace,visibility,default_branch,archived,empty_repo,topics}'
# Git answers a different question: which remote URL and refs exist locally?
git remote -v
git branch -vv
git ls-remote --heads origin
A missing field is evidence, not permission to guess. For example,
default_branch: null can be legitimate for an empty
project. Likewise, an empty protected-branches list means no
returned rules for that project/context; it does not prove an
instance administrator cannot impose other controls.
10. Why these defaults become production dependencies
CI pipeline sources, branch rules, package coordinates, container registry paths, release URLs, webhook targets, environment policies, deployment scripts, and dashboards often reference project identity and default-branch assumptions. A project path that looks cosmetic on day one can be a production interface six months later. Treat creation defaults as architecture: document the owner, namespace, visibility, source-of-truth history, default branch, and lifecycle policy before automation depends on them.
Knowledge check
You clone a project and receive commits, but no GitLab issues or CI variables. Is the clone incomplete?
No. Git clone transfers repository objects and refs, not GitLab-hosted project metadata such as issues, variables, permissions, or policy.
A branch is “protected.” Did Git create a new protected-branch object in the repository?
No. The branch remains a Git ref; GitLab enforces hosted authorization/policy around operations on that ref.
Why can “Initialize with README” be dangerous when you already have a local repository?
It creates an independent remote commit/history. Your local history may then diverge from the server from the very first commit, causing non-fast-forward or unrelated-history problems.
A learner on GitLab.com cannot select Internal visibility. Is that necessarily a permissions bug?
No. Current GitLab documentation limits Internal visibility to Self-Managed and Dedicated for new projects; offering availability must be checked before blaming permissions.
Summary
A GitLab project is a namespace-scoped hosted container around a Git repository, not a synonym for the repository itself. Visibility, feature settings, forks, templates, protected refs, archive/delete state, and namespace ownership live in GitLab. Initialization choices can create real Git history. Production-safe project creation therefore starts by identifying the source of truth, owner, namespace, visibility, default branch, and downstream path dependencies before clicking Create.
Official references
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.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this
address.