Video Lesson: Use Git Flow for reliable version control in Docker

Use Git Flow for reliable version control in Docker

Learn how to use Git Flow to organize development, review changes, and manage reliable software releases.


Lesson Content

Git Flow gives a team a predictable branching model for developing, reviewing, testing, and releasing code. It works especially well as a project and its development team grow.

Start by creating a new repository. A new repository has a master branch and no commits, so create a README file, add it, and make the initial commit:

mkdir foobar && cd foobar
git init
touch README
git add README
git commit -m "Initial commit"

Add the GitHub repository as the origin remote and push the initial commit:

git remote add origin [email protected]:vendor/project.git
git push -u origin master

The develop branch contains completed features and fixes that are ready for the next release. It acts as the working tree for the source repository. Create it from master and push it to the remote:

git checkout -b develop
git push -u origin develop

All new development happens in a feature branch. Feature branches start from develop and use the feature/ prefix. Create a branch for a feature named foo:

git checkout -b feature/foo

Work on the feature and commit the changes as usual. Create foo.js with a single line:

console.log('foo');
vi foo.js
git add foo.js
git commit -m "New foo file"

Create a separate branch for another feature named bar, with a bar.js file:

console.log('bar');
git checkout -b feature/bar develop
vi bar.js
git add bar.js
git commit -m "New bar file"

Keeping feature branches separate isolates all commits related to a specific task. When a feature is complete, merge it back into develop. Teams usually do this through a pull request so another developer can review the code, but you can merge it manually here:

git checkout develop
git merge feature/foo

Push the updated develop branch. Run git pull on develop regularly as well, so your local working tree stays current with the remote repository:

git checkout develop
git push

In this new repository, there are no additional remote changes yet. Before merging another feature, rebase it from develop if the branch may conflict with recent updates or if you want it based on the latest development work.

First inspect the feature branch log:

git checkout feature/bar
git log --oneline

At this point, the feature/bar branch contains the commit that adds bar.js. Rebase it from develop:

git rebase develop

Rebasing rewinds the feature branch, applies the latest commits from develop, and then replays the feature commits on top of them. Check the log again to verify that the commit adding foo.js now appears before the commit adding bar.js:

git log --oneline

Merge the rebased feature into develop and push the updated branch:

git checkout develop
git merge feature/bar
git push origin develop

When the code is ready for release, create a release branch from develop. Release branches use the release version, such as 1.0:

git checkout -b release/1.0
git push -u origin release/1.0

The release branch isolates the release from new work that continues on develop. You can deploy this branch to a staging environment while the QA team tests it.

If QA discovers that the foo text needs to be output twice, update foo.js directly on the release branch and commit the fix:

vi foo.js
git commit -am "Update foo file"

On a larger team, you can instead create a feature branch from the release branch and submit a pull request back to it. Push the release branch after each update and repeat the staging and testing process until the release is ready for production:

git push origin release/1.0

When testing is complete, merge the release branch back into develop. This ensures that fixes made during release testing are not lost when future features are developed:

git checkout develop
git merge release/1.0
git push origin develop

The release branch now contains production-ready code, so merge it into master as well. The master branch should contain only code that is ready for production:

git checkout master
git merge release/1.0

Push master, then tag the release with its version and push the tag to the remote:

git push
git tag v1.0.0
git push origin v1.0.0

The tag identifies the exact code to deploy to production. Your deployment process can use that tag instead of relying on a moving branch.

The only commits on master should be merges from a release branch or a hotfix branch. A hotfix is reserved for an emergency production fix and uses the hotfix/ prefix. Unlike a feature branch, it starts from master:

git checkout -b hotfix/fix-foo master

Make the emergency fix by changing foo.js back to a single console.log('foo');, and commit it. Then merge the hotfix into master, push it, tag the new release, and push the tag:

vi foo.js
git commit -am "Single foo after all"
git checkout master
git merge hotfix/fix-foo
git push
git tag v1.0.1
git push origin v1.0.1

Merge the hotfix into develop as well. Otherwise, the production fix can disappear when later feature work is released:

git checkout develop
git merge hotfix/fix-foo
git push

When a release or hotfix is complete, delete branches that have already been merged. If you use pull requests, you can remove the branches when the pull request is accepted. Otherwise, delete them manually, then list the branches that remain:

git branch -d feature/foo
git branch -d feature/bar
git branch -d hotfix/fix-foo
git branch

With this workflow, develop remains the integration branch, feature branches isolate new work, release branches protect code during testing, master contains only production-ready code, and hotfix branches provide a controlled path for emergency fixes.

Maggie

Hey, I'm Maggie! 👋

Ask me anything.

Want to chat with Maggie?

Log in for AI tutor access.

Comments

Join the discussion!

Notes

Keep track of what you learn!