In short
Version control is the practice of recording every change to a set of files so that any past state can be recovered, compared and attributed. Git is a distributed version control system (created by Linus Torvalds in 2005 for the Linux kernel) in which every developer holds a complete copy of the repository and its history, so commits, branches, diffs and log searches work offline. It is the backbone of the software engineering lab, the mini-project and the final-year project in Indian universities, and it is assumed knowledge in almost every IT interview — TCS, Infosys, Wipro, Cognizant, Accenture, Tech Mahindra and every product company expect fluency with branch, merge, conflict resolution and pull requests. GATE CS does not ask Git commands directly, but university papers ask the concepts (centralized vs distributed, merge vs rebase, repository structure) and viva/placement rounds ask the commands and the recovery scenarios. Day one of an Indian internship typically means cloning from an internal GitLab, Bitbucket or Azure DevOps server and raising your first pull request.
Explained
Why version control, and the two architectures
- Purpose: history and rollback, parallel work by many developers, blame/attribution, release tagging, auditable change trail, and a single source of truth for CI/CD.
- Local VCS (SCCS, RCS, 1970s-80s): versions kept in a local database, one machine only.
- Centralized VCS (CVCS) — CVS, Subversion (SVN), Perforce, Microsoft TFVC: one server holds history; clients check out a *working copy* of one revision. Simple administration and fine-grained locking, but the server is a single point of failure and almost every operation needs the network.
- Distributed VCS (DVCS) — Git, Mercurial, Bazaar: every clone holds the full object database and history. Fast local operations, offline work, cheap branching, natural backup; cost is a steeper mental model and poor handling of very large binary files.
- Terms: *repository* (store of history), *working tree* (the checked-out files), *commit/revision*, *branch*, *tag*, *HEAD* (current position), *upstream/remote*, *clone*, *fork*, *merge*, *conflict*.
- Locking vs merging models: SVN historically allowed exclusive file locks (useful for binaries); Git is purely merge-based (optimistic concurrency).
How Git stores data — the object model
- Git stores snapshots, not deltas. Each commit points to a complete tree of the project (unchanged files are shared by reference, and packfiles later apply delta compression for storage only).
- Four object types, each addressed by the SHA-1 of its contents (content-addressable store):
- blob — file contents (no name, no permissions);
- tree — a directory listing: names, modes, and blob/tree ids;
- commit — one tree id, parent commit id(s), author, committer, timestamp, message;
- tag (annotated) — a named, optionally signed pointer to an object.
- The commit graph is a DAG (directed acyclic graph): one parent = ordinary commit, two or more = merge commit, none = root commit. History is immutable — "editing" history creates *new* objects with new ids.
- Refs are just files containing an id:
refs/heads/main(branch),refs/tags/v1.0,refs/remotes/origin/main. A branch is therefore a movable pointer — which is why branching in Git costs almost nothing. - HEAD normally contains
ref: refs/heads/<branch>; if it contains a raw commit id you are in detached HEAD state and new commits belong to no branch. - **
.gitdirectory** holdsobjects/,refs/,HEAD,index,config,hooks/,logs/(the reflog). - Default hash is SHA-1 (40 hex characters); SHA-256 repositories exist from Git 2.29 onwards but are still not the common default and are not interoperable with SHA-1 repos.
The three areas and the basic workflow
- Working tree → staging area (index) → repository.
git addstages,git commitrecords the staged snapshot,git checkout/git restorecopies back from a commit or the index. - Core sequence:
git initorgit clone <url>→ edit →git status→git diff(working vs index) /git diff --staged(index vs HEAD) →git add -p→git commit -m "..."→git pull --rebase→git push. - File states: untracked, unmodified, modified, staged.
.gitignorekeeps build output,node_modules,*.class,.env, IDE folders out;.gitattributescontrols line endings (text=auto) and diff/merge drivers. - Inspection:
git log --oneline --graph --decorate --all,git show <id>,git blame <file>,git log -S"functionName"(pickaxe, finds commits that changed an occurrence count),git shortlog -sn(commits per author). - Undo ladder:
git restore <file>(discard working change) ·git restore --staged <file>(unstage) ·git commit --amend(fix last commit) ·git revert <id>(new commit that inverts an old one — safe on shared branches) ·git reset(move the branch pointer). - **
git resetmodes:**--softmoves HEAD only (changes stay staged);--mixed(default) also resets the index;--hardalso overwrites the working tree — the only one that destroys uncommitted work. - **
git stash** shelves dirty changes (git stash push -u,git stash list,git stash pop), used when you must switch branches mid-task. - **
git reflog** records every movement of HEAD for ~90 days (30 days by default for entries whose commits are no longer reachable from a branch), so a "lost" commit after a bad reset or rebase is almost always recoverable. - Remotes:
git remote -v,git fetch(download only),git pull(fetch + merge/rebase),git push -u origin <branch>,git push --force-with-lease(safer than--force: refuses if the remote moved).
Branching, merging and rebasing
git switch -c feature/login(or the oldergit checkout -b) creates and moves onto a branch;git branch -ddeletes a merged branch.- Fast-forward merge: if the target branch has not moved, Git simply advances the pointer — no merge commit. Force a record with
--no-ff. - Three-way merge: Git finds the merge base (lowest common ancestor,
git merge-base A B) and combines base, ours and theirs. Default strategy isort(replacedrecursivefrom Git 2.34);octopushandles more than two branches;ours/theirsresolution options exist. - Conflict arises only when both sides change overlapping lines, or one deletes/renames what the other edits. Markers
<<<<<<< HEAD,=======,>>>>>>> branchare written into the file; resolve,git add, thengit commit(orgit merge --abort).git mergetoolandgit diff --name-only --diff-filter=Uhelp. - Rebase replays your commits on a new base, producing *new commit ids* and linear history:
git rebase main,git rebase --continue/--abort/--skip. - Interactive rebase
git rebase -i HEAD~5topick / reword / edit / squash / fixup / drop— used to clean a branch before review. - The golden rule of rebasing: never rebase (or amend, or reset) commits that others have already pulled; rewrite only your own unpushed/unshared work.
- **
git cherry-pick <id>copies one commit elsewhere (hotfix into a release branch).git bisect** binary-searches history for the commit that introduced a bug. - Merge vs rebase vs squash-merge: merge preserves true history and is auditable; rebase gives clean linear history; squash-merge collapses a feature to one commit (default on many Indian service-company GitLab setups for traceability against a Jira/ticket id).
Collaboration models, branching strategies and tooling
- Shared-repository model: everyone has push rights to feature branches of one repo;
mainis protected. Common inside Indian IT companies. - Fork-and-pull model: contributors fork, push to their fork, raise a pull request / merge request; used in open source and in MeitY's OpenForge platform for Indian government code.
- Pull/merge request = the unit of review and gating: diff, discussion, required approvals, CI status checks, and merge only when green. (Review *practice* itself belongs to the code-review topic.)
- Branching strategies:
- Git flow — long-lived
main+develop, plusfeature/*,release/*,hotfix/*. Suited to versioned, scheduled releases. - GitHub flow —
mainplus short-lived feature branches, deploy frommain. - Trunk-based development — everyone commits to trunk at least daily, behind feature flags; the default for continuous delivery.
- Release/maintenance branches for supported versions, with hotfixes cherry-picked forward.
- Git flow — long-lived
- Tags and versions:
git tag -a v2.3.1 -m "..."thengit push --tags. Semantic versioning MAJOR.MINOR.PATCH — breaking change, backward-compatible feature, backward-compatible fix.git describeproduces build strings likev2.3.1-14-gab12cd3. - Hooks: client-side
pre-commit(lint, secret scan),commit-msg(enforce Conventional Commits likefeat:,fix:, or a ticket id); server-sidepre-receive/updatefor policy. Tools:pre-commit, Husky,git-secrets, Gitleaks. - Hosting in India: GitHub, GitLab (self-managed on-premise is common in BFSI and defence work), Bitbucket, Azure DevOps Repos, AWS CodeCommit; government/public-sector code on MeitY's OpenForge.
- Large files and monorepos: Git LFS for media/model binaries, shallow (
--depth 1) and partial clones, sparse-checkout, submodules and subtrees for vendored dependencies. - Signing and compliance:
commit.gpgsign/ SSH signing proves authorship; immutable, timestamped, attributable history supports audit expectations in RBI/SEBI-regulated work and ISO 27001/CMMI assessments. Never commit secrets, Aadhaar/PAN or customer personal data — a pushed secret must be treated as leaked, rotated immediately, and history rewritten (git filter-repo); mishandling personal data engages the Digital Personal Data Protection Act, 2023, and the organisation's CERT-In reporting obligations.
Key points
- Version control - systematic recording of file changes with identity, time and message, allowing recovery and comparison.
- DVCS vs CVCS - Git gives every clone the full history (offline, fast, redundant); SVN keeps history only on the server.
- Snapshot model - each commit references a complete tree; deltas are a packfile storage optimisation, not the data model.
- Content addressing - every object's name is the SHA-1 of its content, so history is tamper-evident.
- Branch = pointer - a 40-character id in a file; creating or deleting a branch is O(1).
- HEAD - where you are now; a bare commit id in HEAD means detached HEAD and commits with no branch.
- Index (staging area) - lets you commit a curated subset of your edits (
git add -p). - Fast-forward vs three-way merge - pointer move when no divergence; merge base + both sides when there is.
- Conflict - overlapping edits on the same lines; Git never resolves semantics, only non-overlapping text.
- revert vs reset - revert adds an inverse commit (shared-safe); reset moves the pointer (rewrites local history).
- reset --hard - the only common command that silently destroys uncommitted work.
- Rebase - replays commits with new ids for linear history; never rebase shared commits.
- cherry-pick - copy a single commit to another branch, typically a hotfix.
- reflog - 90-day log of HEAD movements; the standard recovery route after a bad reset or rebase.
- bisect - binary search over history, finds a regression in about log2(N) tests.
- Strategies - Git flow (scheduled releases), GitHub flow (deploy from main), trunk-based (continuous delivery with feature flags).
- SemVer tags - MAJOR for breaking, MINOR for features, PATCH for fixes; annotated tags mark releases.
- Hooks and protected branches - automate lint/tests/secret scanning and enforce review before merge.
Formulas and examples
git hash-object computes it.Ancestry:
HEAD~n = nth ancestor along *first parents*; HEAD^n = the nth parent of a merge commit. So HEAD~2 = grandparent, HEAD^2 = second parent of a merge.Commits in a range:
git rev-list --count A..B = commits reachable from B but not from A.Bisect tests needed = ceil( log₂ N ), where N = number of suspect commits.
Abbreviated-hash space: k hex characters → 16k distinct prefixes; collisions become likely around √(16k) objects (birthday bound).
Semantic version = MAJOR.MINOR.PATCH (+ optional
-pre.1, +build).Example 1 - Bisecting a regression. A bug exists at main but not at tag v1.4; git rev-list --count v1.4..main returns 1,000.
- Tests needed = ceil(log₂ 1000); 2⁹ = 512 < 1000 ≤ 1024 = 2¹⁰ → 10 tests.
- Commands:
git bisect start→git bisect bad main→git bisect good v1.4→ test, thengit bisect good/git bisect badeach round →git bisect reset. - If each manual test takes 6 minutes, total ≈ 10 × 6 = 60 minutes, against 1,000 × 6 = 6,000 minutes (100 hours) for a linear search. With a test script,
git bisect run ./test.shautomates all 10. - For 5,000 commits: 2¹² = 4096 < 5000 ≤ 8192 = 2¹³ → 13 tests — five times the history, three more tests.
Example 2 - Merge vs rebase, counted. Your feature/upi has 4 commits; main has advanced by 6 commits since you branched.
| Commits added to main | Commits rewritten | Resulting shape | |
|---|---|---|---|
git merge feature/upi (no-ff) | 4 + 1 merge = 5 | 0 | 2 lines joining at a merge commit |
git rebase main then fast-forward | 4 (new ids) | 4 | single straight line |
| Squash-merge | 1 | 4 collapsed | one commit per feature |
- After the rebase,
mainholds 6 + 4 = 10 commits beyond the old branch point; after the merge, 6 + 4 + 1 = 11. The rebased commits have different SHA-1s from your originals — so a teammate who already pulledfeature/upinow has divergent history.
Example 3 - Undoing safely. You pushed 3 bad commits to a shared release branch.
- Wrong:
git reset --hard HEAD~3 && git push --force— rewrites history others hold; their next pull diverges. - Right:
git revert --no-commit HEAD~3..HEADthen one commit, orgit revert -m 1 <merge-id>for a merge. Net effect: 3 bad + 1 inverse commit = 4 commits in history, zero rewritten.
Example 4 - Recovery with reflog. You ran git reset --hard HEAD~5 on your own branch by mistake.
git reflog # e.g. ab12cd3 HEAD@{1}: commit: add OTP retry
git branch rescue ab12cd3 # or: git reset --hard HEAD@{1}
- Committed work is recovered in full. Work that was only *modified or staged*, never committed, is not in the reflog and is gone — the practical argument for committing or stashing early.
Example 5 - Resolving a conflict.
$ git merge feature/pay
CONFLICT (content): Merge conflict in src/pay.java
Automatic merge failed; fix conflicts and then commit the result.
git status→both modified: src/pay.java; 2. open the file, keep the correct logic, delete all three markers; 3.git add src/pay.java; 4.git commit(default messageMerge branch 'feature/pay'); 5. re-run the tests — a textually clean merge can still be semantically broken.git merge --abortreturns to the pre-merge state at any point before step 4.
Abbreviation check. 7 hex characters give 16⁷ = 268,435,456 prefixes, so collisions become likely around √(2.68×10⁸) ≈ 16,400 objects; a repository with a million objects will certainly collide at 7 characters, which is why Git's core.abbrev auto lengthens the prefix (commonly 10-12) in large repos.
| Git | SVN (centralized) | |
|---|---|---|
| History location | Every clone | Server only |
| Offline commit/log/diff | Yes | No |
| Branch cost | A pointer, instant | Server-side copy, heavier |
| Revision id | SHA-1 content hash | Incrementing integer |
| Merge tracking | Native, cheap | Added later, weaker |
| Partial checkout of a subtree | Awkward (sparse-checkout) | Natural |
| Large binaries | Weak (needs LFS) | Better, with locking |
Where it is used
- Every software role: developer, QA/SDET, DevOps, data engineer, ML engineer — Git is the entry point to the codebase and to CI/CD pipelines (Jenkins, GitLab CI, GitHub Actions) triggered by push and merge-request events.
- Indian IT services (TCS, Infosys, Wipro, HCLTech, Cognizant, Capgemini, LTIMindtree): client-hosted GitLab/Bitbucket/Azure Repos, branch-per-ticket tied to Jira or ServiceNow ids, squash-merge with mandatory reviewer approvals.
- Product and fintech (Zoho, Freshworks, Zerodha, Razorpay, PhonePe, Flipkart, Swiggy): trunk-based development with feature flags, protected
main, signed commits and secret scanning; release tags map to app-store builds. - Public sector and research: MeitY's OpenForge for government source code, ISRO/DRDO and PSU projects on self-hosted GitLab in air-gapped networks; university labs use GitHub Classroom for assignments.
- Infrastructure and ML: GitOps (Argo CD, Flux) treats a Git repository as the declarative source of truth for Kubernetes; DVC and Git LFS version datasets and model artefacts alongside code.
- Hiring and academics: a readable commit history on a public GitHub profile is routinely checked for internships and off-campus roles, and project vivas ask you to show the commit log of your own contribution.
Interview questions
- Q: What is the difference between a centralized and a distributed VCS? A: A centralized system keeps the only history on a server and clients hold a working copy, so most operations need the network; in a distributed system such as Git every clone holds the complete history, so commits, branches, diffs and logs are local and fast.
- Q: Does Git store deltas or snapshots? A: Logically snapshots — each commit points to a full tree, with unchanged files shared by reference; delta compression is only a packfile storage optimisation.
- Q: What is the difference between
git fetchandgit pull? A:fetchdownloads remote objects and updates remote-tracking refs without touching your branch;pullisfetchfollowed by a merge (or rebase with--rebase) into your current branch. - Q:
git revertorgit reset— which do you use on a shared branch and why? A:revert, because it adds a new inverse commit and leaves existing history intact;resetmoves the branch pointer and rewriting shared history forces everyone else to reconcile divergence. - Q: Explain
--soft,--mixedand--hardingit reset. A:--softmoves HEAD and leaves changes staged;--mixedalso clears the index;--hardadditionally overwrites the working tree and is the only one that loses uncommitted work. - Q: When would you rebase instead of merge? A: To keep a linear, reviewable history by replaying my own unpushed feature commits on the latest
main; I never rebase commits others have already pulled, because rebasing creates new commit ids. - Q: What is a merge base and how does a three-way merge use it? A: The lowest common ancestor of the two branches; Git compares each side against it and combines non-overlapping changes, reporting a conflict where both sides changed the same region.
- Q: What exactly causes a merge conflict, and what does Git never resolve? A: Overlapping edits to the same lines, or edit-versus-delete/rename on the same file; Git resolves text, never semantics — a conflict-free merge can still break the build, so tests must run after every merge.
- Q: How do you recover a commit lost to
git reset --hard? A: Find it ingit reflog(HEAD movements are kept about 90 days, but entries for commits no longer on any branch only 30 days by default) and rungit reset --hard HEAD@{1}orgit branch rescue <id>; changes that were never committed are not recoverable. - Q: What is detached HEAD and how do you get out of it? A: HEAD points at a commit instead of a branch, so new commits belong to no branch; create a branch at that commit (
git switch -c tmp) or check out an existing branch, in which case the orphaned commits are reachable only via the reflog. - Q: A password was committed and pushed. What now? A: Treat it as compromised: rotate the credential immediately, purge it from history with
git filter-repoand force-push with coordination, invalidate caches/forks, and add a pre-commit secret scan — removing the file in a new commit does not remove it from history. - Q: What is
git cherry-pickused for, and its risk? A: Copying a specific commit onto another branch, typically a hotfix into a release branch; the risk is duplicate commits with different ids and divergent history if the same change is later merged. - Q: What do
HEAD~2andHEAD^2mean? A:HEAD~2is the grandparent along first parents;HEAD^2is the second parent of a merge commit — on a non-merge commitHEAD^2does not exist.
Common mistakes
- Using
git reset --hardorgit checkout .to "clean up", then discovering uncommitted work is unrecoverable — stash or commit first. - Rebasing, amending or force-pushing a branch teammates have already pulled, then force-pushing without
--force-with-lease. - Committing build output,
node_modules,.env, keys or customer data because.gitignorewas added after the first commit (ignore rules do not untrack already-tracked files — usegit rm --cached). - Resolving a conflict by deleting one side wholesale, or leaving
<<<<<<</=======markers in the file, and committing without running the tests. - Confusing
git fetchwithgit pull, orgit revertwithgit reset, in both exam answers and real recovery situations. - One giant commit at the end of the project with the message "final code" — unreviewable, unbisectable, and visibly bad in a viva or interview.
- Saying "a branch is a copy of the code" — in Git it is a pointer to a commit; and calling SHA-1 ids "sequential version numbers" as in SVN.
Related topics
SDLC and Agile · Clean code and code reviews · Test automation and TDD · Software project management and estimation · Software architecture: monoliths and microservices · Operating systems: file systems and hashing