* [RFD] Rewriting safety - warn before/when rewriting published history
@ 2012-02-04 19:45 Jakub Narebski
2012-02-05 14:33 ` Ben Walton
` (2 more replies)
0 siblings, 3 replies; 34+ messages in thread
From: Jakub Narebski @ 2012-02-04 19:45 UTC (permalink / raw)
To: git
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
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFD] Rewriting safety - warn before/when rewriting published history
2012-02-04 19:45 [RFD] Rewriting safety - warn before/when rewriting published history Jakub Narebski
@ 2012-02-05 14:33 ` Ben Walton
2012-02-05 15:05 ` Jakub Narebski
[not found] ` <CAFA910035B74E56A52A96097E76AC39@PhilipOakley>
2012-02-06 0:57 ` Steven Michalske
2 siblings, 1 reply; 34+ messages in thread
From: Ben Walton @ 2012-02-05 14:33 UTC (permalink / raw)
To: Jakub Narebski; +Cc: git
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
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFD] Rewriting safety - warn before/when rewriting published history
2012-02-05 14:33 ` Ben Walton
@ 2012-02-05 15:05 ` Jakub Narebski
0 siblings, 0 replies; 34+ messages in thread
From: Jakub Narebski @ 2012-02-05 15:05 UTC (permalink / raw)
To: Ben Walton; +Cc: git
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.
> > 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.
> > 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
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFD] Rewriting safety - warn before/when rewriting published history
[not found] ` <CAFA910035B74E56A52A96097E76AC39@PhilipOakley>
@ 2012-02-05 16:15 ` Jakub Narebski
2012-02-05 17:29 ` Johan Herland
0 siblings, 1 reply; 34+ messages in thread
From: Jakub Narebski @ 2012-02-05 16:15 UTC (permalink / raw)
To: Philip Oakley; +Cc: git
Please don't remove git mailing list from Cc... Oh, I see that you
forgot to send to list, but resend your email there.
On Sun, 5 Feb 2012, Philip Oakley wrote:
> From: "Jakub Narebski" <jnareb@gmail.com>
> Sent: Saturday, February 04, 2012 7:45 PM
> > 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.
>
> Another area that is implicitly related is that of (lack of) publication of
> sub-module updates. A mechanisms that, in the super project, knows the
> status of the (local) submodules, such as where they would be sourced from,
> i.e. what was last pushed & where, could help in such instances.
"Better support for submodules" had almost the same number of requests
in the latest Git User's Survey 2011 (25% which means 1582 responses).
Remembering when to do recursive push and where would be a very nice thing.
[...]
> Recording where they were pushed to would be useful for synchronising
> sub-modules and their super projects. That is, giving remote users a clue as
> to where they might find mising sub-modules.
Is it a matter of correctly writing configuration with current git?
I don't use submodules myself, so I cannot say.
> > 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.
> >
>
> Being able to mark temporary, out of sequence or other hacks as Secret could
> be useful, as would recording where Public commits had been sent.
Marking as 'secret' must I think be explicit, but I think 'public' phase
should be inferred from remote-tracking branches. The idea of phases is
to allow UI to ask about status of commits: can we amend / rebase it or
not, can we push it or not.
--
Jakub Narebski
Poland
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFD] Rewriting safety - warn before/when rewriting published history
2012-02-05 16:15 ` Jakub Narebski
@ 2012-02-05 17:29 ` Johan Herland
2012-02-05 20:46 ` Jakub Narebski
0 siblings, 1 reply; 34+ messages in thread
From: Johan Herland @ 2012-02-05 17:29 UTC (permalink / raw)
To: Jakub Narebski; +Cc: Philip Oakley, git
2012/2/5 Jakub Narebski <jnareb@gmail.com>:
>> Being able to mark temporary, out of sequence or other hacks as Secret could
>> be useful, as would recording where Public commits had been sent.
>
> Marking as 'secret' must I think be explicit, but I think 'public' phase
> should be inferred from remote-tracking branches. The idea of phases is
> to allow UI to ask about status of commits: can we amend / rebase it or
> not, can we push it or not.
I agree that the 'public' state should (by default) be automatically
inferred from remote-tracking branches. As it stands, we can do this
with current git, by writing a pre-rebase hook that checks if any of
the commits to-be-rebased are reachable from any remote-tracking
branch.
Unfortunately, the pre-rebase hook only affects 'git rebase', and in
order to do the same check on 'git commit --amend' you'd have to write
a similar pre-commit hook (don't know how easy it is to find the
amended commit from within the hook). Maybe we should add a
pre-rewrite hook that trigger in the same situations as the
post-rewrite hook.
This should take care of the simplest 'public' use case in a
push-based workflow. If you publish commits by other means
(send-email, bundles, pulling directly from your repo), you need some
other way to mark the 'public' commits. One solution would be using
'git notes' to annotate the 'public' commits on a 'refs/notes/public'
notes ref. Your pre-rebase/pre-rewrite hook should then check if any
of the commits to-be-rewritten are reachable from any commit annotated
as 'public'.
Also, if you want to record where 'public' commits have been sent
(other than what can be inferred from the remote-tracking branches),
you could write this into the refs/notes/public annotation.
As for 'secret' commits, you could annotate these on a
refs/notes/secret notes ref, and then teach 'git push' (or whatever
other method for publishing commits you use) to refuse to publish
commits annotated on this notes ref. Possibly we would want to add a
"pre-push" or "pre-publish" hook.
Have fun! :)
...Johan
--
Johan Herland, <johan@herland.net>
www.herland.net
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFD] Rewriting safety - warn before/when rewriting published history
2012-02-05 17:29 ` Johan Herland
@ 2012-02-05 20:46 ` Jakub Narebski
2012-02-05 22:49 ` Johan Herland
0 siblings, 1 reply; 34+ messages in thread
From: Jakub Narebski @ 2012-02-05 20:46 UTC (permalink / raw)
To: Johan Herland; +Cc: Philip Oakley, git
On Sun, 5 Feb 2012, Johan Herland wrote:
> 2012/2/5 Jakub Narebski <jnareb@gmail.com>:
> > > Being able to mark temporary, out of sequence or other hacks as Secret could
> > > be useful, as would recording where Public commits had been sent.
> >
> > Marking as 'secret' must I think be explicit, but I think 'public' phase
> > should be inferred from remote-tracking branches. The idea of phases is
> > to allow UI to ask about status of commits: can we amend / rebase it or
> > not, can we push it or not.
>
> I agree that the 'public' state should (by default) be automatically
> inferred from remote-tracking branches. As it stands, we can do this
> with current git, by writing a pre-rebase hook that checks if any of
> the commits to-be-rebased are reachable from any remote-tracking
> branch.
It is nice that we can achieve a large part of this feature with existing
infrastructure. It would be nice if we ship such pre-rebase hook with
git, so people can just enable it if they want to use this functionality,
like the default pre-commit hook that checks for whitespace errors.
> Unfortunately, the pre-rebase hook only affects 'git rebase', and in
> order to do the same check on 'git commit --amend' you'd have to write
> a similar pre-commit hook (don't know how easy it is to find the
> amended commit from within the hook). Maybe we should add a
> pre-rewrite hook that trigger in the same situations as the
> post-rewrite hook.
pre-rewrite hook would be a really nice to have, especially that it would
(I hope) cover third party tools like various GUIs for git; and also
git-filter-branch.
Note however that the safety net, i.e. refusing or warning against attempted
rewrite of published history is only part of issue. Another important part
is querying and showing "phase" of a commit. What I'd like to see is
ability to show among others in "git log" and "git show" output if commit
was already published or not (and if it is marked 'secret').
> This should take care of the simplest 'public' use case in a
> push-based workflow. If you publish commits by other means
> (send-email, bundles, pulling directly from your repo), you need some
> other way to mark the 'public' commits. One solution would be using
> 'git notes' to annotate the 'public' commits on a 'refs/notes/public'
> notes ref. Your pre-rebase/pre-rewrite hook should then check if any
> of the commits to-be-rewritten are reachable from any commit annotated
> as 'public'.
Another solution would be to create "fake" remote-tracking branches
by git-bundle and git-send-email.
> Also, if you want to record where 'public' commits have been sent
> (other than what can be inferred from the remote-tracking branches),
> you could write this into the refs/notes/public annotation.
I wonder if this too can be done by hook...
> As for 'secret' commits, you could annotate these on a
> refs/notes/secret notes ref, and then teach 'git push' (or whatever
> other method for publishing commits you use) to refuse to publish
> commits annotated on this notes ref. Possibly we would want to add a
> "pre-push" or "pre-publish" hook.
Well, addition of pre-push / pre-publish was resisted on the grounds
that all it does is something that can be as easy done by hand before
push. Perhaps this new use case would help bring it forward, don't
you think?
Thanks for all the comments.
--
Jakub Narebski
Poland
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFD] Rewriting safety - warn before/when rewriting published history
2012-02-05 20:46 ` Jakub Narebski
@ 2012-02-05 22:49 ` Johan Herland
2012-02-06 14:44 ` Jakub Narebski
0 siblings, 1 reply; 34+ messages in thread
From: Johan Herland @ 2012-02-05 22:49 UTC (permalink / raw)
To: Jakub Narebski; +Cc: Philip Oakley, git
On Sun, Feb 5, 2012 at 21:46, Jakub Narebski <jnareb@gmail.com> wrote:
> On Sun, 5 Feb 2012, Johan Herland wrote:
>> 2012/2/5 Jakub Narebski <jnareb@gmail.com>:
>> > > Being able to mark temporary, out of sequence or other hacks as Secret could
>> > > be useful, as would recording where Public commits had been sent.
>> >
>> > Marking as 'secret' must I think be explicit, but I think 'public' phase
>> > should be inferred from remote-tracking branches. The idea of phases is
>> > to allow UI to ask about status of commits: can we amend / rebase it or
>> > not, can we push it or not.
>>
>> I agree that the 'public' state should (by default) be automatically
>> inferred from remote-tracking branches. As it stands, we can do this
>> with current git, by writing a pre-rebase hook that checks if any of
>> the commits to-be-rebased are reachable from any remote-tracking
>> branch.
>
> It is nice that we can achieve a large part of this feature with existing
> infrastructure. It would be nice if we ship such pre-rebase hook with
> git, so people can just enable it if they want to use this functionality,
> like the default pre-commit hook that checks for whitespace errors.
Yeah. As it is, the pre-rebase hook shipped with v1.7.9 (when
activated) does something similar (i.e. prevent rewriting 'public'
commits). However, it's highly workflow-specific, since it determines
whether the branch being rebased has been merged into "next" or
"master". IMHO, a hook that tested for reachability from
remote-tracking refs would be more generally useful. Obviously, the
two can be combined, and even further combinations may be desirable
(e.g. also checking for reachability from commits annotated in
refs/notes/public).
>> Unfortunately, the pre-rebase hook only affects 'git rebase', and in
>> order to do the same check on 'git commit --amend' you'd have to write
>> a similar pre-commit hook (don't know how easy it is to find the
>> amended commit from within the hook). Maybe we should add a
>> pre-rewrite hook that trigger in the same situations as the
>> post-rewrite hook.
>
> pre-rewrite hook would be a really nice to have, especially that it would
> (I hope) cover third party tools like various GUIs for git; and also
> git-filter-branch.
>
> Note however that the safety net, i.e. refusing or warning against attempted
> rewrite of published history is only part of issue. Another important part
> is querying and showing "phase" of a commit. What I'd like to see is
> ability to show among others in "git log" and "git show" output if commit
> was already published or not (and if it is marked 'secret').
Today, you can use --decorate to display remote-tracking refs in the
log/show output. However, only the tip commits are decorated, so if
the commits shown are not at the tip, you're out of luck. I believe
teaching log/show to decorate _all_ commits that are reachable from
some given ref(s) should be fairly straightforward.
If you use 'git notes' to annotate 'public' and 'secret' states, then
you can also use the --show-notes=<ref> option to let show/log display
the annotations on 'public'/'secret' commits.
>> This should take care of the simplest 'public' use case in a
>> push-based workflow. If you publish commits by other means
>> (send-email, bundles, pulling directly from your repo), you need some
>> other way to mark the 'public' commits. One solution would be using
>> 'git notes' to annotate the 'public' commits on a 'refs/notes/public'
>> notes ref. Your pre-rebase/pre-rewrite hook should then check if any
>> of the commits to-be-rewritten are reachable from any commit annotated
>> as 'public'.
>
> Another solution would be to create "fake" remote-tracking branches
> by git-bundle and git-send-email.
Good point. Creating such "fake" remote-tracking branches might be a
good idea in those workflows anyway, simply to keep track of what has
been shared, and where.
>> Also, if you want to record where 'public' commits have been sent
>> (other than what can be inferred from the remote-tracking branches),
>> you could write this into the refs/notes/public annotation.
>
> I wonder if this too can be done by hook...
You're looking for someting like a post-push hook that runs on the
_client_ after a successful push. AFAIK, that doesn't exist yet. (Not
to be confused with the receive/update hooks that run on the
_server_.)
>> As for 'secret' commits, you could annotate these on a
>> refs/notes/secret notes ref, and then teach 'git push' (or whatever
>> other method for publishing commits you use) to refuse to publish
>> commits annotated on this notes ref. Possibly we would want to add a
>> "pre-push" or "pre-publish" hook.
>
> Well, addition of pre-push / pre-publish was resisted on the grounds
> that all it does is something that can be as easy done by hand before
> push. Perhaps this new use case would help bring it forward, don't
> you think?
Maybe. I didn't follow the original discussion. From my POV, you could
argue that instead of another hook, you could always write a script
that does the 'secret' check before invoking 'git push', and then
you'd use that script instead of 'git push'. But you could argue the
same point for pretty much all of the other existing hooks (e.g.
instead of a pre-commit hook you could have your own commit wrapper
script). So I don't think that's a sufficient argument to refuse the
existence of a pre-push/publish hook.
Have fun! :)
...Johan
--
Johan Herland, <johan@herland.net>
www.herland.net
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFD] Rewriting safety - warn before/when rewriting published history
2012-02-04 19:45 [RFD] Rewriting safety - warn before/when rewriting published history Jakub Narebski
2012-02-05 14:33 ` Ben Walton
[not found] ` <CAFA910035B74E56A52A96097E76AC39@PhilipOakley>
@ 2012-02-06 0:57 ` Steven Michalske
2012-02-06 6:53 ` Johan Herland
2012-02-06 13:45 ` Jakub Narebski
2 siblings, 2 replies; 34+ messages in thread
From: Steven Michalske @ 2012-02-06 0:57 UTC (permalink / raw)
To: Jakub Narebski; +Cc: git
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
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFD] Rewriting safety - warn before/when rewriting published history
2012-02-06 0:57 ` Steven Michalske
@ 2012-02-06 6:53 ` Johan Herland
2012-02-06 13:45 ` Jakub Narebski
1 sibling, 0 replies; 34+ messages in thread
From: Johan Herland @ 2012-02-06 6:53 UTC (permalink / raw)
To: Steven Michalske; +Cc: Jakub Narebski, git
On Mon, Feb 6, 2012 at 01:57, Steven Michalske <smichalske@gmail.com> wrote:
> On Feb 4, 2012, at 11:45 AM, Jakub Narebski wrote:
>> 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, <johan@herland.net>
www.herland.net
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFD] Rewriting safety - warn before/when rewriting published history
2012-02-06 0:57 ` Steven Michalske
2012-02-06 6:53 ` Johan Herland
@ 2012-02-06 13:45 ` Jakub Narebski
2012-04-07 14:36 ` Steven Michalske
1 sibling, 1 reply; 34+ messages in thread
From: Jakub Narebski @ 2012-02-06 13:45 UTC (permalink / raw)
To: Steven Michalske; +Cc: git
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:
>
> > 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...
> > 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.
[...]
> > 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
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFD] Rewriting safety - warn before/when rewriting published history
2012-02-05 22:49 ` Johan Herland
@ 2012-02-06 14:44 ` Jakub Narebski
2012-02-06 15:59 ` Johan Herland
0 siblings, 1 reply; 34+ messages in thread
From: Jakub Narebski @ 2012-02-06 14:44 UTC (permalink / raw)
To: Johan Herland; +Cc: Philip Oakley, git
On Sun, 5 Feb 2012, Johan Herland wrote:
> On Sun, Feb 5, 2012 at 21:46, Jakub Narebski <jnareb@gmail.com> wrote:
>> On Sun, 5 Feb 2012, Johan Herland wrote:
>>> 2012/2/5 Jakub Narebski <jnareb@gmail.com>:
[...]
>>> I agree that the 'public' state should (by default) be automatically
>>> inferred from remote-tracking branches. As it stands, we can do this
>>> with current git, by writing a pre-rebase hook that checks if any of
>>> the commits to-be-rebased are reachable from any remote-tracking
>>> branch.
>>
>> It is nice that we can achieve a large part of this feature with existing
>> infrastructure. It would be nice if we ship such pre-rebase hook with
>> git, so people can just enable it if they want to use this functionality,
>> like the default pre-commit hook that checks for whitespace errors.
>
> Yeah. As it is, the pre-rebase hook shipped with v1.7.9 (when
> activated) does something similar (i.e. prevent rewriting 'public'
> commits). However, it's highly workflow-specific, since it determines
> whether the branch being rebased has been merged into "next" or
> "master". IMHO, a hook that tested for reachability from
> remote-tracking refs would be more generally useful. Obviously, the
> two can be combined, and even further combinations may be desirable
> (e.g. also checking for reachability from commits annotated in
> refs/notes/public).
Relying on (default) hooks to implement this feature has the disadvantage
that it wouldn't be turned on by default... while this feature would be
most helpful for users new to git (scared by refuse to push).
I am not sure either if everything (wrt. safety net) can be implemented
via hooks. One thing that I forgot about is preventing rewinding of
branch past the published commit using e.g. "git reset --hard <commit>".
Unless `pre-rewrite` hook could be used for that safety too...
[...]
>> Note however that the safety net, i.e. refusing or warning against attempted
>> rewrite of published history is only part of issue. Another important part
>> is querying and showing "phase" of a commit. What I'd like to see is
>> ability to show among others in "git log" and "git show" output if commit
>> was already published or not (and if it is marked 'secret').
>
> Today, you can use --decorate to display remote-tracking refs in the
> log/show output. However, only the tip commits are decorated, so if
> the commits shown are not at the tip, you're out of luck. I believe
> teaching log/show to decorate _all_ commits that are reachable from
> some given ref(s) should be fairly straightforward.
That would be nice.
> If you use 'git notes' to annotate 'public' and 'secret' states, then
> you can also use the --show-notes=<ref> option to let show/log display
> the annotations on 'public'/'secret' commits.
First, in my opinion annotating _all_ commits with their phase is I think
out of question, especially annotating 'public' commits. I don't think
git-notes mechanism would scale well to annotating every commit; but
perhaps this was tested to work, and I am mistaken.
Second, I have doubts if "phase" is really state of an individual commit,
and not the feature of revision walking.
Take for example the situation where given commit is reference by
remote-tracking branch 'public/foo', and also by two local branches:
'foo' with upstream 'public/foo', and local branch 'bar' with no upstream.
Now it is quite obvious that this feature should prevent rewriting 'foo'
branch, for which commits are published upstream. But what about branch
'bar'? Should we prevent rewriting (e.g. rebase) here too? What about
rewinding 'bar' to point somewhere else. What if 'bar' is really detached
HEAD?
These questions need to be answered...
[...]
>>> Also, if you want to record where 'public' commits have been sent
>>> (other than what can be inferred from the remote-tracking branches),
>>> you could write this into the refs/notes/public annotation.
>>
>> I wonder if this too can be done by hook...
>
> You're looking for someting like a post-push hook that runs on the
> _client_ after a successful push. AFAIK, that doesn't exist yet. (Not
> to be confused with the receive/update hooks that run on the
> _server_.)
And such hook could react to what was successfully pushed. Without
such hook we would have to write wrapper around git-push and parse
its output...
Nb. such hook could create "fake" remote-tracking branches if given
push-only remote doesn't have them set up.
>>> As for 'secret' commits, you could annotate these on a
>>> refs/notes/secret notes ref, and then teach 'git push' (or whatever
>>> other method for publishing commits you use) to refuse to publish
>>> commits annotated on this notes ref. Possibly we would want to add a
>>> "pre-push" or "pre-publish" hook.
>>
>> Well, addition of pre-push / pre-publish was resisted on the grounds
>> that all it does is something that can be as easy done by hand before
>> push. Perhaps this new use case would help bring it forward, don't
>> you think?
>
> Maybe. I didn't follow the original discussion. From my POV, you could
> argue that instead of another hook, you could always write a script
> that does the 'secret' check before invoking 'git push', and then
> you'd use that script instead of 'git push'. But you could argue the
> same point for pretty much all of the other existing hooks (e.g.
> instead of a pre-commit hook you could have your own commit wrapper
> script). So I don't think that's a sufficient argument to refuse the
> existence of a pre-push/publish hook.
Right, This would be for this feature very much like pre-commit hook.
--
Jakub Narebski
Poland
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFD] Rewriting safety - warn before/when rewriting published history
2012-02-06 14:44 ` Jakub Narebski
@ 2012-02-06 15:59 ` Johan Herland
2012-02-06 17:14 ` Jakub Narebski
0 siblings, 1 reply; 34+ messages in thread
From: Johan Herland @ 2012-02-06 15:59 UTC (permalink / raw)
To: Jakub Narebski; +Cc: Philip Oakley, git
On Mon, Feb 6, 2012 at 15:44, Jakub Narebski <jnareb@gmail.com> wrote:
> On Sun, 5 Feb 2012, Johan Herland wrote:
> Relying on (default) hooks to implement this feature has the disadvantage
> that it wouldn't be turned on by default... while this feature would be
> most helpful for users new to git (scared by refuse to push).
True. I too believe that this will be most helpful if it is enabled by
default. That said, the easiest way to get there might be through
first demonstrating that it works in practice when implemented as
hooks.
> I am not sure either if everything (wrt. safety net) can be implemented
> via hooks. One thing that I forgot about is preventing rewinding of
> branch past the published commit using e.g. "git reset --hard <commit>".
> Unless `pre-rewrite` hook could be used for that safety too...
Hmm. I don't think we'll be able to "plug" all the holes that might
leave the user in a rewritten state (e.g. what if the user (possibly
with the help of some tool) does an "echo $SHA1 >
.git/refs/head/master"?). And trying to plug too many holes might end
up annoying more experienced users who "know what they're doing".
Instead we might want to add a client-side check at push time. I
realize that this check is already done by the remote end, but the
client-side might be able to give a more helpful response along the
lines of:
You are trying to push branch X to remote Y, but remote Y already
has a branch X that is N commits in front of you. You may want to
rebase your work on top of the remote branch (see 'git pull
--rebase'), If you instead force this push (with --force), you will
remove those N commits, and replace them with the M last commits from
your branch X.
(followed by a list of the remote N and local M commits, respectively)
[...]
>> If you use 'git notes' to annotate 'public' and 'secret' states, then
>> you can also use the --show-notes=<ref> option to let show/log display
>> the annotations on 'public'/'secret' commits.
>
> First, in my opinion annotating _all_ commits with their phase is I think
> out of question, especially annotating 'public' commits. I don't think
> git-notes mechanism would scale well to annotating every commit; but
> perhaps this was tested to work, and I am mistaken.
First, we don't need to annotate _all_ commits. For the 'public'
state, we only annotate the last/tip commit that was pushed/published.
From there, we can defer that all ancestor commits are also 'public'.
For the 'secret' state, we do indeed annotate _all_ secret commits,
but I believe this will be a somewhat limited number of commits. If
your workflow forces you to annotate millions of commits as 'secret',
I claim there is something wrong with your workflow.
Second, git-notes were indeed designed scale well to handle a large
number of notes, up to the same order of magnitude as the number of
commits in your repo. (When git-notes was originally written, I
successfully tested it on versions of a linux-kernel repo where every
single commit was annotated). In this case, the number of 'public'
annotations in your repo would be equal to the number of pushes you
do, and the number of 'secret' annotations would be equal to the
number of 'secret' commits in your repo. I'd expect both of these
numbers to be orders of magnitude smaller than the total number of
commits in your repo (given a fairly typical workflow in a fairly
typical repo).
> Second, I have doubts if "phase" is really state of an individual commit,
> and not the feature of revision walking.
I believe the 'public' state is a "feature of revision walking" (i.e.
one annotated 'public' commit implies that all its ancestors are also
'public'). However, the 'secret' state should be bound to the
individual commit, IMHO.
> Take for example the situation where given commit is reference by
> remote-tracking branch 'public/foo', and also by two local branches:
> 'foo' with upstream 'public/foo', and local branch 'bar' with no upstream.
>
> Now it is quite obvious that this feature should prevent rewriting 'foo'
> branch, for which commits are published upstream. But what about branch
> 'bar'? Should we prevent rewriting (e.g. rebase) here too? What about
> rewinding 'bar' to point somewhere else. What if 'bar' is really detached
> HEAD?
>
> These questions need to be answered...
Good point. There are two questions we may need to answer: "Has commit
X ever been published?", and "Has commit X ever been published in the
context of branch Y?". In the latter case, we do indeed need to take
the upstream branch into account.
Basically, there are three different "levels" for this rewrite/publish
protection to run at:
1. Do not meddle at all. This is the current behavior, and assumes
that if the user rewrites and pushes something, the user knows what
he/she is doing, and Git should not meddle (obviously unless the
server refuses the push).
2. Warn/refuse rewriting commits in your upstream. This would only
check branch X against its registered upstream. Only if there is a
registered upstream, and you're about to rewrite commits that are
reachable from the upstream remote-tracking branch, should Git
intervene and warn/refuse the rewrite. This level would IMHO provide
most of the benefit, and little or no trouble (i.e. false positives).
3. Warn/refuse rewriting _any_ 'public' commit. Refuse to rewrite any
commit that is reachable from any remote-tracking branch. Some would
say that this is a Good Thing(tm), since it prevents a commit from
being _copied_ (i.e. rebased or cherry-picked) between branches (you'd
be in this camp if you run a tightly-controlled workflow, where you
e.g. mandate upmerging patches from the oldest applicable branch
instead of cherry-picking patches from a newer branch). However, other
people would say that this is too limiting, and imposes unnecessary
rules on the workflow of the project (where e.g. copying (by way of
git-rebase) a topic branch from one place to another would cause an
annoying false positive).
[...]
Have fun! :)
...Johan
--
Johan Herland, <johan@herland.net>
www.herland.net
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFD] Rewriting safety - warn before/when rewriting published history
2012-02-06 15:59 ` Johan Herland
@ 2012-02-06 17:14 ` Jakub Narebski
2012-02-06 20:16 ` Johan Herland
0 siblings, 1 reply; 34+ messages in thread
From: Jakub Narebski @ 2012-02-06 17:14 UTC (permalink / raw)
To: Johan Herland; +Cc: Philip Oakley, git
On Mon, 6 Feb 2012, Johan Herland wrote:
> On Mon, Feb 6, 2012 at 15:44, Jakub Narebski <jnareb@gmail.com> wrote:
> > On Sun, 5 Feb 2012, Johan Herland wrote:
> > Relying on (default) hooks to implement this feature has the disadvantage
> > that it wouldn't be turned on by default... while this feature would be
> > most helpful for users new to git (scared by refuse to push).
>
> True. I too believe that this will be most helpful if it is enabled by
> default. That said, the easiest way to get there might be through
> first demonstrating that it works in practice when implemented as
> hooks.
Yes, starting with prototype implementation using existing infrastructure
(hooks) would be a very good idea. (That's how first versions of what
became submodules were implemented.)
OTOH we should be aware of limitations of said prototype due to the fact
that it is a prototype...
> > I am not sure either if everything (wrt. safety net) can be implemented
> > via hooks. One thing that I forgot about is preventing rewinding of
> > branch past the published commit using e.g. "git reset --hard <commit>".
> > Unless `pre-rewrite` hook could be used for that safety too...
>
> Hmm. I don't think we'll be able to "plug" all the holes that might
> leave the user in a rewritten state (e.g. what if the user (possibly
> with the help of some tool) does an "echo $SHA1 >
> .git/refs/head/master"?).
First, I was thinking about having safety net against rewriting published
commits being present only in porcelain. Plumbing would be not affected
(perhaps there would be need to extend or add new plumbing to query "phase"
state, though).
> And trying to plug too many holes might end
> up annoying more experienced users who "know what they're doing".
Second, forcing via command line parameter should always be an option.
> Instead we might want to add a client-side check at push time. I
> realize that this check is already done by the remote end, but the
> client-side might be able to give a more helpful response along the
> lines of:
[...]
Explanation is good, but the whole idea of rewriting safety is that you
are informed (warned or denied) _before_ attempting rewrite and doing much
work.
> > > If you use 'git notes' to annotate 'public' and 'secret' states, then
> > > you can also use the --show-notes=<ref> option to let show/log display
> > > the annotations on 'public'/'secret' commits.
> >
> > First, in my opinion annotating _all_ commits with their phase is I think
> > out of question, especially annotating 'public' commits. I don't think
> > git-notes mechanism would scale well to annotating every commit; but
> > perhaps this was tested to work, and I am mistaken.
>
> First, we don't need to annotate _all_ commits. For the 'public'
> state, we only annotate the last/tip commit that was pushed/published.
> From there, we can defer that all ancestor commits are also 'public'.
Right.
> For the 'secret' state, we do indeed annotate _all_ secret commits,
> but I believe this will be a somewhat limited number of commits. If
> your workflow forces you to annotate millions of commits as 'secret',
> I claim there is something wrong with your workflow.
Well, for the 'secret' we can rely on the fact that child of 'secret'
commit must also be 'secret' (non-publishable) if secret is to stay
secret. Still marking all 'secret' commits might be better idea from
UI and from performance point of view.
> Second, git-notes were indeed designed scale well to handle a large
> number of notes, up to the same order of magnitude as the number of
> commits in your repo. (When git-notes was originally written, I
> successfully tested it on versions of a linux-kernel repo where every
> single commit was annotated).
Ah. That is very nice!
> In this case, the number of 'public'
> annotations in your repo would be equal to the number of pushes you
> do, and the number of 'secret' annotations would be equal to the
> number of 'secret' commits in your repo. I'd expect both of these
> numbers to be orders of magnitude smaller than the total number of
> commits in your repo (given a fairly typical workflow in a fairly
> typical repo).
Right.
> > Second, I have doubts if "phase" is really state of an individual commit,
> > and not the feature of revision walking.
It matters to presentation: can commit be simultaneously 'public' because
of one branch, and 'draft' because of other.
> I believe the 'public' state is a "feature of revision walking" (i.e.
> one annotated 'public' commit implies that all its ancestors are also
> 'public'). However, the 'secret' state should be bound to the
> individual commit, IMHO.
Good call, otherwise 'secret' commit could have been "side-leaked"
by other refs being pushed.
This means though that 'public' / 'draft' while looking similar to 'secret'
are in fact a bit different things. In other words 'immutable' and
'impushable' traits are quite a bit different in behavior...
Especially that one acts at pre-rewrite time, and second pre-push time.
> > Take for example the situation where given commit is reference by
> > remote-tracking branch 'public/foo', and also by two local branches:
> > 'foo' with upstream 'public/foo', and local branch 'bar' with no upstream.
> >
> > Now it is quite obvious that this feature should prevent rewriting 'foo'
> > branch, for which commits are published upstream. But what about branch
> > 'bar'? Should we prevent rewriting (e.g. rebase) here too? What about
> > rewinding 'bar' to point somewhere else. What if 'bar' is really detached
> > HEAD?
> >
> > These questions need to be answered...
>
> Good point. There are two questions we may need to answer: "Has commit
> X ever been published?", and "Has commit X ever been published in the
> context of branch Y?". In the latter case, we do indeed need to take
> the upstream branch into account.
I think the second one is more interested for rewrite safeties.
> Basically, there are three different "levels" for this rewrite/publish
> protection to run at:
>
> 1. Do not meddle at all. This is the current behavior, and assumes
> that if the user rewrites and pushes something, the user knows what
> he/she is doing, and Git should not meddle (obviously unless the
> server refuses the push).
I think that there should be some easy way to force such behavior,
i.e. to discard rewrite safeties.
> 2. Warn/refuse rewriting commits in your upstream. This would only
> check branch X against its registered upstream. Only if there is a
> registered upstream, and you're about to rewrite commits that are
> reachable from the upstream remote-tracking branch, should Git
> intervene and warn/refuse the rewrite. This level would IMHO provide
> most of the benefit, and little or no trouble (i.e. false positives).
Right. I wonder if we can get usage statistics from Mercurial users
about usage of their "phases" feature... though mapping terminology
for example 'upstream' from Git to Mercurial and vice versa can be
a pain, I guess.
> 3. Warn/refuse rewriting _any_ 'public' commit. Refuse to rewrite any
> commit that is reachable from any remote-tracking branch. Some would
> say that this is a Good Thing(tm), since it prevents a commit from
> being _copied_ (i.e. rebased or cherry-picked) between branches (you'd
> be in this camp if you run a tightly-controlled workflow, where you
> e.g. mandate upmerging patches from the oldest applicable branch
> instead of cherry-picking patches from a newer branch). However, other
> people would say that this is too limiting, and imposes unnecessary
> rules on the workflow of the project (where e.g. copying (by way of
> git-rebase) a topic branch from one place to another would cause an
> annoying false positive).
Well, we could always 'deny' on 2nd, and just 'warn' on 3rd...
--
Jakub Narebski
Poland
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFD] Rewriting safety - warn before/when rewriting published history
2012-02-06 17:14 ` Jakub Narebski
@ 2012-02-06 20:16 ` Johan Herland
2012-02-07 14:31 ` Jakub Narebski
0 siblings, 1 reply; 34+ messages in thread
From: Johan Herland @ 2012-02-06 20:16 UTC (permalink / raw)
To: Jakub Narebski; +Cc: Philip Oakley, git
On Mon, Feb 6, 2012 at 18:14, Jakub Narebski <jnareb@gmail.com> wrote:
> On Mon, 6 Feb 2012, Johan Herland wrote:
>> On Mon, Feb 6, 2012 at 15:44, Jakub Narebski <jnareb@gmail.com> wrote:
>> > Relying on (default) hooks to implement this feature has the disadvantage
>> > that it wouldn't be turned on by default... while this feature would be
>> > most helpful for users new to git (scared by refuse to push).
>>
>> True. I too believe that this will be most helpful if it is enabled by
>> default. That said, the easiest way to get there might be through
>> first demonstrating that it works in practice when implemented as
>> hooks.
>
> Yes, starting with prototype implementation using existing infrastructure
> (hooks) would be a very good idea. (That's how first versions of what
> became submodules were implemented.)
>
> OTOH we should be aware of limitations of said prototype due to the fact
> that it is a prototype...
Agreed, but AFAICS (and modulo the addition of pre-rewrite and
pre/post-push hooks mentioned earlier) all of the things discussed so
far in this thread can be implemented as hooks.
>> > I am not sure either if everything (wrt. safety net) can be implemented
>> > via hooks. One thing that I forgot about is preventing rewinding of
>> > branch past the published commit using e.g. "git reset --hard <commit>".
>> > Unless `pre-rewrite` hook could be used for that safety too...
>>
>> Hmm. I don't think we'll be able to "plug" all the holes that might
>> leave the user in a rewritten state (e.g. what if the user (possibly
>> with the help of some tool) does an "echo $SHA1 >
>> .git/refs/head/master"?).
>
> First, I was thinking about having safety net against rewriting published
> commits being present only in porcelain. Plumbing would be not affected
> (perhaps there would be need to extend or add new plumbing to query "phase"
> state, though).
I also think this is very much a porcelain-only feature. I'd be more
worried if plumbing changes were needed.
>> And trying to plug too many holes might end
>> up annoying more experienced users who "know what they're doing".
>
> Second, forcing via command line parameter should always be an option.
Obviously, but if a large portion of the Git community felt the need
to always disable this feature, I'd say that we'd failed. The best
features are those that Just Work(tm).
>> Instead we might want to add a client-side check at push time. I
>> realize that this check is already done by the remote end, but the
>> client-side might be able to give a more helpful response along the
>> lines of:
>
> [...]
>
> Explanation is good, but the whole idea of rewriting safety is that you
> are informed (warned or denied) _before_ attempting rewrite and doing much
> work.
True, but there may be cases where the rewrite is not apparent until
after it has happened. E.g. a novice user may use 'git reset --hard'
in order to get to an earlier state for testing purposes, and then -
after completing the test - 'git reset --hard' back to the starting
point. I know this is not best practice, but is it bad enough that we
want to refuse it?
>> First, we don't need to annotate _all_ commits. For the 'public'
>> state, we only annotate the last/tip commit that was pushed/published.
>> From there, we can defer that all ancestor commits are also 'public'.
>
> Right.
>
>> For the 'secret' state, we do indeed annotate _all_ secret commits,
>> but I believe this will be a somewhat limited number of commits. If
>> your workflow forces you to annotate millions of commits as 'secret',
>> I claim there is something wrong with your workflow.
>
> Well, for the 'secret' we can rely on the fact that child of 'secret'
> commit must also be 'secret' (non-publishable) if secret is to stay
> secret. Still marking all 'secret' commits might be better idea from
> UI and from performance point of view.
I don't think we should automatically assume that all children of a
'secret' commit are also 'secret'. First of all, the git DAG was not
made for iterating forwards in history, so given a 'secret' commit, it
is computationally expensive to enumerate all its implied-'secret'
descendants. More importantly though, I don't agree with the premise.
I would typically use the 'secret' state as follows: While debugging a
piece of code, I might commit a few debug print statements, and I
would typically mark this debug commit as 'secret', in order to
prevent myself from accidentally pushing this. Although it probably
doesn't matter in practice, I think it is wrong for the commits made
(temporarily) on top of this debug commit to be also considered
'secret'. They are only unpublishable as a consequence of being based
on the debug commit, and only until I get around to rebasing away the
'secret' debug commit.
>> > Second, I have doubts if "phase" is really state of an individual commit,
>> > and not the feature of revision walking.
>
> It matters to presentation: can commit be simultaneously 'public' because
> of one branch, and 'draft' because of other.
>
>> I believe the 'public' state is a "feature of revision walking" (i.e.
>> one annotated 'public' commit implies that all its ancestors are also
>> 'public'). However, the 'secret' state should be bound to the
>> individual commit, IMHO.
>
> Good call, otherwise 'secret' commit could have been "side-leaked"
> by other refs being pushed.
>
> This means though that 'public' / 'draft' while looking similar to 'secret'
> are in fact a bit different things. In other words 'immutable' and
> 'impushable' traits are quite a bit different in behavior...
>
> Especially that one acts at pre-rewrite time, and second pre-push time.
Exactly. I find Mercurial 'phase' language confusing, precisely for
the reason that 'public' and 'secret' are DIFFERENT concepts. One
hinders rewrite and naturally applies to a commit AND its ancestors,
while the other hinders push and only applies to the commit itself.
The fact that they could be implemented by the same mechanisms (hooks
and notes) does not make them the same thing.
>> > Take for example the situation where given commit is reference by
>> > remote-tracking branch 'public/foo', and also by two local branches:
>> > 'foo' with upstream 'public/foo', and local branch 'bar' with no upstream.
>> >
>> > Now it is quite obvious that this feature should prevent rewriting 'foo'
>> > branch, for which commits are published upstream. But what about branch
>> > 'bar'? Should we prevent rewriting (e.g. rebase) here too? What about
>> > rewinding 'bar' to point somewhere else. What if 'bar' is really detached
>> > HEAD?
>> >
>> > These questions need to be answered...
>>
>> Good point. There are two questions we may need to answer: "Has commit
>> X ever been published?", and "Has commit X ever been published in the
>> context of branch Y?". In the latter case, we do indeed need to take
>> the upstream branch into account.
>
> I think the second one is more interested for rewrite safeties.
>
>> Basically, there are three different "levels" for this rewrite/publish
>> protection to run at:
>>
>> 1. Do not meddle at all. This is the current behavior, and assumes
>> that if the user rewrites and pushes something, the user knows what
>> he/she is doing, and Git should not meddle (obviously unless the
>> server refuses the push).
>
> I think that there should be some easy way to force such behavior,
> i.e. to discard rewrite safeties.
Indeed. We should probably have a simple config flag to enable the
rewrite protection. In fact I would argue that the flag should default
to false (disable protection) when unset, and then we should let
init/clone set the config flag to true (enable protection) in newly
created repos (unless explicitly disabled in the user/system configs).
This way, behavior does not change for existing repos, but new repos
are protected by default (with only a single command needed to disable
the protection).
>> 2. Warn/refuse rewriting commits in your upstream. This would only
>> check branch X against its registered upstream. Only if there is a
>> registered upstream, and you're about to rewrite commits that are
>> reachable from the upstream remote-tracking branch, should Git
>> intervene and warn/refuse the rewrite. This level would IMHO provide
>> most of the benefit, and little or no trouble (i.e. false positives).
>
> Right. I wonder if we can get usage statistics from Mercurial users
> about usage of their "phases" feature... though mapping terminology
> for example 'upstream' from Git to Mercurial and vice versa can be
> a pain, I guess.
I'm unsure how useful it would be. IMHO Git and Mercurial are
different enough (and promote sightly different workflows) that I
don't trust the the average Mercurial user's preference for
Mercurial's 'phase' behavior to be transferable to the average Git
user's preference for a similar behavior in Git.
>> 3. Warn/refuse rewriting _any_ 'public' commit. Refuse to rewrite any
>> commit that is reachable from any remote-tracking branch. Some would
>> say that this is a Good Thing(tm), since it prevents a commit from
>> being _copied_ (i.e. rebased or cherry-picked) between branches (you'd
>> be in this camp if you run a tightly-controlled workflow, where you
>> e.g. mandate upmerging patches from the oldest applicable branch
>> instead of cherry-picking patches from a newer branch). However, other
>> people would say that this is too limiting, and imposes unnecessary
>> rules on the workflow of the project (where e.g. copying (by way of
>> git-rebase) a topic branch from one place to another would cause an
>> annoying false positive).
>
> Well, we could always 'deny' on 2nd, and just 'warn' on 3rd...
Good idea.
Have fun! :)
...Johan
--
Johan Herland, <johan@herland.net>
www.herland.net
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFD] Rewriting safety - warn before/when rewriting published history
2012-02-06 20:16 ` Johan Herland
@ 2012-02-07 14:31 ` Jakub Narebski
2012-02-07 15:09 ` Johan Herland
2012-02-07 17:27 ` Ronan Keryell
0 siblings, 2 replies; 34+ messages in thread
From: Jakub Narebski @ 2012-02-07 14:31 UTC (permalink / raw)
To: Johan Herland; +Cc: Philip Oakley, git
On Mon, 6 Feb 2012, Johan Herland wrote:
> On Mon, Feb 6, 2012 at 18:14, Jakub Narebski <jnareb@gmail.com> wrote:
>> On Mon, 6 Feb 2012, Johan Herland wrote:
>>> On Mon, Feb 6, 2012 at 15:44, Jakub Narebski <jnareb@gmail.com> wrote:
[...]
>> Yes, starting with prototype implementation using existing infrastructure
>> (hooks) would be a very good idea. (That's how first versions of what
>> became submodules were implemented.)
>>
>> OTOH we should be aware of limitations of said prototype due to the fact
>> that it is a prototype...
>
> Agreed, but AFAICS (and modulo the addition of pre-rewrite and
> pre/post-push hooks mentioned earlier) all of the things discussed so
> far in this thread can be implemented as hooks.
That would be nice.
And the new hooks (pre-rewrite, pre/post-push) would be useful anyway,
I think.
[...]
>>> And trying to plug too many holes might end
>>> up annoying more experienced users who "know what they're doing".
>>
>> Second, forcing via command line parameter should always be an option.
>
> Obviously, but if a large portion of the Git community felt the need
> to always disable this feature, I'd say that we'd failed. The best
> features are those that Just Work(tm).
Well, we have some features in git like advice.* that cater to newbies.
This could be such newbie-mostly feature too.
Anyway what I was thinking about is that forcing is for those hopefully
rare cases where Git safety net is too strict, where DWIM-mery fails.
>>> Instead we might want to add a client-side check at push time. I
>>> realize that this check is already done by the remote end, but the
>>> client-side might be able to give a more helpful response along the
>>> lines of:
>>
>> [...]
>>
>> Explanation is good, but the whole idea of rewriting safety is that you
>> are informed (warned or denied) _before_ attempting rewrite and doing much
>> work.
>
> True, but there may be cases where the rewrite is not apparent until
> after it has happened. E.g. a novice user may use 'git reset --hard'
> in order to get to an earlier state for testing purposes, and then -
> after completing the test - 'git reset --hard' back to the starting
> point. I know this is not best practice, but is it bad enough that we
> want to refuse it?
I'd like to have safety net also for using 'git reset --hard' to rewind
publishable branch past published history. Though preventing e.g. force
rename of other branch to publishable branch so it doesn't fast-forward
WRT its upstream would be going to far, I guess...
>>> First, we don't need to annotate _all_ commits. For the 'public'
>>> state, we only annotate the last/tip commit that was pushed/published.
>>> From there, we can defer that all ancestor commits are also 'public'.
>>
>> Right.
>>
>>> For the 'secret' state, we do indeed annotate _all_ secret commits,
>>> but I believe this will be a somewhat limited number of commits. If
>>> your workflow forces you to annotate millions of commits as 'secret',
>>> I claim there is something wrong with your workflow.
>>
>> Well, for the 'secret' we can rely on the fact that child of 'secret'
>> commit must also be 'secret' (non-publishable) if secret is to stay
>> secret. Still marking all 'secret' commits might be better idea from
>> UI and from performance point of view.
>
> I don't think we should automatically assume that all children of a
> 'secret' commit are also 'secret'.
All right. What is important is that safety net related to 'secret'
commits would prevent publishing such commits even if you build non-secret
commits on top of 'secret' one.
> First of all, the git DAG was not
> made for iterating forwards in history, so given a 'secret' commit, it
> is computationally expensive to enumerate all its implied-'secret'
> descendants.
Right, this would enormously complicate detecting 'secret'-ness of commit
when browsing history / querying "phase" of a commit..
> More importantly though, I don't agree with the premise.
> I would typically use the 'secret' state as follows: While debugging a
> piece of code, I might commit a few debug print statements, and I
> would typically mark this debug commit as 'secret', in order to
> prevent myself from accidentally pushing this. Although it probably
> doesn't matter in practice, I think it is wrong for the commits made
> (temporarily) on top of this debug commit to be also considered
> 'secret'. They are only unpublishable as a consequence of being based
> on the debug commit, and only until I get around to rebasing away the
> 'secret' debug commit.
Right, thanks for sanity check.
So another difference that in its full complexity the 'secret' is an
attribute of an individual commit which is (usually) local to repository,
while 'public' is in its full complexity an attribute of revision walking
rather than something that can be attached to a commit.
Also, when thinking about different scenarios of why one would like to
mark commit as 'secret', we might want to be able to mark commit as
secret / unpublishable with respect to _subset_ of remotes, so e.g.
I am prevented from accidentally publishing commits marked as 'secret'
to public repository, or to CI/QA repository, but I can push (perhaps
with warning) to group repository, together with 'secret'-ness state
of said commit...
... though it wouldn't be as much 'secret' as 'confidential' ;-)
>>>> Second, I have doubts if "phase" is really state of an individual commit,
>>>> and not the feature of revision walking.
>>
>> It matters to presentation: can commit be simultaneously 'public' because
>> of one branch, and 'draft' because of other.
>>
>>> I believe the 'public' state is a "feature of revision walking" (i.e.
>>> one annotated 'public' commit implies that all its ancestors are also
>>> 'public'). However, the 'secret' state should be bound to the
>>> individual commit, IMHO.
>>
>> Good call, otherwise 'secret' commit could have been "side-leaked"
>> by other refs being pushed.
>>
>> This means though that 'public' / 'draft' while looking similar to 'secret'
>> are in fact a bit different things. In other words 'immutable' and
>> 'impushable' traits are quite a bit different in behavior...
>>
>> Especially that one acts at pre-rewrite time, and second pre-push time.
>
> Exactly. I find Mercurial 'phase' language confusing, precisely for
> the reason that 'public' and 'secret' are DIFFERENT concepts. One
> hinders rewrite and naturally applies to a commit AND its ancestors,
> while the other hinders push and only applies to the commit itself.
> The fact that they could be implemented by the same mechanisms (hooks
> and notes) does not make them the same thing.
Well, if one doesn't think about all possible usages and complications,
the simplicity of metaphor of "phases" is quite compelling. We have
(at first glance)
public < draft < secret
states of a commit (changeset), just like we have
solid < liquid < gaseous
phases of matter.
If we treat traits of 'immutability' and 'publishability' as true boolean,
such ordering of "phases" looks natural. Just like matter goes from gas
to liquid to solid with lowering temperature, changeset "phase" goes from
'secret' to 'draft' to 'public' following ancestry chain.
But if we go for expressivity and power like the rest of Git, rather than
for simplicity like Mercurial does, the differences between 'secret'-ness
and 'public'-ness make it unlikely that it would be a good idea to encompass
those in a single UI and a single concept. I guess that it can be another
issue where Mercurial oversimplifies its approach (c.f. branches which
started from clone to branch and anonymous branches, to "named branches"
which are really commit labels, to local-only bookmark branches, to
transferrable Git-like bookmark branches but with single namespace, and
only just considering equivalent of Git's refspec and refs mapping; c.f.
revision ranges based on local numbering of commits which made ranges
local too, to new Git-like topological `--ancestry-path`-like ranges).
Also with per-remote 'secret'-ness, we might have the scenario where
a commit is marked as 'secret' for public repo, we have pushed it to
group repo (and it's 'secret'-ness trait together with it), an now we
want to be warned if we try to rewrite said commit.
So, separate traits it is (of revision walk, or of a commit), rather
than "smush-together" antity / attribute of "phase" of revision.
That is BTW why I wanted us to have this discussion... :-D
[...]
>>> Basically, there are three different "levels" for this rewrite/publish
>>> protection to run at:
>>>
>>> 1. Do not meddle at all. This is the current behavior, and assumes
>>> that if the user rewrites and pushes something, the user knows what
>>> he/she is doing, and Git should not meddle (obviously unless the
>>> server refuses the push).
>>
>> I think that there should be some easy way to force such behavior,
>> i.e. to discard rewrite safeties.
>
> Indeed. We should probably have a simple config flag to enable the
> rewrite protection. In fact I would argue that the flag should default
> to false (disable protection) when unset, and then we should let
> init/clone set the config flag to true (enable protection) in newly
> created repos (unless explicitly disabled in the user/system configs).
> This way, behavior does not change for existing repos, but new repos
> are protected by default (with only a single command needed to disable
> the protection).
And commit option for discarding safeties for specific push, or for
specific rewrite (e.g. pushed at night, noticed an error in commit
message, force-amended, and force-pushed again, hoping that the window
of opportunity is sufficintly small so that nobody will be affected).
>>> 2. Warn/refuse rewriting commits in your upstream. This would only
>>> check branch X against its registered upstream. Only if there is a
>>> registered upstream, and you're about to rewrite commits that are
>>> reachable from the upstream remote-tracking branch, should Git
>>> intervene and warn/refuse the rewrite. This level would IMHO provide
>>> most of the benefit, and little or no trouble (i.e. false positives).
>>
>> Right. I wonder if we can get usage statistics from Mercurial users
>> about usage of their "phases" feature... though mapping terminology
>> for example 'upstream' from Git to Mercurial and vice versa can be
>> a pain, I guess.
>
> I'm unsure how useful it would be. IMHO Git and Mercurial are
> different enough (and promote sightly different workflows) that I
> don't trust the the average Mercurial user's preference for
> Mercurial's 'phase' behavior to be transferable to the average Git
> user's preference for a similar behavior in Git.
Well, bad statistics might be better than no statistics. What would
be especially interesting is _complaints_ about "phases" feature,
don't you think, i.e. where the "phases" metaphor fails.
[...]
--
Jakub Narebski
Poland
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFD] Rewriting safety - warn before/when rewriting published history
2012-02-07 14:31 ` Jakub Narebski
@ 2012-02-07 15:09 ` Johan Herland
2012-02-10 19:38 ` Jakub Narebski
2012-04-07 14:49 ` Steven Michalske
2012-02-07 17:27 ` Ronan Keryell
1 sibling, 2 replies; 34+ messages in thread
From: Johan Herland @ 2012-02-07 15:09 UTC (permalink / raw)
To: Jakub Narebski; +Cc: Philip Oakley, git
(we are pretty much in violent agreement, so I will only comment where
I find it necessary)
On Tue, Feb 7, 2012 at 15:31, Jakub Narebski <jnareb@gmail.com> wrote:
> Also, when thinking about different scenarios of why one would like to
> mark commit as 'secret', we might want to be able to mark commit as
> secret / unpublishable with respect to _subset_ of remotes, so e.g.
> I am prevented from accidentally publishing commits marked as 'secret'
> to public repository, or to CI/QA repository, but I can push (perhaps
> with warning) to group repository, together with 'secret'-ness state
> of said commit...
>
> ... though it wouldn't be as much 'secret' as 'confidential' ;-)
Another way to achieve this would be to have a config flag to control
whether Git checks for the 'secret' flag before pushing. This config
flag could be set at the system/user level (to enable/disable the
feature as a whole), at the repo level (to enable/disable it in a
given repo), at the remote level (to enable/disable it on a given
repo), and finally at the branch level (to enable-disable it for a
given branch (and its upstream)). Thus you could have a .git/config
that looked like this:
[core]
refusePushSecret = true
[remote "foo"]
refusePushSecret = false
url = ...
fetch = ...
[branch "baz"]
remote = foo
merge = refs/heads/baz
refusePushSecret = true
This config would:
- refuse to push 'secret' commits from branch 'baz'
(branch.baz.refusePushSecret == true)
- but allow to push other branches with 'secret' commits to remote
'foo' (remote.foo.refusePushSecret == false)
- but refuse to push 'secret' commits to other remotes
(core.refusePushSecret == true)
(The order of precedence would be: branch config > remote config >
repo config > user config > system config > default when unset)
I am unsure whether the 'secret'-ness of a commit should follow across
the push, but if you do (assuming we store the 'secret' flag using
git-notes) this is simply a matter of synchronizing the
refs/notes/secret to the same remote.
Have fun! :)
...Johan
--
Johan Herland, <johan@herland.net>
www.herland.net
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFD] Rewriting safety - warn before/when rewriting published history
2012-02-07 14:31 ` Jakub Narebski
2012-02-07 15:09 ` Johan Herland
@ 2012-02-07 17:27 ` Ronan Keryell
1 sibling, 0 replies; 34+ messages in thread
From: Ronan Keryell @ 2012-02-07 17:27 UTC (permalink / raw)
To: Jakub Narebski; +Cc: git
>>>>> On Tue, 7 Feb 2012 15:31:07 +0100, Jakub Narebski <jnareb@gmail.com> said:
>> Agreed, but AFAICS (and modulo the addition of pre-rewrite and
>> pre/post-push hooks mentioned earlier) all of the things
>> discussed so far in this thread can be implemented as hooks.
Jakub> That would be nice.
Jakub> And the new hooks (pre-rewrite, pre/post-push) would be
Jakub> useful anyway, I think.
Yes, to deal with file metadata in git for example. :-)
--
Ronan KERYELL |\/ Phone: +1 408 844 4720
Wild Systems / HPC Project, Inc. |/) Cell: +33 613 143 766
5201 Great America Parkway #3241 K Ronan.Keryell@hpc-project.com
Santa Clara, CA 95054 |\ skype:keryell
USA | \ http://hpc-project.com
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFD] Rewriting safety - warn before/when rewriting published history
2012-02-07 15:09 ` Johan Herland
@ 2012-02-10 19:38 ` Jakub Narebski
2012-02-10 20:19 ` Philip Oakley
2012-02-11 13:10 ` Johan Herland
2012-04-07 14:49 ` Steven Michalske
1 sibling, 2 replies; 34+ messages in thread
From: Jakub Narebski @ 2012-02-10 19:38 UTC (permalink / raw)
To: Johan Herland; +Cc: Philip Oakley, git
On Tue, 7 Feb 2012, Johan Herland wrote:
> (we are pretty much in violent agreement, so I will only comment where
> I find it necessary)
So now comes the hard part: actually implementing (well, designing and
implementing) prototypes for 'secret' trait and 'public' trait...
> On Tue, Feb 7, 2012 at 15:31, Jakub Narebski <jnareb@gmail.com> wrote:
> > Also, when thinking about different scenarios of why one would like to
> > mark commit as 'secret', we might want to be able to mark commit as
> > secret / unpublishable with respect to _subset_ of remotes, so e.g.
> > I am prevented from accidentally publishing commits marked as 'secret'
> > to public repository, or to CI/QA repository, but I can push (perhaps
> > with warning) to group repository, together with 'secret'-ness state
> > of said commit...
> >
> > ... though it wouldn't be as much 'secret' as 'confidential' ;-)
>
> Another way to achieve this would be to have a config flag to control
> whether Git checks for the 'secret' flag before pushing. This config
> flag could be set at the system/user level (to enable/disable the
> feature as a whole), at the repo level (to enable/disable it in a
> given repo), at the remote level (to enable/disable it on a given
> repo), and finally at the branch level (to enable-disable it for a
> given branch (and its upstream)). Thus you could have a .git/config
> that looked like this:
>
> [core]
> refusePushSecret = true
>
> [remote "foo"]
> refusePushSecret = false
> url = ...
> fetch = ...
>
> [branch "baz"]
> remote = foo
> merge = refs/heads/baz
> refusePushSecret = true
>
> This config would:
>
> - refuse to push 'secret' commits from branch 'baz'
> (branch.baz.refusePushSecret == true)
>
> - but allow to push other branches with 'secret' commits to remote
> 'foo' (remote.foo.refusePushSecret == false)
>
> - but refuse to push 'secret' commits to other remotes
> (core.refusePushSecret == true)
>
> (The order of precedence would be: branch config > remote config >
> repo config > user config > system config > default when unset)
You read my mind.
> I am unsure whether the 'secret'-ness of a commit should follow across
> the push, but if you do (assuming we store the 'secret' flag using
> git-notes) this is simply a matter of synchronizing the
> refs/notes/secret to the same remote.
I think it should, so that 'secret' commit would not escape by accident
via a group secret repository.
What makes it hard (I think) is that we would prefer to transfer
'secret'-ness only for pushed commits. That might be problem for notes
based implementation of 'secret' annotation and 'secret'-ness transfer...
though I guess knowing that there exist 'secret' commit with given SHA1
which we do not have and should not have is not much breach of
confidentiality. Still...
--
Jakub Narebski
Poland
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFD] Rewriting safety - warn before/when rewriting published history
2012-02-10 19:38 ` Jakub Narebski
@ 2012-02-10 20:19 ` Philip Oakley
2012-02-11 13:10 ` Johan Herland
1 sibling, 0 replies; 34+ messages in thread
From: Philip Oakley @ 2012-02-10 20:19 UTC (permalink / raw)
To: Jakub Narebski, Johan Herland; +Cc: git
From: "Jakub Narebski" <jnareb@gmail.com> Sent: Friday, February 10, 2012
7:38 PM
> On Tue, 7 Feb 2012, Johan Herland wrote:
>
>> (we are pretty much in violent agreement, so I will only comment where
>> I find it necessary)
>
> So now comes the hard part: actually implementing (well, designing and
> implementing) prototypes for 'secret' trait and 'public' trait...
It all sounds very sensible.
The one additional implemenation idea I'd like is to have, which is somewhat
at a tangent to the secrecy issue, is having some record of what was pushed
(made Public). For the sub-module case this is so that its super project can
know if its submodules are public or not. A public super project that has
'secret' sub-modules is awkward to say the least.
That's my thought anyway...
>
>> On Tue, Feb 7, 2012 at 15:31, Jakub Narebski <jnareb@gmail.com> wrote:
>
>> > Also, when thinking about different scenarios of why one would like to
>> > mark commit as 'secret', we might want to be able to mark commit as
>> > secret / unpublishable with respect to _subset_ of remotes, so e.g.
>> > I am prevented from accidentally publishing commits marked as 'secret'
>> > to public repository, or to CI/QA repository, but I can push (perhaps
>> > with warning) to group repository, together with 'secret'-ness state
>> > of said commit...
>> >
>> > ... though it wouldn't be as much 'secret' as 'confidential' ;-)
>>
>> Another way to achieve this would be to have a config flag to control
>> whether Git checks for the 'secret' flag before pushing. This config
>> flag could be set at the system/user level (to enable/disable the
>> feature as a whole), at the repo level (to enable/disable it in a
>> given repo), at the remote level (to enable/disable it on a given
>> repo), and finally at the branch level (to enable-disable it for a
>> given branch (and its upstream)). Thus you could have a .git/config
>> that looked like this:
>>
>> [core]
>> refusePushSecret = true
>>
>> [remote "foo"]
>> refusePushSecret = false
>> url = ...
>> fetch = ...
>>
>> [branch "baz"]
>> remote = foo
>> merge = refs/heads/baz
>> refusePushSecret = true
>>
>> This config would:
>>
>> - refuse to push 'secret' commits from branch 'baz'
>> (branch.baz.refusePushSecret == true)
>>
>> - but allow to push other branches with 'secret' commits to remote
>> 'foo' (remote.foo.refusePushSecret == false)
>>
>> - but refuse to push 'secret' commits to other remotes
>> (core.refusePushSecret == true)
>>
>> (The order of precedence would be: branch config > remote config >
>> repo config > user config > system config > default when unset)
>
> You read my mind.
>
>> I am unsure whether the 'secret'-ness of a commit should follow across
>> the push, but if you do (assuming we store the 'secret' flag using
>> git-notes) this is simply a matter of synchronizing the
>> refs/notes/secret to the same remote.
>
> I think it should, so that 'secret' commit would not escape by accident
> via a group secret repository.
>
> What makes it hard (I think) is that we would prefer to transfer
> 'secret'-ness only for pushed commits. That might be problem for notes
> based implementation of 'secret' annotation and 'secret'-ness transfer...
> though I guess knowing that there exist 'secret' commit with given SHA1
> which we do not have and should not have is not much breach of
> confidentiality. Still...
>
> --
> Jakub Narebski
> Poland
> --
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
>
> -----
> No virus found in this message.
> Checked by AVG - www.avg.com
> Version: 2012.0.1913 / Virus Database: 2112/4801 - Release Date: 02/10/12
>
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFD] Rewriting safety - warn before/when rewriting published history
2012-02-10 19:38 ` Jakub Narebski
2012-02-10 20:19 ` Philip Oakley
@ 2012-02-11 13:10 ` Johan Herland
2012-02-11 13:45 ` Jakub Narebski
2012-04-07 15:01 ` [RFD] Rewriting safety - warn before/when rewriting published history Steven Michalske
1 sibling, 2 replies; 34+ messages in thread
From: Johan Herland @ 2012-02-11 13:10 UTC (permalink / raw)
To: Jakub Narebski; +Cc: Philip Oakley, git
On Fri, Feb 10, 2012 at 20:38, Jakub Narebski <jnareb@gmail.com> wrote:
> On Tue, 7 Feb 2012, Johan Herland wrote:
>> On Tue, Feb 7, 2012 at 15:31, Jakub Narebski <jnareb@gmail.com> wrote:
>> I am unsure whether the 'secret'-ness of a commit should follow across
>> the push, but if you do (assuming we store the 'secret' flag using
>> git-notes) this is simply a matter of synchronizing the
>> refs/notes/secret to the same remote.
>
> I think it should, so that 'secret' commit would not escape by accident
> via a group secret repository.
>
> What makes it hard (I think) is that we would prefer to transfer
> 'secret'-ness only for pushed commits. That might be problem for notes
> based implementation of 'secret' annotation and 'secret'-ness transfer...
> though I guess knowing that there exist 'secret' commit with given SHA1
> which we do not have and should not have is not much breach of
> confidentiality. Still...
If you don't want to transfer all of refs/notes/secret, you would
probably have to extend the git protocol with a per-commit 'secret'
flag (which would then be applied to the receiving repo's
refs/notes/secret).
Still, this is all specific to the 'secret' feature, which IMHO is
much less important then the 'public' feature. Implementing the
barebones 'public' feature (i.e. refuse rewrite of commits reachable
from upstream) is much less work, and would be enough for 90% of git
users, I believe.
...Johan
--
Johan Herland, <johan@herland.net>
www.herland.net
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFD] Rewriting safety - warn before/when rewriting published history
2012-02-11 13:10 ` Johan Herland
@ 2012-02-11 13:45 ` Jakub Narebski
2012-02-20 21:07 ` [RFC] pre-rebase: Refuse to rewrite commits that are reachable from upstream Johan Herland
2012-04-07 15:01 ` [RFD] Rewriting safety - warn before/when rewriting published history Steven Michalske
1 sibling, 1 reply; 34+ messages in thread
From: Jakub Narebski @ 2012-02-11 13:45 UTC (permalink / raw)
To: Johan Herland; +Cc: Philip Oakley, git
On Sat, 11 Feb 2012, Johan Herland wrote:
> On Fri, Feb 10, 2012 at 20:38, Jakub Narebski <jnareb@gmail.com> wrote:
> > On Tue, 7 Feb 2012, Johan Herland wrote:
[...]
> > > I am unsure whether the 'secret'-ness of a commit should follow across
> > > the push, but if you do (assuming we store the 'secret' flag using
> > > git-notes) this is simply a matter of synchronizing the
> > > refs/notes/secret to the same remote.
> >
> > I think it should, so that 'secret' commit would not escape by accident
> > via a group secret repository.
> >
> > What makes it hard (I think) is that we would prefer to transfer
> > 'secret'-ness only for pushed commits. That might be problem for notes
> > based implementation of 'secret' annotation and 'secret'-ness transfer...
> > though I guess knowing that there exist 'secret' commit with given SHA1
> > which we do not have and should not have is not much breach of
> > confidentiality. Still...
>
> If you don't want to transfer all of refs/notes/secret, you would
> probably have to extend the git protocol with a per-commit 'secret'
> flag (which would then be applied to the receiving repo's
> refs/notes/secret).
Or create per-remote custom notes ref, for example for 'foo' remote it
would be 'refs/remotes/foo/notes/secret'... assuming that canonalization
of remote-tracking refs goes in (refs/remotes/foo/{heads,tags,notes,replace})
This would be updated with 'secret'-ness state of comits being pushed
before actual push, and secretness notes ref would be pushed together
with actual push.
> Still, this is all specific to the 'secret' feature, which IMHO is
> much less important then the 'public' feature. Implementing the
> barebones 'public' feature (i.e. refuse rewrite of commits reachable
> from upstream) is much less work, and would be enough for 90% of git
> users, I believe.
Hmmm... I thought that is 'public' feature that is more work, especially
in full incarnation. But perhaps bare bones (no 'pre-push' or 'pre-rewrite'
hooks, no traits info in "git log" output, per remote tracking of 'public'
status only, no support for bundles or send-email, etc.) could be as easy
or easier.
As to what is more important for git users... perhaps short survey would
help here? I wonder if asking Mercurial users about their use of "phases"
on their mailing would help us...
--
Jakub Narebski
Poland
^ permalink raw reply [flat|nested] 34+ messages in thread
* [RFC] pre-rebase: Refuse to rewrite commits that are reachable from upstream
2012-02-11 13:45 ` Jakub Narebski
@ 2012-02-20 21:07 ` Johan Herland
2012-02-20 21:21 ` Johan Herland
2012-02-20 22:43 ` Junio C Hamano
0 siblings, 2 replies; 34+ messages in thread
From: Johan Herland @ 2012-02-20 21:07 UTC (permalink / raw)
To: git; +Cc: Johan Herland, gitster, jnareb, philipoakley
Teach the pre-rebase sample hook to refuse rewriting commits on a branch
that are present in that branch's @{upstream}. This is to prevent users
from rewriting commits that have already been published.
If the branch has no @{upstream}, or the commits-to-be-rebased are not
reachable from the upstream (hence assumed to be unpublished), the rebase
is not refused.
This patch is not an ideal solution to the problem, for at least the
following reasons:
- There is no way for the user to override this check, except skipping
the pre-rebase hook entirely with --no-verify.
- The check only works for branches with a configured upstream. If the
user's workflow does not rely on upstream branches, or uses some other
method of publishing commits, the check will produce false negatives
(i.e. allow rebases that should have been refused).
- The check only applies to rebase. I wanted to add the same check
on 'commit --amend', but there's no obvious way to detect --amend
from within the pre-commit hook.
- There may be other rewrite scenarios where we want to do this check,
such as 'git reset'. Maybe a pre-rewrite hook should be added?
- Some (including myself) want this check to be performed by default,
since it's mostly targeted at newbies that are less likely to enable
the pre-rebase (pre-rewrite) hook, so maybe the check should be added
to core git instead.
Discussed-with: Jakub Narebski <jnareb@gmail.com>
Signed-off-by: Johan Herland <johan@herland.net>
---
templates/hooks--pre-rebase.sample | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/templates/hooks--pre-rebase.sample b/templates/hooks--pre-rebase.sample
index 053f111..4c28b27 100755
--- a/templates/hooks--pre-rebase.sample
+++ b/templates/hooks--pre-rebase.sample
@@ -25,6 +25,20 @@ else
exit 0 ;# we do not interrupt rebasing detached HEAD
fi
+# Are we rewriting upstreamed commits?
+upstream=`git rev-parse --verify "${topic#refs/heads/}@{u}" 2>/dev/null`
+if test -n "$upstream"
+then
+ # See if any of the commits to be rebased are reachable from upstream.
+ basecommit=`git rev-parse --verify "$basebranch"`
+ mergebase=`git merge-base "$basecommit" "$upstream"`
+ if test "$basecommit" != "$upstream" -a "$basecommit" = "$mergebase"
+ then
+ echo >&2 "Cannot rebase commits that are in $topic's upstream"
+ exit 1
+ fi
+fi
+
case "$topic" in
refs/heads/??/*)
;;
--
1.7.9.1.314.ga9004
^ permalink raw reply related [flat|nested] 34+ messages in thread
* Re: [RFC] pre-rebase: Refuse to rewrite commits that are reachable from upstream
2012-02-20 21:07 ` [RFC] pre-rebase: Refuse to rewrite commits that are reachable from upstream Johan Herland
@ 2012-02-20 21:21 ` Johan Herland
2012-02-20 22:43 ` Junio C Hamano
1 sibling, 0 replies; 34+ messages in thread
From: Johan Herland @ 2012-02-20 21:21 UTC (permalink / raw)
To: git; +Cc: Johan Herland, gitster, jnareb, philipoakley
On Mon, Feb 20, 2012 at 22:07, Johan Herland <johan@herland.net> wrote:
> Teach the pre-rebase sample hook to refuse rewriting commits on a branch
> that are present in that branch's @{upstream}. This is to prevent users
> from rewriting commits that have already been published.
>
> If the branch has no @{upstream}, or the commits-to-be-rebased are not
> reachable from the upstream (hence assumed to be unpublished), the rebase
> is not refused.
>
> This patch is not an ideal solution to the problem, for at least the
> following reasons:
>
> - There is no way for the user to override this check, except skipping
> the pre-rebase hook entirely with --no-verify.
>
> - The check only works for branches with a configured upstream. If the
> user's workflow does not rely on upstream branches, or uses some other
> method of publishing commits, the check will produce false negatives
> (i.e. allow rebases that should have been refused).
>
> - The check only applies to rebase. I wanted to add the same check
> on 'commit --amend', but there's no obvious way to detect --amend
> from within the pre-commit hook.
>
> - There may be other rewrite scenarios where we want to do this check,
> such as 'git reset'. Maybe a pre-rewrite hook should be added?
>
> - Some (including myself) want this check to be performed by default,
> since it's mostly targeted at newbies that are less likely to enable
> the pre-rebase (pre-rewrite) hook, so maybe the check should be added
> to core git instead.
>
> Discussed-with: Jakub Narebski <jnareb@gmail.com>
> Signed-off-by: Johan Herland <johan@herland.net>
> ---
I forgot to explain that this patch is not really submitted for
inclusion, but rather to continue the discussion of getting rewrite
safety properly implemented in git. As such, the problems noted in the
above commit message are probably more important than the patch
itself...
Also, this implements only a small subset of what has been discussed
regarding 'public' and 'secret' properties of commits in the preceding
thread. However, I believe solving this part of the problem
(preventing upstreamed commits from being rewritten) will make 90% of
users happy, and that it's worth fixing on its own merits.
Have fun! :)
...Johan
--
Johan Herland, <johan@herland.net>
www.herland.net
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFC] pre-rebase: Refuse to rewrite commits that are reachable from upstream
2012-02-20 21:07 ` [RFC] pre-rebase: Refuse to rewrite commits that are reachable from upstream Johan Herland
2012-02-20 21:21 ` Johan Herland
@ 2012-02-20 22:43 ` Junio C Hamano
2012-02-21 0:03 ` Johan Herland
1 sibling, 1 reply; 34+ messages in thread
From: Junio C Hamano @ 2012-02-20 22:43 UTC (permalink / raw)
To: Johan Herland; +Cc: git, jnareb, philipoakley
Johan Herland <johan@herland.net> writes:
> Teach the pre-rebase sample hook to refuse rewriting commits on a branch
> that are present in that branch's @{upstream}. This is to prevent users
> from rewriting commits that have already been published.
If the user has configured an option to always create @{u} when creating a
branch from somewhere else, transplanting $n good commits from his master
that is forked from the shared master onto his maint would be done like
this:
$ git checkout -b copy master
$ git rebase -i --onto maint HEAD~$n
If these good commits have been published to 'master', because the
upstream of 'copy' is set to the local 'master', would the new mechanism
hinder this attempt to backport good fixes? Perhaps it is safer to
trigger only when @{u} exists and it is not local?
But because you wanted to discuss more about the issues than the
implementation, let me think aloud a bit, reviewing what I usually do.
I keep things simpler by sticking to a very simple rule. I allow myself to
rebase only what is not yet in 'next', so the logic becomes a simple "am I
creating a new commit based on what is already in 'next'?"
During the course of integration testing with 'next', however, I often
find a topic or two that I have merged to it is less than ideal, and of
course, the whole point of doing integration testing with 'next' is to
find such problematic topics before pushing 'next' out. I rewind 'next',
rebuild the problematic topics, and then rebuild 'next', and all of these
happen before 'next' is pushed out. The step that rewinds 'next' that
acquired problematic versions of the topics makes the topics eligible for
rebase.
That would mean that a configuration variable "rebase.bottomLimit = next"
is sufficient to implement such a check for me. No per-branch bottom is
needed, because everything is merged to 'next' and tested to see if they
do not need further rebases for fixing them up before they are published.
Perhaps "I mistakenly rebased something that I have already published" is
a mere symptom a bigger problem. The issue may not be that we do not give
them a good tool to help them to be more careful with less effort on their
part before they rebase. It may instead be that it is too easy to publish
branches that are not ready to be pushed out, and that is the real cause
of the "I realized I need to fix the topic and I fixed it, but I did not
realize that it was too late and I shouldn't have rebased" problem.
I wonder if it would be a more direct solution to the issue you are
raising to give them a good tool to help them to be more careful with less
effort on their part before they publish (not before they rebase).
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFC] pre-rebase: Refuse to rewrite commits that are reachable from upstream
2012-02-20 22:43 ` Junio C Hamano
@ 2012-02-21 0:03 ` Johan Herland
2012-02-21 7:44 ` Junio C Hamano
0 siblings, 1 reply; 34+ messages in thread
From: Johan Herland @ 2012-02-21 0:03 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, jnareb, philipoakley
On Mon, Feb 20, 2012 at 23:43, Junio C Hamano <gitster@pobox.com> wrote:
> Johan Herland <johan@herland.net> writes:
>> Teach the pre-rebase sample hook to refuse rewriting commits on a branch
>> that are present in that branch's @{upstream}. This is to prevent users
>> from rewriting commits that have already been published.
>
> If the user has configured an option to always create @{u} when creating a
> branch from somewhere else, transplanting $n good commits from his master
> that is forked from the shared master onto his maint would be done like
> this:
>
> $ git checkout -b copy master
> $ git rebase -i --onto maint HEAD~$n
>
> If these good commits have been published to 'master', because the
> upstream of 'copy' is set to the local 'master', would the new mechanism
> hinder this attempt to backport good fixes? Perhaps it is safer to
> trigger only when @{u} exists and it is not local?
Ah, you're talking about setting branch.autosetupmerge = always. I
didn't know about that until I looked it up, just now. My first
impression is "who would want to use that?", but since it's there, we
should not break it. So, yes, we should probably apply the check when
@{u} exists, and refers to a remote-tracking branch. (One could argue
that this is also unsafe, since the current repo is a perfectly valid
remote, but if you do that, I'd be inclined to let you shoot yourself
in the foot.)
Also, if this check becomes part of core git, we obviously want some
config option to en/disable it. Preferably at multiple levels, as
discussed earlier in this thread:
core.rewriteUpstream = refuse/false, warn, allow/true
(en/disables the check for the entire repo, but may be overridden by:)
remote.<name>.rewriteUpstream = refuse/false, warn, allow/true
(en/disables the check for branches whose upstream is the given
remote, but may be overridden by:)
branch.<name>.rewriteUpstream = refuse/false, warn, allow/true
(en/disables the check for the given local branch)
This allows fine-grained control of which branches/remotes you
consider 'public', and which are ok to rewrite.
> But because you wanted to discuss more about the issues than the
> implementation, let me think aloud a bit, reviewing what I usually do.
>
> I keep things simpler by sticking to a very simple rule. I allow myself to
> rebase only what is not yet in 'next', so the logic becomes a simple "am I
> creating a new commit based on what is already in 'next'?"
>
> During the course of integration testing with 'next', however, I often
> find a topic or two that I have merged to it is less than ideal, and of
> course, the whole point of doing integration testing with 'next' is to
> find such problematic topics before pushing 'next' out. I rewind 'next',
> rebuild the problematic topics, and then rebuild 'next', and all of these
> happen before 'next' is pushed out. The step that rewinds 'next' that
> acquired problematic versions of the topics makes the topics eligible for
> rebase.
>
> That would mean that a configuration variable "rebase.bottomLimit = next"
> is sufficient to implement such a check for me. No per-branch bottom is
> needed, because everything is merged to 'next' and tested to see if they
> do not need further rebases for fixing them up before they are published.
What you are describing here may be a common workflow, but
"rebase.bottomLimit" is still very specific to that kind of workflow.
What I'm after is a much more workflow-agnostic concept of:
"If I have pushed something, I should probably not rebase it"
I believe this rule is sufficiently common in most workflows to
warrant the addition of this safety-check to Git. (And making the
safety-check configurable caters to those that don't need/want it.)
> Perhaps "I mistakenly rebased something that I have already published" is
> a mere symptom a bigger problem. The issue may not be that we do not give
> them a good tool to help them to be more careful with less effort on their
> part before they rebase. It may instead be that it is too easy to publish
> branches that are not ready to be pushed out, and that is the real cause
> of the "I realized I need to fix the topic and I fixed it, but I did not
> realize that it was too late and I shouldn't have rebased" problem.
>
> I wonder if it would be a more direct solution to the issue you are
> raising to give them a good tool to help them to be more careful with less
> effort on their part before they publish (not before they rebase).
Yes, in many cases, the user will probably agree that the rewrite
should ideally have happened _before_ the branch was first published.
However, I'm not sure how we can help the user _not_ publish the
branch until it's ready. We could throw in a warning (or even a stupid
"Are you really sure you want to publish?") before pushing a branch,
but I don't think it would help at all.
I think the following decribes what often happens for many users:
1. User A pushes the branch to a public repo.
2. User B points out a simple mistake in the branch.
3. User A makes a fix
4. User A squashes the fix into the (already-published) history.
5. User A attempts to push the "fixed" history (but is rejected by
the public repo because of non-fast-forward).
At this point, the damage is already done, since often neither of the
following alternatives are desirable:
6a. (safe) User A realizes the error and undoes the history-rewrite
(this is not easy for novice users), leaving the fix on top of the
already-published history, and re-pushes a fast-forwarding history.
OR
6b. (dangerous) User A reattempts the push with --force. User B (and
user C, D, ...) is left to clean up the mess.
You could say that User A should be more careful and push to a "less
public" repo in step #1 (thus allowing the fix to be squashed before
pushing to a "more public" repo in step #5), but how "public" is
"public" enough to have someone point out the bug, but still
"unpublic" enough to allow rebase?
In general, I really cannot see any opportunity before step #4 where
we can stop (or warn) the user from what is about to happen. And I
think that refusing rewrites of commits that are already present in
the @{upstream} remote-tracking branch is good enough to help most
users avoid steps #4 through #6 (in a push-based workflow[1]). In
fact, from a pedagogical POV, I think step #4 is probably the best
spot for novice users to learn exactly the distinction between
acceptable and unacceptable history rewrites (instead of having it
explained to them as a consequence of the step #5).
Thanks for your insight,
...Johan
[1]: For non-push-based workflows (such as send-email, sharing
bundles, pulls from local repo, etc.) we will need other methods for
determining which commits have been published. This have been
discussed earlier in the thread, but is outside the scope of what I
want to accomplish for now.
--
Johan Herland, <johan@herland.net>
www.herland.net
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFC] pre-rebase: Refuse to rewrite commits that are reachable from upstream
2012-02-21 0:03 ` Johan Herland
@ 2012-02-21 7:44 ` Junio C Hamano
2012-02-21 23:23 ` Johan Herland
0 siblings, 1 reply; 34+ messages in thread
From: Junio C Hamano @ 2012-02-21 7:44 UTC (permalink / raw)
To: Johan Herland; +Cc: git, jnareb, philipoakley
Johan Herland <johan@herland.net> writes:
> What you are describing here may be a common workflow, but
> "rebase.bottomLimit" is still very specific to that kind of workflow.
> What I'm after is a much more workflow-agnostic concept of:
>
> "If I have pushed something, I should probably not rebase it"
Your "this branch pushes directly to that remote branch, so I can check if
it will result in rewrite of published commit" is even *less* generic than
having a single bottomLimit in my illustration.
I may not push out my topic branches directly, only the aggregate of them
in 'next', but once 'next' is pushed out, they are not eligible for
rebasing. A per-branch bottom, e.g. rebase.$branch.bottomLimit, might
make it more flexible to cover such a case, though.
On the other hand, without any such safety, a merge to 'next' would give
many conflicts and "shortlog master..next" will show many duplicates after
any topic that are already merged to it are accidentally rewritten, and it
is just the matter of using reflog on topic branches to recover from such
a mistake.
>> I wonder if it would be a more direct solution to the issue you are
>> raising to give them a good tool to help them to be more careful with less
>> effort on their part before they publish (not before they rebase).
>
> ..., I'm not sure how we can help the user _not_ publish the
> branch until it's ready.
I think we are in agreement that we do not think of a good solution
offhand to the real cause of the issue, except by encouraging the use of
throw-away review branches, perhaps.
> I think the following decribes what often happens for many users:
>
> 1. User A pushes the branch to a public repo.
> 2. User B points out a simple mistake in the branch.
That's the CVS workflow, and it is not "a" public repo but "the" public
repo shared between A and B (and also with all the project participants).
> 3. User A makes a fix
> 4. User A squashes the fix into the (already-published) history.
> 5. User A attempts to push the "fixed" history (but is rejected by
> the public repo because of non-fast-forward).
> At this point, the damage is already done,...
Which is probably a sufficient safety which the user can learn from. If
this happens too often, that probably means we are not helping them enough
to learn not to "commit --amend" or "rebase" if they are using Git as a
better CVS.
> You could say that User A should be more careful and push to a "less
> public" repo in step #1 (thus allowing the fix to be squashed before
> pushing to a "more public" repo in step #5),...
That is essentially a workflow that uses throw-away review branches in a
distributed environment, and at that point, we are not constrained by the
limitation of the CVS workflow. While still in early review cycles (which
corresponds to being in our 'pu'), "commit --amend" and "rebase" are fine
tool to be used. And...
> but how "public" is
> "public" enough to have someone point out the bug, but still
> "unpublic" enough to allow rebase?
... I can imagine that currently that is determined purely by project
convention. Perhaps there needs a way to mark throw-away review branches
like 'pu' (or saying the same thing from the different perspective, to
mark cast-in-stone integration branches like 'next') so that tools can
mechanically decide what should and should not be rewritten.
To extend the idea of promoting throw-away review branches further,
perhaps it might help if there is an easy way to let the users publish
their "master" to a branch that is not the "master" of the central shared
repository even in the CVS workflow (e.g. by default a push from user A
always goes to refs/review/A/master), and to have an option to "git push"
that makes it go to the "master" when the user really means the branch is
ready (and it would move refs/review/A/master to attic to be later gc'ed).
> ... And I
> think that refusing rewrites of commits that are already present in
> the @{upstream} remote-tracking branch is good enough to help most
> users avoid steps #4 through #6 (in a push-based workflow[1]).
See above regarding branches that should not be rebased even if they are
not directly pushed out.
> In
> fact, from a pedagogical POV, I think step #4 is probably the best
> spot for novice users to learn exactly the distinction between
> acceptable and unacceptable history rewrites (instead of having it
> explained to them as a consequence of the step #5).
I doubt you have enough information at point #4, unless you restrict the
workflow you allow your novice users to use fairly severely, to give
appropriate advice. While I agree with you that it would be the best if
we could do so at step #4 without stopping the user from doing what s/he
needs to do with false positive, I think it is not pedagogical POV but
dreaming if the world were ideal without knowing what it would take to
make it ideal.
At least I don't know offhand what kind of changes are needed to restrict
the user actions to an "approved" workflow so that step #4 can make a
useful decision (that is, no false positives and small enough false
negatives).
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFC] pre-rebase: Refuse to rewrite commits that are reachable from upstream
2012-02-21 7:44 ` Junio C Hamano
@ 2012-02-21 23:23 ` Johan Herland
2012-02-21 23:43 ` Junio C Hamano
0 siblings, 1 reply; 34+ messages in thread
From: Johan Herland @ 2012-02-21 23:23 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, jnareb, philipoakley
On Tue, Feb 21, 2012 at 08:44, Junio C Hamano <gitster@pobox.com> wrote:
> Johan Herland <johan@herland.net> writes:
>
>> What you are describing here may be a common workflow, but
>> "rebase.bottomLimit" is still very specific to that kind of workflow.
>> What I'm after is a much more workflow-agnostic concept of:
>>
>> "If I have pushed something, I should probably not rebase it"
>
> Your "this branch pushes directly to that remote branch, so I can check if
> it will result in rewrite of published commit" is even *less* generic than
> having a single bottomLimit in my illustration.
>
> I may not push out my topic branches directly, only the aggregate of them
> in 'next', but once 'next' is pushed out, they are not eligible for
> rebasing. A per-branch bottom, e.g. rebase.$branch.bottomLimit, might
> make it more flexible to cover such a case, though.
But you would have to maintain rebase.$branch.bottomLimit separately
for each topic branch, updating it whenever the topic branch is merged
to 'next'. Is that practical?
> On the other hand, without any such safety, a merge to 'next' would give
> many conflicts and "shortlog master..next" will show many duplicates after
> any topic that are already merged to it are accidentally rewritten, and it
> is just the matter of using reflog on topic branches to recover from such
> a mistake.
All true, but my experience is that novice users will not enjoy this
experience, and rather become frustrated with Git for "putting them in
this situation" (i.e. giving them more rope than they can handle).
Maybe I'm doing something wrong...
>>> I wonder if it would be a more direct solution to the issue you are
>>> raising to give them a good tool to help them to be more careful with less
>>> effort on their part before they publish (not before they rebase).
>>
>> ..., I'm not sure how we can help the user _not_ publish the
>> branch until it's ready.
>
> I think we are in agreement that we do not think of a good solution
> offhand to the real cause of the issue, except by encouraging the use of
> throw-away review branches, perhaps.
Agreed. We should probably focus more on this when teaching novice users.
>> I think the following decribes what often happens for many users:
>>
>> 1. User A pushes the branch to a public repo.
>> 2. User B points out a simple mistake in the branch.
>
> That's the CVS workflow, and it is not "a" public repo but "the" public
> repo shared between A and B (and also with all the project participants).
>
>> 3. User A makes a fix
>> 4. User A squashes the fix into the (already-published) history.
>> 5. User A attempts to push the "fixed" history (but is rejected by
>> the public repo because of non-fast-forward).
>> At this point, the damage is already done,...
>
> Which is probably a sufficient safety which the user can learn from. If
> this happens too often, that probably means we are not helping them enough
> to learn not to "commit --amend" or "rebase" if they are using Git as a
> better CVS.
>
>> You could say that User A should be more careful and push to a "less
>> public" repo in step #1 (thus allowing the fix to be squashed before
>> pushing to a "more public" repo in step #5),...
>
> That is essentially a workflow that uses throw-away review branches in a
> distributed environment, and at that point, we are not constrained by the
> limitation of the CVS workflow. While still in early review cycles (which
> corresponds to being in our 'pu'), "commit --amend" and "rebase" are fine
> tool to be used. And...
>
>> but how "public" is
>> "public" enough to have someone point out the bug, but still
>> "unpublic" enough to allow rebase?
>
> ... I can imagine that currently that is determined purely by project
> convention. Perhaps there needs a way to mark throw-away review branches
> like 'pu' (or saying the same thing from the different perspective, to
> mark cast-in-stone integration branches like 'next') so that tools can
> mechanically decide what should and should not be rewritten.
Yes. Maybe it should be a tri-state thing:
- "rebase-prone" will allow rewrites without asking.
- unset will warn, but still allow rewrites. The warning should
explain the potential problem that may arise from rewriting, and
should also explain how to get rid of the warning by setting this
config to either of the above/below options. Ideally the warning
should also explain how the user may undo the rewrite. Obviously, most
of this warning should be controlled by a corresponding advice.*
config.
- "cast-in-stone" will refuse rewrites.
I notice that this config is not really per-branch, but rather per
upstream branch. I wonder how to best encode that in the config...
Also, how a remote repo may best communicate which branches are
"rebase-prone"/"cast-in-stone".
> To extend the idea of promoting throw-away review branches further,
> perhaps it might help if there is an easy way to let the users publish
> their "master" to a branch that is not the "master" of the central shared
> repository even in the CVS workflow (e.g. by default a push from user A
> always goes to refs/review/A/master), and to have an option to "git push"
> that makes it go to the "master" when the user really means the branch is
> ready (and it would move refs/review/A/master to attic to be later gc'ed).
This goes against many workflows, and many users' expectations.
Although it may be a Good(tm) practice, I don't think it's universal
enough to be worth "breaking" 'push'. What about adding a new 'git
review' command which defaults to this behavior (but can be overridden
by Gerrit and other code-review systems to do what's appropriate in
their cases)?
>> ... And I
>> think that refusing rewrites of commits that are already present in
>> the @{upstream} remote-tracking branch is good enough to help most
>> users avoid steps #4 through #6 (in a push-based workflow[1]).
>
> See above regarding branches that should not be rebased even if they are
> not directly pushed out.
True. Is it universally acceptable to assume that a topic branch that
has been merged to a "cast-in-stone" branch, should not be
rebased/rewritten (unless forced by the user)?
There are several aspects to this: First, any commits on the topic
branch that have been made _since_ the merge should obviously be
rewritable (since they have yet to be merged). And commits made
_before_ the merge should probably not be rewritable. I.e. in the
following figure, the 'y' commits should be rewritable, but the 'x'
commits (preceding the merge 'M') should probably not.
--o---o---o---o---o---o---M <- master (cast-in-stone)
\ /
x---x---x---x---x---x---y---y <- topicA
But what if we have two topic branches with shared history, like this:
--o---o---o---o---o---o---M <- master (cast-in-stone)
\ /
x---x---x---x---x---x---y---y <- topicA
\
z---z <- topicB
We cannot say whether the 'x' commits "belong" to topicA or topicB.
Also, we cannot determine whether the merge M happened with topicA or
topicB (unless the default merge message has been preserved). Now,
given that we try to rewrite the entire topicB branch (including the
'x' commits): Should we refuse rewriting the 'x' commits because they
are reachable from master (regardless of whether topicA or topicB was
merged), or should we allow rewriting the 'x' commits on the basis
that topicA may be the branch that was merged in 'M', and since topicB
are "unaware" that the 'x' commits have been merged, it should thus be
allowed to rewrite them?
Now, what if you want to backport 'topicA' from 'master' to 'maint'.
You could do so like this:
git checkout -b topicA_maint topicA
git rebase --onto maint master
(note that topicA_maint is a special case of topicB in the above
graph) In this case, we would expect the 'x' commits to be rewritable,
or we could not perform the backport.
The conclusion seems to be that we _cannot_ refuse rewriting commits
merely on the basis that they have been merged to a cast-in-stone
branch.
>> In
>> fact, from a pedagogical POV, I think step #4 is probably the best
>> spot for novice users to learn exactly the distinction between
>> acceptable and unacceptable history rewrites (instead of having it
>> explained to them as a consequence of the step #5).
>
> I doubt you have enough information at point #4, unless you restrict the
> workflow you allow your novice users to use fairly severely, to give
> appropriate advice. While I agree with you that it would be the best if
> we could do so at step #4 without stopping the user from doing what s/he
> needs to do with false positive, I think it is not pedagogical POV but
> dreaming if the world were ideal without knowing what it would take to
> make it ideal.
>
> At least I don't know offhand what kind of changes are needed to restrict
> the user actions to an "approved" workflow so that step #4 can make a
> useful decision (that is, no false positives and small enough false
> negatives).
Ok, trying to make as few assumptions about user workflows as
possible: Assuming there were a (machine-parsable) way to mark
branches as either "rebase-prone" or "cast-in-stone". Could we then
assume that rebasing commits that exist on a cast-in-stone branch's
remote-tracking @{upstream} should be refused by default? I'm trying
(without much success, it seems) to find _something_ that will help
the 1525 users that want Git to "warn before/when rewriting published
history"[1], but won't cause any false positives (and small enough
false negatives). If there really is no way to implement this, then we
shouldn't give users false hopes by putting it in the survey...
Have fun! :)
...Johan
[1]: Question 17 in https://www.survs.com/results/Q5CA9SKQ/P7DE07F0PL
--
Johan Herland, <johan@herland.net>
www.herland.net
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFC] pre-rebase: Refuse to rewrite commits that are reachable from upstream
2012-02-21 23:23 ` Johan Herland
@ 2012-02-21 23:43 ` Junio C Hamano
2012-02-21 23:59 ` Dave Zarzycki
0 siblings, 1 reply; 34+ messages in thread
From: Junio C Hamano @ 2012-02-21 23:43 UTC (permalink / raw)
To: Johan Herland; +Cc: Junio C Hamano, git, jnareb, philipoakley
Johan Herland <johan@herland.net> writes:
> history"[1], but won't cause any false positives (and small enough
> false negatives). If there really is no way to implement this, then we
> shouldn't give users false hopes by putting it in the survey...
I think that question should be "warn before pushing out a commit that the
user may later regret to have pushed out" ;-)
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFC] pre-rebase: Refuse to rewrite commits that are reachable from upstream
2012-02-21 23:43 ` Junio C Hamano
@ 2012-02-21 23:59 ` Dave Zarzycki
2012-02-22 7:09 ` Jeff King
0 siblings, 1 reply; 34+ messages in thread
From: Dave Zarzycki @ 2012-02-21 23:59 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Johan Herland, git, jnareb, philipoakley
On Feb 21, 2012, at 6:43 PM, Junio C Hamano <gitster@pobox.com> wrote:
> Johan Herland <johan@herland.net> writes:
>
>> history"[1], but won't cause any false positives (and small enough
>> false negatives). If there really is no way to implement this, then we
>> shouldn't give users false hopes by putting it in the survey...
>
> I think that question should be "warn before pushing out a commit that the
> user may later regret to have pushed out" ;-)
Why limit this proposal to just the commits that are reachable from upstream? What if somebody pulls from your repo?
In other words, wouldn't it be better to have a git track "unshared" commits and only let those be rewritten? The theory being that if the given commits haven't been pushed or pulled anywhere, then they are safe to rewrite.
davez
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFC] pre-rebase: Refuse to rewrite commits that are reachable from upstream
2012-02-21 23:59 ` Dave Zarzycki
@ 2012-02-22 7:09 ` Jeff King
2012-02-22 8:00 ` Dave Zarzycki
0 siblings, 1 reply; 34+ messages in thread
From: Jeff King @ 2012-02-22 7:09 UTC (permalink / raw)
To: Dave Zarzycki; +Cc: Junio C Hamano, Johan Herland, git, jnareb, philipoakley
On Tue, Feb 21, 2012 at 06:59:38PM -0500, Dave Zarzycki wrote:
> > I think that question should be "warn before pushing out a commit that the
> > user may later regret to have pushed out" ;-)
>
> Why limit this proposal to just the commits that are reachable from
> upstream? What if somebody pulls from your repo?
>
> In other words, wouldn't it be better to have a git track "unshared"
> commits and only let those be rewritten? The theory being that if the
> given commits haven't been pushed or pulled anywhere, then they are
> safe to rewrite.
You don't necessarily know who has read from you. Depending on your
setup, the user running git code may not have write access to the
repository (e.g., Alice runs "git pull ~bob/project.git"). Where would
Alice write the list of commits she pulled so that when Bob later runs
git, he knows that she has pulled them?
There is also the issue of "dumb" transports in which no git code is
running on the remote repo at all (e.g., Alice fetches from Bob via dumb
http; Bob's server doesn't even have git at all).
There may be clever or complex ideas to tackle those problems, but I
suspect that handling push would cover most practical cases (e.g., in
the dumb http case, Bob's commits probably ended up on the server via
push). So perhaps it is a good place to start.
-Peff
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFC] pre-rebase: Refuse to rewrite commits that are reachable from upstream
2012-02-22 7:09 ` Jeff King
@ 2012-02-22 8:00 ` Dave Zarzycki
0 siblings, 0 replies; 34+ messages in thread
From: Dave Zarzycki @ 2012-02-22 8:00 UTC (permalink / raw)
To: Jeff King; +Cc: Junio C Hamano, Johan Herland, git, jnareb, philipoakley
On Feb 22, 2012, at 2:09 AM, Jeff King <peff@peff.net> wrote:
> On Tue, Feb 21, 2012 at 06:59:38PM -0500, Dave Zarzycki wrote:
>
>>> I think that question should be "warn before pushing out a commit that the
>>> user may later regret to have pushed out" ;-)
>>
>> Why limit this proposal to just the commits that are reachable from
>> upstream? What if somebody pulls from your repo?
>>
>> In other words, wouldn't it be better to have a git track "unshared"
>> commits and only let those be rewritten? The theory being that if the
>> given commits haven't been pushed or pulled anywhere, then they are
>> safe to rewrite.
>
> You don't necessarily know who has read from you. Depending on your
> setup, the user running git code may not have write access to the
> repository (e.g., Alice runs "git pull ~bob/project.git"). Where would
> Alice write the list of commits she pulled so that when Bob later runs
> git, he knows that she has pulled them?
>
> There is also the issue of "dumb" transports in which no git code is
> running on the remote repo at all (e.g., Alice fetches from Bob via dumb
> http; Bob's server doesn't even have git at all).
>
> There may be clever or complex ideas to tackle those problems, but I
> suspect that handling push would cover most practical cases (e.g., in
> the dumb http case, Bob's commits probably ended up on the server via
> push). So perhaps it is a good place to start.
Fair points. Honestly, I was thinking more about a developer pulling changes between locations within his or her control, say a laptop and a desktop, or simply between multiple clones on the same machine. In this scenario, it would be useful to warn the developer that: "[some of] the commits you are about to rewrite, while not in the upstream repository, have been replicated into other repositories within your control. These other repositories will not be rewritten. Are you sure you want to continue?"
davez
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFD] Rewriting safety - warn before/when rewriting published history
2012-02-06 13:45 ` Jakub Narebski
@ 2012-04-07 14:36 ` Steven Michalske
0 siblings, 0 replies; 34+ messages in thread
From: Steven Michalske @ 2012-04-07 14:36 UTC (permalink / raw)
To: Jakub Narebski; +Cc: git
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:
>
>> See inlined responses below.
>
> Is this comment necessary at all?
Oddly enough yes.
>
>> 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.
>
> 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...
>
>>> 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.
>
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.
>
>> 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.
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.
>
>> 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.
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.
>>
>> 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.
I don't work in the environment of the best practices. I most often work with a central authoritative repo.
>
>> 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.
>
>> 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.
>
> [...]
>>> 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
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFD] Rewriting safety - warn before/when rewriting published history
2012-02-07 15:09 ` Johan Herland
2012-02-10 19:38 ` Jakub Narebski
@ 2012-04-07 14:49 ` Steven Michalske
1 sibling, 0 replies; 34+ messages in thread
From: Steven Michalske @ 2012-04-07 14:49 UTC (permalink / raw)
To: Johan Herland; +Cc: Jakub Narebski, Philip Oakley, git
On Feb 7, 2012, at 11:09 PM, Johan Herland wrote:
> (we are pretty much in violent agreement, so I will only comment where
> I find it necessary)
>
> On Tue, Feb 7, 2012 at 15:31, Jakub Narebski <jnareb@gmail.com> wrote:
>> Also, when thinking about different scenarios of why one would like to
>> mark commit as 'secret', we might want to be able to mark commit as
>> secret / unpublishable with respect to _subset_ of remotes, so e.g.
>> I am prevented from accidentally publishing commits marked as 'secret'
>> to public repository, or to CI/QA repository, but I can push (perhaps
>> with warning) to group repository, together with 'secret'-ness state
>> of said commit...
>>
>> ... though it wouldn't be as much 'secret' as 'confidential' ;-)
>
> Another way to achieve this would be to have a config flag to control
> whether Git checks for the 'secret' flag before pushing. This config
> flag could be set at the system/user level (to enable/disable the
> feature as a whole), at the repo level (to enable/disable it in a
> given repo), at the remote level (to enable/disable it on a given
> repo), and finally at the branch level (to enable-disable it for a
> given branch (and its upstream)). Thus you could have a .git/config
> that looked like this:
>
> [core]
> refusePushSecret = true
>
> [remote "foo"]
> refusePushSecret = false
> url = ...
> fetch = ...
>
> [branch "baz"]
> remote = foo
> merge = refs/heads/baz
> refusePushSecret = true
>
> This config would:
>
> - refuse to push 'secret' commits from branch 'baz'
> (branch.baz.refusePushSecret == true)
>
> - but allow to push other branches with 'secret' commits to remote
> 'foo' (remote.foo.refusePushSecret == false)
>
> - but refuse to push 'secret' commits to other remotes
> (core.refusePushSecret == true)
>
> (The order of precedence would be: branch config > remote config >
> repo config > user config > system config > default when unset)
>
> I am unsure whether the 'secret'-ness of a commit should follow across
> the push, but if you do (assuming we store the 'secret' flag using
> git-notes) this is simply a matter of synchronizing the
> refs/notes/secret to the same remote.
>
I think this would allow teamwork on selected remotes!
Though after reading all the discussion on this thread I now feel that there are some different forms of secret.
Stuff you want to only exist on your repository, hacks, junk and stuff.
or
Material that should not go to your public facing repository.
or
A commit containing a file that is not for public consumption, but something you want tracked in the same repo.
This might be an incompatible concept; I cope with this by using a git submodule called internal in the code base, it works well.
>
> Have fun! :)
>
> ...Johan
>
> --
> Johan Herland, <johan@herland.net>
> www.herland.net
> --
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [RFD] Rewriting safety - warn before/when rewriting published history
2012-02-11 13:10 ` Johan Herland
2012-02-11 13:45 ` Jakub Narebski
@ 2012-04-07 15:01 ` Steven Michalske
1 sibling, 0 replies; 34+ messages in thread
From: Steven Michalske @ 2012-04-07 15:01 UTC (permalink / raw)
To: Johan Herland; +Cc: Jakub Narebski, Philip Oakley, git
On Feb 11, 2012, at 9:10 PM, Johan Herland wrote:
> On Fri, Feb 10, 2012 at 20:38, Jakub Narebski <jnareb@gmail.com> wrote:
>> On Tue, 7 Feb 2012, Johan Herland wrote:
>>> On Tue, Feb 7, 2012 at 15:31, Jakub Narebski <jnareb@gmail.com> wrote:
>>> I am unsure whether the 'secret'-ness of a commit should follow across
>>> the push, but if you do (assuming we store the 'secret' flag using
>>> git-notes) this is simply a matter of synchronizing the
>>> refs/notes/secret to the same remote.
>>
>> I think it should, so that 'secret' commit would not escape by accident
>> via a group secret repository.
>>
>> What makes it hard (I think) is that we would prefer to transfer
>> 'secret'-ness only for pushed commits. That might be problem for notes
>> based implementation of 'secret' annotation and 'secret'-ness transfer...
>> though I guess knowing that there exist 'secret' commit with given SHA1
>> which we do not have and should not have is not much breach of
>> confidentiality. Still...
>
> If you don't want to transfer all of refs/notes/secret, you would
> probably have to extend the git protocol with a per-commit 'secret'
> flag (which would then be applied to the receiving repo's
> refs/notes/secret).
Implementing these as bi-directional transfer of flag attributes might be a good working concept.
This way we could implement the public flag and later add the secret flag, and later add the foo flag.
I say bidirectional because if Tom and mary are working on a group project. Mary publishes a commit to the public repo.
When Tom pulls from Mary he should get the update for the flags that Mary published. If Mary pushes to Tom's repo it should update Tom's flags as well.
>
> Still, this is all specific to the 'secret' feature, which IMHO is
> much less important then the 'public' feature. Implementing the
> barebones 'public' feature (i.e. refuse rewrite of commits reachable
> from upstream) is much less work, and would be enough for 90% of git
> users, I believe.
>
>
There are two kinds of pushes. Those to public facing repositories and those to a private working repository. Like a build bot repo. Pushes to that repo might not want to mark a commit as public.
Steve
> ...Johan
>
> --
> Johan Herland, <johan@herland.net>
> www.herland.net
> --
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 34+ messages in thread
end of thread, other threads:[~2012-04-07 15:01 UTC | newest]
Thread overview: 34+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-02-04 19:45 [RFD] Rewriting safety - warn before/when rewriting published history Jakub Narebski
2012-02-05 14:33 ` Ben Walton
2012-02-05 15:05 ` Jakub Narebski
[not found] ` <CAFA910035B74E56A52A96097E76AC39@PhilipOakley>
2012-02-05 16:15 ` Jakub Narebski
2012-02-05 17:29 ` Johan Herland
2012-02-05 20:46 ` Jakub Narebski
2012-02-05 22:49 ` Johan Herland
2012-02-06 14:44 ` Jakub Narebski
2012-02-06 15:59 ` Johan Herland
2012-02-06 17:14 ` Jakub Narebski
2012-02-06 20:16 ` Johan Herland
2012-02-07 14:31 ` Jakub Narebski
2012-02-07 15:09 ` Johan Herland
2012-02-10 19:38 ` Jakub Narebski
2012-02-10 20:19 ` Philip Oakley
2012-02-11 13:10 ` Johan Herland
2012-02-11 13:45 ` Jakub Narebski
2012-02-20 21:07 ` [RFC] pre-rebase: Refuse to rewrite commits that are reachable from upstream Johan Herland
2012-02-20 21:21 ` Johan Herland
2012-02-20 22:43 ` Junio C Hamano
2012-02-21 0:03 ` Johan Herland
2012-02-21 7:44 ` Junio C Hamano
2012-02-21 23:23 ` Johan Herland
2012-02-21 23:43 ` Junio C Hamano
2012-02-21 23:59 ` Dave Zarzycki
2012-02-22 7:09 ` Jeff King
2012-02-22 8:00 ` Dave Zarzycki
2012-04-07 15:01 ` [RFD] Rewriting safety - warn before/when rewriting published history Steven Michalske
2012-04-07 14:49 ` Steven Michalske
2012-02-07 17:27 ` Ronan Keryell
2012-02-06 0:57 ` Steven Michalske
2012-02-06 6:53 ` Johan Herland
2012-02-06 13:45 ` Jakub Narebski
2012-04-07 14:36 ` Steven Michalske
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).