LinkORB Engineering
Team members’ contributions to a pull request (PR) can quickly increase the PR’s commit history when collaborating on a project. You accept a small typo fix here, a great suggestion there, and before you know it, you’ve added 100 commits to a PR you planned to keep small. While, LinkORB prefers to keep the size of PRs small, having a small PR with a large number of commits can make it difficult to review, undo, or track changes.
To maintain a cleaner, more manageable commit history, we recommend squashing similar and related commits on a child branch before merging a PR. Squashing is the process of merging similar and related commits into one before or after pushing changes upstream.
This document provides guidance on how to squash commits using:
Specifically, it discusses:
Git provides a rebase
command that allows users to rewrite the history of a repository by:
Assuming you’ve been assigned the task of customizing a web app template and updating the app’s documentation. The commit history of your branch may look similar to the below example.
82af5ac (HEAD -> customize-template-4096) docs: paraphrase sentence #4096
5c2195e docs: fix typo #4096
73a05c3 docs: update README.md #4096
a8f3604 fix: missing semi-colon (pesky eslint!) #4096
852495f refactor: reduce login controller length #4096
c2c9c96 feat: initial commit (definitely buggy) #4096
Although each of the three latest commits (prefixed by docs
) introduces a different change, taken together, they simply update the app’s documentation (in the README.md file). For this reason, you may clean up the commit history by squashing all three commits into one. The commit history example above will look similar to the following after all docs changes are squashed:
30a2041 (HEAD -> customize-template-4096) docs: update README.md #4096
a8f3604 fix: missing semi-colon (pesky eslint!) #4096
852495f refactor: reduce login controller length #4096
c2c9c96 feat: initial commit (definitely buggy) #4096
Consider squashing related commits when a PR:
Ships a non-complex feature or fix that has a large commit history.
Contains multiple commits that are similar or related. For example, three subsequent related commits may be squashed into one if the last two fix an error in the first.
Includes multiple commits that can be grouped into logical units. For example, you may squash 30 commits that contain code and documentation changes into two (one docs and one feat) commits.
Organize and squash related commits into logical units instead of squashing all commits into one.
Only contains documentation.
Documentation commits are great candidates for squashing. However, commits should be squashed with discretion when they contain functional code. Look out for and resolve all rebase conflicts in messages and alerts shown after each step before finalizing the squashing operation.
Squashing is recommended but not required. If squashing related commits takes more than 90 minutes or results in difficult-to-resolve conflicts, please abort (e.g., git rebase --abort
) the squashing operation and request that the PR be merged as-is.
Squash related commits using GitHub Desktop as follows:
Use Git to squash multiple commits from the command line as follows:
Open a terminal and navigate to the root of the repository’s folder.
Ensure you’re on the branch you wish to squash (some) of its commits by running the below command:
git branch
The selected branch is marked by an asterisk. Proceed to step 3 below if you’re on the correct branch. Or, run git switch YOUR-BRANCH-NAME
to switch to the branch you want to change.
Print a compressed version of the branch’s history to the screen by running the following command:
git log --oneline
Locate the oldest commit in the range of commits that you want to squash and copy the hash of the commit directly before (below) it. Note that the latest commit is shown first in the commit history.
For example, if you want to squash the latest three documentation commits in the below example, copy the hash of the fix commit (i.e., a8f3604 fix: missing semi-colon (pesky eslint!) #4096
) that is directly before (below) it.
82af5ac (HEAD -> customize-template-4096) docs: paraphrase sentence #4096
5c2195e docs: fix typo #4096
73a05c3 docs: update README.md #4096
a8f3604 fix: missing semi-colon (pesky eslint!) #4096
852495f refactor: reduce login controller length #4096
c2c9c96 feat: initial commit (definitely buggy) #4096
Start the interactive rebase editor by running the below command. Replace COMMIT-HASH-YOU-COPIED
with the commit hash you copied in the previous step.
git rebase -i COMMIT-HASH-YOU-COPIED
For example, if you want Git to merge all three docs commits in the above example into a single one, pass the hash (a8f3604) of the fix commit directly before (below) it to the git rebase
command:
git rebase -i a8f3604
git rebase -i a8f360
instructs git to use commit a8f360
as the base or as the latest commit upon which the squashed commits will be placed. a8f360
, in the above example, is essentially the latest snapshot of the branch before the squashed commits are added to the commit history.
Skip the first line (oldest commit) of the rebase editor and replace the word pick with squash or s in subsequent lines that start with the word pick.
The contents of the rebase editor of our example will look similar to the following after we complete this step:
pick 73a05c3 docs: update README.md #4096
s 5c2195e docs: fix typo #4096
s 82af5ac docs: paraphrase sentence #4096
Merge the squashed commits into the branch’s history with the below command:
git rebase --continue
Modify and/or save the merge/commit messages for the squashed commits and close the merge/commit editor.
The squashed commit history of our example will look like the following after committing the changes:
08c4754 (HEAD -> customize-template-4096) docs: update README.md #4096
a8f3604 fix: missing semi-colon (pesky eslint!) #4096
852495f refactor: reduce login controller length #4096
c2c9c96 feat: initial commit (definitely buggy) #4096
Push the changes to GitHub
git push origin BRANCH-NAME
If you pushed the commits to GitHub before squashing them, you may need to pass the -f
option or --force
flag to the git push
command.
git push -f origin BRANCH-NAME
Git Graph is a VSCode extension for managing Git repositories. It provides a graphical user interface that may be used to squash related commits in a local VSCode environment or a GitHub Codespace as follows:
Install Git Graph in your Codespace or VSCode instance if it isn’t already installed.
Click the Git Graph button on VSCode’s bottom pane.
If the branch on which you want to squash commits isn’t checked out, check it out by right-clicking the branch’s name in the Graph field and selecting Checkout branch.
Right-click the commit message previous to the oldest commit in the range of commits you want to squash. For example, if you want to squash the three commits highlighted by a purple rectangle in the image shown below, right-click the commit highlighted by the orange rectangle.
Select Rebase current branch to this commit.
Tick the Launch interactive rebase in new terminal checkbox.
Click Yes, rebase.
Skip the first line (oldest commit) of the rebase editor and replace the word pick with squash or s in subsequent lines that start with the word pick.
The contents of the rebase editor of our example will look similar to the following after we complete this step:
pick 73a05c3 docs: update README.md #4096
s 5c2195e docs: fix typo #4096
s 82af5ac docs: paraphrase sentence #4096
If your branch includes unrelated commits added after or in between the commits that you want to squash, do not replace pick
with s
or squash
in the lines that hold the records of those commits. Please see do not alter unrelated commits for more information.
Click the source control button on VSCode’s side pane.
If necessary, modify the commit message.
Click Continue.
Click Publish branch to push the commits to GitHub.
Please refer to the following guides for additional Git collaboration guidance:
#git
)