Encodo Git Handbook 3.0
Encodo first published a Git Handbook for employees in September 2011 and last updated it in July of 2012. Since then, we've continued to use Git, refining our practices and tools. Although a lot of the content is still relevant, some parts are quite outdated and the overall organization suffered through several subsequent, unpublished updates.
What did we change from the version 2.0?
- We removed all references to the Encodo Git Shell. This shell was a custom environment based on Cygwin. It configured the SSH agent, set up environment variables and so on. Since tools for Windows have improved considerably, we no longer need this custom tool. Instead, we've moved to PowerShell and PoshGit to handle all of our Git command-line needs.
- We removed all references to Enigma. This was a Windows desktop application developed by Encodo to provide an overview, eager-fetching and batch tasks for multiple Git repositories. We stopped development on this when SmartGit included all of the same functionality in versions 5 and 6.
- We removed all detailed documentation for Git submodules. Encodo stopped using submodules (except for one legacy project) several years ago. We used to use submodules to manage external binary dependencies but have long since moved to NuGet instead.
- We reorganized the chapters to lead off with a quick overview of Basic Concepts followed by a focus on Best Practices and our recommended Development Process. We also reorganized the Git-command documentation to use a more logical order.
You can download version 3 of the Git Handbook or get the latest copy from here.
Chapter 3, Basic Concepts and chapter 4, Best Practices have been included in their entirety below.
3 Best Practices
3.1 Focused Commits
Focused commits are required; small commits are highly recommended. Keeping the number of changes per commit tightly focused on a single task helps in many cases.
- They are easier to resolve when merge conflicts occur
- They can be more easily merged/rebased by Git
- If a commit addresses only one issue, it is easier for a reviewer or reader to decide whether it should be examined.
For example, if you are working on a bug fix and discover that you need to refactor a file as well, or clean up the documentation or formatting, you should finish the bug fix first, commit it and then reformat, document or refactor in a separate commit.
Even if you have made a lot of changes all at once, you can still separate changes into multiple commits to keep those commits focused. Git even allows you to split changes from a single file over multiple commits (the Git Gui provides this functionality as does the index editor in SmartGit).
Use the staging area to make quick snapshots without committing changes but still being able to compare them against more recent changes.
For example, suppose you want to refactor the implementation of a class.
- Make some changes and run the tests; if everythings ok, stage those changes
- Make more changes; now you can diff these new changes not only against the version in the repository but also against the version in the index (that you staged).
- If the new version is broken, you can revert to the staged version or at least more easily figure out where you went wrong (because there are fewer changes to examine than if you had to diff against the original)
- If the new version is ok, you can stage it and continue working
3.3 Developing New Code
Where you develop new code depends entirely on the project release plan.
- Code for releases should be committed to the release branch (if there is one) or to the develop branch if there is no release branch for that release
- If the new code is a larger feature, then use a feature branch. If you are developing a feature in a hotfix or release branch, you can use the optional base parameter to base the feature on that branch instead of the develop branch, which is the default.
3.4 Merging vs. Rebasing
Follow these rules for which command to use to combine two branches:
- If both branches have already been pushed, then merge. There is no way around this, as you wont be able to push a non-merged result back to the origin.
- If you work with branches that are part of the standard branching model (e.g. release, feature, etc.), then merge.
- If both you and someone else made changes to the same branch (e.g. develop), then rebase. This will be the default behavior during development
4 Development Process
A branching model is required in order to successfully manage a non-trivial project.
Whereas a trivial project generally has a single branch and few or no tags, a non-trivial project has a stable releasewith tags and possible hotfix branchesas well as a development branchwith possible feature branches.
A common branching model in the Git world is called Git Flow. Previous versions of this manual included more specific instructions for using the Git Flow-plugin for Git but experience has shown that a less complex branching model is sufficient and that using standard Git commands is more transparent.
However, since Git Flow is a very widely used branching model, retaining the naming conventions helps new developers more easily understand how a repository is organized.
4.1 Branch Types
The following list shows the branch types as well as the naming convention for each type:
- master is the main development branch. All other branches should be merged back to this branch (unless the work is to be discarded). Developers may apply commits and create tags directly on this branch.
- feature/name is a feature branch. Feature branches are for changes that require multiple commits or coordination between multiple developers. When the feature is completed and stable, it is merged to the master branch after which it should be removed. Multiple simultaneous feature branches are allowed.
- release/vX.X.X is a release branch. Although a project can be released (and tagged) directly from the master branch, some projects require a longer stabilization and testing phase before a release is ready. Using a release branch allows development on the develop branch to continue normally without affecting the release candidate. Multiple simultaneous release branches are strongly discouraged.
- hotfix/vX.X.X is a hotfix branch. Hotfix branches are always created from the release tag for the version in which the hotfix is required. These branches are generally very short-lived. If a hotfix is needed in a feature or release branch, it can be merged there as well (see the optional arrow in the following diagram).
The main difference from the Git Flow branching model is that there is no explicit stable branch. Instead, the last version tag serves the purpose just as well and is less work to maintain. For more information on where to develop code, see 3.3 Developing New Code.
To get a better picture of how these branches are created and merged, the following diagram depicts many of the situations outlined above.
The diagram tells the following story:
- Development began on the master branch
- v1.0 was released directly from the master branch
- Development on feature B began
- A bug was discovered in v1.0 and the v1.0.1 hotfix branch was created to address it
- Development on feature A began
- The bug was fixed, v1.0.1 was released and the fix was merged back to the master branch
- Development continued on master as well as features A and B
- Changes from master were merged to feature A (optional merge)
- Release branch v1.1 was created
- Development on feature A completed and was merged to the master branch
- v1.1 was released (without feature A), tagged and merged back to the master branch
- Changes from master were merged to feature B (optional merge)
- Development continued on both the master branch and feature B
- v1.2 was released (with feature A) directly from the master branch
- Circles depict commits
- Blue balloons are the first commit in a branch
- Grey balloons are a tag
- Solid arrows are a required merge
- Dashed arrows are an optional merge