The first GitLab screen can make a tiny project feel oddly official. There is a namespace to choose, a visibility decision, a README checkbox, and—waiting behind all of that—a terminal that may already contain months of work. The good news is that the setup is not fragile once you decide one thing first: does your code already have Git history?
This walkthrough follows an existing local folder into a new GitLab project, then shows the cleaner alternative when you are starting from nothing. The Git commands were exercised with Git 2.43.0 against a disposable local bare remote; GitLab interface, authentication, and branch-protection behavior were checked against current official documentation.
First, untangle the four names on the screen
Project: the GitLab workspace containing the repository, issues, merge requests, CI/CD settings, and members.
Repository: the Git object history and files inside that project.
Namespace: the user, group, or subgroup that owns the project and forms the URL path.
Project slug: the final URL component. “Weather CLI” might live at
gitlab.com/acme-tools/weather-cli.
The README checkbox decides which road you are on
You already have a local project
Create a blank GitLab project and leave Initialize repository with a README cleared. GitLab then gives you an empty remote that can accept your existing history without inventing a competing first commit.
You are beginning a brand-new project
Select Initialize repository with a README, then clone the repository and work inside that clone. Your local copy begins with the same default-branch history as GitLab.
Create the empty GitLab home for existing code
Select Create new → New project/repository → Create blank project.
Choose a project name and inspect the generated slug.
Select the correct personal or group namespace; it becomes part of the remote URL.
Choose visibility according to who should read the source—not according to who may eventually use the deployed software.
Leave Initialize repository with a README cleared for existing local history.
Optionally enable security scanners available to your plan and instance, then create the project.
Pause before the first commit
git --version
git status --short --branchgit version 2.43.0
## No commits yet on main
?? .env
?? .gitignore
?? README.md
?? src/That uncomfortable .env line is a gift
git status --short --branchreports branch and concise file states without changing the working tree.??means Git is not tracking the path; it does not mean the path is safe to commit.Add secrets, generated output, dependencies, editor state, and local configuration to a project-appropriate
.gitignorebefore staging.If a secret was committed, removing the working-tree file is insufficient. Rotate the credential and use a reviewed history-cleaning procedure.
Turn the folder into a deliberate first commit
git init -b main
git add README.md src/ .gitignore
git diff --cached --stat
git commit -m "Initial commit" README.md | 12 ++++++++++++
.gitignore | 3 +++
src/main.py | 24 ++++++++++++++++++++++++
3 files changed, 39 insertions(+)
[main (root-commit) a1b2c3d] Initial commitA first commit should be boring in the best way
git init -b maincreates a local repository and branch; it uploads nothing.Explicit paths are easier to review than blindly staging the entire folder.
git diff --cached --statsummarizes the staged snapshot;git diff --cachedshows its actual lines.git commitrecords locally. The sample hash will differ on your machine.If Git requests identity, configure suitable
user.nameanduser.email; they identify commits and are not login credentials.
Connect the exact remote GitLab gives you
git remote add origin git@gitlab.com:YOUR_NAMESPACE/weather-cli.git
git remote -vorigin git@gitlab.com:YOUR_NAMESPACE/weather-cli.git (fetch)
origin git@gitlab.com:YOUR_NAMESPACE/weather-cli.git (push)Replace the placeholder; do not type around it
Copy the SSH or HTTPS URL from the project’s Code menu so host, namespace, and slug are exact.
originis a conventional local nickname, not a GitLab requirement.git remote -vverifies configuration only; it does not prove authentication or access.For SSH, add and test a GitLab SSH key. For HTTPS with two-factor authentication, use a suitable personal access token.
Push once, then verify from both sides
git push --set-upstream origin main
git status --short --branch
git branch -vvTo gitlab.com:YOUR_NAMESPACE/weather-cli.git
* [new branch] main -> main
branch 'main' set up to track 'origin/main'.
## main...origin/main
* main a1b2c3d [origin/main] Initial commitWhat success actually proves
--set-upstream(short form-u) links localmainwithorigin/mainfor later push and pull defaults.main...origin/mainwithout ahead or behind counts means the local tracking references agree at that moment.Open the GitLab repository page and confirm the expected files, branch, and commit message.
The output contains placeholders and a sample hash. The command sequence was validated locally; no live GitLab account operation is claimed.
If GitLab already has a README, begin by cloning
git clone git@gitlab.com:YOUR_NAMESPACE/weather-cli.git
cd weather-cli
git status --short --branchCloning into 'weather-cli'...
## main...origin/mainWhy cloning feels quieter
git clonecreates a directory, copies reachable history, configuresorigin, and checks out the default branch.Do not clone into a different non-empty project folder and expect Git to merge two projects automatically.
Add your source inside the clone, review it, commit it, and push through the shared history.
GitLab defaults to
mainonly when project, group, and instance settings specify no other name. Trust the branch the clone checks out.
Give the project a safe first week
Describe it: document purpose, setup, tests, and ownership in the README.
Invite deliberately: use roles matching what each person must do; never share credentials.
Inspect branch rules: GitLab protects default branches by default, with details influenced by group and instance settings.
Prefer merge requests: push a feature branch, run CI, request review, and merge into the protected branch.
Add honest CI: a small pipeline running a real project check beats decorative green YAML.
Review secrets: enable suitable scanners, but treat them as a backstop rather than permission to commit credentials.
When the first push pushes back
`Permission denied (publickey)`: confirm the remote host, loaded SSH identity, GitLab account, and authentication test.
HTTP authentication failed: verify token scope and expiry; keep the token out of remote URLs, history, and files.
`remote origin already exists`: inspect it, then use
git remote set-url origin <copied-url>if it is wrong.Remote contains work: stop and inspect it. You may have initialized a README; do not overwrite history you have not reviewed.
Protected branch denied: push a feature branch and open a merge request, or ask a Maintainer about intended permissions.
`src refspec main does not match any`: confirm a commit exists and inspect
git branch --show-current.
The moment it becomes a real project
It is not the moment GitLab draws a repository page. It is the quieter moment when you can make a change on a branch, see exactly what you are about to commit, push without fear, and explain who is allowed to merge it. Every later pipeline and merge request rests on that small sense of control.
Comments and corrections