Skip to content

Creating a Git Repository

Before Git can track the history of a project, the project must be inside a Git repository.

The command used to create a new Git repository is:

Terminal window
git init

This command initializes a Git repository inside the current directory.

Suppose we create a normal project directory:

Terminal window
mkdir my-project
cd my-project

At this point, my-project is only a normal folder. It is not yet a Git repository.

If we run a Git command that requires a repository:

Terminal window
git status

Git may display an error similar to:

fatal: not a git repository (or any of the parent directories): .git

This means Git could not find repository information in the current directory or its parent directories.

While inside the project folder, run:

Terminal window
git init

Git creates a hidden directory named:

.git

The project folder is now associated with a local Git repository.

You can verify this using:

Terminal window
git status

You may see output similar to:

On branch main
No commits yet
nothing to commit

The exact initial branch name may depend on your Git configuration.

git init creates the internal structure Git needs to manage repository data.

Conceptually, the result looks like:

my-project/
├── .git/ Git repository data
├── src/ Visible project files
├── README.md
└── other files

The visible project directory is called the working tree or working directory.

The hidden .git directory stores Git’s internal repository data.

Project folder
├── Working tree → Files you open and edit
└── .git → Git metadata, objects, references, and history

These terms are related, but they are not exactly the same.

Working tree

The checked-out project files you open, edit, create, and delete in your editor.

For example: index.html, auth.js, src/, README.md

.git directory

Git’s private data: objects, branch and tag references, repository configuration, the index once the staging area is used, and history once commits exist.

You work with it through Git commands, not by editing it directly.

The working tree contains the checked-out project files that you can view and edit.

Examples:

index.html
auth.js
src/
README.md

Technically, the hidden .git directory contains the local Git repository data.

It stores the information Git uses to manage:

  • Commits and other Git objects.
  • Branch references.
  • Tags.
  • Repository configuration.
  • The current branch reference.
  • The staging area or index when it is created.
  • Repository history after commits exist.

In everyday conversation, developers may call the entire project folder “the repository,” even though the working tree and .git directory have different responsibilities.

After initialization, .git may contain entries such as:

.git/
├── HEAD
├── config
├── objects/
├── refs/
└── hooks/

Some files, such as the index, may appear only after performing additional Git operations.

HEAD tells Git which branch or commit is currently checked out.

Before the first commit, the initial branch exists as an unborn branch: it has a name, but it does not point to a commit yet.

Stores configuration specific to this repository.

You can view local configuration using:

Terminal window
git config --local --list

Stores Git objects, including blobs, trees, and commits, after those objects are created.

Stores references used by branches and tags.

Represents the staging area. It stores the project state prepared for the next commit.

The .git/index file may not exist immediately after an empty git init; Git creates or updates it when the staging area is used.

Contains sample hooks that can run scripts when certain Git events occur.

Hooks are an advanced topic and will be explained later if needed.

In a normal, non-bare project, the hidden .git directory is the local Git repository database and metadata.

The visible files beside it form the working tree.

Together, they provide the normal development experience:

Working tree .git repository
Files you edit ↔ History and Git data

No. Running:

Terminal window
git init

creates the repository structure, but it does not automatically place the current project files into Git history.

Immediately after initialization, existing files normally appear as untracked files:

Terminal window
git status

Example:

Untracked files:
README.md
auth.js

To prepare files for the first commit:

Terminal window
git add README.md auth.js

Then record the staged snapshot:

Terminal window
git commit -m "Initial commit"

The detailed behavior of git add, the index, and git commit is covered in the following workflow lessons.

After git init, the repository has no commits.

The first commit is commonly called the initial commit:

Terminal window
git add .
git commit -m "Initial commit"

After this commit:

  • Git has its first recorded snapshot.
  • The current branch points to the new commit.
  • The repository history has begun.

On Git Bash, Linux, or macOS:

Terminal window
ls -la

On PowerShell:

Terminal window
Get-ChildItem -Force

You should see .git inside the initialized project folder.

If neither the current directory nor one of its parent directories contains a valid .git repository, commands such as these will fail:

Terminal window
git status
git add .
git commit
git log

Commands that do not require an existing repository, such as the following, can still work:

Terminal window
git --version
git config --global --list

When you run a Git command inside a subdirectory, Git usually searches upward through parent directories until it finds .git.

For example:

my-project/
├── .git/
└── src/
└── features/

Running git status from src/features/ still uses the repository located at my-project/.git.

This means you normally run git init once at the project root, not inside every subfolder.

Do not normally run git init inside a subfolder that is already part of another repository.

This can create a nested repository:

main-project/
├── .git/
└── package/
└── .git/

The outer repository may then treat the inner repository differently from normal files, which can confuse beginners.

Initialize Git at the intended project root.

If you accidentally run git init again inside an existing Git repository, Git normally reports that it reinitialized the repository.

It does not normally erase existing commits, but repeatedly running the command is unnecessary.

Always confirm your current directory before initialization:

Terminal window
pwd
git status

In PowerShell, you can also display the current path using:

Terminal window
Get-Location
Terminal window
mkdir my-project
cd my-project
git init
git status
touch README.md
git status
git add README.md
git commit -m "Initial commit"
git log --oneline

On PowerShell, create the file using:

Terminal window
New-Item README.md

git init converts a normal directory into a directory containing a local Git repository by creating the hidden .git folder.

The visible files form the working tree. The .git directory stores Git’s internal repository data, including objects, references, configuration, staging information, and recorded history.

Initialization makes version tracking possible, but it does not automatically track or commit your files:

Normal folder

A plain directory. Git is not tracking anything yet.

Git repository

git init

Creates the hidden .git directory. Version tracking is now possible.

Changes prepared

git add

Selected files are placed in the staging area.

First snapshot

git commit

History begins; the current branch points to the new commit.