Instiq
Chapter 1 · Software Development and Design·v1.0.0·Updated 7/20/2026·~16 min

What's changed: Initial version

1.4Version control and Git

Key points

Covers the benefits of version control with Git, the roles of clone, add, commit, push/pull, branch, and merge, plus resolving a merge conflict and reading a unified diff (@@ hunks and +/- lines), framed as interpreting and diagnosing given artifacts: "what does this git output mean and what do I do next?"

In the era of infrastructure-as-code (IaC), configs and scripts are version-managed with Git by default. What is tested—and needed on the job—is less memorizing command names than the ability to read the git output in front of you and decide the next move: why a push was rejected, what conflict markers mean, and what a diff is showing. This section first fixes the benefits of (distributed) Git and the roles of the core commands, then covers resolving a merge conflict and reading a unified diff by diagnosing real output.

1.4.1Benefits of version control

  • Git is distributed version control: each developer works in a local repository holding the full history and can revert to any point. Who changed what, when, and why stays in history, and if something breaks you can recover to the previous commit—this is the biggest safety net over manual operation.
  • With branches you diverge from the mainline (e.g., main) to develop safely and integrate later via merge. Multiple people can work different features in parallel with conflicts managed, and review (pull request) and automated tests can be inserted before merging. In IaC, the history and rollback of config changes especially pay off.

1.4.2Roles of the core commands

  • git clone <url> copies an entire remote repository to your local machine. git add <file> stages changes (marks them for the next commit). git commit -m "..." records staged changes in local history (not yet on the remote at this point).
  • git push sends local commits to the remote. git pull fetches remote changes and integrates them into your work (fetch + merge). git branch/git checkout -b create/switch branches. git rm records the deletion of a tracked file. The canonical order is change -> add -> commit -> (pull to update) -> push.

1.4.3Reading merge conflicts and diffs

  • A merge conflict arises when integrating branches that changed the same line differently. Git marks the spot with <<<<<<< HEAD / = / >>>>>>> branch. The top is your (HEAD) side and the bottom is the other branch's content, and a human decides which to take (or how to combine), removes the markers, then adds and commits.
  • A unified diff shows changes with - (removed lines) and + (added lines), and a hunk header like @@ -10,3 +10,4 @@ gives the change location (from old line 10 for 3 lines / new line 10 for 4 lines). git diff shows the working-tree difference and git log the history. Reading diffs lets you instantly judge "what did this commit change?" in review.
Exam point

Most-tested: add = stage, commit = record locally, push = send to remote, pull = fetch + integrate; conflict markers <<<<<<< HEAD/=/>>>>>>> with top = yours, bottom = theirs; a unified diff uses - remove/+ add and @@ for location; a rejected push (non-fast-forward) means pull first. Questions arrive as interpretation: "what does this git output mean?" and "which command should I run next?"

You finish work on a feature branch and run git push, but the remote returns ! [rejected] ... (non-fast-forward) and hint: Updates were rejected because the remote contains work that you do not have locally. Forcing it with git push --force here is a dangerous call—it can overwrite a colleague's commit and corrupt history. The correct reading is "the remote has changes you do not have yet, so take them in first," and the next move is git pull (fetch + merge). On pulling, a merge conflict arises because both of you changed the same line of the same config file, and the spot shows: <<<<<<< HEAD / timeout = 30 / = / timeout = 60 / >>>>>>> origin/main. The top block (HEAD) is your change (30) and the bottom block is theirs (60). What to do is decide which value is correct against the team's intent, delete all three marker lines (<<<<<<<, =, >>>>>>>) and combine into one correct line, stage with git add <file>, record the resolution with git commit, and finally git push. After resolving, viewing the unified diff with git diff or git log -p shows the hunk @@ -12,1 +12,1 @@ with - timeout = 30 and + timeout = 60, reading at a glance as "changed the value on line 12 from 30 to 60." The key is the judgment to read rejected and conflict markers not as errors to fear but as the entrance to a set procedure: "remote is ahead -> pull and integrate -> a human decides the conflict and removes markers -> add/commit/push." Reading a diff's +/- and @@ correctly lets you instantly explain in review "what this change changed and how."

Command/markerMeaningTypical use
clone / pullCopy / fetch + integrateInitial copy / update before work
add / commitStage / record in local historyFinalize and record changes
pushSend local commits to remoteShare after recording
branch / mergeDiverge / integrateParallel work and joining
<<< === >>> / +,-,@@Conflict markers / diff add-remove, locationConflict resolution and review
Warning

Trap: When a push is rejected as non-fast-forward, "shove it in with git push --force" is wrong—it can erase a colleague's commit. The correct move is to git pull and integrate first. Also wrong: "git commit also reflects to the remote"—commit records to local history, and sharing requires push. The conflict marker = is a divider, and unless you remove all three marker lines and combine, a broken file remains.

Basic Git commands and reading merge conflicts/unified diffs.
Reading git output to decide the next move

1.4.4Section summary

  • Git is distributed, holds full history, and can revert to any point; branch for parallel work and merge to integrate, with review/tests before merging
  • The canonical order is change -> add (stage) -> commit (local record) -> pull (update) -> push (send to remote); commit alone does not reach the remote
  • A rejected push (non-fast-forward) means pull first; a merge conflict is resolved by removing all three markers, combining, then add/commit; a unified diff uses - remove/+ add and @@ for location

Sign in to track progress — Log in.

Quick check

(just a quick review)

Q1. Running `git push` on a feature branch returned `! [rejected] ... (non-fast-forward)` and a hint that "the remote has work you do not have locally." What is the most appropriate next step that does not corrupt history?

Q2. When merging a config file, a conflict showed `<<<<<<< HEAD` / `timeout = 30` / `=======` / `timeout = 60` / `>>>>>>> origin/main`. Which is the most appropriate interpretation and correct resolution?

Q3. A commit's `git diff` output shows, under the hunk header `@@ -12,1 +12,1 @@`, the lines `- timeout = 30` and `+ timeout = 60`. Which interpretation of this unified diff is most appropriate?

Check your understandingPractice questions for Chapter 1: Software Development and Design