четвъртък, 19 януари 2012 г.

Central workflow with Git

Abstract: This post will describe the characteristics of a development workflow in a traditional software enterprise, and prescribe a Git workflow which implements it.

More and more large software enterprises are basing their development infrastructure on Git. (The possible reasons will not be discussed in this post.)

An interesting thing about this phenomenon is that tranditional software development in these companies is done with a very centralized process. More precisely, there is one central repository per project. Everybody "submits" and "syncs" from one and the same "development" / "stream" branch in that repo.
Furthermore, people do not want to isolate themselves from others' changes, or isolate others from their changes, when in the "stream" branch. On the contrary, they want to share changes with others as often as possible, and always work with the latest and greatest from other team members, effectively practicing what is known as "Continuous Integration".

On the other hand, Git beginners do not know how to implement this wokflow with Git. They work ineffectively with it and abuse it. This is so because Git is very complex - the author's humble opinion is that it is much more complex than it should be.
A typical sign of this inefficiency is people merging their own changes, or, in general, commits which contain no diff but only merge histories.

The Workflow
This was first suggested to me by Borislav Kapukaranov.

Peter wants to develop feature "Adding validation logic to editor"

1. Create a branch "validation"
2. Develop Commit develop Commit develop Commit. Done, ready to submit
3. Pull master to obtain latest changes from the team
4. Rebase "validation" on top of master. This replays your local work on top of the new origin/master history. It rewrites your commits as if you were always developing on top of the latest version of the remote. This is exactly your intention in a centralized / continuous integration workflow.
Please make sure your working tree is clean when doing a rebase, otherwise it won't work. Working tree clean means you have committed all your local changes.

5. (Optional) Rebase fails because of conflicts with  remote history
6.  (Optional) Peter resolves conflicts through IDE or text editor. Peter adds the modified files to the staging area by performing "git add" on the modified files
7.(Optional) Peter continues rebase.
 git rebase --continue
Rebase finishes successfully.

8. Peter is ready to push their work to the remote master:
git push origin validation:refs/heads/master
(push my local branch "validation" to the remote branch "master" of remote "origin")

The lazy Workflow
This is "the fucking short version" for people who do not wanna bother with creating local branches for everything they develop. Okay. Working on the master branch is not a good practice, and I do it too.

Why working on master branch is inferior from the above described approach:
- If you create dedicated branch for every task you do, you can work on many pieces of work independently by just switching branches;
- If  you work on local dedicated branch, when you git pull master, there will never be conflicts.

Anyways, here is the lazy workflow

1. Develop commit develop commit develop commit
2. git pull --rebase
3. (optional)  Rebase fails. Resolve conflicts, add files to index, continue rebase
4. git push