openskills.info
Git Fundamentals logo

Git Fundamentals

itDevOps and software delivery

Git Fundamentals

Git is a distributed version control system: each ordinary clone contains the project files, the repository's reachable history, and references such as branches and tags. Most inspection and history operations are therefore local. A hosting service can coordinate collaboration, but it is not Git itself and it is not the only copy of the repository.

The useful beginner model is not “Git saves files.” Git records snapshots and relationships. A commit identifies a project tree, its parent commit or commits, author and committer information, and a message. Commits and file contents are immutable objects; names such as main, feature/login, and v1.0.0 are references that make selected objects convenient to find.

The four places you reason about

Day-to-day Git becomes predictable when you distinguish four places:

  1. Working tree — the files you are editing.
  2. Index, usually called the staging area — the exact file contents proposed for the next commit.
  3. Current commit (HEAD) — the snapshot currently checked out through a branch, or directly in detached-HEAD state.
  4. Remote-tracking references — local records such as origin/main describing the last state fetched from a remote.

git status summarizes differences among these places. git diff compares the working tree with the index by default; git diff --staged compares the index with HEAD. git add copies selected working-tree content into the index. git commit turns the index into a new commit and advances the current branch to it.

This separation is deliberate. You can edit several files, stage only one coherent change, inspect exactly what will be committed, and leave unrelated work for later. A commit is not a cloud upload: it updates local history. Network exchange is a separate operation.

A safe everyday loop

Start with observation:

git status
git diff

Stage intentionally, inspect the proposal, then commit:

git add path/to/file
git diff --staged
git commit -m "Explain the reason for the change"

Inspect history with git log, and inspect one commit with git show <revision>. Prefer small commits that express one reviewable idea. Git will accept a chaotic snapshot; it cannot supply the judgement that makes history useful.

Branches and integration

A branch is a movable name for a commit, not a second copy of the directory. git switch -c topic creates a branch and switches to it. New commits advance that branch. git switch main updates the index and working tree to match main; Git normally refuses a switch that would lose local changes.

git merge topic integrates the named history into the current branch. It may fast-forward the current branch, create a merge commit, or stop for conflict resolution. A merge commit preserves both parent histories.

git rebase main takes commits unique to the current branch and reapplies their changes on a new base. The result can be easier to read, but the reapplied commits have new identities. Rebase private work freely when it helps; do not casually rewrite commits other people may already depend on.

Conflicts are not Git malfunctioning. They mean Git cannot safely combine competing changes without a human decision. Resolve the files, stage the resolutions, then continue or abort the operation using the command Git reports.

Remotes are explicit

A remote is a named collection of repository URLs, conventionally origin after cloning. git fetch origin downloads objects and updates remote-tracking references without integrating them into the current branch. This makes fetch a useful inspect-first operation.

git pull fetches and then integrates, using merge or rebase according to arguments and configuration. It is convenient, but it combines two decisions. When history matters, fetching first makes the incoming state visible before integration.

git push asks a remote to update references using objects from your repository. A push can be rejected when the remote branch contains work your local branch does not include. That is protection against accidentally discarding shared history, not a prompt to force by reflex.

Undo by identifying the layer

“Undo” is ambiguous in Git. Name the place and whether history is already shared:

  • To unstage while keeping the working-tree edit, use git restore --staged <path>.
  • To discard an unstaged working-tree change, use git restore <path> only when that loss is intentional.
  • To create a new commit that reverses an existing commit, use git revert <commit>; this is usually appropriate for shared history.
  • To move a branch and optionally change the index or working tree, use git reset only after choosing its mode deliberately.
  • To recover a locally “lost” commit, inspect git reflog; reflogs record local reference movement and are not shared with remotes.

git reset --hard and forced pushes can destroy reachable work or overwrite shared references. They are precision tools, not generic error recovery. Observe first, preserve a reference when uncertain, and prefer a new corrective commit on shared branches.

Where Git fits—and where it does not

Git is strong at versioned text, branching, reviewable change sets, and distributed collaboration. It does not replace backups: local reflogs expire, unreachable objects may eventually be pruned, and a force push can remove the reference other people expected. It is also a poor default for large frequently-changing binary assets unless the project adopts an appropriate extension and storage policy.

The practical goal is not memorizing every command. It is learning to ask: which repository state am I looking at, which reference will move, and will this operation preserve or rewrite history?

Relevant careers