Are You Familiar with Git? A Practical Guide to the Version Control System

Are You Familiar with Git? A Practical Guide to the Version Control System
“Are you familiar with Git?” is one of the most common questions in developer interviews, and for good reason. Git is used in almost every software project today, from a small personal blog to the Linux kernel. In this article we will look at what Git is, how it works under the hood, which commands you use every day, how teams organize their work with it, and what to do when something goes wrong.
What is Git?
Git is a distributed version control system. It records the history of changes in your project, lets you go back to any previous state, work on several features in parallel and combine the work of many developers.
Git was created in 2005 by Linus Torvalds for developing the Linux kernel. Its main goals were speed, reliability and support for a large, distributed team.
Centralized vs. distributed version control
- Centralized systems (for example, SVN) have one central server with the history. Developers get only the current version of files, and most operations require a connection to the server.
- Distributed systems (Git, Mercurial) give every developer a full copy of the repository with the entire history. You can commit, view history, create branches and compare versions offline. A remote server such as GitHub or GitLab is simply another copy used for sharing.
It is also important not to confuse Git with GitHub. Git is the tool that runs on your computer. GitHub, GitLab and Bitbucket are services that host Git repositories and add pull requests, code review, CI/CD and issue tracking.
How Git works: key concepts
Snapshots, not diffs
Each commit in Git is a snapshot of the whole project at a moment in time, plus the author, date, message and a link to the parent commit. Unchanged files are not copied again; Git just references the already stored version. Every commit has a unique identifier, a hash such as a1b2c3d.
Three areas
To understand Git, you need to understand where your changes live:
- Working directory: the files you are editing right now.
- Staging area (index): changes you have selected for the next commit with
git add. - Repository: the saved history of commits in the
.gitfolder.
The staging area lets you commit only part of your changes, for example, to separate a bug fix from a refactoring even if you did both in the same file.
Branches and HEAD
A branch in Git is just a lightweight pointer to a commit. Creating a branch is instant and costs almost nothing, so developers create a separate branch for every feature or fix. HEAD is a pointer to the branch (or commit) you are currently on.
Everyday commands
# One-time setup
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
git config --global init.defaultBranch main
# Start a project or copy an existing one
git init
git clone git@github.com:user/project.git
# See what changed
git status
git diff # unstaged changes
git diff --staged # changes that will go into the next commit
# Save changes
git add app/models/user.rb
git commit -m "Add email validation to User"
# History
git log --oneline --graph --all
Working with branches
git switch -c feature/user-avatars # create a branch and switch to it
git switch main # switch back
git branch # list local branches
git branch -d feature/user-avatars # delete a merged branch
The older command git checkout does the same things and more, but git switch (for branches) and git restore (for files) are clearer and safer.
Working with a remote repository
git remote -v # list remotes
git fetch # download changes without applying them
git pull # fetch + merge (or rebase) into the current branch
git push -u origin feature/user-avatars # publish a branch
Merge vs. rebase
There are two ways to bring changes from one branch into another:
- Merge (
git merge) combines branches and creates a merge commit. History stays exactly as it happened, but can become cluttered. - Rebase (
git rebase) replays your commits on top of another branch, giving a clean, linear history. However, it rewrites commits, creating new hashes.
# Update your feature branch with the latest main
git switch feature/user-avatars
git fetch origin
git rebase origin/main
# Or merge instead
git merge origin/main
The golden rule: do not rebase commits that other people have already based their work on, such as a shared main branch. Rebasing your own local feature branch is fine.
Resolving merge conflicts
A conflict happens when two branches change the same lines of the same file. Git stops and marks the problem area:
<<<<<<< HEAD
validates :email, presence: true
=======
validates :email, presence: true, uniqueness: true
>>>>>>> feature/unique-emails
You edit the file to keep the correct version, remove the markers, then run git add and continue with git commit (for merge) or git rebase --continue (for rebase). If things get too messy, git merge --abort or git rebase --abort returns everything to the state before you started.
Undoing changes
Knowing how to undo mistakes is what separates a confident Git user from a beginner:
git restore config/routes.rb # discard unstaged changes in a file
git restore --staged config/routes.rb # remove a file from staging, keep the changes
git commit --amend # fix the last commit (message or content)
git reset --soft HEAD~1 # undo the last commit, keep changes staged
git reset --hard HEAD~1 # undo the last commit and DELETE the changes
git revert a1b2c3d # create a new commit that undoes a1b2c3d
- Use
git revertfor commits that are already pushed: it does not rewrite history, so it is safe for shared branches. - Use
git resetand--amendonly for local commits that nobody else has. - Be careful with
--hard: uncommitted changes are lost.
And the lifesaver: git reflog shows everywhere HEAD has been, including commits “lost” after a reset or a failed rebase. You can almost always recover work that was once committed.
git reflog
git reset --hard HEAD@{2} # go back to the state from two moves ago
Useful commands worth knowing
git stash: temporarily put away unfinished changes, for example, to switch to an urgent bug fix. Bring them back withgit stash pop.git cherry-pick <hash>: copy one specific commit to the current branch.git blame <file>: see who last changed each line and in which commit.git bisect: binary search through history to find the commit that introduced a bug.git tag v1.2.0: mark a release.git rebase -i HEAD~3: interactive rebase to squash, reorder or rename your recent local commits before opening a pull request.
Team workflows
- GitHub Flow:
mainis always deployable; every change goes through a short-lived feature branch and a pull request with code review. Simple and popular for web applications. - Git Flow: separate
develop,release/*andhotfix/*branches. Suitable for products with planned releases, but heavier for continuous deployment. - Trunk-based development: everyone integrates into
mainvery often, with small changes and feature flags. Works well with strong automated testing.
Git in a Rails project
A new Rails application already comes with a .gitignore. It is important to keep secrets and generated files out of the repository:
# .gitignore (key lines)
/config/master.key
/config/credentials/*.key
/log/*
/tmp/*
/storage/*
/public/assets
/node_modules
.env
- Never commit
config/master.keyor.envfiles. The encryptedcredentials.yml.enccan be committed, but the key must be passed to the server separately. - Commit
Gemfile.lockanddb/schema.rb, so all developers and servers use the same gem versions and database structure. - Keep a migration and the code that depends on it in the same commit or pull request.
If a secret was committed by mistake, deleting the file in a new commit is not enough: it remains in history. Rotate the secret immediately, and then clean the history if needed.
Good commit messages
A good commit history is documentation for your future self and your team:
- Write a short summary line (up to about 50 characters) in the imperative mood: “Add avatar upload”, not “Added avatars”.
- If needed, add a blank line and a longer explanation of why the change was made.
- Make each commit one logical change. Do not mix formatting, refactoring and new features.
git commit -m "Fix N+1 query on articles index" -m "Preload authors and comments counts to cut page load from 40 to 3 queries."
Best practices
- Commit often, push regularly. Small commits are easier to review, revert and understand.
- Work in branches and merge through pull requests with code review.
- Pull before you start and keep your branch up to date to avoid big conflicts.
- Do not rewrite shared history and avoid
git push --forceon shared branches. If you must force-push your own branch, use--force-with-lease. - Review before committing with
git diff --staged. - Keep secrets out of the repository and set up
.gitignorefrom day one. - Use SSH keys or tokens for authentication with remote repositories.
How to answer “Are you familiar with Git?” in an interview
A simple “yes” is not enough. A strong answer shows that you understand the concepts, not just a few commands. For example: explain that Git is a distributed version control system, describe the three areas and branches, mention your team's workflow (feature branches, pull requests, code review), explain the difference between merge and rebase, and give an example of a situation where you resolved a conflict or recovered lost work with git reflog. Real examples from your own experience are always more convincing than definitions.
Conclusion
Git is a fundamental tool for every developer. It keeps the history of your project, lets you experiment safely in branches and makes teamwork possible. Learn the basic commands, understand how commits, branches and the staging area work, know how to undo mistakes, and follow good practices for commits and secrets. Then Git will stop being a source of fear and become a reliable safety net for your code.
Back



