Continue reading "How to cherry-pick Specific Files from a Commit"
Git Tag Message Guidelines
Embedded Artistry projects use git annotated tags to indicate the status of versioned software builds. The following guidelines will improve auditability and traceability for software builds.
There are four distinct categories of tag messages that apply to versioned builds:
In-process Tag
The In-process Tag is generated by the Jenkins build server at the start of a clean versioned build. This tag is never to be pushed to the git server; instead, the tag is deleted at the end of the build process in all cases. Public tags matching the In-process Tag format indicate an error with the build process.
The In-process Tag message takes the following form:
git tag -a '${version}' -m 'Creating tag to build ${version}'
Release Candidate Tag
The Release Candidate Tag is used to mark passing clean versioned builds. This tag is pushed to the git server at the end of a successful build.
The Release Candidate Tag message takes the following form:
git tag -a '${version}' -m 'Successful CV build ${version}'
Approved Release Tag
The Approved Release Tag is used when a Release Candidate successfully passes acceptance testing for projects where such procceses are used. The corresponding version tag should be updated to indicate release approval.
The Approved Release Tag message should take the following form:
git tag -a '${version}' -m 'Customer Release ${version}'
Special Purpose Tag
A Special Purpose Tag is any tag which accomplishes a purpose not described above. Such tags must have an annotated tag message which is differentiated from the other forms. The Special Purpose Tag message should include the motivation for the tag and the expected tag lifetime.
Resolving Git Commit History Divergence Due to Case-Sensitive Rename Operations
Continue reading "Resolving Git Commit History Divergence Due to Case-Sensitive Rename Operations"
Dealing with Signed Commits When Creating and Splitting a Monorepo
Continue reading "Dealing with Signed Commits When Creating and Splitting a Monorepo"
Share code with git bundles instead of zip files
I’m sure many of you have sent code to someone else as a zip file (or any other compressed archive file type). Usually this happens when you want to share code with someone outside of your organization, and you want them to have a copy of the code instead of direct access to the repository and all its history. Sometimes it’s done to share code with someone who cannot connect to your servers for any number of reasons. Maybe you release code to people in an archive. Maybe a vendor releases code to you via an archive.
This approach of sharing code in a zip file is often “good enough” for many use cases. But any time it’s not meant as a one-off delivery, it can be problematic, especially if you’re making your own changes to the file or trying to send modifications back to the originator. Managing source code this way quickly becomes a nightmare.
An alternative that we can use for sharing our code is to generate a git bundle. Essentially, a bundle is an archive file that a user can use with the git clone
command to create a local repository. The bundle contains your source code, as well as the change history for the commits and branches that you reference during the bundle creation step.
Even though I have been using git for most of my career, I only heard about git bundles thanks to Klemens Morgenstern and his Heapless C++ course. As with all of our courses, the exercise code is kept under source control. One of the course design problems was having a way to share the source code and the solutions with users without sharing the solutions in an obvious way. Klemens’s idea was to generate a git bundle that contained the source code for the exercises on the primary branch. Each solution would have its own branch. This meant that solutions were locally available to users, but they had to take an explicit step to see them: changing to the target branch.
We’ve come to see how this is useful for code distribution in general:
- We can easily share private code with students without making repositories public for the world to access
- It’s easier to incorporate updates to a bundle you’re working in, since you can control how/what gets merged without destroying your own work
- Students can send us bundles when we need to investigate problems
- Students can send us bundles with corrections/improvements that we can easily merge upstream
Want to learn more about working with git bundles? Check out our workflow notes.
References
- Git Bundle Workflow
- Git Tools: Bundling (from the Git Book)
- git-bundle command documentation
- Commit Ranges (from the Git Book)
Git Bundle Workflow
This guide documents the workflow we typically use with bundles, as well as documentation for those using bundles in our courses.
Creating a Git Bundle
The git bundle create
command will let you create a new bundle from your repository.
git bundle create repo.bundle main
The file repo.bundle
will be created from the main
branch of the current repository and will contain all of its history. You can specify more than one branch, and you can also reference specific commits. All arguments following the bundle name will be included in the bundle. If you wanted to include all of the branches and tags, you could include the arguments --branches --tags
following the bundle name. If you wanted a full mirror of your repository, including all of the remote refs, you could use the --all
argument.
Note: If you’re sharing a bundle with someone, it’s a smart idea to use a tag to represent the commit used for the bundle. That way you won’t forget, and you can use it when sending incremental updates.
We can also create a bundle that is an incremental set of changes. For example, we might do this when we want to share incremental updates with another person, or when we want to send our local changes to the person who sent us the bundle.
For example, if you used a tag to mark the last bundle creation point, you could send an incremental update by creating a new bundle:
git bundle create repo_update.bundle latestBundleRelease..main
This command will pull in all the commits from the last release (indicated by latestBundleRelease
) to the latest commit on main
.
You might also reference a version tag:
git bundle create repo_update.bundle v1.3.2..main
If you’re using tags to mark bundle releases, you’ll want to update the commit reference for the latest release or make a new tag.
Note: For more on this process and the options that are available, see the git-bundle command documentation. The Commit Ranges entry in the Git Book will also be helpful.
Alternatively, you might have local changes that you want to send back to the person who created the bundle. Assuming you made your commits on main
, you could put these new commits in a bundle with:
git bundle create repo_update.bundle main ^origin/main
The range main ^origin/main
will grab all commits that are on your local main
branch but not in the origin/main
that you originally cloned with the bundle.
Note: An alternative range specification would be
origin/main..main
.
Checking the Contents of a Bundle
You can check the contents of a bundle (and whether it can be applied to your project) using the verify
command:
git bundle verify repo.bundle
You will see output like this:
git bundle verify repo.bundle
The bundle contains this ref:
50e7871b95f19273deeec646526e1060b07791d0 refs/heads/master
The bundle records a complete history.
/Users/phillip/src/ea/libflex/buildresults/repo.bundle is okay
An incremental bundle will show information like this:
git bundle verify repo_update.bundle
The bundle contains this ref:
f2761f5fe9349ab96ef3fcdfbad11fd976bd6dcf refs/heads/master
The bundle requires this ref:
50e7871b95f19273deeec646526e1060b07791d0
repo_update.bundle is okay
Incremental bundle verification checks should be run from within your repository, otherwise you will get a failing message:
git bundle verify repo_update.bundle
error: need a repository to verify a bundle
If you lacked the required base ref in your repository, you would instead see something like:
git bundle verify repo_update.bundle
error: Repository lacks these prerequisite commits:
error: 50e7871b95f19273deeec646526e1060b07791d0 Checkout master before bundling
Cloning from a Git Bundle
You can supply the bundle file to the git clone
command in order to create a repository with its contents
git clone repo.bundle repo
This command will use the repo.bundle
file to create a local repository named repo
in the current folder.
Pulling in Changes
You can pull the commits from a new bundle (or an incremental update bundle) with git pull
.
git pull repo_update.bundle main
Note: You need to specify a branch name, or else it will default to pulling in
HEAD
.
If you made changes locally, or you want to see what changed before fully committing, you could pull the updates into a new branch:
git pull commits.bundle main:other-main
This pulls from main
in the bundle into the other-main
branch in your repository. You can then merge the changes at your convenience.
Configuring a Git Bundle as a Remote
If you’re going to be receiving commits from someone regularly through a git bundle, you can also set up the bundle file as a git remote
. This has a few requirements:
- Your bundle file will always need to have the same name
- You will need to place the bundle file inside of the repository (top-level)
We can set this up with the following command pattern:
git remote add bundle filename.bundle
This command will create a new remote named bundle
that is mapped to filename.bundle
, which is relative to the repository root. After this remote has been configured, you could pull in new commits from filename.bundle
with:
git pull bundle
References
- Share code with git bundles instead of zip files
- Git Tools: Bundling (from the Git Book)
- git-bundle command documentation
- Commit Ranges (from the Git Book)
Source Control Commit Guidelines
Preparing quality commits in a source control system is an underrated skill. Commit messages help explain the context for set of changes. We can’t always find an explanation or context for why code was changed by looking at the code. We must keep a detailed project history in some other way, and the commit tree is one of the best places. This history is invaluable when debugging future problems or trying to understand why a previous change was made.
Additionally, how we structure our commits matters. With commits that are too large, reviewers will have trouble processing all of the information. Future debugging efforts are also hindered, because developers cannot pinpoint exactly where an error was introduced when large commits are the norm. We want to build a project history that is truly a future resource for future developers.
The following commit guidelines are used on Embedded Artistry open source software projects to provide a consistent organization style. If your commits and messages are not of sufficient quality, you may be asked to amend them before a pull request is accepted.
In general, these guidelines will serve you well no matter your organization. For other takes on writing quality commit messages, see the Further Reading section below.
Table of Contents:
- Prefer Atomic Commits
- Commit Message Guidelines
- Revise Your Commits Before Submitting a PR
- Further Reading
Prefer Atomic Commits
In general, the smaller the commit, the better. We prefer atomic commits, which apply a distinct and related set of changes in a single action.
What does this mean in practical terms?
- All changes in a commit should be related.
- Don’t combine changes that address different problems into a single commit.
- All changes in a commit should address a single aspect of a problem or change.
- Don’t be afraid to break up a new feature, bug fix, or refactoring effort into multiple distinct changes.
- This will help you keep track of what works and what doesn’t: if there’s a problem, you can always revert back to the last known good state. If you wait too long between commits, you may lose a lot of work or spend too long finding the source of the problem.
- Prefer small commits to large commits.
- This helps reviewers by allowing them to focus on a small set of related changes.
- This helps future debugging efforts by increasing the probability that a
git bisect
operation will quickly identify the source of the problem.
Splitting Commits
Sometimes, we accidentally commit distinct sets of changes together. Or we might mess up a rebase effort, accidentally squashing two unrelated commits.
To undo this problem, review our process on splitting up git commits in the middle of a branch.
Whitespace and Formatting Cleanup
Don’t mix code changes with whitespace or formatting changes! If you are fixing code formatting, include those changes separately from your code changes. If your request is unreadable due to whitespace changes, it will be rejected.
Many of our projects enforce automated code formatting using clang-format
. Formatting is enforced by the Jenkins build server which runs continuous integration for this project. Your Pull Request cannot be accepted if the formatting check fails. If your changes are rejected by the server, please include the auto-format updates in a separate commit.
You can auto-format your code to match the style guidelines by issuing the following command:
make format
If you don’t have clang-format
installed, we can apply the format changes for you.
Commit Message Guidelines
Below is a visual representation of the Embedded Artistry git commit message format:
50-char-ish"subject" which summarizes the change
After the first line, include additional explanatory text. Include
one blank line in between the summary and the body. Various tools
like git log, git shortlog, and git rebase get confused if the two
sections run together.
You can also include bullet points:
* A
* B
* C
Reference issues at the bottom, like this:
Fixes #102
Relates to #100, #8
The Subject
Treat the first line of a commit message like an email subject line.
We recommend a maximum length of 50 characters because it works best with git’s command line tools.
We also recommend using the imperative mood for subjects. This might be what you think of as “commanding” or “instructing”. Examples include:
- Refactor subsystem X
- Implement feature Y
- Remove deprecated methods
- Update version to 1.2.3
Another way to look at it is to have your subject line complete the following sentence:
If applied, this commit will [subject line here].
We don’t worry about manual line breaks in our commit message bodies. Text wrapping works well in modern tools.
The Message Body
Please separate the body from the subject with a blank line.
Most importantly, the commit message body should be used to explain what you are doing and why you did it that way, rather than how you did it. The code itself serves to explain the how. Focus on side effects, compatibility changes, or other consequences that are not immediately obvious from reviewing the code. Also include any important factors that helped you arrive at your particular approach.
Not all commit messages require both a subject and a body. You can include only a subject if it is sufficient for a given commit.
Reference Issue Numbers
When working with GitHub projects, reference relevant issue numbers in your commit message body.
You can have a commit automatically close an issue when it is merged to master
by saying something like the following in your message body:
Fixes #123
Fixes: #123
Resolves: #123
You can also reference issues in other repositories by adding a prefix for organization/repository
:
Fixes octo-org/octo-repo#100
The full list of keywords that will close an issue is found in the GitHub documentation.
If other issues or PRs are related to this commit, but it doesn’t address the problem, you can include the issue/PR number without using a keyword like “fixes” or “resolves”. This will link the commit and the issue in GitHub’s web interface.
On Cherry-Picked Commits
Sometimes, we cherry-pick changes from one branch to another. We recommend using the -x
flag with git cherry-pick
, which references the original commit ID.
For more information, see Git Cherry-pick Recommendations.
Revise Your Commits Before Submitting a PR
While you’re working on a problem on your own branch, don’t worry about getting these commit details perfect. Instead, clean up your branch before you submit a PR. You can perform a git rebase to squash commits, amend commit messages, and more.
We often use a visual tool, such as Sourcetree, for complex rebase process.
Further Reading
For more on writing quality git commit messages:
- Chris Beams: How to Write a Git Commit Message
- AboutCode: Writing good Commit Messages
- tbaggery: A Note About Git Commit Messages
- Contribution Guidelines — Zephyr Project Documentation
- Separate subject from body with a blank line
- Limit the subject line to 50 characters
- Capitalize the subject line
- Do not end the subject line with a period
- Use the imperative mood in the subject line
- Wrap the body at 72 characters
- Use the body to explain what and why vs. how
For more valuable processes to follow:
Safely Storing Secrets in Git
Code Cleanup: Splitting Up git Commits In the Middle of a Branch
Continue reading "Code Cleanup: Splitting Up git Commits In the Middle of a Branch"
A GitHub Issue Template for Your Projects
Continue reading "A GitHub Issue Template for Your Projects"