

TL;DR
- Git is the version control system behind virtually every modern software project.
- Git tracks every change to your project so you can collaborate, review, and ship safely.
- Daily commands include clone, status, add, commit, pull, push, branch, and merge.
- Workflow choice (trunk, GitFlow, fork PRs) shapes code review, testing, and CI/CD behavior.
- Automation runs on Git events (pushes, PRs, tags, etc.), so tests and quality gates run before production.
Version control plays an important role in any development project, including test automation. It is the practice of tracking and providing control over changes made in the source code.
Git is one of the most widely used distributed version control systems (DVCS): every clone is a full history, and work can continue offline. For test automation and quality engineering, Git connects local experiments, shared branches, pull requests, and pipeline triggers.
What is Git?
The Git project’s own manual opens with a straight definition: “Git is a fast, scalable, distributed revision control system with an unusually rich command set that provides both high-level operations and full access to internals.”
That “distributed” bit matters for testing and delivery, as your laptop has a full copy of history, not a thin client to someone else’s truth.
What are Git commands?
Git commands are the CLI (and sometimes GUI) operations that read or update the repository: history, branches, remotes, and the index (staging area).
Git commands were originally designed for coordinating work among programmers who were making changes to source code during software development.
Git commands were originally designed for coordinating work among programmers who were making changes to source code during software development.
Benefits of Git
- Free and open source: It’s managed under the GPL-2.0 license.
- Performance: Faster and more reliable than any other version control software, focusing on file content rather than file names.
- Integrity: Git provides security by protecting the code and the change history through a cryptographically secure hashing algorithm called SHA1.
- Adoption: Git is the de facto standard in modern software delivery, including CI/CD and test automation workflows.
Terminology
- Repository (repo): The data structure where Git stores the complete history of your project lives in the .git directory at the root of your project. All files, every single change, and every branch are all in here.
- Working directory: This reflects the actual files on your disk. This is what you edit. It’s distinct from what Git has recorded.
- Staging area (index): This is a holding zone between your working directory and the repository. When you git add a file, you move your file here. When you perform a git commit, you’re recording whatever’s in the staging area.
- Commit: An immutable snapshot of the staging area at a point in time with metadata (author, message, parent commits). Every commit gets a unique SHA-1 hash.
- Branch: A movable pointer to a commit (a line of development). “Branching” means you diverge from the main line of development and continue to do work without messing with that main line.
- Remote: A version of your repository hosted somewhere else, such as GitHub, GitLab, Bitbucket, or your company’s internal server. You push to and pull from remotes.
- Clone: A local copy of a remote repository with history.
- Pull request/merge request: A review workflow built on branches (not a core Git command, but central to team practices).
- Merge conflict: This is what happens when two branches have changed the same lines in the same file, and Git can’t figure out which version to keep.
- HEAD: The current commit/branch pointer you have checked out.
- Fast-forward: A merge that simply moves the branch pointer forward when no divergent commits exist.
- Detached HEAD: Checking out a specific commit (not a branch tip), which can be useful for inspection—know before you commit new work there.
Commands developers use daily
These are the commands that live in the muscle memory of most developers. Using git help in the command prompt (on Windows), terminal (on Mac), or shell (on Linux) will give you a list of available Git commands.

1. git status
git status
It tells you what’s changed, what’s staged, what’s untracked, and what branch you’re on.
2. git add
git add <file>
git add .
git add -p
Stages changes for the next commit. You can stage individual files, everything in the current directory, or—with the -p (patch) flag—interactively choose specific hunks of changes within the file.
3. git commit
git commit -m "Fix null pointer in payment validation"
Records the staged snapshot. Write commit messages that explain why, not what—the diff already shows what changed.
4. git push
git push
git push --set-upstream origin feature/login-redesign
Sends your local commits to the remote repository. If the branch doesn’t exist remotely yet, you’ll need –set-upstream (or -u for short) to create the tracking relationship.
5. git pull
git pull
git pull --rebase
Fetches remote changes and merges them into your current branch. The –rebase variant replays your local commits on top of the fetched changes instead of creating a merge commit, keeping the history linear.
6. git fetch
git fetch
git fetch --all
Downloads changes from the remote without merging anything. It’s the non-destructive sibling of git pull.
7. git diff
git diff
git diff --staged
git diff main..feature/new-api
Shows the actual line-by-line differences. Without arguments, it shows unstaged changes. With –staged, it shows what’s about to be committed. With two branch names, it compares them.
8. git log
git log
git log --oneline
git log --oneline --graph --all
Shows commit history. The default output is verbose; –oneline compresses each commit to a single line. Add –graph –all and you get an ASCII-art visualization of your branch topology, useful when you’re trying to understand how a feature branch diverged.
9. git branch
git branch
git branch feature/checkout-flow
git branch -d old-experiment
git branch -m old-name new-name
Lists, creates, deletes, or renames branches. The -d flag is a safe delete (it won’t let you delete an unmerged branch). Use -D to force it, but you’re throwing away work this way.
10. git checkout / git switch
git checkout feature/api-v2
git switch feature/api-v2
git switch -c feature/new-thing
Switches branches. git switch was introduced because git checkout was overloaded—it also restores files, which confused people.
11. git merge
git merge feature/user-auth
Combines the history of one branch with another. If Git can do it cleanly (no conflicting changes), it’s seamless. If not, you’ll need to resolve conflicts manually.
12. git clone
git clone https://github.com/your-org/your-repo.git
git clone <url> -b <branch>
Downloads an entire repository and its history to your local machine. You generally do this once per project.
Setting up and configuring git
These commands set the stage. You use them when you’re starting a new project, joining a team, or customizing how Git behaves on your machine.
13. git init
git init
git init my-new-project
Creates a new Git repository. It generates the .git directory and all its internal structure. You’ll use this when starting a project from scratch.
14. git config
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
git config --global core.editor "code --wait"
git config --list
Sets configuration values at the system, global (user), or repository level. At a minimum, set your name and email as they’re attached to every commit you make.
15. git help
git help commit
git help -a
Opens the manual page for any Git command. The -a flag lists every available command.
16. git version
git version
Prints the installed Git version. Useful when debugging behavior differences between machines.
Branching, merging, and navigating history
Branching is Git’s “killer feature. It’s cheap (a branch is just a 41-byte file containing a commit hash), fast, and enables the kind of parallel development workflows that would have been impractical with older version control systems.
17. git rebase
git rebase main
git rebase -i HEAD~5
Replays your commits on top of another branch’s tip, creating a linear history. Interactive rebase (-i) lets you squash, reorder, edit, or drop commits before they’re shared. Never rebase commits that have already been pushed to a shared branch.
18. git tag
git tag v2.1.0
git tag -a v2.1.0 -m "Release 2.1.0"
git push origin v2.1.0
Marks specific commits, typically releases. Lightweight tags are just pointers; annotated tags (-a) store the tagger’s name, date, and message. Most release workflows use annotated tags.
19. git mergetool
git mergetool
Launches a visual merge conflict resolution tool based on your git config (VS Code, IntelliJ’s built-in merger, and the venerable vimdiff).
Working with changes
These commands manage the life cycle of your modifications—from the moment you make a change to the moment you decide what to do with it.
20. git stash
git stash
git stash save "work in progress: login form"
Temporarily shelves uncommitted changes so you can work on something else.
21. git stash pop
git stash pop
Reapplies the most recently stashed changes and removes them from the stash.
22. git stash list
git stash list
Shows all stashed change sets. Stashes are indexed as stash@{0}, stash@{1}, etc. If you’ve been stashing liberally, this helps you find the right one.
23. git stash drop
git stash drop stash@{2}
Deletes a specific stash entry. Use it to clean up stashes you no longer need.
24. git rm
git rm obsolete-file.txt
git rm --cached sensitive-config.yaml
Removes a file from both the working directory and the staging area. The –cached flag removes it from tracking without deleting it from disk. Useful when you’ve accidentally committed a file that should be in .gitignore.
25. git mv
git mv old-name.js new-name.js
Renames or moves a file and stages the change in one step.
26. git restore
git restore modified-file.js
git restore --staged accidentally-added.js
git restore discards working directory changes; git restore –staged unstages a file without touching the working directory.
27. git reset
git reset HEAD~1
git reset --soft HEAD~1
git reset --hard HEAD~1
Moves HEAD and (optionally) modifies the staging area and working directory. This is a blunt instrument with three modes: –soft keeps your changes staged, –mixed (the default) unstages them, and –hard discards everything. –hard is destructive and unforgiving.
Inspecting history and debugging
When something breaks, these commands help you figure out what happened, when it happened, and who’s responsible.
28. git show
git show abc1234
git show HEAD~3
Displays the details of a specific commit (i.e., the author, timestamp, message, and the actual diff).
29. git blame
git blame src/utils/validate.js
Annotates each line of a file with the commit and author who last modified it.
30. git shortlog
git shortlog -s -n
Summarizes commit history by author. The -s flag shows counts only; -n sorts by number of commits.
31. git reflog
git reflog
Shows a log of where HEAD has pointed (i.e., every checkout, commit, reset, rebase, and merge). If you’ve lost a commit through a bad reset or rebase, git reflog can help you find it.
32. git log -p
git log -p -- src/api/handler.js
Shows the full diff (patch) for each commit. The — followed by a file path limits the output to a single file’s history.
33. git diff –name-only
git diff --name-only main..HEAD
Lists only the names of changed files, without the actual diffs.
Collaboration and remotes
Git is a distributed system, which means every developer has a complete copy of the repository. These commands manage how those copies stay in sync.
34. git remote
git remote
git remote -v
Lists the named remote connections. The -v flag shows the URLs for fetch and push operations.
35. git remote add
git remote add upstream https://github.com/original/repo.git
Adds a new remote. If you’ve forked a repository, you’ll typically add the original as upstream so you can pull in changes from the source.
36. git remote remove
git remote remove old-origin
Removes a remote connection.
37. git push –force-with-lease
git push --force-with-lease
A safer alternative to git push –force. It will refuse to overwrite the remote branch if someone else has pushed commits since you last fetched.
38. git pull –rebase
git pull --rebase origin main
Fetches and rebases instead of merging. This avoids the “merge commit clutter” that accumulates when multiple developers regularly pull from a shared branch.
Undoing mistakes and rewriting history
Everyone makes mistakes. These commands show you how to fix them gracefully, if possible.
39. git revert
git revert abc1234
Creates a new commit that undoes the changes from a previous commit. This is the safe way to undo something that’s already been pushed.
40. git commit –amend
git commit --amend -m "Corrected commit message"
git commit --amend --no-edit
Modifies the most recent commit. Use it to fix a typo in a commit message or to add a forgotten file. The –no-edit flag keeps the original message. Don’t amend commits you’ve already pushed unless you’re the only one working on the branch.
41. git cherry-pick
git cherry-pick abc1234
Applies a single commit from one branch onto another. Useful when you need a specific fix from a development branch on a release branch without merging everything.
42. git clean
git clean -n
git clean -fd
Removes untracked files from the working directory. The -n flag does a dry run (shows what would be deleted). The -f flag is required to actually delete anything—Git forces you to be explicit about destruction. The -d flag includes untracked directories.
Searching and debugging
When you need to find something in a codebase, such as a string or a bug’s origin, you’ll often find these commands are faster than grepping through files manually.
43. git grep
git grep "TODO" -- "*.java"
git grep -n "deprecated" HEAD~10
Searches the contents of tracked files. It’s faster than system grep because it operates on Git’s internal data structures. You can search across commits, branches, or file patterns.
44. git bisect
git bisect start
git bisect bad HEAD
git bisect good v2.0.0
# Git checks out a commit; you test it
git bisect good # or bad
# Repeat until Git identifies the first bad commit
git bisect reset
Binary-searches through your commit history to find the exact commit that introduced a bug. You tell Git one commit where the bug exists (bad) and one where it doesn’t (good). Git checks out the midpoint; you test it and report.
45. git log –oneline –graph –all
git log --oneline --graph --all
Renders a compact, visual representation of all branches and their relationships. It’s the fastest way to get a mental model of what’s happening in a repository without opening a GUI.
46. git log –author
git log --author="Andreea" --since="2025-01-01"
Filters commit history by author and/or date range. Useful during incident reviews or when tracking down who introduced a specific pattern.
Advanced and power-user commands
You might go weeks or months without needing these. But when you need them, nothing else will do.
47. git worktree
git worktree add ../hotfix-branch hotfix/critical-fix
git worktree list
git worktree remove ../hotfix-branch
Creates additional working directories linked to the same repository. Instead of stashing your work and switching branches, you can have multiple branches checked out simultaneously in different directories.
48. git submodule
git submodule add https://github.com/lib/useful-library.git
git submodule update --init --recursive
Embeds one Git repository inside another. This sounds elegant in theory, but in practice, submodules have a reputation for being finicky—as in, they require explicit initialization and updates, and new contributors frequently clone a repo and wonder why certain directories are empty.
49. git subtree
git subtree add --prefix=vendor/library https://github.com/lib/library.git main --squash
An alternative to submodules that merges another repository’s contents directly into a subdirectory. It avoids many of the submodule’s usability issues but makes the host repository’s history more complex.
50. git archive
git archive --format=tar --output=release.tar HEAD
Creates a compressed archive of a tree. Useful for generating clean release packages without the .git directory or any untracked files.
51. git bundle
git bundle create repo.bundle --all
git clone repo.bundle
Packages a repository (or a subset of its history) into a single binary file that can be transferred offline. Niche, but essential if you need to move a repo across an air-gapped network.
52. git gc
git gc
git gc --aggressive
Runs garbage collection, wherein it compresses file revisions, removes unreachable objects, and optimizes the repository. Git runs this periodically on its own, but you might trigger it manually on large repositories where performance has degraded.
53. git fsck
git fsck
Verifies the integrity of the repository’s object database. If you suspect corruption (disk issues, incomplete transfers), this is the diagnostic tool to use.
54. git rev-parse
git rev-parse HEAD
git rev-parse --short HEAD
git rev-parse --show-toplevel
Translates Git references into SHA-1 hashes. Mostly used in scripts—it’s how automation tools resolve branch, names, tags, and relative references into concrete commit hashes.
55. git describe
git describe --tags
Gives a human-readable name to a commit based on the nearest tag. The output looks like v2.1.0-14-gabc1234—meaning 14 commits after tag v1.2.0 , at commit abc1234. CI systems often use this to generate build version numbers.
56. git sparse-checkout
git sparse-checkout init --cone
git sparse-checkout set src/frontend
Limits the working directory to a subset of the repository’s files. Essential for monorepos where you don’t need (or want) the entire codebase checked out.
57. git maintenance
git maintenance start
Configures automatic background maintenance tasks—prefetching, garbage collection, commit-graph updates.
58. git range-diff
git range-diff main..feature-v1 main..feature-v2
Compares two versions of a patch series. If you’ve rebased a feature branch and want to verify that the rebase preserved your changes correctly, range-diff shows exactly what changed between the old and new versions.
59. git rerere
git config --global rerere.enabled true
Short for “reuse recorded resolution.” Once enabled, Git remembers how you resolved a merge conflict and automatically applies the same resolution if it encounters the same conflict again.
60. git notes
git notes add -m "Reviewed by QA" abc1234
git log --show-notes
Attaches metadata to commits without modifying them. Useful for adding review notes, QA status, or deployment annotations to existing history.
Patching and sharing changes outside of remotes
Sometimes you need to share changes without pushing to a remote—for email-based workflows, offline code review, or applying fixes across disconnected repositories.
61. git format-patch
git format-patch -3
git format-patch main..feature-branch --output-directory patches/
Generates patch files from commits, one file per commit. The Linux kernel development community, where Git originated, still uses this workflow for submitting changes via email.
62. git apply
git apply fix.patch
Applies a patch file to the working directory without creating a commit. Use git am (below) if you want to preserve the original commit metadata.
63. git am
git am patches/*.patch
Applies a series of patches from mailbox-format files, creating commits for each. It’s the receiving end of git format-patch.
Large files and special situations
64. git lfs
git lfs install
git lfs track "*.psd"
git add .gitattributes
Git Large File Storage replaces large binary files (images, datasets, compiled assets) with text pointers in the repository, storing the actual file content on a separate server.
65. git filter-repo
git filter-repo --path src/ --force
The modern replacement for git filter-branch, used to rewrite repository history—typically to remove sensitive data that was accidentally committed, or to extract a subdirectory into its own repository.
66. git config core.hooksPath
git config core.hooksPath .githooks
Redirects Git’s hook scripts to a directory you can commit to version control. By default, hooks live in .git/hooks/ and aren’t shared across clones. Setting a custom hooks path means your team’s pre-commit linters and pre-push checks travel with the repository.
67. git diff –check
git diff --check
Flags whitespace errors such as trailing spaces, mixed tabs/spaces, and blank lines at the end of files. Many teams include this in pre-commit hooks to keep diffs clean.
68. git log –all –full-history — <path>
git log --all --full-history -- src/deleted-file.ts
Traces the complete history of a file, even after it’s been deleted. If someone removed a file and you need to understand what it contained or why it was removed, this will find it.
69. git update-index –assume-unchanged
git update-index --assume-unchanged local-config.yaml
Tells Git to stop tracking changes to a specific file without removing it from the index. Useful for local configuration files that you need to modify but never commit. To undo: –no-assume-unchanged.
70. git rev-list –count HEAD
git rev-list --count HEAD
Counts the total number of commits reachable from HEAD. Some build systems use this as a simple, monotonically increasing build number.
Git commands cheat sheet
| Category | Command | What it does |
| Setup | git init | Create a new repository |
| git clone <url> | Copy a remote repository locally | |
| git config | Set user name, email, preferences | |
| Daily | git status | Show working directory state |
| git add | Stage changes | |
| git commit | Record staged snapshot | |
| git push | Upload local commits to remote | |
| git pull | Fetch + merge remote changes | |
| git diff | Show line-by-line changes | |
| Branching | git branch | List, create, or delete branches |
| git switch / checkout | Change branches | |
| git merge | Combine branch histories | |
| git rebase | Replay commits on a new base | |
| git tag | Mark specific commits | |
| Undoing | git revert | Undo a commit with a new commit |
| git reset | Move HEAD, optionally discard changes | |
| git restore | Discard working directory changes | |
| git stash | Temporarily shelve changes | |
| Inspecting | git log | View commit history |
| git blame | See who changed each line | |
| git reflog | View HEAD movement history | |
| git bisect | Binary-search for a bug | |
| Collaboration | git remote | Manage remote connections |
| git fetch | Download without merging | |
| git push –force-with-lease | Safe force push | |
| Advanced | git worktree | Multiple working directories |
| git sparse-checkout | Partial repo checkout | |
| git rerere | Reuse conflict resolutions | |
| git lfs | Handle large binary files |
Common Git workflows
Git doesn’t prescribe a workflow. It provides the primitives, and teams build processes over them. Here are some of the most widely adopted patterns.
1. Feature branch workflow
Every new feature or fix gets its own branch. Development happens in isolation, and when the work is complete, it’s merged into main via a pull request. This is the default at most organizations and maps naturally to code review processes.
2. Gitflow
This was formalized by Vincent Driessen in a 2010 blog post. It defines specific branch types, such as main, develop, feature/*, release/*, hotfix/*, with strict rules about how they merge. Gitflow works well for projects with scheduled releases.
3. Trunk-based development
In this form of workflow, developers commit to main (or a short-lived branch that merges within hours, not days). This approach requires strong automated testing because you need confidence that each merge doesn’t break anything.
As Martin Fowler writes on his website: “Continuous Integration encourages all members of a development team to integrate their work daily, instead of developing features in isolation for days or weeks.”
4. Forking workflow
In this mode, each developer forks the repository, works in their fork, and submits pull requests to the upstream repository. This is very common in open-source projects where contributors don’t have write access to the main repository.
How Git workflows affect software testing
Your Git branching strategy isn’t just a developer convenience; it directly shapes how effectively your team tests software:
When each feature lives on its own branch, you can run targeted test suites against just the changed code.
1. Branch isolation determines test scope
When each feature lives on its own branch, you can run targeted test suites against just the changed code. Short-lived branches mean faster feedback loops; long-lived branches accumulate merge debt and make integration testing harder the longer they exist.
2. Merge strategy affects test reliability
Teams that use merge commits create a clear integration point where a full test suite should run. Teams that rebase get a cleaner history but lose the explicit “these two together here” marker that helps when diagnosing test failures after integration.
3. Tagging drives release testing
If your team tags releases, those tags become anchors for regression test suites. QA can then reliably spin up the exact state of the codebase that corresponds to, say, v3.2.1 and test against it without having to guess which commit corresponds to which release.
4. Environment branching creates testing bottlenecks
Some organizations maintain branches, like branching or QA, that correspond to deployment environments. This provides stable targets for testing but can create bottlenecks when multiple teams need to deploy to the same environment simultaneously.
How automated testing fits into Git-based pipelines
Modern CI/CD systems are deeply intertwined with Git. Nearly every automated testing workflow starts with a Git event such as a push, a pull request, a tag, or a merge.
Pre-commit hooks
Pre-commit hooks run tests or linters locally before a commit is even created. If the tests fail, the commit is rejected. This catches issues at the earliest possible moment, before they would end up entering the repository’s history.
One can configure them via .git/hooks/pre-commit or can even use a framework that version-controls hook configuration.
CI triggers on push/PR
CI triggers on push/PR occur when a developer pushes a branch or opens a pull request and the CI server (GitHub Actions, GitLab CI, Jenkins, etc.) checks out that exact commit and runs the test suite. The results are reported back to the pull request as status checks.
This is the most common pattern and the one where Git and testing are most tightly coupled.
Merge gates
Merge gates prevent code from being merged unless CI passes. This is a policy decision configured in your Git hosting platform, such as GitHub’s “required status checks,” GitLab’s “merge request approvals,” etc.
It means no code reaches main without passing automated tests, which is table stakes for any team that ships frequently.
Tag-triggered deployment pipelines
Tag-triggered deployment pipelines use Git tags to kick off release processes. When a tag matching a pattern is pushed, the CI system builds a release artifact, runs the full regression suite, and (if everything passes) deploys to production.
The tag provides an immutable reference point that ties a deployment to a specific state of the code.
Diff-aware test selection
Diff-aware test selection uses git diff –name-only to identify which files changed, then runs only the tests that cover those files. This is a significant optimization for large codebases where the full test suite might take hours to finish.
Tools like Tricentis and others implement risk-based or change-based test selection that leverages Git metadata to prioritize testing.
The most effective developers work in environments where every push, merge, and tag automatically triggers the right tests, at the right scope, with results that flow back to the people who need them.
Conclusion
Git manages change, but Tricentis manages the confidence that those changes work. Git tells you what changed, when, and by whom. Tricentis’s continuous testing platform tells you whether those changes broke anything, and where to focus testing effort when you can’t test everything.
The most effective developers work in environments where every push, merge, and tag automatically triggers the right tests, at the right scope, with results that flow back to the people who need them. That’s modern quality engineering, and it starts with the workflows this guide covers.
