First things first, why do we even need workflow for working with git? To answer this question, we need to understand following:
- What problem should workflow solve for our team?
- What problems we solve by organizing our commits, and how we produce releases?
- Who is responsible for the code in our repository and for each specific editing?
- What procedure should be organized for "external" contributor's edits?
Due to git distributed nature, it makes it very flexible to organize the work of separate teams. At the same time, this flexibility may lead to a variety of integration errors of the new code into the main development branch and therefore slow down "release of the release" of our product.
The first thing that git offers us - the opportunity to work with "fork", taking the data from a remote repository and sending to the other. The basic scheme of the organization of this work is described in the «Pro Git».
But often, especially on small projects, such complexity in the organization of the repositories is not needed, so we can use "centralized scheme." But the rules of the development and rules of third-party edits adoption is still needed because the organization of the history of the development is comparable with the organization of the code in the project - if you do not pay attention to this, soon nobody will be able to figure it out.
Knowledge of how to deal with the development history is essential and helps to understand how to use our code by ourselves and 3rd-party users. In particular, to answer the questions:
- How do I participate in the release cycle?
- Which version is now stable?
- When and who broke the code?
Workflow allows us to answer those questions in advance.
The aim of this guide is to give the understanding that git
, GitHub
and gitflow
are only a tools
to achieve your/project goals, to show pros and cons of our approach, and how to prevent and evade possible issues.
If you are new to git or not confident enough in how it works, please, refer to any basic git introduction. Our advice is to google up “A Visual Git Reference” and get back here once you’re done!
So the very important thing is to understand main concepts:
feature
- is a complete piece of functionality, it could be a new feature, hotfix, doc, test, refactoring, and so on;branches
- should serve to separate your work by type of goals you want to achieve or to react on issues in production, likehotfixes
, with corresponding flows and actions;pull request
- let you tell others about changes you've pushed to a repository on GitHub. Once a pull request is opened, you can discuss and review the potential changes with collaborators and add follow-up commits before the changes are merged into the repository :)
This ‘git flow’ is our vision on the perfect way to develop things. But there is never ‘ideal’ way of development, you know, so let’s look at strong and weak parts of it.
- Separation of concepts - each branch has clear purpose and flow how to work with it;
- Confidence - at any given point of time
master
andrelease
branches are stable and ready for production; - Isolation - you develop independent and isolated feature, so you can focus on problem;
- Continuous processes - continuous deployment and testing for feature branches, continuous integration for
master
branch; - Code review - pull request allows to increase code quality and knowledge rotation in team, and as a consequence reduce "bus factor";
- "Scary merge" - well-illustrated problem by Martin Fowler (look him up, he’s a cool guy), to avoid it keep semantic changes as separate branches (explained later);
- "Afraid of refactoring" - semantic changes (refactoring, renaming) leads to "scary merges", so try to do it when code targeted by refactoring is not changed by any other branches;
- Dependencies (libraries) update - makes Pull Requests view polluted by library files and in general useless, so keep these updates as separate branches;
- Branches
- Environments
- Branch name conventions
- Pull Requests
- Merging via Pull Request
- Commits guideline
- Initiate repository with main branches
- Feature branches flow
- Hotfix branches flow
- Release branches flow
- Required reading
master
- always stable and release ready branch;development
- default branch, contains latest features and fixes, on which developers should orient;feature-*
- branches feature development and dependencies update;realese-*
- branches for release(production) version;hotfix-*
- branches for releasefixes
;refactor-*
- branches for semantic changes;
master
- production;development
- stagingrelease-*
- for history reasons or supporting several versions at production;feature-*
- continuous deployment to test environment;hotfix-*
- development (local);
Branch names should only contain lowercase letters
, numbers
and hyphens
,
regexp: /[a-z0-9\-]+/
Important : Why not with slashes, you might ask, like in other git flow by, for
example, Vincent Driessen? Because of continuous deployment to the
for example: feature-ui-auth
will be deployed to ui-auth.project.com
,
this is why we should use only symbols allowed for DNS names
- For each pull request, there’s should be created a corresponding ‘issue’ (except for documentation);
- Note: issue should answer on: what you should do and why?;
- Pull Request must have a description, which should explain what was done and how it affects project
- Note: Pull Request must have a description, which explains what was done and how it affects the project;
- Fixed issue has to be mentioned at the end of Pull Request Name: "
[fixes #123]
" (same for commit names) - Pull Requests should be small and focused (see "Commits guideline")
- All pull request should satisfy Definition of Done (DoD) and Acceptance Criteria used by project's team
- Commits in pull request should follow to corresponding code conventions
Important: keep semantic changes (refactoring, renaming) and library updates as separate pull requests
This flow will be used almost by any branch flow, so pay attention to it!
- Create
PR
fromcurrent
branch totarget
branch
- Note:
current
andtarget
branches depends on what you are doing, see branch flows below - Note: except
hotfix
branches,target
branch isdevelopment
- assign it to yourself
- add corresponding labels
- When you are done with changes in the branch:
-
Optional: you can reset your commits and arrange them into meaningful commits in interactive way
git rebase -i
-
Rebase your branch on top of
target
branch, which is usuallydevelopment
one.# checkout current-branch git checkout current-branch # fetch latest changes git fetch origin --prune # rebase on top of development branch git rebase origin/development
-
In case of merge conflicts - solve them :)
-
While rebasing
# run merge tool git mergetool # clean up after merge find -name "*.orig" -delete # continue rebasing git rebase --continue # repeat this steps until all merging conflicts solved
-
Abort rebasing and use merge
# abort rebase git rebase --abort # merge the latest development into your branch git merge origin/development
-
-
Link to PR should be sent to your team chat with code review request (note, that code review is mandatory, it really helps to make things move faster);
Sample: "Please review my Pull Request: https://github.com/org/project/pull/1"
-
If there are some code review notes which should be applied, apply them and goto step
2
; -
When Pull Request was approved by at least 2 team members
- Note: you can use 👍 as an approvement
- Note: reviewer, who gave the second approvement, can send a note to
PR
author, to make things go faster - When pull request got 2 approvements it should be merged by code author
Important:
- commits without task id (link for asana) are not allowed (except docs and libs version updates)
- keep application version bump as separate commits
Make the changes to the code and tests and then commit to your branch. Be sure to follow the commit message conventions.
Commit message summaries must follow this basic format:
Tag: Message [Action #1234]
The Tag
is one of the following:
Fix
- for a bug fix.Update
- for a backwards-compatible enhancement.Breaking
- for a backwards-incompatible enhancement.Docs
- changes to documentation only.Build
- changes to build process only.New
- implemented a new feature.Upgrade
- for a dependency upgrade.Message
is short description of what have been done
Action
- depends on used task tracking, but in general case:
refs
- link commit to taskfixes
- closes task, moving it to testing state Important: usefixes
only in Pull Request name
The message summary should be a one-sentence description of the change. The issue number should be mentioned at the end. If the commit doesn't completely fix the issue, then use [refs #1234]
instead of [fixes #1234]
.
Here are some good commit message summary examples:
Build: Update Travis to only test Node 0.10 [refs #734]
Fix: Semi rule incorrectly flagging extra semicolon [fixes #840]
Upgrade: Esprima to 1.2, switch to using Esprima comment attachment [fixes #730]
The commit message format is important because these messages are used to create a changelog later for each release. The tag and issue number help to create more consistent and useful changelogs.
master
branch should be in place for any repository by default.
Create development
branch and make it as default on GitHub
.
git checkout -b development origin/master
# switched to a new branch 'development'
git push origin development
At GitHub:
- Open repository
Settings
->Options
->Settings
section - Set
developement
as default branch (it will ease Pull Request creation in future)
feature
branch should be started fromdevelopment
and merged back.- should not change version (version will be changed while creating release)
- Create
feature
branch fromdevelopment
head
# update your local repository with latest changes
git fetch origin --prune
# create feature branch from development head
git checkout -b feature-you-will-do origin/development
-
Create a Pull Request when
feature
implementation done (see DoD ...comming) -
Go through Pull Request review process
-
Cleanup local repository
# origin/feature will be removed by Github
git fetch origin --prune
git branch -d feature-you-will-do
- If automatic
PR
merging not available, mergedevelopment
tofeature
branch locally and start from step3
git fetch origin --prune
git pull origin
git checkout feature-you-will-do
git merge development
# if automatic merging of Pull Request is not available
# it means that there are merge conflicts and we need to solve them locally
git mergetool
# remove trash after merge
find -name "*.orig" -delete
# merge commit will be auto-generated, no need for commit message
git commit
git push origin feature-you-will-do
- Cleanup branches
git fetch origin --prune
git checkout development
git pull origin development
# delete remote branch
git push origin :feature-you-will-do
# delete local branch
git branch -d feature-you-will-do
- should be used only to fix bugs at production
hotfix
branch should be started frommaster
and must be merged back tomaster
anddevelopment
hotfix
branch may be started fromrelease
branch and then must be merged back torelease
,master
anddevelopment
branches- Important:
hotfix
branch name contains full version number, sample:hotfix-1.2.2
and notrelease-1.2
- Important: each
hotfix
should increase PATCH version of project
- Create
hotfix
branch frommaster
(orrelease
)
git fetch origin --prune
# create hot fix brach
git checkout -b hotfix-0.1.2 origin/master
- Bump application version and make a separate commit for it
# bump application PATCH version
./bumpApplicationVersion.sh "0.1.2"
git commit -am "Bumped version number to 0.1.2"
- Fix an issue, commit your changes and push to repository
git commit -am "Fix: terrible production bug fixed [refs #123]"
git push origin hotfix-0.1.2
- Go through merging process via Pull Request to
master
- Note: in case of emergency, approvement and code review may be done later
- Note: if
hotfix
was started fromrelease
branch it must be merged torelease
branch it was started
-
When pull request closed, merge
hotfix
branch todevelopment
andmaster
(ifhotfix
was started fromrelease
branch) -
Cleanup branches
git fetch origin --prune
git checkout development
git pull origin development
# delete remote branch
git push origin :hotfix-0.1.2
# delete local branch
git branch -d hotfix-0.1.2
- should be used when all features required by next release already in
development
branch - any
release
branch should start fromdevelopment
branch - starting
release
branch unblocksdevelopment
for new features development - merging
release
branch tomaster
automatically means new release to production, and could be used as an event for continuous integration - Important: all features planned for next release should not be merged in
development
until currentrelease
branch created - Important:
release
branch name contains only MAJOR and MINOR version number, sample:release-1.2
and notrelease-1.2.3
. PATCH version of project has to be increased only byhotfix
branches
- Create
release
branch fromdevelopment
head
# update local version of development to latest state
git checkout origin development
git pull origin development
# create new release branch
git checkout -b release-1.2 development
# bump project version
./bump-project-version.sh 1.2
# keep version bump commit as separate one
git commit -am "Bumped version number to 1.2"
# push your changes to Github
git push origin release-1.2
-
Deploy to staging, test on real data, test on the appliance to Definition of Done, Acceptance Criteria, Code conventions, etc...
-
When
release
fully tested and ready for production, start Pull Request tomaster
branch
- Note: if you have Continuous Integration, closing Pull Request will start to deploy to production, so be ready for fun and choose a proper time (not a Friday evening!)
- Finish
release
- Note: could be merge conflicts
# get latest master state
git checkout master
git pull origin master
# add release tag to merge commit
git tag -a 1.2
# push tag to repository
git push origin master --tags
# merge release back to development
git checkout development
git pull origin development
git merge master
git push origin development --tags
- Delete
release
branch and use tags
git branch -l | egrep -v "^\*|master|development" | xargs -n 1 git branch -D
Pay attention to Feature Branching with Pull Requests