This workflow is opinionated and tailored for teams who value a streamlined, GitHub-centric process. If you share our approach, this workflow will suit you well.
👉 GitHub-Centric: We use GitHub repositories, issues, projects, and actions as the backbone of our workflow.
👉 Kanban Approach: Our kanban board is implemented using GitHub issues and a single project that serves as both our upstream and downstream board.
👉 Single Long-Lived Branch: We maintain only one long-lived branch, main. All other branches are short-lived and intended to be closed as soon as possible.
👉 Issue-Driven Development: Every addition—be it development, bug-fixing, or refactoring—starts with a GitHub issue. No commits are allowed on main unless they are linked to an issue.
👉 Pristine Main: The main branch is always shippable and pristine. Only commits that pass the pre-deliver quality gate are allowed, and only fast-forward merges are permitted.
👉 Squashed Commits: All commits on development branches are squashed into a single commit, which is then pushed as a ready branch (ready/**).
👉 Five-Tier Automated Testing:
- Issue branches (
[0-9]-**) trigger apre-deliverworkflow for internal status checks. ready/**branches trigger areadyworkflow. If all checks pass, the branch is automatically merged tomain.- Commits on
mainare deployed to thedevenvironment and tested. Passing commits are labeled as release candidates (<major>.<minor>.<sequence>rc). - Release candidates are deployed to
qa(stage) and tested. Passing commits are marked as shippable. - When ready for production, the latest shippable commit is labeled (
<major>.<minor>.<patch>) and deployed toprod.
👉 Mentorship Over Pull Requests: Instead of pull requests, we use a RESPONSIBLES file (similar to CODEOWNERS). If a commit affects files with assigned responsibles, those individuals are mentioned on the issue to review or assist. This trust-based mentorship model replaces traditional quality gates.
The gh extension devx-cafe/gh-tt is designed to support this workflow, with three core subcommands: workon, wrapup, and deliver, which manage the branching strategy.
Additional supporting tools include:
thetechcollective/gh-rotator: Orchestrates individually releasable components (repos) into a composite product that rotates automatically when any part is updated.thetechcollective/gh-downstream: Reports lead times in our kanban board.
This is the core development cycle. Each increment to main follows this process:
Checks out a branch for an issue. If a branch already exists (locally or remotely), it reuses it; otherwise, it creates a new branch. The issue is assigned to you. If a GitHub project is connected, the issue is added to the project and its status is set to Work in Progress.
gh tt workon -i 23Typically, you start with an issue in the To Do column of the downstream board. The context is always the current repository—cross-repo work requires checking out the other repo.
To create and immediately work on a new issue:
gh tt workon -t "Correcting some spelling"This is syntactic sugar for:
issue_number=$(gh issue create -t "Correcting some spelling" -b "" | grep -oE '[0-9]+$')
gh tt workon -i "$issue_number"All gh tt commands support --verbose for detailed output and --help for usage information:
Stages your changes (if not already staged), creates a commit with your message and a reference to the issue, and checks the RESPONSIBLES file for any additional reviewers. If responsibles are found, it comments on the issue and mentions them. Finally, it pushes the branch, triggering the pre-deliver workflow.
gh tt wrapup -m "Finished a subset of the issue, taking a break"Reasons to use wrapup:
- To safely push your current work before a break.
- To celebrate a milestone.
- To notify a responsible when touching unfamiliar files.
- To request help from a colleague.
- To leverage detailed insights from the
pre-deliverworkflow.
There are no strict rules on the issue branch—work as you see fit. Use --verbose to see detailed operations.
Requires your development branch to be rebased onto main. Squashes all commits on your issue branch into a single commit, using the issue title as the commit message header and listing all individual commit messages. Pushes this as a ready/** branch, triggering the ready workflow. If all checks pass, the branch is fast-forward merged to main, and both the issue and ready branches are deleted. The issue is then closed.
gh tt deliverIf the ready/** branch fails checks, simply continue working on the issue branch, use wrapup as needed, and rerun deliver when ready.