git notes main page | gitolite main page | license
IMPORTANT NOTE:
although this page has a "gitolite.com" URL, this is not about gitolite.
That's just an artifact of "sitaramc.github.com" being translated to
"gitolite.com" and so ALL my git related stuff gets carried over.
Gitolite documentation has another /gitolite
in the URL, so
you can tell. My apologies for this confusion.
This is one possible workflow for dev/integ using gitolite. It assumes that there is one “integrator” and N developers “dev1”, … “devN”.
integ
– a branch that is R
(readonly) for devs, RW+
for integrator. This branch will always be kept in a compilable, basically runnable, state by the integrator. The history of this branch will be kept reasonably clean.
Each developer will start a new piece of work or task using integ
as a starting point, and making sure that when he submits his work it builds upon this stable point.
dev/dev1/
, dev/dev2/
, … dev/devN/
branches under the dev/devX/
hierarchy belong to the developer called devX
. He submits his work to the integrator by pushing to one such branch and emailing the integrator the branch name (say dev/sitaram/issue3423
or dev/someone-else/bugfix-2321
.
master – a branch that is even more sacred than integ
. Its usage and role are optional in the below described flow, but it can be used to filter integ
even more, maybe based on some EQA (External Quality Assurance) perhaps. If so, its name can be changed to reflect that.
integ
, even if it is bare minimum code in the beginningWe use a sample developer called dev5 in the examples below.
dev5 gets some work/spec/issue to work on. He is given, or chooses, a short name for the work he is doing. Examples:
xyz-module-error-23
bugfix-2321
issue-3394
add-vorbis-support
In the rest of this example we will use issue-3394
dev clones the repo, if not already cloned
git clone [...]
fetch and checkout the current integ
branch, making the new issue-3394
branch from it
git fetch origin
git checkout -b issue-3394 origin/integ
---o---o---I
(o, o = previous commits, irrelevant to us)
I = origin/integ = issue-3394
(current branch is issue-3394)
(LOOP POINT) work on this branch
git checkout issue-3394
# (edit/compile/test)
git add, git commit
# repeat as needed
# the last step should be a "test", ideally
---o---o---I---a---b---c---d
I = origin/integ
a,b,c = intermediate commits
d = issue-3394
(current branch is issue-3394)
now he’s ready to send. In the meantime, integ
may have moved ahead, and he has to make it work against that:
fetch integ again and rebase
git fetch origin
---o---o---I---J---K
K = origin/integ now
git checkout issue-3394 # if not already done
git rebase origin/integ
what does this rebase do? It takes this:
---o---o---I---J---K
\
\
a---b---c---d
and moves the “a, b, c, d” on top of K:
---o---o---I---J---K---a'---b'---c'---d'
(a',b',c',d' are rebased versions of a,b,c,d)
(K = origin/integ, d' = issue-3394)
There is a reason for doing it this way. Dev5 is the one who knows the new code best, and he should be integrating it with the latest version of integ
at any time he submits. And since issue-3394
is a private branch, he can rebase it as often as he likes.
[SIDE NOTE] why do we use rebase instead of merge here?
this is not a hard and fast rule – you can use merge if you like. Feel free to experiment and see what works best for your team, because a lot also depends on their level of comfort with the process
However, in my opinion, work that has not been pushed out and accepted upstream should ideally be rebased against new upstream. The main difference is that, if the acceptance of the work goes through a few iterations (let’s say it is rejected and partially redone 2-3 times), using rebases is easier to do, and also will result in a cleaner looking final commit list.
retest one more time, to make sure the new J
and K
commits have not caused a problem for issue-3394
if the test fails, he has to fix his commits (a’, b’, c’, d’) or add some new commits (maybe e, f) and make it work.
when test OK, push issue-3394
under your own hierarchy (each time he comes back to “LOOP POINT” because something was rejected by code review or integ testing, the v1
will increase – v2
, v3
, etc)
git push origin issue-3394:dev/dev5/issue-3394/v1
send email to integrator asking him to pull and test dev/dev5/issue-3394/v1
receive mail from dev5 saying issue-3394
is done and ready
clone repo if not already done
fetch, make a test branch for testing issue-3394
git fetch origin
git checkout -b test_issue-3394 origin/dev/dev5/issue-3394
test, or do whatever he wants to do initially (maybe code review). If he doesn’t like it, send it back for more work. dev5 then restarts his process from the point marked “LOOP POINT” in his workflow above
if it is OK so far, test merge it with the current integ branch. Ideally, this should be a fast forward, because dev5 already did this.
git checkout -b test_integ_issue-3394 integ
git merge origin/dev/dev5/issue-3394
# this should be a fast forward, ideally
# make some final tests
If something went wrong, no problem; just delete the test branch and email dev5 saying what the problems are. For dev5, work again starts at “LOOP POINT”
git branch -D test_integ_issue-3394
However, if the tests were all ok, move integ forward and delete test merge branch
git checkout integ
git merge origin/dev/dev5/issue-3394
git branch -D test_integ_issue-3394
This issue (3394) is now closed, unless there is a regression later. It has been integrated successfully, and dev5 can be assigned some other task.
Here’s a typical gitolite conf file:
@myteam = dev1 dev2 ... devN
repo myrepo
RW+ = integrator
RW+ dev/USER/ = @myteam
That’s it? How does, say dev5
(assuming he is a member of @myteam
), get access to write to dev/dev5/something
?
That is a unique feature of gitolite :-) When a rule has the string /USER/
in the “refex” (see gitolite documentation for details), it replaces it with the name of the user invoking the push. This is effectively the same as manually adding one line like this
RW+ dev/sitaram/ = sitaram
for each member of @myteam
.