Hi everyone,
recently on IRC we had a case where someone had accidentally deleted
the "current" branch (i.e. thing pointed to by HEAD) by using "git push
origin :master". This broke the remote HEAD as well as the local
refs/remotes/origin/HEAD. Not good. I think we want to make it harder
to get into this situation.
Personally, without being aware of any potential counterindications, I
think the best solution from a usability point of view would
be to have receive-pack reject deletions of what's currently in HEAD.
The question is, of course: how do we go about situations where someone
actually wants to delete the branch HEAD points at?
1. reject deletion and point out a command to change HEAD first (I
don't think we've got a command to do this remotely; do we want one?)
2. automatically change HEAD to something else if there's any other
branch (eww)
3. accept the deletion but warn the user that she just broke the
repository (especially eww because it also breaks the local tracking
ref)
Any smart ideas?
-Jan
On Sat, Feb 7, 2009 at 5:27 PM, Jan Krüger [off-list ref] wrote:
Hi everyone,
recently on IRC we had a case where someone had accidentally deleted
the "current" branch (i.e. thing pointed to by HEAD) by using "git push
origin :master". This broke the remote HEAD as well as the local
refs/remotes/origin/HEAD. Not good. I think we want to make it harder
to get into this situation.
Personally, without being aware of any potential counterindications, I
think the best solution from a usability point of view would
be to have receive-pack reject deletions of what's currently in HEAD.
The question is, of course: how do we go about situations where someone
actually wants to delete the branch HEAD points at?
1. reject deletion and point out a command to change HEAD first (I
don't think we've got a command to do this remotely; do we want one?)
2. automatically change HEAD to something else if there's any other
branch (eww)
3. accept the deletion but warn the user that she just broke the
repository (especially eww because it also breaks the local tracking
ref)
Any smart ideas?
This was brought up before:
http://marc.info/?l=git&m=123254293910829&w=2
But I don't think it reached any conclusion.
--
Felipe Contreras
On Sun, 8 Feb 2009 00:05:05 +0200, Felipe Contreras
[off-list ref] wrote:
This was brought up before:
http://marc.info/?l=git&m=123254293910829&w=2
But I don't think it reached any conclusion.
Okay, somehow I missed that. To reiterate the things from that
discussion that I think are most reasonable:
1) a local broken symref should generally be ignored unless we actually
need the symref.
2) there should be a more convenient (porcelain) way to change a
refs/remotes/foo/HEAD symref, e.g. git remote set-default, possibly
with an option to re-sync from the remote head (we could even make
that an option for git remote update).
Regarding 2): if we managed to add an option to that to change the
remote HEAD, we could disallow deleting a remote branch that HEAD
points to, and refer to this command. I think the problem is that we
would have to add symref updating logic for all types of remote
protocols.
If people agree with these ideas I think I'll write up a couple of
patches to implement these changes. So, any protests?
-Jan
On Sun, Feb 08, 2009 at 01:18:02AM +0100, Jan Krüger wrote:
Okay, somehow I missed that. To reiterate the things from that
discussion that I think are most reasonable:
1) a local broken symref should generally be ignored unless we actually
need the symref.
I think this is almost as easy as:
diff --git a/refs.c b/refs.c
index 024211d..9601101 100644
--- a/refs.c
+++ b/refs.c
@@ -276,7 +276,6 @@ static struct ref_list *get_ref_dir(const char *base, struct ref_list *list)
continue;
}
if (!resolve_ref(ref, sha1, 1, &flag)) {
- error("%s points nowhere!", ref);
continue;
}
list = add_ref(ref, sha1, flag, list, NULL);
Since this is just called when enumerating all of the loose refs (via
get_loose_refs(), which is generally called from for_each_ref).
However, there is one other complication. rename_ref uses get_loose_refs
to check whether the destination space is available:
if (!is_refname_available(newref, oldref, get_loose_refs(), 0))
return 1;
so you can get funny behavior through:
git branch -m foo bar
when "bar" is a symref pointing to a non-existent ref. Of course, we are
not _changing_ that behavior, since we always just ignored that symref.
But we are removing the warning message that might clue the user that
something confusing is about to happen.
2) there should be a more convenient (porcelain) way to change a
refs/remotes/foo/HEAD symref, e.g. git remote set-default, possibly
with an option to re-sync from the remote head (we could even make
that an option for git remote update).
Yes, I think that is a good idea (optionally with a switch to just
re-grab the information from the remote).
Regarding 2): if we managed to add an option to that to change the
remote HEAD, we could disallow deleting a remote branch that HEAD
points to, and refer to this command. I think the problem is that we
would have to add symref updating logic for all types of remote
protocols.
Yes, the protocol support would make this a much bigger patch (and you
would have to handle the case where the remote side didn't support it).
But bear in mind that deleting the remote HEAD breaks things not just
for you, but for other people who are cloning that remote. Maybe we
should refuse such updates unless "-f" is given (similar to
non-fast-forward updates); I haven't looked to see if we even have the
remote's HEAD information during push, though.
If people agree with these ideas I think I'll write up a couple of
patches to implement these changes. So, any protests?
I say go for it.
-Peff