diff --git a/resources/public/assets/git-workflows/RC-workflow.png b/resources/public/assets/git-workflows/RC-workflow.png new file mode 100644 index 0000000..2d489cf Binary files /dev/null and b/resources/public/assets/git-workflows/RC-workflow.png differ diff --git a/resources/public/assets/git-workflows/feature-branching-on-develop.png b/resources/public/assets/git-workflows/feature-branching-on-develop.png new file mode 100644 index 0000000..01cb9e8 Binary files /dev/null and b/resources/public/assets/git-workflows/feature-branching-on-develop.png differ diff --git a/resources/public/assets/git-workflows/feature-branching.png b/resources/public/assets/git-workflows/feature-branching.png new file mode 100644 index 0000000..fdb1c10 Binary files /dev/null and b/resources/public/assets/git-workflows/feature-branching.png differ diff --git a/resources/public/assets/git-workflows/forking.png b/resources/public/assets/git-workflows/forking.png new file mode 100644 index 0000000..ed350cc Binary files /dev/null and b/resources/public/assets/git-workflows/forking.png differ diff --git a/resources/public/assets/git-workflows/gitflow.png b/resources/public/assets/git-workflows/gitflow.png new file mode 100644 index 0000000..d0e0216 Binary files /dev/null and b/resources/public/assets/git-workflows/gitflow.png differ diff --git a/resources/public/assets/git-workflows/release-branching.png b/resources/public/assets/git-workflows/release-branching.png new file mode 100644 index 0000000..ad9f08d Binary files /dev/null and b/resources/public/assets/git-workflows/release-branching.png differ diff --git a/resources/public/assets/git-workflows/trunk-based-dev.png b/resources/public/assets/git-workflows/trunk-based-dev.png new file mode 100644 index 0000000..58219d6 Binary files /dev/null and b/resources/public/assets/git-workflows/trunk-based-dev.png differ diff --git a/resources/public/css/style.css b/resources/public/css/style.css index 01d1763..0d4defc 100644 --- a/resources/public/css/style.css +++ b/resources/public/css/style.css @@ -179,6 +179,16 @@ li a { padding: 0; } +img, +svg { + display: block; + margin: auto; +} + +.image img { + max-width: 10rem; +} + section button { padding: 0.5rem; background-color: var(--bg-primary-color); @@ -187,10 +197,8 @@ section button { border-color: var(--text-primary-color); } -img, -svg { - display: block; - margin: auto; +section img { + text-align: center; } .container { @@ -734,6 +742,12 @@ footer .contact-icons img { text-align: center; } +/* Posts */ + +.post-body img { + width: 100%; +} + .post-body .links { padding: 0 } @@ -900,11 +914,6 @@ section .post-body .info { text-align: center; } -section img { - max-width: 10rem; - text-align: center; -} - @media (max-width: 1024px) { section .post .post-body { padding: 0.5rem; diff --git a/resources/public/main.js b/resources/public/main.js index d816c17..470a2a9 100644 --- a/resources/public/main.js +++ b/resources/public/main.js @@ -1880,7 +1880,7 @@ h.add=function(a,b){Cb(this);this.lb=null;a=Db(this,a);var c=this.Pa.get(a);c||t h.ee=function(){Cb(this);const a=Array.from(this.Pa.values()),b=Array.from(this.Pa.keys()),c=[];for(let d=0;dOb)return qd(a,"#");qd(a,c);if(0===Wb.j(f))D(g)&&qd(a,function(){var y=mk.j(f);return q(y)?y:"..."}());else{if(D(g)){var l=E(g);b.l?b.l(l,a,f):b.call(null,l,a,f)}for(var m=F(g),p=Wb.j(f)-1;;)if(!m||null!=p&&0===p){D(m)&&0===p&&(qd(a,d),qd(a,function(){var y=mk.j(f);return q(y)?y:"..."}()));break}else{qd(a,d);var t=E(m);c=a;g=f;b.l?b.l(t,c,g):b.call(null,t,c,g);var w=F(m);c=p-1;m=w;p=c}}return qd(a,e)}finally{Ob=k}} function nk(a,b){b=D(b);for(var c=null,d=0,e=0;;)if(e So, what is GitHub Flow? +> +> - Anything in the `master` branch is deployable +> - To work on something new, create a descriptively named branch off of `master` (ie: `new-oauth2-scopes`) +> - Commit to that branch locally and regularly push your work to the same named branch on the server +> - When you need feedback or help, or you think the branch is ready for merging, open a [pull request](http://help.github.com/send-pull-requests/) +> - After someone else has reviewed and signed off on the feature, you can merge it into master +> - Once it is merged and pushed to 'master', you can and *should* deploy immediately + +### Should you use it? + +Yes. Actually, pretty much everybody uses feature branches. + +## Forking + +### Timeline Example + +![Forking](/assets/git-workflows/forking.png) + +### Open Source Contributions + +Forking is the method used for open-source project contributions. In short, you could clone the repo locally but you won’t be able to push any branches. So the trick is to `fork` (making a copy of the repo) to your own GitHub account. Then you work from there. The original repo is called the `upstream` and your own copy of the repo is called the `origin`. + +So once your feature implemented, you can push the code to `origin` (your fork) and then raise a PR to merge the feature to the `upstream/main`branch. When the author/maintainers of the upstream repo approve your PR and merge it to `upstream/main` , you can then “sync” (merge `upstream/main` to `origin/main`) and start working on another feature. + +To link the forking to our previous strategies, you can see that you are basically doing `feature branching` again. + +Some open-source authors might push directly to their `main` branch while accepting PR from forks. In that specific scenario, we can see that authors are doing trunk-based development while requiring external contributors to follow feature branching. Interesting, isn’t it? + +## Release Branches + +### Timeline Example + +![Release Branching](/assets/git-workflows/release-branching.png) + +### It’s getting ugly + +Indeed, some projects might have multiple versions deployed and accessible by clients at the same time. The common example would be the need to still support old products or old API versions. + +In the timeline chart above, you can see that it is getting a bit more verbose but not so difficult to grasp. We branch `release-1.0` from `main`. Bob starts working on features and merge them to `release-1.0`. At some point, the code is deemed ready to be deployed and therefore merged to `main`. Bob quickly move on to build features for the next release `release1.1`. + +Unfortunately, a bug is discovered in production and need urgent fixing. Alice merges some hotfix into `main` to patch the issue. The production is now stable and a new version arises from the patch: `v1.0.1`. We then sync `release-1.0` with `main` so our version on `release-1.0` is also `v1.0.1` + +While Alice was patching `production`, Bob already pushed some features to the new release branch. So, we need to merge the patches made by Alice to Bob’s new code and that is why we also need to sync `release-1.1` with `main`. After syncing, Bob can merge is new release as `1.1.1` to `main`. + +If you got confused with the version numbers, I redirect you to [SemVer](https://semver.org/) but in short, a version is of format Major.Minor.Patch. Major used for incompatible codes (like 2 independent API versions). Minor is in our example the `release` and Patch is the `hotfix` from Alice. This way when Bob merged his branch `release-1.1`, he did include the hotfix of Alice making the new version in `main` not `1.1.0` but indeed `1.1.1`. + +### Should you use it? + +If you don’t need to support multiple releases at once, no, don’t use it. Ideally, you merge your features quite frequently and one release does not break the other ones. It is actually very often the case that we do not need to support old versions. So if you can, don’t use it. + +## GitFlow + +### Timeline Example + +![GitFlow](/assets/git-workflows/gitflow.png) + +### Fatality + +To quote [Atlassian](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow): + +> Gitflow is a legacy Git workflow that was originally a disruptive and novel strategy for managing Git branches. Gitflow has fallen in popularity in favor of [trunk-based workflows](https://www.atlassian.com/continuous-delivery/continuous-integration/trunk-based-development), which are now considered best practices for modern continuous software development and [DevOps](https://www.atlassian.com/devops/what-is-devops) practices. Gitflow also can be challenging to use with [CI/CD](https://www.atlassian.com/continuous-delivery). +> + +So GitFlow is obsolete and you will soon understand why. + +It is similar to what we just saw with the **release branching** but now we have another branch called `develop`. So every feature is merge to `develop`. Once a version is ready we merge it to the corresponding `release` branch. On that release branch, some additional commits might be pushed before merging to `main`. On new version merged to `main`, we need to sync A LOT. You can see on the chart above all the potential merge conflicts represented by a sword. I hope this visual representation highlights the problem: too many potential merge conflicts. + +### But why? + +It is a good question, I am not sure. The idea of having a `develop` branch is very common in a lot of projects, but why combine it with `release` branches like that I am not sure to be frank. I don’t recommend to use GitFlow and it seems obsolete for a reason. In general we want the following: + +- as few branches as possible +- short lived branches with small or partial but workable features to be deployed + +I see `GitFlow` as the opposite of `Continuous Integration` (in the sense of merging frequently new features and having new deployable codes ready regularly). For fun, let’s have a look at what happens after a hotfix in prod: + +- hotfix-1.0.1 ⚔️ main +- main ⚔️ release-1.0 +- main ⚔️ release-1.1 +- main ⚔️ develop +- develop ⚔️ feature + +I am grateful that I never had to work with `GitFlow` and I have the feeling that implementing it would mean having a dedicated engineer to take care of the branching, a sort of Git gardener. + +## Feature branching on develop + +### Timeline Example + +![Feature Branching on Develop](/assets/git-workflows/feature-branching-on-develop.png) + +### Develop branch + +The GitFlow aspect that most people still use is the `develop` branch. All the feature branches are merged to `develop` instead of `main`. Once `develop` is deemed ready for release, it is merged to `main`. + +This is useful for a few reasons: + +- at any time, we know the commit of the stable release (code in prod) via the `main` branch +- at any time, we know what is the latest commit of the ongoing new version via the `develop` branch + +This seems like the sweet spot for most cases and that is why it is popular. + +Merging a `feature` to `develop` triggers a bunch of CI jobs (the usual, format check, test checks etc) + +Merging `develop` to `main` triggers a bunch of CI jobs (build a docker image, push it to a container registry for instance) + +### Should you use it? + +Yes. It is simple yet efficient. + +## Release Candidate workflow + +### Timeline Example + +![Release Candidate Workflow](/assets/git-workflows/RC-workflow.png) + +It is very similar to **Feature Branching to Develop**. The only difference is that when `develop` is merged to `main` it creates a **Release Candidate** (RC) to be tested in a test/staging environment. If an issue in the test environment arises, a hotfix is done and we have a new RC (RC2 in this case). Once everything is ok in the test env, we have a stable release (we just tag a branch basically). + +The advantage of this strategy is that `main` is the line of truth for both test and prod env. `main` contains the RC and stable versions which is great for reporting what went wrong in the test cluster and what is stable in prod. + +### CI/CD Example + +In a project, the application is deployed in a POD (group of docker containers) in an AWS EKS cluster (k8s on AWS). There are 2 clusters: `test` and `prod`. + +When the code is ready to be deployed in the `test` cluster, we merge `develop` to `main` as Release Candidate (RC1). The deployment in EKS is done by another project from the devops team. So our CD triggered on merging to `main` only does the following: + +- build a container image from our app with a name such as `image-1.0.0-RC1` +- push this image to a container registry. + +For every PR from a `feature` to `develop`, some CI is triggered with format check, test check etc. + +The RC fixes (feedback from test cluster deployment) and the hotfixes for prod are both directly merged to `main` but with different tags. + +### Tagging Example + +- We increment RCp by 1 for a RC fix (i.e. `v1.0.0-RC2`) +- When all the test passes in test cluster, we just change a version file with the new stable version (i.e. `v1.0.0`) +- After a hot fix, increment the stable version by 1 (i.e. `v1.0.1`) + +Therefore, only the `main` branches contains tags as `main` represents the live version of truth. + +### Recap + +- `feature` branches are merged to `develop` +- `develop` branch is merged to `main` as version x.y.z-RC1 +- `RC-fixes` branches are merged to `main` as new RCs until test passes in test env. Version is x.y.z-RC(p+1) +- `hot-fix` branches are merged to `main` if urgent bug in prod env and version is incremented by x.y.z+1 +- `main` branch is merged to `develop` (Sync) and eventual conflicts with new features are resolved +- new `features` are implemented for the version x.y+1.z +- Tags are only for `main` branch + +### Should you use it? + +If you need a test/staging environment to test changes, RC strategy is good for you. However, if you don’t have only one env and your CD is not critical (don’t deploy directly to EKS in the example above but just push a docker image in a container registry), then prefer the **Feature branching to develop** + +## Conclusion + +Don’t use **GitFlow**. Use **trunk-based** development if you are working alone on a project with simple or non-critical CI/CD but prefer **feature branching** for the PR dedicated CI/feedback from colleagues if any (or yourself!). Having a **develop** branch between the `features` and `main` branches helps you follow the “Continuous Integration” philosophy in the sense of frequently merging short-lived feature branches to a development line of truth (even if a bit ahead/diverging from main, production/live line of truth). Only use **release branching** if it is absolutely required because of older release maintenance constraints. If you have a test/staging env that needs to go through integration testing before going to prod, the Release Candidate workflow is advisable. + +I think people tends to refer to CI as the test jobs done on PR from `feature` to `develop` and CD to refer to the build jobs happening on merge to `main`. CI as the philosophy of merging short/partial (but working) features as quickly as possible can be applied in **Feature branching to develop** in my opinion. + +Taking the time to have the simplest branching strategy as possible to your project can really make the development experience a bliss to all developers of your team. People should focus on implementing quality features and not doing some botanic (lots of branches…anybody?).