Depending on how they're used, you can divide branches into two major groups.
Please keep in mind, though, that this is just a semantic division. Technically (and practically), a branch is just a branch and always works in the same way.
(A) Short-Lived / Topic Branches
Earlier in this book, you've already read my advice to be generous about creating branches for new features, bug fixes, and experiments. Branches for these kinds of things share two important characteristics:
- They are about a single topic and are used to isolate code belonging to this topic from any other code. You shouldn't create a "shopping-cart" branch to then also commit code dealing with newsletter signup or bug #341 to it.
- They typically have a rather short lifespan, usually only until you've finished working on the topic (i.e. when the bug is fixed, the feature is complete...). Then, the branch will be integrated into the broader context of your project and can be deleted.
(B) Long-Running Branches
Other branches are used on a higher level, independent of a single feature or bugfix development. They represent states in your project lifecycle - like a "production", "testing", or "development" state - and remain in your project for a longer time (or even all the time). Typically, a couple of rules apply to this kind of branches:
- You shouldn't work on them directly. Instead, you integrate other branches (possibly feature branches or other long-running branches) into them, but rarely add commits directly to them.
- Often, long-running branches have a hierarchy between them: e.g. "master" is used as the highest-order branch. It should only contain production code. Subordinate to it exists a "development" branch. It's used to test developed features and is then integrated into "master"...
Which long-running branches should be created and how they should be used can't be generalized. This depends a lot on the team (its size and style of development) and the requirements of the project (and possibly also the customer). Clear rules must exist and be agreed on by everybody in the team.
A Very Simple Branching Strategy
As already said, each team must find its own branching strategy. However, we'll look at a very simple workflow that should fit for a lot of teams.
One Long-Running Branch Only
Although you could of course introduce multiple long-running branches, there are a couple of reasons against this: most notably, it complicates things! Having only a single long-running branch in your workflow keeps things as simple as possible.
In such a scenario, the "master" branch effectively represents your production code. This has one important consequence: everything that gets merged into "master" must be stable! It must be tested, reviewed, and approved by whatever methods else you have to assure quality.
This also means that no work should happen directly on "master" (which is also a very common rule). Therefore, if you should find yourself typing "git checkout master", followed by "git commit", you should ask yourself if you're doing the right thing...
Every time you start working on a new feature or bugfix, you should create a new branch for this topic. This is a common practice in almost all branching workflows and should become a habit for you, too.
As you only have a single long-running branch in your repository, all new topic branches are based off of this "master" branch. And when your work is done in this topic, of course, it should be merged back into "master".
In the meantime, it might be that new code gets integrated into "master" by your teammates while you're still working on your feature. It's both recommended and simple to merge new stuff often from master into your development branch. This ensures that you're staying up-to-date - and thereby reduces the risk of merge conflicts that come with large integrations.
Don't forget the golden rule that comes with such a simple workflow: code that gets integrated into "master" must be stable! How you ensure this is up to you and your team: use unit tests, code reviews, etc.
Keep the Remote in Sync
In Git, remote and local branches can be completely independent from each other. However, it makes great sense to regard local and remote branches as counterparts of each other.
This doesn't mean that you need to publish each of your local branches: it can still make perfect sense to keep some of your branches private, e.g. when you're doing experimental stuff that you're working on alone.
However, if you do publish a local branch, you should name its remote counterpart branch the same. If you have a local branch named "login-ui", you should also name it "login-ui" when you push it to your remote repository.
Keeping the remote in sync doesn't stop with the structure: publishing your work often via "git push" makes sure that everybody has always access to the latest developments. And, as a bonus, it can serve as your remote backup.
Other Branching Strategies
The above strategy is best suited for small, agile teams. Especially larger teams might need more rules and more structures.
Searching the web for other teams' strategies will present you with many interesting alternatives. One particular workflow that might be worth a look is the popular "git-flow".
In my personal opinion, git-flow is a bit too heavy of a component:
- It comes with its own script that introduces a layer on top of Git and its commands. This makes it hard to use from a GUI application.
- It comes with the noble endeavour to simplify Git - however, it thereby forces the user to learn almost a meta-language with new commands.
You might find that properly learning the Git basics and agreeing on a common workflow in a team will make "supplements" like git-flow superfluous.