Keep Secrets Out of Git

GitBeginner
Practice Now

Introduction

A file can be useful on your machine and still be inappropriate for a source-code commit. This fresh DeskLite repository has a small business change and a private configuration containing a fictional credential. The private file was accidentally staged but has never been committed.

You will learn the Git working area, staging area, and commit snapshot; separate private settings from deliverable examples; and use a prepared credential scanner. You need no Git account, remote repository, or prior Git knowledge.

Locate the Working and Staging Areas

In this step, you will identify which files Git is preparing to save.

Git records selected versions of files in a repository. Its working tree contains the files you edit. The staging area holds the next snapshot you intend to commit. A commit saves that staged snapshot in local history; it does not automatically upload anything.

cd /home/labex/project/desklite-git

git status compares these areas:

git status

The prepared terminal may color file categories; the wording is what matters. Look for two different categories. private.env appears under changes to be committed: its content is already staged. service/app.py appears under changes not staged for commit: its business edit is still only in the working tree. The branch name may vary and does not affect this task.

git ls-files lists tracked paths, including new files staged for their first commit:

git ls-files

The private file appears even though it has not been committed. This is the moment to prevent the leak. The initial committed history is clean. Do not make a commit yet: first inspect what would go into it.

Compare the Two Kinds of Change

In this step, you will compare the business edit with the staged private configuration.

git --no-pager diff shows unstaged changes. The global --no-pager option keeps the output directly in the terminal, so no separate viewer needs to be closed. Limit it to the business file by naming that path:

git --no-pager diff service/app.py

Lines beginning with - show old content; lines beginning with + show new content. The new program prints DeskLite tickets ready. Keep this intended business change.

git --no-pager diff --cached shows staged content instead. The --cached option selects the staging area:

git --no-pager diff --cached

You should see private.env and its SERVICE_NAME and API_TOKEN keys. The token is fictional and works nowhere outside this course. Nevertheless, it represents the kind of value that should remain private.

A staged snapshot can differ from the file currently on disk. Checking only the working tree can therefore miss something already prepared for a commit. Before committing, inspect both kinds of change.

The repository already has a local example author identity configured. You will not supply personal information or connect Git to an external service.

Read a Redacted Credential Finding

In this step, you will run the prepared scanner against the private file and interpret the finding.

Gitleaks detects text patterns associated with credentials. The course launcher course-secrets runs Gitleaks 8.24.2 with one fixed local rule for our synthetic labex_ token format. It redacts matched values and makes no network request. This limited course rule is not a complete production secret-detection policy.

Give the launcher a file or directory to scan its current contents:

course-secrets private.env

Expect a finding identified by desklite-practice-token, a filename/line number, and a redacted secret. The command intentionally exits with status 1 because it found a credential. A finding is different from a tool failing to run.

This command scans the current file, regardless of whether Git tracks it. A history scan, introduced later, inspects committed changes. A clean history would not make this uncommitted file safe to stage.

The private value is only in staged/working content here. If a real credential had already been exposed, removing it from a new commit would not invalidate it or erase old copies: its owner would need to revoke or replace it. This exercise does not teach history rewriting.

Separate Private Settings from the Example

In this step, you will remove private settings from Git tracking, add a narrow ignore rule, and create a usable public example.

git rm --cached removes a path from the staging/tracking area while preserving the local file. Here it undoes the accidental staging of a new private file:

git rm --cached private.env

Open .gitignore, which tells Git which untracked paths to leave out:

nano .gitignore

Enter this single rule, then save with Ctrl+O, Enter, Ctrl+X:

/private.env

The leading / anchors the rule to this repository's root. Do not ignore service/: it contains files that should be delivered. Ignore rules do not automatically remove already tracked files or old commits; that is why the previous command was necessary.

Create a public example using the same configuration keys:

nano service/config.example.env

Save:

SERVICE_NAME=DeskLite
API_TOKEN=REPLACE_ME

The example tells a future operator which settings are needed without supplying a working credential. Keep the original private file locally.

ls private.env
git status

The private path should no longer be staged or listed as untracked. .gitignore and the public example should be untracked and ready for deliberate staging. The existing business change remains unstaged.

Stage Only the Delivery Files

In this step, you will prepare the exact files intended for the next commit.

git add copies the current content of named paths into the staging area. Name each intended delivery file explicitly:

git add service/app.py service/config.example.env .gitignore

Review both the file categories and the staged content:

git status
git --no-pager diff --cached

Expect exactly the intended business edit, the narrow ignore rule, and the safe example. There should be no private token. If you edit a file again after git add, you must stage the updated content before committing; Git does not automatically replace an earlier staged snapshot.

List tracked paths again:

git ls-files

The three delivery paths should appear; private.env should not. This check answers a different question from ls: the local private file still exists, but it is outside Git tracking.

The next step scans the deliverable directory. Scanning a deliberately limited delivery scope does not establish that every file elsewhere on the machine is secret-free.

Scan the Delivery Content

In this step, you will check the source directory that will be delivered while preserving the private local settings.

Run the same fixed-rule scanner against the service directory:

course-secrets service

Expect no leaks found and a successful exit. The scanner processes actual source and example content. It does not rely on a manually edited report.

The private configuration lives at the repository root, outside this delivery directory. Scanning that private file again would still report its token; that is expected. We have separated audiences rather than claimed that sensitive data has ceased to exist.

Inspect the staged snapshot once more:

git --no-pager diff --cached

The directory scan checks current files; the diff checks what Git will save. Both must agree on the intended delivery content. A scan with no findings only supports the configured rule and scope—it cannot establish that all possible secrets or security flaws are absent.

You now have a reviewed staged snapshot. The next step saves it as a local commit.

Save a Local Commit

In this step, you will save the reviewed staged snapshot in local history.

git commit records the staging area. The -m option supplies a short message describing the change; quotes keep its words together:

git commit -m "Deliver ticket message and safe configuration example"

Expect a commit summary with the three changed paths. Commit IDs and file statistics can vary, so focus on what was included.

git status

Expect a clean working tree. The ignored private file still exists even though git status does not list it.

A commit is local. Nothing has been pushed, uploaded, or shared with a remote service. This is enough to practice preparing a safe handoff without a personal account.

If Git reports nothing to commit, compare git status, git ls-files, and the staged diff with the previous steps. Do not solve an unexpected state by deleting the repository or its existing history.

Check History and the Business Change

In this step, you will scan the committed history and exercise the small program you preserved.

The launcher's --history option selects Gitleaks Git-history scanning. The final . means this repository:

course-secrets --history .

Expect no leaks found. The clean initial commit and your new delivery commit should both pass the fixed rule. A successful file scan earlier would not by itself prove this history result.

python3 runs the supplied Python program. You do not need to edit or understand Python syntax in this lab:

python3 service/app.py

Expect:

DeskLite tickets ready

Confirm the local private file remains outside Git tracking:

ls private.env
git ls-files

You now have useful delivery files, a safe configuration example, and a local commit without the practice credential. The private file has not been deleted, and the business change still works. No copied scan report or investigation file is required.

Summary

You separated local private settings from source delivery, reviewed staging before committing, and checked both current delivery files and local Git history with a fixed redacted credential scan. The business change and useful public example remain, while private settings stay outside the commit.