Git Interview Questions and Answers (2026) Part 01
30 real-world Git scenario-based interview questions and answers covering branching strategies, merge/rebase, undoing changes, conflict resolution, Git internals, hooks, submodules, security, monorepos, and troubleshooting — Senior DevOps Engineer Edition.
Basic Interview Questions
origin refers to the default name given to the remote repository from which the local repository was cloned. It is used as a reference to control fetches, pulls, and pushes..gitignore file tells Git which files and folders to ignore when tracking changes. It prevents unnecessary files — such as logs, temporary files, or compiled artifacts — from being committed to the repository, keeping it clean and focused on important source files only.Using Git provides several advantages:
- Supports teamwork by allowing multiple developers to collaborate on the same project simultaneously.
- Each developer holds a full local copy of the repository, improving performance and enabling offline work.
- Free, open-source, and widely supported across platforms.
- Suitable for projects of all sizes and types.
- Each repository contains a single
.gitdirectory managing the entire history.
Git usually handles merges automatically, but conflicts arise when:
- Two branches edit the same line of a file differently.
- One branch deletes a file that another branch has modified.
In such cases, Git cannot decide which change to keep and requires manual resolution.
Use git commit --amend to modify the most recent commit:
- Make your changes to the files.
- Stage them with
git add. - Run the amend command:
git commit --amend
Git will open your default editor to update the commit message. Save and close to apply.
Note: Avoid amending commits that have already been pushed to a shared remote, as it rewrites history.
- Rename the current branch:
git branch -m <new_branch_name>
- Rename a different branch:
git branch -m <old_branch_name> <new_branch_name>
- Push the renamed branch to remote and update tracking:
git push origin -u <new_branch_name>
git push origin --delete <old_branch_name>
Intermediate Interview Questions
| Feature | git fetch | git pull |
|---|---|---|
| Purpose | Downloads changes from remote but doesn’t apply them | Downloads and merges changes into your current branch |
| Working Directory | No changes — safe to inspect before merging | Changes are applied immediately |
| Use Case | When you want to review changes before merging | When you want to update your branch quickly |
| Workflow | Often followed by git merge or git rebase | Combines fetch + merge in one step |
Using git fetch with manual merge:
git fetch origin
git log origin/main # inspect incoming changes
git merge origin/main # apply after review
Using git pull directly:
git pull origin main
Pull Requests (PRs) are a core part of collaborative development:
- Code Review: Team members can review code before it is merged, ensuring higher quality and catching bugs early.
- Collaboration: Developers can discuss, comment, and suggest changes within the PR itself.
- Version Control: Tracks proposed changes clearly and keeps the main branch stable.
- Accountability: Maintains a clear record of who approved and merged each change.
git stash temporarily saves uncommitted changes so you can switch context — such as moving to another branch — without losing your in-progress work. Stashed changes can be reapplied later.
| Command | Purpose |
|---|---|
git stash | Save current uncommitted changes |
git stash list | View all saved stashes |
git stash pop | Reapply the most recent stash and remove it from stash list |
git stash apply | Reapply a stash without removing it from history |
git stash drop stash@{n} | Delete a specific stash entry |
Use git revert — it creates a new commit that undoes the changes, preserving history:
- Switch to the target branch:
git checkout <branch_name>
- Find the commit hash:
git log
- Revert the commit:
git revert <commit-hash>
Git opens an editor to confirm the revert message. Save and close.
Push the revert commit:
git push origin <branch_name>
Why
git revertovergit reset? Revert is safe for shared repositories because it does not rewrite history.
| Parameter | git reset | git revert |
|---|---|---|
| History | Moves HEAD to a previous commit, removing commits from history | Creates a new commit that undoes changes, keeping history intact |
| Safety | Risky on shared/public branches | Safe to use on shared repositories |
| Use Case | Undoing local, unpushed commits | Undoing commits that are already pushed |
git reflog | git log |
|---|---|
| Tracks all movements of HEAD and branch pointer changes | Displays the commit history of the current branch |
| Shows references even if they are no longer part of any branch | Only shows commits reachable from the current branch |
| Can help recover lost commits or deleted branches | Does not track changes outside the commit chain |
| Useful for disaster recovery and debugging | Used for reviewing past changes and audit trails |
HEAD is a special pointer in Git that always refers to the current position in the repository:
- Points to the latest commit on the currently checked-out branch.
- When you switch branches, HEAD automatically updates to the tip of the new branch.
- A detached HEAD state occurs when HEAD points directly to a specific commit instead of a branch — common when checking out a tag or old commit.
git tag -a creates an annotated tag, which stores additional metadata alongside the tag reference:
- Tagger’s name and email
- Date and time of tagging
- A custom descriptive message
Create an annotated tag:
git tag -a v1.0 -m "Version 1.0 Release"
Push the tag to remote:
git push origin v1.0
Annotated tags are preferred over lightweight tags for marking official releases because of their stored metadata.
| Concept | HEAD | Working Tree | Index (Staging Area) |
|---|---|---|---|
| Definition | Reference to the current commit or branch | Directory containing your actual project files | Buffer between working tree and repository |
| Contains | Pointer stored in .git/HEAD | Unstaged edits and new files | Changes staged with git add, ready to commit |
| Location | .git/HEAD | Your local project folder | .git/index |
- Identify conflicting files:
git status
- Open the conflicted file. Git marks conflicts like this:
<<<<<<< HEAD
Your changes
=======
Incoming changes
>>>>>>> feature-branch
Manually edit the file to keep your changes, the incoming changes, or a combination of both. Remove all conflict markers.
Stage the resolved file:
git add <file>
- Commit the merge:
git commit
- If rebasing, continue with:
git rebase --continue
| # | git merge | git rebase |
|---|---|---|
| How it works | Combines two branches and creates a merge commit | Reapplies commits from one branch on top of another |
| History | Preserves both branches’ full history | Rewrites commit history to produce a linear timeline |
| Merge commit | Yes — a merge commit is created | No — history is rewritten without merge commits |
| Best for | Collaborative branches where history matters | Personal branches or cleanup before opening a PR |
Rule of thumb: Use merge to preserve context in team workflows; use rebase to maintain a clean, readable history on feature branches.
git push origin --delete <branch_name>
To also remove the local tracking reference:
git fetch --prune
git cherry-pick applies changes from a specific commit to the current branch without merging the entire source branch.
Key use cases:
- Selective commit application: Pick only the commits you need.
- Bug fixes: Backport a specific fix to another branch (e.g., a release branch).
- No full branch merge required: Incorporate isolated changes cleanly.
- New commit: The picked changes are applied as a new commit on the current branch.
git cherry-pick <commit-hash>
Advanced Interview Questions
A Git hook is a script that runs automatically at specific points in the Git workflow. They live inside .git/hooks/ and can be written in any scripting language.
| Hook | Trigger | Common Use |
|---|---|---|
pre-commit | Before a commit is created | Run linters or unit tests |
commit-msg | After commit message is written | Enforce commit message format |
post-commit | After a commit is completed | Trigger notifications or logging |
pre-push | Before pushing to remote | Run full test suite |
Example — pre-commit hook to run ESLint:
#!/bin/sh
npx eslint . || exit 1
Make hooks executable:
chmod +x .git/hooks/pre-commit
For team-wide hooks, consider tools like Husky to version-control them alongside your project.
Use git reset with the appropriate flag depending on what you want to keep:
- Keep changes staged (soft reset):
git reset --soft HEAD~1
- Keep changes in working directory but unstaged (mixed reset — default):
git reset --mixed HEAD~1
- Discard all changes completely (hard reset):
git reset --hard HEAD~1
Use
--hardwith caution — changes are permanently lost unless recoverable viagit reflog.
- Start an interactive rebase for the last N commits:
git rebase -i HEAD~<number-of-commits>
- In the editor, leave the first commit as
pickand change subsequent ones tosquash(ors):
pick a1b2c3d First commit message
squash e4f5g6h Second commit message
squash i7j8k9l Third commit message
Save and close. Git opens another editor to combine the commit messages — edit as needed and save.
Force-push if the branch was already pushed:
git push origin <branch_name> --force-with-lease
Use a soft reset to move HEAD back while leaving your files and staged changes intact:
git reset --soft <commit-hash>
Your commits are undone, but all the changes remain staged — ready to be re-committed or reorganized.
| Command | What it resets | Affects tracked files | Affects untracked files |
|---|---|---|---|
git reset --hard | HEAD, index, and working directory to a specific commit | ✅ Yes — discards modifications | ❌ No — leaves untracked files untouched |
git clean -fd | Only the working directory | ❌ No — ignores tracked files | ✅ Yes — removes untracked files and directories |
Combined usage — to fully clean a repository:
git reset --hard HEAD
git clean -fd
A file in Git moves through four primary states:
| State | Description |
|---|---|
| Untracked | Newly created file not yet known to Git |
| Modified | File has been edited since the last commit |
| Staged | File added via git add, queued for the next commit |
| Committed | File permanently saved to repository history via git commit |
Full lifecycle example:
# Create a new file
touch feature.js
# Stage it
git add feature.js
# Commit it
git commit -m "Add feature.js"
# Modify it
vim feature.js
# Stage and commit the update
git add feature.js
git commit -m "Update feature.js"
Each git commit creates an immutable snapshot of all staged files at that point in time.
Git provides three reset modes, each with a different scope of impact:
| Type | Command | Behaviour |
|---|---|---|
| Soft | git reset --soft <commit> | Moves HEAD only — index and working directory remain unchanged. Changes stay staged. |
| Mixed | git reset --mixed <commit> | Moves HEAD and clears the index — changes remain in the working directory as unstaged. |
| Hard | git reset --hard <commit> | Moves HEAD, clears the index, and discards working directory changes completely. |
Decision guide:
- Use
--softto re-commit with a different message or grouping. - Use
--mixedto unstage changes and re-evaluate what to commit. - Use
--hardonly when you are certain you want to throw away all changes.
Git tags are named pointers to specific commits — most commonly used to mark release points (e.g., v1.0, v2.1). Unlike branches, tags do not move; they permanently reference an exact commit.
Types of tags:
| Type | Description |
|---|---|
| Lightweight | A simple pointer to a commit, no extra metadata |
| Annotated | Stores tagger name, email, date, and a message — recommended for releases |
Common tag commands:
| Command | Purpose |
|---|---|
git tag v1.0 | Create a lightweight tag |
git tag -a v2.0 -m "Release 2.0" | Create an annotated tag |
git tag | List all tags |
git show v2.0 | View tag details |
git push origin v2.0 | Push a specific tag to remote |
git push origin --tags | Push all local tags to remote |
git bisect uses binary search through commit history to efficiently pinpoint the commit that introduced a bug — without manually checking each one.
- Start bisecting:
git bisect start
- Mark the current (bad) commit:
git bisect bad
- Mark a known good commit:
git bisect good <commit-hash>
- Git checks out a commit halfway between. Test your code, then tell Git the result:
git bisect good # if the bug is not present
git bisect bad # if the bug is present
Repeat until Git identifies the exact commit that introduced the bug.
End the session:
git bisect reset
For large repositories,
git bisectcan find the culprit commit inO(log n)steps — dramatically faster than manual search.
Add More Questions to This Guide
Know questions that should be here? Share them and help the community!
Open Google Form