Lester Caine <les...@lsces.co.uk> writes:

> Kris Craig wrote:
>> I count myself lucky in that I started using Git before Subversion.  People
>> with that background often have an easier time at first because they aren't
>> burdened with having to un-learn a bunch of "bad habits."
>
> I feel I HAVE to comment on that statement. A 'different way of work' is not
> bad habits' ... most of the time I am criticised for my method of working, but
> it has worked well of a long time now, and it's people who have never used a
> decent integrated IDE that complain that it's bad. Most of the 'extras' that 
> are
> being bolted on now, and the changes to a 'git' mentality simply don't live 
> well
> when one has an existing functional method of working ... but 'bad habits' do
> not come into it!

I'd like to do a little bit of clarification here. Apologies in advance
if this is a boring bunch of review for anyone.

"Bad habits" in this context is not referring to your workflow using svn
being a bad thing. It refers to "not using git in a manner in line with
its philosophy", or more generally "using a tool in a manner that is
impractical for that tool".

Svn is all about preserving commit history. A commit in svn represents a
*permanent* point in the global history of a repository. You can make
modifications to it, but it's painful because you're not intended to --
and if you feel the need to, you are not using svn "correctly", or you
have bad habits when working with svn.

Git is also about preserving commit history, but since commits can
happen locally and never be shared with anybody, git only cares about it
for commits that are shared. The change in mentality, and change in
habits largely comes from thinking about the commits that exist only on
*your* machine as only *your* commits. 

This is what all the extra crap that's annoying to wrap your head around
is about. While git happens to preserve public commit history, it's more
of a result of its primary goals than a goal itself. Its goal is to
allow someone working on a codebase to freely experiment and take
exploratory lines of development while staying current with what other
people are doing.

To accomplish the above goal, git makes its primary operations ones that
are operations on a DAG that represents commits. If you have a repo with
the following history (where letters are commits):

    A -> B -> C

If you want to develop a feature, you make a branch. To git, a branch is
just a pointer to a commit, so you end up with a graph like this:

    A -> B -> C
               \-> D -> E -> F

If work has been done on the same line of development while you've been
working on your feature, you could have a graph looking like this:

    A -> B -> C -> G -> H -> I
               \-> D -> E -> F

Now, if you wanted to share your changes, you *could* merge these
branches, but this gives you a graph like this:

    A -> B -> C -> G -> H -> I --> J
               \-> D -> E -> F /

Which *does* serve your purpose, but it also exposes the fact that your
development happened in a separate part of the graph. It's likely that
you don't actually care about this, and neither do the people receiving
the commits you're sharing. This is what "rebasing" is for. If instead
of merging, you rebased your feature branch onto its parent, you'd get a
graph like this:

    A -> B -> C -> G -> H -> I
                              \-> D -> E -> F

Git takes the work that's been done since you branched, and makes it so
that the commits you made were made after that work was done, as far as
the commit history is concerned. When you then share your changes by
merging them into the parent branch, git is smart enough to see that
this is a linear line of development, and doesn't create a new commit:

    A -> B -> C -> G -> H -> I -> D -> E -> F

You can also tell git to take the *sum* of your changes and combine them
into *one* commit on the parent branch instead of the three you made
(referred to as squashing), if you don't think that anything but the end
result is relevant for the people you're sharing with.

Doing this "rebase into my feature branch and then merge into the parent
branch" dance means that if conflicts happen, they happen locally, and
only with the commits you have made -- which makes them easier to
fix. The *ability* of git to do things like this means you can be very
fluid with your workflow on your own machine, while not disturbing the
workflows of other developers.

In svn, the DAG in question still exists conceptually, but it's
represented in a different way. Because operations that modify it
effect everyone with a checkout, it's very difficult to modify it, and
people merge branches with caution.

In git, branching tends to be something people do ridiculously often,
so much that the history of what branch was made and merged into what
and so on becomes noise in a majority of cases. As such, people tend to
use a workflow that is a bit different from the svn workflow as far as
their machine is concerned, one that lets them keep the commit history
that other people may have to go through clean.

I hope that clarifies things a bit. It definitely doesn't make grokking
things a whole lot easier, and it is certainly *possible* to follow a
very svnish workflow using git (and may sometimes make sense to,
although I am struggling to thing of such a time).

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to