[RFD] Rewriting safety - warn before/when rewriting published history

7 messages, 4 authors, 2016-06-15 · open the first message on its own page

[RFD] Rewriting safety - warn before/when rewriting published history

From: Jakub Narebski <hidden>
Date: 2016-06-15 22:52:56

Git includes protection against rewriting published history on the 
receive side with fast-forward check by default (which can be 
overridden) and various receive.deny* configuration variables,
including receive.denyNonFastForwards.

Nevertheless git users requested (among others in Git User's Survey) 
more help on creation side, namely preventing rewriting parts of 
history which was already made public (or at least warning that one is 
about to rewrite published history).  The "warn before/when rewriting 
published history" answer in "17. Which of the following features would 
you like to see implemented in git?" multiple-choice question in latest
Git User's Survey 2011[1] got 24% (1525) responses.

[1]: https://www.survs.com/results/Q5CA9SKQ/P7DE07F0PL

So people would like for git to warn them about rewriting history before 
they attempt a push and it turns out to not fast-forward.


What prompted this email is the fact that Mercurial includes support for 
tracking which revisions (changesets) are safe to modify in its 2.1 
latest version:

  http://lwn.net/Articles/478795/
  http://mercurial.selenic.com/wiki/WhatsNew

It does that by tracking so called "phase" of a changeset (revision).

  http://mercurial.selenic.com/wiki/Phases
  http://mercurial.selenic.com/wiki/PhasesDevel

  http://www.logilab.org/blogentry/88203
  http://www.logilab.org/blogentry/88219
  http://www.logilab.org/blogentry/88259
  

While we don't have to play catch-up with Mercurial features, I think 
something similar to what Mercurial has to warn about rewriting 
published history (amend, rebase, perhaps even filter-branch) would
be nice to have.  Perhaps even follow UI used by Mercurial, and/or
translating its implementation into git terms.

In Mercurial 2.1 there are three available phases: 'public' for
published commits, 'draft' for local un-published commits and
'secret' for local un-published commits which are not meant to
be published.

The phase of a changeset is always equal to or higher than the phase
of it's descendants, according to the following order:

      public < draft < secret

Commits start life as 'draft', and move to 'public' on push.

Mercurial documentation talks about phase of a commit, which might
be a good UI, ut also about commits in 'public' phase being "immutable".
As commits in Git are immutable, and rewriting history is in fact
re-doing commits, this description should probably be changed.

While default "push matching" behavior makes it possible to have 
"secret" commits, being able to explicitly mark commits as not for
publishing might be a good idea also for Git.


What do you think about this?
-- 
Jakub Narebski
Poland

Re: [RFD] Rewriting safety - warn before/when rewriting published history

From: Ben Walton <hidden>
Date: 2016-06-15 22:52:57

Excerpts from Jakub Narebski's message of Sat Feb 04 14:45:53 -0500 2012:

Hi Jakub,

These items are as much about UI as anything else, I think.  UI that
better helps users to know the state of their commits and branches can
only be a good thing.  People that have used git for a while and are
comfortable with it may not see the need/point of these, but I think
they could both really help new users.
In Mercurial 2.1 there are three available phases: 'public' for
published commits, 'draft' for local un-published commits and
'secret' for local un-published commits which are not meant to be
published.
How do you envision such a feature in git?

A 'draft' commit (or chain of commits) could be determined from the
push matching definitions and then marked with simple decorations in
log output...This would extend the ability of status to note that your
are X commits ahead of foo.  This would see any commit on a branch
that would be pushed automatically decorated with a 'draft' status.
While default "push matching" behavior makes it possible to have
"secret" commits, being able to explicitly mark commits as not for
publishing might be a good idea also for Git.
Do you see using configuration or convention to achieve this?

For example, any branch named private/foo could, by convention, be
un-pushable without a force option?  Alternately, a config item
similar to the push matching stuff to allow the users to designate
un-pushable branches could work too.

Please don't take the above implementation possibilities as anything
more than a starting point for discussion as they may be deeply
flawed.  I'm just tossing a few things out there as I think this is a
good discussion to have.

Thanks
-Ben
--
Ben Walton
Systems Programmer - CHASS
University of Toronto
C:416.407.5610 | W:416.978.4302

Re: [RFD] Rewriting safety - warn before/when rewriting published history

From: Jakub Narebski <hidden>
Date: 2016-06-15 22:52:57

On Sun, 5 Feb 2012, Ben Walton wrote:
Excerpts from Jakub Narebski's message of Sat Feb 04 14:45:53 -0500 2012:

Hi Jakub,

These items are as much about UI as anything else, I think.  UI that
better helps users to know the state of their commits and branches can
only be a good thing.  People that have used git for a while and are
comfortable with it may not see the need/point of these, but I think
they could both really help new users.
As I said, 1500+ git users would like to have such feature, according
to latest Git User's Survey.
quoted
In Mercurial 2.1 there are three available phases: 'public' for
published commits, 'draft' for local un-published commits and
'secret' for local un-published commits which are not meant to be
published.
How do you envision such a feature in git?

A 'draft' commit (or chain of commits) could be determined from the
push matching definitions and then marked with simple decorations in
log output...This would extend the ability of status to note that your
are X commits ahead of foo.  This would see any commit on a branch
that would be pushed automatically decorated with a 'draft' status.
I think that in its basic form (treating all remotes equally) commits
in 'public' phase would be those reachable from remote-tracking branches.
Otherwise commits would be in 'draft' phase, unless explicitly marked
as 'secret' (it we implement 'secret' phase, that is).

The safety new I think of would (similarly to Mercurial phases) prevent
or warn about amending published commit, and rebasing commits which were
already published (in 'public' phase).  That would require modifications
to git-commit and git-amend, I think...

Maybe even Git could refuse or warn on the local side about non
fast-forward update of public branch, to help users of third-party tools.
 
quoted
While default "push matching" behavior makes it possible to have
"secret" commits, being able to explicitly mark commits as not for
publishing might be a good idea also for Git.
Do you see using configuration or convention to achieve this?

For example, any branch named private/foo could, by convention, be
un-pushable without a force option?  Alternately, a config item
similar to the push matching stuff to allow the users to designate
un-pushable branches could work too.
I'm not sure, but the config item might be a good solution.  Git would
skip publishing 'secret' commits (commits from 'secret' branch) if it
would otherwise publish it due to glob refspec, and refuse (or warn)
publishing 'secret' branches explicitly.

Currently if you use default "push matching", then those branches that
you didn't push explicitly wouldn't be pushed.  But that does not prevent
pushing them by accident, and does not give UI to check if branch is
private or not (e.g. to use in git-aware shell prompt).

-- 
Jakub Narebski
Poland

Re: [RFD] Rewriting safety - warn before/when rewriting published history

From: Steven Michalske <hidden>
Date: 2016-06-15 22:52:57

See inlined responses below.

On Feb 4, 2012, at 11:45 AM, Jakub Narebski wrote:
So people would like for git to warn them about rewriting history before 
they attempt a push and it turns out to not fast-forward.
I like this idea and I encounter this issue with my co-workers new to git.
It scares them thinking they broke the repository.
In Mercurial 2.1 there are three available phases: 'public' for
published commits, 'draft' for local un-published commits and
'secret' for local un-published commits which are not meant to
be published.

The phase of a changeset is always equal to or higher than the phase
of it's descendants, according to the following order:

     public < draft < secret
Let's not limit ourselves to just three levels.  They are a great start but I propose the following.

published - The commits that are on a public repository that if are rewritten will invoke uprisings.
	general rule here would be to revert or patch, no rewrites.
based - The commits that the core developers have work based upon. (not just the commits in their repo.)
	general rule is notify your fellow developers before a rewrite.
shared - The commits that are known to your fellow core developers.
	These commits are known, but have not had work based off of them.  Minimal risk to rewrite.
local - The commits that are local only, no one else has a copy.
	Commits your willing to share, but have not been yet shared, either from actions of you, or a fetch from others.
restricted or private - The commits that you do not want shared.
	Manually added, think of a branch tip marked as restricted automatically promotes commits to the branch as restricted.

Maybe make these like nice levels, but as two components, publicity 0-100 and rewritability 0-100
	Published is publicity 100 and rewritability 0
	Restricted is publicity 0 and rewritability 100
	Based publicity 75 and rewritability 25
	Shared publicity 50 and rewritability 50
	Local publicity 25 and rewritability 75
	Restricted publicity 0 and rewritability 100

Other option are flags stating if the commit is published, based, shared, or restricted.
You could have a published and based commit that is more opposed to rewrite than a public commit.

Call security on a published restricted commit ;-)

Commits are by default local.

Commits are published when they are pushed or fetched and merged to a publishing branch of a repository.
	On fetch/merge a post merge hook should send back a note to the remote repository that the commits were published.

Restricted commits/branches/tags should not be made public, error out and require clearing of the attribute or a --force-restricted option that automatically removes the restricted attribute.  They are at least promoted to shared, if not published.

Based is only used in situations where you have developers sharing amongst their repositories, and you want a rule that is less restrictive than no rewrites.

Shared is what we have now when a commit is in a remote repository without the no rewrite options. e.g. receive.denyNonFastForwards.

As it stands now we can infer local and shared,  we need metadata to know when a commit is made based, published, or restricted.


Using the nomenclature from Mercurial 
     public < draft < secret
public -> publicity 100, rewritability 0
draft -> publicity ?, rewritability 50
secret -> publicity 0, rewritability 100

Steve

Re: [RFD] Rewriting safety - warn before/when rewriting published history

From: Johan Herland <hidden>
Date: 2016-06-15 22:53:00

On Mon, Feb 6, 2012 at 01:57, Steven Michalske [off-list ref] wrote:
On Feb 4, 2012, at 11:45 AM, Jakub Narebski wrote:
quoted
In Mercurial 2.1 there are three available phases: 'public' for
published commits, 'draft' for local un-published commits and
'secret' for local un-published commits which are not meant to
be published.

The phase of a changeset is always equal to or higher than the phase
of it's descendants, according to the following order:

     public < draft < secret
Let's not limit ourselves to just three levels.  They are a great start but I propose the following.

published - The commits that are on a public repository that if are rewritten will invoke uprisings.
       general rule here would be to revert or patch, no rewrites.
based - The commits that the core developers have work based upon. (not just the commits in their repo.)
       general rule is notify your fellow developers before a rewrite.
shared - The commits that are known to your fellow core developers.
       These commits are known, but have not had work based off of them.  Minimal risk to rewrite.
local - The commits that are local only, no one else has a copy.
       Commits your willing to share, but have not been yet shared, either from actions of you, or a fetch from others.
restricted or private - The commits that you do not want shared.
       Manually added, think of a branch tip marked as restricted automatically promotes commits to the branch as restricted.

Maybe make these like nice levels, but as two components, publicity 0-100 and rewritability 0-100
       Published is publicity 100 and rewritability 0
       Restricted is publicity 0 and rewritability 100
       Based publicity 75 and rewritability 25
       Shared publicity 50 and rewritability 50
       Local publicity 25 and rewritability 75
       Restricted publicity 0 and rewritability 100

[...]
With all due respect, I believe this is crazy. You're adding an entire
layer of complexity on top of commits that every user has to know
about, and has little or no value to most of them. IMHO, most users
only want Git to help them avoid doing something stupid (rewriting
'public' commits or publishing 'secret' commits), and to do so with
the minimal amount of manual user interaction. The above idea is more
suitable for armchair dictators that want to micromanage their commits
along two arbitrary axes of evil^H^H^H^Hpointlessness. On both axes,
you'll need threshold values where Git starts refusing to
publish/rewrite your commit. Hence, the only thing that matters is
whether the 'publicity'/'rewritability' value is above/below that
threshold, at which point you could save yourself a lot of trouble by
making them simple boolean flags instead.

Having said that, you can use 'git notes' along with existing and
proposed hooks (as described elsewhere in this thread) to implement
whatever crazy commit publishing/rewriting scheme you desire. To
misquote someone famous: I disapprove of what you want to do with Git,
but I will defend to the death your right to make Git do what you want
(in the privacy of your own repos). ;)


Have fun! :)

...Johan

-- 
Johan Herland, [off-list ref]
www.herland.net

Re: [RFD] Rewriting safety - warn before/when rewriting published history

From: Jakub Narebski <hidden>
Date: 2016-06-15 22:53:00

On Mon, 6 Feb 2012, Steven Michalske wrote:
See inlined responses below.
Is this comment necessary at all?
 
On Feb 4, 2012, at 11:45 AM, Jakub Narebski wrote:
quoted
So people would like for git to warn them about rewriting history before 
they attempt a push and it turns out to not fast-forward.
I like this idea and I encounter this issue with my co-workers new to git.
It scares them thinking they broke the repository.
It is true that while this feature would be useful also for "power
users", it would be most helpful for newbies (users new to git).

So I am afraid that implementing it with example hooks that must be
turned on explicitly might be not enough...
 
quoted
In Mercurial 2.1 there are three available phases: 'public' for
published commits, 'draft' for local un-published commits and
'secret' for local un-published commits which are not meant to
be published.

The phase of a changeset is always equal to or higher than the phase
of it's descendants, according to the following order:

     public < draft < secret
Let's not limit ourselves to just three levels.  They are a great start
but I propose the following. 
As we don't have any implementation, I'd rather we don't multiply entities.
I was even thinking about limiting to just 'public' and 'draft' "phases".
 
published - The commits that are on a public repository that if are
      rewritten will invoke uprisings. general rule here would be
      to revert or patch, no rewrites. 
based - The commits that the core developers have work based upon.
      (not just the commits in their repo.) 
	general rule is notify your fellow developers before a rewrite.
shared - The commits that are known to your fellow core developers.
	These commits are known, but have not had work based off of them.
	Minimal risk to rewrite. 
All these are very fairly nuanced, with minuscule differences between
them.  I'd rather not multiply entities, especially not introduce such
hard to guess what it about from their name.

In Mercurial phases share hierarchy of traits:
http://mercurial.selenic.com/wiki/Phases
 
           |        traits       |
           .......................  
           | immutable | shared  |
 ----------+-----------+---------+
 public    | x         | x       | ^
 draft     |           | x       | ^
 secret    |           |         | ^
	
The names of those traits probably should be changed in Git.

Those traits are boolean in Mercurial, but I think we can implement
what you would like to have to change them to tristate: 'deny' (unless
forced, i.e. the same as true), 'warn', 'ignore' (i.e. the same as false).

I think that it would be nice to be able to tune "severity" of trait
on per-remote and/or per-branch basis.  This way you would get warned
before rewriting commits that were pushed to your group repository,
and prevented from rewriting commits that are present in projects public
repository.

Nevertheless I think it is something better left for later, and added
only if it turns out to be really needed.
local - The commits that are local only, no one else has a copy.
	Commits your willing to share, but have not been yet shared,
	either from actions of you, or a fetch from others. 
That's Mercurial's 'draft' phase.
restricted or private - The commits that you do not want shared.
	Manually added, think of a branch tip marked as restricted
	automatically promotes commits to the branch as restricted. 
That's Mercurial 'secret' phase.

 
Maybe make these like nice levels, but as two components,
publicity 0-100 and rewritability 0-100 
	Published is publicity 100 and rewritability 0
	Restricted is publicity 0 and rewritability 100
	Based publicity 75 and rewritability 25
	Shared publicity 50 and rewritability 50
	Local publicity 25 and rewritability 75
	Restricted publicity 0 and rewritability 100
Continuous traits are IMHO a bad idea.  You would have to quantize them
and turn them on into specific behavior: ignore, warn, deny.

For example WTF does 25 "publicity" (bad name) or "rewritability" actually
means in term of git behavior, eh?
 
Other option are flags stating if the commit is published, based,
shared, or restricted.  You could have a published and based commit
that is more opposed to rewrite than a public commit. 

Call security on a published restricted commit ;-)
Please note that while "phases" look like they are trait of individual
commits, they are in fact artifact of revision walking.  The idea is
that ancestors of 'private' commit can be 'private', 'draft' or 'public',
that ancestors of 'draft' commit are 'draft' or 'public', and that _all_
ancestors of 'public' commit are 'public'.
 
Commits are by default local.
This 'by default' needs to be specified further, because for example
all commits in freshly cloned repository should be in 'public' phase
by default.  

Also, don't say 'commits are local', 'commits are published'; use "phases"
nomenclature (at least until we invent something so much better that it
is worth breaking consistency with Mercurial terminology).
Commits are published when they are pushed or fetched and merged to
a publishing branch of a repository. 
BTW. I am not sure if pushing to remote repository updates (or can update)
any remote-tracking branches...
	On fetch/merge a post merge hook should send back a note to
	the remote repository that the commits were published. 
I think this is unnecessary in the "best practices" scenario, where each
user has separate private repository where he/she does his/her work, and
one's own public repository, where people fetch from.  He/she can push
to some shared repository, and that has to be supported too.

Though there is mothership/ sattellite situation, where you can pull and
push only from one direction.  There we might want for some way to notify
that some commits were fetched and should now be considered 'public'.
Though I am not sure if it is really necessary.
 
Restricted commits/branches/tags should not be made public, error out and
require clearing of the attribute or a --force-restricted option that
automatically removes the restricted attribute.  They are at least promoted
to shared, if not published.   
Or just skip them (silently or not) if we push using globbing refspec, and
glob matches some refs marked as 'private'.
 
Based is only used in situations where you have developers sharing amongst
their repositories, and you want a rule that is less restrictive than
no rewrites.  
Multiplying entities.
 
Shared is what we have now when a commit is in a remote repository without
the no rewrite options. e.g. receive.denyNonFastForwards. 
Multiplying entities.
 
[...]
quoted
Using the nomenclature from Mercurial 
     public < draft < secret
public -> publicity 100, rewritability 0
draft -> publicity ?, rewritability 50
secret -> publicity 0, rewritability 100
That doesn't really help, at all.

-- 
Jakub Narebski
Poland

Re: [RFD] Rewriting safety - warn before/when rewriting published history

From: Steven Michalske <hidden>
Date: 2016-06-15 22:53:29

Saw that this was put into GSOC and reread the thread.


On Feb 6, 2012, at 9:45 PM, Jakub Narebski wrote:
On Mon, 6 Feb 2012, Steven Michalske wrote:
quoted
See inlined responses below.
Is this comment necessary at all?
Oddly enough yes.
quoted
On Feb 4, 2012, at 11:45 AM, Jakub Narebski wrote:
quoted
So people would like for git to warn them about rewriting history before 
they attempt a push and it turns out to not fast-forward.
I like this idea and I encounter this issue with my co-workers new to git.
It scares them thinking they broke the repository.
It is true that while this feature would be useful also for "power
users", it would be most helpful for newbies (users new to git).

So I am afraid that implementing it with example hooks that must be
turned on explicitly might be not enough...
quoted
quoted
In Mercurial 2.1 there are three available phases: 'public' for
published commits, 'draft' for local un-published commits and
'secret' for local un-published commits which are not meant to
be published.

The phase of a changeset is always equal to or higher than the phase
of it's descendants, according to the following order:

    public < draft < secret
Let's not limit ourselves to just three levels.  They are a great start
but I propose the following. 
As we don't have any implementation, I'd rather we don't multiply entities.
I was even thinking about limiting to just 'public' and 'draft' "phases".
quoted
published - The commits that are on a public repository that if are
     rewritten will invoke uprisings. general rule here would be
     to revert or patch, no rewrites. 
based - The commits that the core developers have work based upon.
     (not just the commits in their repo.) 
	general rule is notify your fellow developers before a rewrite.
shared - The commits that are known to your fellow core developers.
	These commits are known, but have not had work based off of them.
	Minimal risk to rewrite. 
All these are very fairly nuanced, with minuscule differences between
them.  I'd rather not multiply entities, especially not introduce such
hard to guess what it about from their name.
Fair enough, the intent was to get folks thinking about where they could go.

As for published, it carries a higher meaning than public.  For example I have a public repo, and all the commits are public.
but if I make a notice that 1 of the branches "in_progress" is often rebased.... (I know of one stacked git user that does this)
 and that the master and dev branches are never going to be rewritten.  So master and dev are Published and Public, where "in_progress" is not.

So it would be nice that git would warn me if I based a branch off of a non published branch.
In Mercurial phases share hierarchy of traits:
http://mercurial.selenic.com/wiki/Phases

          |        traits       |
          .......................  
          | immutable | shared  |
----------+-----------+---------+
public    | x         | x       | ^
draft     |           | x       | ^
secret    |           |         | ^
Not sure I agree with shared name,  is shared the same as sharable?
	
The names of those traits probably should be changed in Git.

Those traits are boolean in Mercurial, but I think we can implement
what you would like to have to change them to tristate: 'deny' (unless
forced, i.e. the same as true), 'warn', 'ignore' (i.e. the same as false).

I think that it would be nice to be able to tune "severity" of trait
on per-remote and/or per-branch basis.  This way you would get warned
before rewriting commits that were pushed to your group repository,
and prevented from rewriting commits that are present in projects public
repository.

Nevertheless I think it is something better left for later, and added
only if it turns out to be really needed.
There was a good comment on this in the thread.
quoted
local - The commits that are local only, no one else has a copy.
	Commits your willing to share, but have not been yet shared,
	either from actions of you, or a fetch from others. 
That's Mercurial's 'draft' phase.
quoted
restricted or private - The commits that you do not want shared.
	Manually added, think of a branch tip marked as restricted
	automatically promotes commits to the branch as restricted. 
That's Mercurial 'secret' phase.
quoted
Maybe make these like nice levels, but as two components,
publicity 0-100 and rewritability 0-100 
	Published is publicity 100 and rewritability 0
	Restricted is publicity 0 and rewritability 100
	Based publicity 75 and rewritability 25
	Shared publicity 50 and rewritability 50
	Local publicity 25 and rewritability 75
	Restricted publicity 0 and rewritability 100
Continuous traits are IMHO a bad idea.  You would have to quantize them
and turn them on into specific behavior: ignore, warn, deny.
Continuous vs enumerated vs boolean,  I'd like to see enumerated honestly.
I proposed continuous to get the idea out there.
For example WTF does 25 "publicity" (bad name) or "rewritability" actually
means in term of git behavior, eh?
Yea, a set of flags is a better idea.
quoted
Other option are flags stating if the commit is published, based,
shared, or restricted.  You could have a published and based commit
that is more opposed to rewrite than a public commit. 

Call security on a published restricted commit ;-)
Please note that while "phases" look like they are trait of individual
commits, they are in fact artifact of revision walking.  The idea is
that ancestors of 'private' commit can be 'private', 'draft' or 'public',
that ancestors of 'draft' commit are 'draft' or 'public', and that _all_
ancestors of 'public' commit are 'public'.
quoted
Commits are by default local.
This 'by default' needs to be specified further, because for example
all commits in freshly cloned repository should be in 'public' phase
by default.  
New commits
Also, don't say 'commits are local', 'commits are published'; use "phases"
nomenclature (at least until we invent something so much better that it
is worth breaking consistency with Mercurial terminology).
Sorry, I didn't like their terminology for my expanded concept, that allowed co-devlopers to work on secret work together.

Pretend we are co-workers on super cool new feature.
If you and I are working on a project at work, I can share my secrets with you, but I can't push it to the public servers yet.

Another concept that is similar to secret is internal code.
Working on code that has public source and source that is for inside your company.
	Though this is more an attribute of a file.
	Warn about commits with internal files being pushed to an external repository. 
quoted
Commits are published when they are pushed or fetched and merged to
a publishing branch of a repository. 
BTW. I am not sure if pushing to remote repository updates (or can update)
any remote-tracking branches...
quoted
	On fetch/merge a post merge hook should send back a note to
	the remote repository that the commits were published. 
I think this is unnecessary in the "best practices" scenario, where each
user has separate private repository where he/she does his/her work, and
one's own public repository, where people fetch from.  He/she can push
to some shared repository, and that has to be supported too.

Though there is mothership/ sattellite situation, where you can pull and
push only from one direction.  There we might want for some way to notify
that some commits were fetched and should now be considered 'public'.
Though I am not sure if it is really necessary.
I don't work in the environment of the best practices.  I most often work with a central authoritative repo.
quoted
Restricted commits/branches/tags should not be made public, error out and
require clearing of the attribute or a --force-restricted option that
automatically removes the restricted attribute.  They are at least promoted
to shared, if not published.   
Or just skip them (silently or not) if we push using globbing refspec, and
glob matches some refs marked as 'private'.
Agreed,  explicit pushes were what I was referring to.
quoted
Based is only used in situations where you have developers sharing amongst
their repositories, and you want a rule that is less restrictive than
no rewrites.  
Multiplying entities.
quoted
Shared is what we have now when a commit is in a remote repository without
the no rewrite options. e.g. receive.denyNonFastForwards. 
Multiplying entities.

[...]
quoted
quoted
Using the nomenclature from Mercurial 
    public < draft < secret
public -> publicity 100, rewritability 0
draft -> publicity ?, rewritability 50
secret -> publicity 0, rewritability 100
That doesn't really help, at all.

-- 
Jakub Narebski
Poland
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help