Thursday, June 17, 2021

A GIT Branching Strategy and Release Management

MacOS 11.4
Git 2.17.1



Goals:

  • Present a development model to build software that is explicitly versioned, including the branching strategy and the release strategy.
  • Present a set of procedures that every team member has to follow in order to come to a managed software development process.





Branching Strategy:

  • The central repo holds two main branches with an infinite lifetime, the master and develop:

    • origin/master or origin/main
      • The main branch where the source code of HEAD always reflects a production-ready state.
    • origin/develop
      • The main branch where the source code of HEAD always reflects a state with the latest delivered development changes for the next release. This is where any automatic nightly builds are built from.
  • Next to the main branches master and develop, this development model uses a variety of supporting branches. Unlike the main branches, these branches always have a limited life time, since they will be removed eventually. Each of these branches have a specific purpose and are bound to strict rules:
    • feature branches
      • Used to develop new features for the upcoming or a distant future release.
      • It exists as long as the feature is in development. 
      • May branch off from develop and must merge back into develop after passing the developer tests.
      • Git commands:
        • git checkout develop
        • git checkout -b <feature-branch-name>
    • release branches
      • Support preparation of a new production release.
      • May branch off of develop and must merge back into develop and master.
      • Branch naming convention: release-<name-or
    • hotfix branches
      • Arise from the necessity to act immediately upon an undesired state of a live production version.
      • May branch off from master and must merge back into master and develop branches.
      • Branch naming convention: hotfix-*



  • Pull Requests (PR) allows developers to create whatever branches they want without polluting the main fork of the repository.
    • Include the ability to request a review from another developer.
    • Reviews allow collaborators to comment on the changes proposed in pull requests, approve the changes, or request further changes before the pull request is merged.
    • A review has three possible statuses:
      • Comment: Submit general feedback without explicitly approving the changes or requesting additional changes.
      • Request changes: Submit feedback that must be addressed before the pull request can be merged.
      • Approve: Submit feedback and approve merging the changes proposed in the pull request.
    • Repository administrators can require that all pull requests are approved before being merged.

Release Management:

  • Using a dedicated branch to prepare releases makes it possible for one team to polish the current release while another team continues working on features for the next release. It also creates well-defined phases of development and we can actually see it in the structure of the repository.
  • Once develop branch has acquired enough features for a release (or a predetermined release date is approaching), we fork a release branch off of develop.
    • Creating this branch starts the next release cycle, so no new features can be added after this point—only bug fixes, documentation generation, and other release-oriented tasks should go in this branch (rather than on the develop branch).
    • Git commands to create a release branch:
      • git checkout develop
      • git checkout -b release/<x>.<y>.<z>
  • Finishing a release branch:
    • Once the release is ready to ship, the release branch gets merged into master and tagged with a version number.
    • Each time when changes are merged back into master, this is a new production release by definition. Theoretically, we could use a Git hook script to automatically build and roll-out our software to our production servers every time there was a commit on master.
    • Git commands to merge release branch and create a tag:
      • git checkout master
      • git merge release/<x>.<y>.<z>
      • git tag <tag-name> -a
      • git push origin <tag-name>
    • In addition, the release branch should be merged back into develop branch, which may have progressed since the release process was initiated. It’s important to merge back into develop because critical updates may have been added to the release branch and they need to be accessible to future features. This step may well lead to a merge conflict.
    • The release branch may be removed




Hotfix branches:

  • Hotfix branches are used to quickly patch production releases.
  • They are a lot like release branches and feature branches except they're based on master instead of develop. This is the only branch that should fork directly off of master.
  • As soon as the fix is complete, it should be merged into both master and develop, and master should be tagged with an updated version number.
  • Having a dedicated line of development for bug fixes lets the team address issues without interrupting the rest of the workflow or waiting for the next release cycle. We can think of hotfix branches as ad hoc release branches that work directly with master.
  • Git commands to create a hotfix branch:
    • git checkout master
    • git checkout -b hotfix/<x>.<y>.<k>
  • Similar to finishing a release branch, a hotfix branch gets merged into both master and develop branches.
  • Git commands to merge a hotfix branch to master:
    • git checkout master
    • git merge hotfix/<x>.<y>.<k>
  • Git commands to merge a hotfix branch to develop. This step may well lead to a merge conflict.
    • git checkout develop
    • git merge hotfix/<x>.<y>.<k>


References:

  • A successful Git branching model
  • Gitflow Workflow 
  • A Branching and Releasing Strategy That Fits GitHub Flow 
  • Github Releases 
  • Github Tags 
  • Semantic Versioning 
  • NPM Docs - About Semantic Versioning
  • Set Up a Private Git Server

    Ubuntu 20.04
    GIT 2.17.1



    Goals:
    • Create a private Git repository server without the restrictions of the providers free plans.
    • Replicate the state of an origin repository, including all the branches (including master) and all the tags as well.


    Install:
    • SSH keys:
      • If you have a  ~/.ssh  folder but don't have a public key on it (e.g: id_rsa.pub):
        •  Generate a public key using the private key using the command below:
          • ssh-keygen -y -f  /home/ubuntu/.ssh/id_rsa  >  /home/ubuntu/.ssh/id_rsa.pub
      • Show the ssh public key. It will be used later during the installation.
          • cat /home/ubuntu/.ssh/id_rsa.pub
    • Git Server:
      • Install Git server:
        • sudo apt update
        • sudo apt install git
      • Create a git user and a base repository folder:
        • sudo useradd -r -m -U -d /home/git -s /bin/bash git
        • sudo su - git
          • mkdir ~/.ssh
          • chmod 0700 ~/.ssh
          • touch ~/.ssh/authorized_keys
          • chmod 0600 ~/.ssh/authorized_keys
          • Copy the content of the file  /home/ubuntu/.ssh/id_rsa.pub  to the file  /home/git/.ssh/authorized_keys. Also add the public keys of any users you want to access your private git server.
            • nano ~/.ssh/authorized_keys
          • cd /home/git
          • Create the git base repository name (optional).
            • mkdir /home/git/private-repo
    • Mirror an existing Git repository:
      • Go to the git base directory and clone the existing repo using https. One advantage of using https is that we don't need to have a firewall rule to allow ssh port traffic:
        • cd /home/git/private-repo
        • git clone --mirror https://github.com/velosomarcus/aws-kubectl.git
          • Inform username and password to do the mirror over https.
      • Open a terminal on another computer to test the access to the private repo. The ssh public key of the computer/user should be added to the  /home/git/.ssh/authorized_keys  of the private Git Server computer:
        • cd /home/ubuntu
        • git clone git@192.168.1.105:private-repo/aws-kubectl.git
        • Expected output:
          • Cloning into 'aws-kubectl'...
      • After that, everytime we want to update the mirror repo we need to:
        • sudo su - git
        • cd /home/git/private-repo/aws-kubectl.git
        • git remote update

    Testing:
    • Create a new empty repository:
      • Open a terminal on the Git Server machine.
        • sudo su - git 
      • Create an empty repo:
        • git init --bare /home/git/private-repo/project-name.git
        • Expected output:
          • Initialized empty Git repository in /home/git/private-repo/project-name.git/
      • Configuring a local Git Repository, potentially on another machine:
        •  cd /path/to/local/project
        • git init .
      • Add the git remote to your local repository:
        • git remote add origin git@192.168.1.105:private-repo/project-name.git
      • Create a test file:
        • touch test_file
        • git add .
        • git commit -m "Initial commit"
        • git push -u origin master
        • Expected output:
          • Counting objects: 3, done.
          • Writing objects: 100% (3/3), 218 bytes | 218.00 KiB/s, done.
          • Total 3 (delta 0), reused 0 (delta 0)
          • To 192.168.1.105:private-repo/project-name.git
          •  * [new branch]      master -> master
          • Branch 'master' set up to track remote branch 'master' from 'origin'.
      • It is important to note that the remote repository must exist before you add the git remote to your local repository.
      • To be able to push the local git changes to the private Git server you’ll need to add your local user ssh public key to the remote `git` user’s  `/home/git/.ssh/authorized_keys` file. To add a new collaborator, just copy its public ssh key to the `git` authorized_keys file.

    References: