Git is the most widely used version control system in software development, so it comes up in almost every technical interview, whether you are a fresher or a senior engineer. Interviewers use Git questions to check how well you manage code changes, work with a team and recover when something goes wrong.
This article covers the most common Git interview questions for freshers, intermediate developers and experienced developers with scenario-based questions and tips for answering them well.
Also Explore: GIT Cheat Sheet
These questions are asked in interviews to check whether freshers understand the basics of Git, how it works and how they can use it in real software development projects. Here are some of them:
Git is a free and open-source version control system that helps developers track changes in their code. It allows multiple developers to work on the same project, create branches and manage different versions of files. It also helps developers restore earlier versions of their code when needed.
A repository, or repo, is a place where Git stores and manages a project's files and their change history. It contains the project files and the information that Git needs to track changes. A repository can be local on a computer or remote on a platform such as GitHub.
The .git directory is a hidden folder that stores the information Git needs to manage a repository. It contains commit history, branch information, configuration settings and other internal data. If we remove this directory, we lose Git's tracking information for that repository, although the project files may remain.
The git clone command creates a local copy of an existing Git repository. It downloads the project files and the repository's history from a remote location. It also sets up a connection to the original remote repository, which allows us to fetch updates and push changes when we have the required permissions.
Example:
| git clone https://github.com/user/project.git |
This command creates a local copy of the specified repository.
The main difference is that a fork creates a copy on a hosting platform, while a clone creates a copy on a local computer. Here is their brief differentiation:
| Feature | Fork | Clone |
| Meaning | Creates a copy of a repository under your account on a hosting platform. | Creates a local copy of a repository on your computer. |
| Location | Usually stored on a platform such as GitHub. | Stored on your local computer. |
| Purpose | Helps you contribute to another project without directly changing the original repository. | Helps you work on a project locally. |
| Internet Access | Requires internet access to create a fork on the hosting platform. | Requires internet access to download a remote repository initially. |
| Original Repository | The fork remains a separate repository from the original. | The clone can maintain a connection to the original remote repository. |
| Changes | You can push changes to your fork if you have the required permissions. | You can commit changes locally and push them to a remote repository if you have the required permissions. |
| Common Use | Contributing to open-source projects. | Developing, testing and editing code on your computer. |
HEAD is a reference that shows our current position in the Git repository. In normal situations, it points to the current branch, which in turn points to the latest commit on that branch. When we switch branches or make a new commit, the HEAD reference changes accordingly.
For example, if we switch to the main branch, HEAD normally points to that branch.
Git and GitHub are related tools, but they serve different purposes in software development. The following table compares them based on their features and key differences:
| Feature | Git | GitHub |
| Type | Version control system | Online code hosting platform |
| Purpose | Tracks changes in files and code | Hosts repositories and supports collaboration |
| Working | Works mainly on a local computer | Works online through a web platform |
| Version History | Tracks commits and code changes | Displays repository history through Git |
| Branching | Creates and manages branches | Allows users to view and collaborate on branches |
| Collaboration | Supports collaboration through Git commands | Supports pull requests, code reviews and issue tracking |
| Internet Access | Works offline for many tasks | Requires internet access for most online features |
| Cost | Free and open-source | Offers free and paid plans |
A Version Control System is a tool that tracks changes in files over time. It helps developers maintain different versions of their code, compare changes and restore earlier versions when needed. Git is a popular example of a version control system.
The Git workflow is the process that developers follow to manage and save changes to their code. It usually includes working on files, staging changes, committing them and sharing them with a remote repository.
The basic Git workflow includes these steps:
Example commands:
| git status git add . git commit -m "Add new feature" git push |
These commands help us check changes, stage files, save a commit and push our changes to a remote repository.
Git has numerous advantages of its usage in code management, but it has some drawbacks too.
In general, it is possible to say that Git is a great tool for tracking changes, keeping code versions under control and promoting teamwork in software development.
Read Also: Complete List of Command Prompt (CMD) Commands
These questions help interviewers check a candidate’s practical knowledge of Git, their problem-solving skills and their ability to manage code changes in a team.
We can use the git rebase -i HEAD~N command to squash the last N commits into one commit. The interactive rebase window allows us to keep the first commit and squash the remaining commits into it.
For example, if we want to combine the last three commits, we can run:
| git rebase -i HEAD~3 |
Then, we can keep pick for the first commit and change pick to squash or s for the other two commits. After that, we can save the changes and edit the final commit message if needed.
Note: We should be careful when we squash commits that have already been pushed to a shared branch because this process changes the commit history.
We can recover the branch from the central repository if the branch still exists there. First, we can fetch the latest updates from the remote repository and then check the available remote branches.
| git fetch origin git branch -r |
If the branch is available as origin/feature-branch, we can recreate the local branch by running:
| git switch -c feature-branch --track origin/feature-branch |
This command creates a local branch and connects it to the remote branch.
If the branch has also been deleted from the central repository, we can check the reflog, other repository copies, or existing commit references to recover the lost work.
We ask this question to check whether candidates understand how Git gets updates from a remote repository and when they should use each command while working in a team.
| Basis | git fetch | git pull |
| Meaning | It downloads updates from a remote repository. | It downloads updates and integrates them into the current branch. |
| Changes to current branch | It does not update the current branch. | It updates the current branch by merging or rebasing, depending on the configuration and options. |
| Working files | It does not change the working files. | It may change the working files when the fetched changes are integrated. |
| When to use | We can use it when we want to review changes before integrating them. | We can use it when we are ready to integrate remote changes into our current branch. |
| Example | git fetch origin | git pull origin main |
In simple words: We can use git fetch to check for updates first, while git pull can help us download and integrate those updates into our current branch.
A Git commit object contains the information that identifies a particular version of our project. It includes the following details:
Git also stores a unique object ID for the commit based on its contents. This information helps Git track changes and maintain the project’s history.
Git has three main configuration levels. These levels help us set options for a single repository, a particular user, or the whole system.
| Level | Purpose | Command |
| System | It applies settings to all users and repositories on the system. | git config --system |
| Global | It applies settings to the current user across their repositories. | git config --global |
| Local | It applies settings only to the current repository. | git config --local |
For example, we can set our name and email by running:
| git config --global user.name "Your Name" git config --global user.email "you@example.com" |
We can set a different name for one repository by running:
| git config --local user.name "Work Name" |
Local settings generally take priority over global and system settings when the same option is defined at multiple levels. Git can also use command-specific configuration options and additional configuration sources.
A detached HEAD happens when HEAD points directly to a commit instead of pointing to a branch name. It can happen when we check out a commit ID or a tag instead of a branch.
For example:
| git checkout <commit-id> |
In this state, we can inspect the code and make changes. However, if we create commits without creating or switching to a branch, those commits may become difficult to find later.
We can avoid this situation by switching to an existing branch or creating a new branch before making commits.
| git switch main |
If we want to work from the detached commit, we can create a branch with:
| git switch -c new-feature |
This way, our new commits can be tracked by a branch.
The git annotate command helps us identify who last changed each line of a file and when the change was made. It also shows the commit that introduced the latest change to each line.
For example:
| git annotate app.py |
This command displays information about the authorship of the lines in app.py.
We can use it to understand why a particular line of code was added or changed and to find the commit that contains that change.
In many projects, we can also use git blame, which provides similar line-by-line information.
Both commands help us restore changes that we have temporarily saved using git stash. The main difference is whether the saved stash entry remains in the stash list.
For example:
| git stash apply git stash pop |
We can use git stash apply when we may need the same saved changes again. We can use git stash pop when we want to restore the changes and remove the stash entry.
If conflicts occur, we may need to resolve them manually before continuing our work.
We can use the git diff command to compare the changes between two branches. It helps us identify which lines have been added, removed, or modified.
For example:
| git diff main feature-branch |
This command compares the file contents at the tips of the two branches.
If we want to see the commits that are present in one branch but not the other, we can use:
| git log main..feature-branch |
We can also use the following command to compare changes introduced on a feature branch since it split from the main branch:
| git diff main...feature-branch |
We can use these commands during code reviews to understand the changes before merging a feature branch.
These three commands help us undo or change different parts of our Git work, but they work in different ways.
| Command | Purpose | Example |
| git reset | It moves the current branch reference and can change the staging area or working files, depending on the option. | git reset --soft HEAD~1 |
| git revert | It creates a new commit that reverses the changes from an earlier commit. | git revert <commit-id> |
| git restore | It restores files in the working directory or staging area. | git restore app.py |
For example, we can use git reset --soft HEAD~1 to undo the latest commit while keeping its changes staged.
We can use git revert <commit-id> when we want to undo a commit without rewriting the existing history. This is often safer for shared branches.
We can use git restore app.py to discard unstaged changes in a file and restore it to the version in the index.
The main difference is that git reset changes the branch position or the state of our files, git revert creates a new commit to undo earlier changes; and git restore restores file contents.
Also Explore: Ubuntu vs Kali Linux
These questions check the depth of an experienced candidate's Git knowledge, their ability to handle complex history problems and their judgment when working on shared branches.
I can use git rebase -i HEAD~3 to combine the last three commits into one commit. I can keep the first commit as pick and change the other commits to squash or s. Then, I can save the changes and write a single commit message.
I should use interactive rebase before I share my changes with the team. I should avoid rewriting shared commit history because it can affect other developers.
Git merge and Git rebase are two ways to combine changes from different branches. Both help developers keep their code updated, but they handle commit history differently.
| Basis | Git Merge | Git Rebase |
| Meaning | It combines changes from two branches. | It moves your commits on top of another branch. |
| Commit history | It can create a merge commit and preserve the branch history. | It creates a cleaner, more linear commit history. |
| Existing commits | It keeps existing commits unchanged. | It creates new commit IDs for the commits that are rebased. |
| Conflict handling | Conflicts can occur during the merge and must be resolved. | Conflicts can occur during the rebase and may need to be resolved for multiple commits. |
| Best use | It is useful when a team wants to preserve the history of branches. | It is useful when a developer wants to keep a feature branch history clean. |
| Team project | It is a good choice for combining shared branches safely. | It is a good choice for updating a personal feature branch before merging it. |
| Example command | git merge main | git rebase main |
In simple words: Merge joins branches while preserving their history, whereas rebase places your commits on top of another branch to create a linear history.
I can use git reflog to find the previous position of my branch or HEAD. Then, I can identify the commit that contains my lost changes and use git reset --hard <commit-hash> to restore my branch to that commit.
Before I use the hard reset, I should save any important uncommitted changes because this command can remove them. I can also create a recovery branch with git branch recovery <commit-hash> to protect the recovered commit.
I can use git revert <commit-hash> to create a new commit that reverses the changes from the selected commit. Then, I can push the new commit to the shared branch after the required review.
I should prefer git revert over git reset because it preserves the shared commit history. I should also inform my teammates about the change.
I can use git bisect start to begin the search. Then, I can mark the current version as bad with git bisect bad and a known working version as good with git bisect good <commit-hash>.
Git can test the commits between these two versions. I can test each selected version and mark it as good or bad until Git identifies the commit that introduced the bug. Finally, I can run git bisect reset to return to my original state.
I would check each conflict and compare the changes from both branches. I would edit the affected files, keep the correct changes and run the required tests.
Then, I would use git add <file> to mark each conflict as resolved and git rebase --continue to continue the process. If the rebase became too complicated, I could use git rebase --abort to return to the state before the rebase started.
I would switch to the target branch using git switch <target-branch>. Then, I would use git cherry-pick <commit-hash> to apply the selected commit to that branch.
Conflicts can occur when the same lines have different changes or when the target branch does not contain the required code. I would resolve the conflicts, test the changes and continue with git cherry-pick --continue.
I can use Git worktrees to create separate working directories for different branches of the same repository. For example, I can use git worktree add ../bugfix bugfix-branch to work on a bug fix while keeping my main project open in another directory.
This approach can save time because I do not need to switch branches in the same working directory. I can also test changes or fix urgent bugs without interrupting my current work.
I can use git reflog to find the commit that existed before the reset. Then, I can create a recovery branch or use git reset --hard <commit-hash> to restore my branch, provided that I have identified the correct commit and saved any important work.
The three reset options work differently:
I would choose the option based on whether I need to keep my changes staged, unstaged, or discard them.
I would use Git LFS for large files such as videos, design files and other binary assets. I would also use shallow clones when I need only limited commit history and partial clones when I need to reduce the amount of data downloaded.
I would remove unnecessary files from the repository, avoid committing generated files and use .gitignore to exclude files that do not belong in version control. These steps can reduce repository size and improve performance.
Read Also: Top 10 High Paying IT Jobs in India
Scenario-based questions help interviewers understand how a candidate handles real workplace problems, protects code and works with a development team.
I would first run git status to identify the files with conflicts. Then, I would open each file and review the conflicting changes from both developers.
I would discuss the changes with my teammate if I needed clarification. After selecting the correct code, I would remove the conflict markers, save the file and run git add <file>. Then, I would complete the merge and test the application to confirm that everything works correctly.
I would first check whether I had pushed the commit to the remote repository. If I had not pushed it, I could create a new branch with git branch <correct-branch> to preserve the commit.
Then, I could switch to the correct branch and continue working. If I needed to remove the commit from the original branch, I would use an appropriate reset after protecting my changes. If I had already pushed the commit, I would coordinate with my team before changing the shared history.
I can use git reset --soft HEAD~1 to undo the last commit while keeping the changes staged. If I want to keep the changes but unstage them, I can use git reset --mixed HEAD~1.
If I have already pushed the commit to a shared branch, I would usually use git revert HEAD because it creates a new commit that reverses the previous changes without rewriting shared history.
I would first run git fetch to update my remote tracking information. Then, I would use git status and git log to compare my local branch with the remote branch.
I would check which commits were added or removed and save any important local changes before making further updates. I would coordinate with my teammate and integrate the correct changes carefully. I would avoid another force push until we agreed on the recovery plan.
I would first revoke or rotate the exposed password or API key because removing the file from Git does not make the secret safe again.
Then, I would remove the file from the repository and add it to .gitignore if it should not be tracked. If the secret existed in previous commits, I would use a history-rewriting tool, such as git filter-repo, to remove it from the repository history. I would coordinate with my team because rewriting shared history can affect other developers.
If I had not pushed the commit yet, I would add the missing file using git add <file> and run git commit --amend --no-edit to include it in the previous commit without changing the commit message.
If I had already pushed the commit, I would consider creating a new commit with the missing file. If the team required an amended commit, I would coordinate with the team before rewriting the shared history.
I would first run git fetch to get the latest remote changes. Then, I would check the differences between my local branch and the remote branch.
If my branch had no conflicting local commits, I could use git pull --ff-only to update it safely. If I had local commits, I would choose merge or rebase based on the team's workflow. I would resolve any conflicts and run tests before pushing my changes.
I would review the commit history and identify the unrelated commits. Then, I would create a clean branch from the correct target branch and use git cherry-pick to apply only the required commits.
I would run the tests, check the final commit history and update the pull request with the corrected branch. This approach would help keep the pull request focused and make the code review easier.
I would first check whether the commit had been pushed. If it had not been pushed, I could create a feature branch from the current commit to preserve my work. Then, I could move the main branch back to its previous commit, provided that I had confirmed the correct commit and no other work would be lost.
If the commit had already been pushed, I would inform the team and follow the team's recovery process. I would avoid resetting the shared main branch without approval.
I would run git fetch and review the commit history to understand which commits exist on each branch. Then, I would save any uncommitted changes before integrating the remote updates.
I could use git merge to combine the two histories or git rebase to place my local commits on top of the remote branch. I would follow the team's workflow, resolve conflicts if needed and run tests before pushing the updated branch.
If I used rebase on a branch that other developers shared, I would coordinate with them before rewriting its history.
Also Read: Best IT Courses and Certifications In Demand
An interviewer looks for the following characteristics in the answer:
A good answer should not only list the commands but also explain why we use them, what problems they may cause and how we can check that the issue is fixed.
Git is an essential skill in software engineering and is often used in interviews to evaluate candidates' code management capabilities. While beginners should at least be aware of the basics, intermediate and advanced developers must master rebase, reflog, bisect and conflict resolution techniques.
Make sure to practice all these commands in a test repository, be aware of the associated risks, keep your uncommitted work safe and communicate with the team before changing the shared history.