{"id":17011974,"url":"https://github.com/jaythomas/one-branch-git-workflow","last_synced_at":"2025-03-22T13:43:54.499Z","repository":{"id":151338330,"uuid":"301779993","full_name":"jaythomas/one-branch-git-workflow","owner":"jaythomas","description":null,"archived":false,"fork":false,"pushed_at":"2020-10-06T17:27:28.000Z","size":6,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-27T13:14:50.752Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jaythomas.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-10-06T15:55:43.000Z","updated_at":"2021-08-06T17:42:20.000Z","dependencies_parsed_at":null,"dependency_job_id":"9eceffef-441a-4431-9095-37e3a55082f0","html_url":"https://github.com/jaythomas/one-branch-git-workflow","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaythomas%2Fone-branch-git-workflow","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaythomas%2Fone-branch-git-workflow/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaythomas%2Fone-branch-git-workflow/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaythomas%2Fone-branch-git-workflow/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jaythomas","download_url":"https://codeload.github.com/jaythomas/one-branch-git-workflow/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244966462,"owners_count":20539794,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-14T06:09:03.533Z","updated_at":"2025-03-22T13:43:54.477Z","avatar_url":"https://github.com/jaythomas.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# The One-Branch Git Workflow\n\nWhat if we could have a single git branch for our workflow and tag commits that we want to mark as releases?\nWhat if we could have a clearer git history that is human readable and easy to track down releases?\nWhat if all this reduced the amount of steps in the CI pipeline as well?\n\n\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n- [Features](#features)\n- [Examples](#examples)\n  - [Scenario 1 - Staging a release](#scenario-1---staging-a-release)\n  - [Scenario 2 - Asynchronous work](#scenario-2---asynchronous-work)\n\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n## Features\n\n1. Git version tagging must be used to reference all commits that are release candidates. Git works very different than mercurial and SVN in this way. A branch can contain a release and simultaneously contain commits not in that release. This makes the need for maintaining multiple branches redundant, which leads to feature 2.\n2. The development branch is the **only branch**. It is the master/default/source-of-all-truth branch. This eliminates trying to keep 3+ separate branches (codebases) in sync with each other when you want to introduce production deployment and a deployable release staging area.\n\n## Examples\n\nLet's walk through scenarios for staging release candidates, making releases, and applying hotfixes.\nYou can follow along with these examples by creating a new folder and following the commands exactly as shown.\n\n### Scenario 1 - Staging a release\n\nBefore a release goes out, you may want to create a staging area where a release candidate can be generated.\n\n```bash\n# Create repo\ngit init one-branch-git-workflow \ncd one-branch-git-workflow\n\n# Git created a \"master\" branch. Working with other developers we don't want to commit directly\n# to master and instead create a throw-away branch and perhaps open a \"Pull Request\" (GitHub\n# terminology)/\"Merge Request\" (GitLab terminology) from this branch to master.\ngit checkout -b staging\n\n# Create and commit something\ntouch README.md\ngit add README.md \u0026\u0026 git commit -m \"Initial commit\"\n\n# Immediately tag our release candidate so we can deploy it\n# CI should be able to parse the tag name from the webhook\n# \"v\" prefix for version tag and \"-rc*\" suffix for release candidate\ngit tag v1.0.0-rc0\ngit push origin staging --tags\n\n# Everything looked good? Create a new \"version 1.0.0\" release\ngit tag v1.0.0\ngit checkout master\ngit merge staging\ngit push origin master --tags\n\n# No longer necessary\ngit branch -D staging\ngit push origin :staging\n```\n\nNow do a `git log` and things should look similar to our history on the old git workflow.\nNotice also we have a tag on the commit that can be referenced at any point no matter where your current working branch is.\n\n```\ncommit 31966eb6b4f592b8c3fd030051c26130888cfc41 (HEAD -\u003e master, tag: v1.0.0-rc0, tag: v1.0.0)\nAuthor: Jay Thomas \u003cjay@gfax.ch\u003e\nDate:   Tue Oct 6 12:55:59 2020 -0400\n\n    Initial commit\n```\n\n### Scenario 2 - Asynchronous work\n\nContinuing off the previous scenario's repo, let's stage multiple release candidates while `master` diverges with separate commits.\n\n```bash\n# Let's add a new feature to go into the release candidate\ntouch file.b\ngit add . \u0026\u0026 commit -m \"Add file B\"\n# Recreating staging branch. Keep in mind the name is\n# arbitrary as the branch's existence is inconsequential.\ngit checkout -b staging\n# Immediately tag our rc with a version\ngit tag v2.0.0-rc0\n\n# But let's add a new \"feature\" to master while testing staging\ngit checkout master\ntouch file.c\ngit add . \u0026\u0026 git commit -m \"Add file C\"\n\n# Go back to testing staging. Uh oh, we found a bug we need to fix.\ngit checkout staging\necho \"my file fixes\" \u003e README.md  # Make the fix\n\n# Fix it within staging. master and staging have diverged.\ngit commit -am \"Fix README\"\ngit tag v2.0.0-rc1\n\n# ...Everything looks good. Cut a release\ngit tag v2.0.0\ngit checkout master\ngit merge staging\n\n# No longer needed. Delete it to avoid confusion that there is still\n# a pending release. Clear the canvas for the next RC so to speak.\ngit branch -D staging\n\n# Push everything up\ngit push origin master :staging --tags\n```\n\nNow if you `git log` on master you can see it contains the latest staging as well as the new work that is exclusive to development:\n\n```bash\ncommit b119b5d73b8efb02177fffa4538d4651ca91f08c (HEAD -\u003e master)\nMerge: 8ed8494 59ed050\nAuthor: Jay Thomas \u003cjay@gfax.ch\u003e\nDate:   Mon Nov 25 17:49:11 2019 -0500\n\n    Merge branch 'staging' into master\n\ncommit d637b8fecabe6a4f68f9b4846f1c2773576ec8d0\nAuthor: Jay Thomas \u003cjay2@gfax.ch\u003e\nDate:   Tue Nov 26 10:19:41 2019 -0500\n\n    Add file C\n\ncommit 8cbf6f6af52391d90a3be708cd64f8dd5514b600 (tag: v2.0.0-rc1, tag: v2.0.0)\nAuthor: Jay Thomas \u003cjay@gfax.ch\u003e\nDate:   Mon Nov 25 16:20:31 2019 -0500\n\n    Fix README\n\ncommit dad9b824a9d070637d975853d5d4ea785585cba3 (tag: v2.0.0-rc0)\nAuthor: Jay Thomas \u003cjay@gfax.ch\u003e\nDate:   Mon Nov 25 16:18:10 2019 -0500\n\n    Add file B\n\ncommit 2dabe9ae38501d8228bb168540364ab979ad56bc (tag: v1.0.0-rc0, tag: v1.0.0)\nAuthor: Jay Thomas \u003cjay@gfax.ch\u003e\nDate:   Mon Nov 25 15:38:24 2019 -0500\n\n    Add file A\n```\n\nBut we don't want file C in the release, and it's not. Have a look at `git log v2.0.0`:\n\n```bash\ncommit 8cbf6f6af52391d90a3be708cd64f8dd5514b600 (tag: v2.0.0-rc1, tag: v2.0.0)\nAuthor: Jay Thomas \u003cjay@gfax.ch\u003e\nDate:   Mon Nov 25 16:20:31 2019 -0500\n\n    Fix README\n\ncommit dad9b824a9d070637d975853d5d4ea785585cba3 (tag: v2.0.0-rc0)\nAuthor: Jay2 Thomas \u003cjay2@gfax.ch\u003e\nDate:   Tue Nov 26 10:19:26 2019 -0500\n\n    Add file B\n\ncommit 2dabe9ae38501d8228bb168540364ab979ad56bc (tag: v1.0.0-rc0, tag: v1.0.0)\nAuthor: Jay Thomas \u003cjay@gfax.ch\u003e\nDate:   Mon Nov 25 15:38:24 2019 -0500\n\n    Add file A\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjaythomas%2Fone-branch-git-workflow","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjaythomas%2Fone-branch-git-workflow","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjaythomas%2Fone-branch-git-workflow/lists"}