Please get familiar with some terminology first. If you want to adopt Kull in your project, follow the setup guide.
Kull is a collaboration convention for teams working together through distributed version control (DVCS, like Git) that preserves order through clear rules and processes. These are the main points:
- commit message format:
type(scope): summary
as described in Karma Runner with predefined scopes, enforced using a Git commit-msg hook - branching: default + descriptively named feature branches; draft pull requests for documentation
- reviewing: the contributor is responsible for opening and merging his pull requests; review comments are only resolved by the reviewer
- merging: after approval, merge a branch via squash or rebase and then delete it
To ease grasping the history, back-tracing of regressions and automated processing,
Kull follows the Karma Runner commit message convention.
The first line is in type(scope): summary
format
with the summary in imperative mood.
List closed issues with the "Closes" keyword on a separate line in the footer, e.g. "Closes #1, #23, #34".
The convention is managed and enforced by a .dev
folder in the root of the repository.
It holds shared Git hooks in a folder called githooks
,
enabled by running git config core.hooksPath .dev/githooks
.
The commit-msg hook will then automatically refuse commits which do not adhere to the format,
and the prepare-commit-msg hook helps people follow best practices.
Since there is no single definition of what constitutes a "scope",
the script will try to read the file .dev/scopes.txt
in the repository.
It should contain a newline-separated list of scopes allowed in the project.
The script admits an additional commit type called rework for migration from a less strict convention or for beta stages where commits often end up too broad to fit into a single type. For mature projects it should be removed from the hook (by modifying the Regex at line 8) since it is unhelpful in the long-term. It also adds a release type in case the project wants to specially highlight release commits that only bump version numbers - it may be removed as well.
A repository usually consists of a default branch and feature branches as described in GitHub Flow.
Feature branch names should be descriptive and follow a similar style as the commits,
i.e. type/scope/summary
, though either scope or type are often omitted.
Avoid direct pushes to the default branch to prevent failing builds through hasty fixes.
Sometimes there is an additional development branch, but it is often superfluous. Releases are generally better handled with tags instead of separate branches. Whether it is main or development, the default branch should always build, so there is rarely a clear distinction.
Upon pushing a new feature branch, create a corresponding draft pull request with a title that summarizes the changes and conforms to the commit message convention, unless you want to signal that this will not be a squash merge. An open pull request is above all documentation of work done and is not expected to be minded until its owner explicitly requests reviews. If a branch has no associated PR and no recent activity, it is subject to deletion.
Review thoroughly to ensure long term alignment. To prevent misunderstandings, the PR owner should answer a review comment with a reference to his solution. The reviewer can then decide whether to resolve the matter or explain why the solution is not sufficient.
To build on top of unmerged changes, branch off rather than adding features to a branch in review. Only request review for that new branch once the base branch is merged.
A pull request should be approved by at least one other person and pass all tests before being merged. The owner of the PR should merge it as he knows the state and content best.
Merge using either squash or rebase to keep noise such as experimental and merge commits out of the main history.
The default is squash merging,
with the title of the PR as the title of the commit
and a description summarising the changes and fixes.
Due to this it is not as important to keep feature branch history clean -
experimental and even merge commits are acceptable within a branch if it is certain to be squashed.
A rebase may be appropriate if each commit in the PR builds on its own.
On the other hand, if the changes are too big for a squash to seem appropriate, they should be split up -
rebase merging will likely put redundant or meaningless commits into the history of the merge target.