Skip to content
DevOps devops git 6 min read

Git Basics (init, add, commit)

Every single thing you do with Git comes back to three commands: git init to start tracking a folder, git add to pick the changes you want to save, and git commit to save them permanently. Master this small loop and you have the foundation for branching, collaboration, and the automated pipelines that power DevOps. This page walks through that loop step by step on Ubuntu, and spends extra time on the staging area — the one part that confuses almost every beginner.

This guide assumes you already have Git installed. If git --version returns an error, see Installing Git first.

The three-stage model

Before any commands, you need the mental picture. Git keeps your project in three places at once, and your changes move from left to right:

  1. Working directory — the real files on your disk that you edit in your text editor. This is “right now”.
  2. Staging area (also called the index — a holding zone) — a list of exactly which changes you have chosen to include in your next commit.
  3. Repository — the hidden .git folder that stores the permanent, committed history of snapshots.

The flow is always: edit a file (working directory) → git add it (staging area) → git commit it (repository).

StageWhat it holdsCommand to move into it
Working directoryYour live, edited files(you just edit them)
Staging area / indexChanges chosen for the next commitgit add
Repository (.git)Permanent committed historygit commit

Why a staging area at all?

This is the question every beginner asks. Other tools save everything you changed in one go, so why does Git make you add first?

The answer: the staging area lets you craft a clean commit. Say you fixed a bug in app.py and also half-finished an unrelated experiment in config.yaml. You only want the bug fix in this commit. With staging you git add app.py alone, commit just that, and leave the experiment for later. Without it, the two unrelated changes would be tangled together forever in your history.

When to use it (and when not): Stage deliberately when a commit should tell one clear story. When you genuinely changed only one thing and want it all in, the shortcut git add . (stage everything) or git commit -am "msg" (stage all tracked files and commit in one step) is fine. The control is there when you need it; ignore it when you don’t.

Starting a repository with git init

A repository (or repo) is just an ordinary folder that Git is watching. git init creates the hidden .git directory inside it that holds the history. Run it once, when a project starts.

mkdir ~/web-app
cd ~/web-app
git init

Output:

Initialized empty Git repository in /home/ubuntu/web-app/.git/

That .git/ folder is your repository. Delete it and you delete all history (the files themselves stay). You can confirm it exists:

ls -a

Output:

.  ..  .git

Checking state with git status

git status is the command you run more than any other. It tells you what stage everything is in: what is changed but unstaged, what is staged and ready to commit, and what Git is not tracking yet. Get into the habit of running it constantly.

Create a file first, then check:

echo "print('hello devops')" > app.py
git status

Output:

On branch main

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)
	app.py

nothing added to commit but untracked files present (use "git add" to commit)

Untracked means Git sees the file but is not yet recording its changes. That changes the moment you stage it.

Staging changes with git add

git add copies the current state of a file into the staging area. You can name one file, several files, or use . to stage everything in the current folder.

git add app.py
git status

Output:

On branch main

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
	new file:   app.py

Notice the wording changed from “Untracked files” to “Changes to be committed”. The file is now staged and ready.

Gotcha: git add takes a snapshot of the file as it is right now. If you edit app.py again after adding it, those newer edits are NOT staged — you must git add again. Run git status and you will see the same file listed as both staged and modified. This trips up nearly everyone once.

Recording a snapshot with git commit

git commit writes everything in the staging area into the repository as a permanent snapshot. The -m flag attaches a message describing what changed — always include one.

If this is your first commit ever on this machine, set your identity once (Git stamps every commit with your name and email):

git config --global user.name "Your Name"
git config --global user.email "[email protected]"

Now commit:

git commit -m "Add initial app.py"

Output:

[main (root-commit) a1b2c3d] Add initial app.py
 1 file changed, 1 insertion(+)
 create mode 100644 app.py

root-commit means this is the very first commit. a1b2c3d is the start of the commit hash — a unique fingerprint identifying this exact snapshot. After committing, git status is clean again:

git status

Output:

On branch main
nothing to commit, working tree clean

A full first-commit walkthrough

Here is the entire loop end to end, including a second commit so you see the cycle repeat:

mkdir ~/demo && cd ~/demo
git init                               # 1. create the repo
echo "# Demo Project" > README.md      # 2. edit the working directory
git add README.md                      # 3. stage the change
git commit -m "Add README"             # 4. commit to history

echo "MIT License" > LICENSE           # edit again
git add LICENSE                        # stage the new file
git commit -m "Add license"            # second commit

Output:

Initialized empty Git repository in /home/ubuntu/demo/.git/
[main (root-commit) f0e1d2c] Add README
 1 file changed, 1 insertion(+)
 create mode 100644 README.md
[main 9a8b7c6] Add license
 1 file changed, 1 insertion(+)
 create mode 100644 LICENSE

Viewing history with git log

git log shows your commits, newest first. The full output is verbose; --oneline gives a compact one-line-per-commit summary that is far easier to scan.

git log --oneline

Output:

9a8b7c6 Add license
f0e1d2c Add README

Add --stat to also see which files each commit touched, or just git log for the full detail (author, date, full hash, and message). Press q to quit the log viewer.

Best Practices

  • Run git status constantly. Before staging, before committing, and after — it removes all guesswork about what state you are in.
  • Commit small, focused changes. One logical change per commit makes history readable and rollbacks safe.
  • Write clear messages in the imperative mood. “Add nginx config”, not “stuff” or “changes”.
  • Stage deliberately when it matters. Use git add <file> to keep unrelated changes out of the same commit.
  • Re-add after editing a staged file. Remember the snapshot is taken at add time, not at commit time.
  • Set your name and email once with git config --global so every commit is correctly attributed.
  • Never commit secrets. Keep keys and passwords out with a .gitignore file.
Last updated June 15, 2026
Was this helpful?