From: Junio C Hamano <hidden> Date: 2016-06-15 22:46:12
Daniel Barkalow [off-list ref] writes:
In fact, if you expect to be pushing to a non-bare repository, you
probably want to have HEAD contain the actual commit currently checked
out (instead of a reference to externally mutable storage), which you
can do with "git checkout refs/heads/master".
"git checkout master^0" is shorter ;-)
For people who do not follow the git list regularly, a "HEAD contain the
actual commit" is often called "detached".
Daniel Barkalow <barkalow <at> iabervon.org> writes:
quoted
In fact, if you expect to be pushing to a non-bare repository, you
probably want to have HEAD contain the actual commit currently checked
out (instead of a reference to externally mutable storage), which you
can do with "git checkout refs/heads/master".
"git checkout master^0" is shorter
For people who do not follow the git list regularly, a "HEAD contain the
actual commit" is often called "detached".
Could you have that done automatically?
Namely rather to denying push to a branch b where HEAD->b, when you get such
push you detach head?
If you set 'detach' option, this clueless user is not helped; he will
happily keep working and would make tons of commits on detached HEAD,
and next time he switches to another branch, will lose all of them.
I guess that git does not let you commit on a detached head without
crying out loud.
Furthermore, one could do just a bit more than detaching, namely store
the fact that head got detached and the name of the branch where the
head was.
With this, when the unconscious user types git status or git commit the
system could alert him that head got detached because someone updated
the branch behind his shoulders from remote... and then suggest the
option to either create a new branch from the detached head (I believe
that this is what gets suggested anyway when one tries to commit from a
detached head) or to stash the current tree status, get back onto the
former branch and try applying the changes on the new head of the branch.
The flag triggering this warning at a git status or git commit command
should then be cleared at the first occasion when the head is changed.
To me this seems natural and helpful. Am I missing something?
Sergio
From: Johannes Schindelin <hidden> Date: 2016-06-15 22:46:12
Hi,
On Mon, 16 Feb 2009, Sergio Callegari wrote:
Jeff King wrote:
quoted
If you set 'detach' option, this clueless user is not helped; he will
happily keep working and would make tons of commits on detached HEAD,
and next time he switches to another branch, will lose all of them.
I guess that git does not let you commit on a detached head without
crying out loud.
Wrong. It cries out loud when you detach, not when you commit to a
detached HEAD. For good reason: Already at the second commit it would
stop being funny.
Furthermore, one could do just a bit more than detaching, namely store
the fact that head got detached and the name of the branch where the
head was. With this, when the unconscious user types git status or git
commit the system could alert him that head got detached because someone
updated the branch behind his shoulders from remote...
And of course, you need a way to show the user all the updates the branch
went through while the HEAD was detached, so that the user has a chance of
understanding what happened in the meantime.
So much additional work, just to fix up the shortcomings of the 'detach'
paradigm? I take it as a clear mark of a not-so-elegant design.
Ciao,
Dscho
From: Jay Soffian <hidden> Date: 2016-06-15 22:46:12
On Mon, Feb 16, 2009 at 12:43 PM, Johannes Schindelin
[off-list ref] wrote:
And of course, you need a way to show the user all the updates the branch
went through while the HEAD was detached, so that the user has a chance of
understanding what happened in the meantime.
So much additional work, just to fix up the shortcomings of the 'detach'
paradigm? I take it as a clear mark of a not-so-elegant design.
You did plant a seed in my head with PUSH_HEAD though, and I'm still
thinking about it. :-)
I think the right thing is *not to detach*, but rather when pushing
into a non-bare repo for it to go into refs/remotes. Too bad clone
doesn't set it up this way by default when cloning from a non-bare
repo[*]. That would probably make more sense for new users.
[*] Clone can't currently know it's cloning from a non-bare repo, at
least via git://, as I recall...
j.
Wrong. It cries out loud when you detach, not when you commit to a
detached HEAD. For good reason: Already at the second commit it would
stop being funny.
Right, I was wrong in expecting complaints. But... if it cried out at
the first commit, for many people there would probably not be a second.
Btw, I am ignorant on this: is there some case where one wants and has
reasons to commit to a detached head before making a temporary branch on it?
quoted
Furthermore, one could do just a bit more than detaching, namely store
the fact that head got detached and the name of the branch where the
head was. With this, when the unconscious user types git status or git
commit the system could alert him that head got detached because someone
updated the branch behind his shoulders from remote...
And of course, you need a way to show the user all the updates the branch
went through while the HEAD was detached, so that the user has a chance of
understanding what happened in the meantime.
So much additional work, just to fix up the shortcomings of the 'detach'
paradigm? I take it as a clear mark of a not-so-elegant design.
Well not that much additional work...
when you push to the checked out branch, head gets detached and branch
name (say /ref/heads/master) gets stored (say in .git/pre_push_branch).
when you run status or commit, you realize that there is a
pre_push_branch and you give the warning, saying what the
pre_push_branch was.
Now, since before the push you were at the tip of that branch, to know
what happened it should be enough to ask the log (or the diff) from
pre_push_branch to HEAD.
At the first user command that moves HEAD, pre_push_branch should get
deleted.
Btw, what does happen now if you delete the branch the remote worktree
is on? Don't you get a "dangling" head pointing to a non-existing branch
and the system claiming that it is at the initial commit? Maybe, this
too is a bit inelegant. In the other scenario, you would get a detached
head and in pre_push_branch the info the name of a no more existing
branch (mainig clear that you were on a branch that got deleted) and
this info could be returned to the user.
Of course, I am not claiming that forbidding pushes to branches with
checked out tree is bad. It is a good idea in my opinion.
I am just suggesting that one still wanting to allow that push in spite
of all the potential consequences (namely wanting to mess with the
relevant config variable), might prefer detaching head, storing the
pre_push_branch and getting some info on status and commit rather than
merely allowing the push.
In fact, I believe that the point is that with the current push-allowing
behavior, when the push happens you loose the information about the
precise commit against which the changes in the worktree were made.
Which might be a useful piece of info.
Ciao,
Sergio
From: Jay Soffian <hidden> Date: 2016-06-15 22:46:13
On Mon, Feb 16, 2009 at 3:02 PM, Johannes Schindelin
[off-list ref] wrote:
Hi,
On Mon, 16 Feb 2009, Jay Soffian wrote:
quoted
I think the right thing is *not to detach*, but rather when pushing
into a non-bare repo for it to go into refs/remotes.
I do not think that is consistent.
Not consistent with what?
So let's say I have a workstation and a laptop. The "sane" thing to do
is probably something like this:
workstation$ mkdir project && cd project && git init
workstation$ (add, commit, ...)
workstation$ git clone --bare . ../project.git
workstation$ git remote add origin ../project.git
laptop$ git clone ssh://workstation/~/project.git project
And now I have two non-bare working repos with the intermediate bare
repo. So at both ends I can push/pull in the way that the designers of
git had in mind. :-)
But I don't think this recipe is well documented for beginners. So
they end up w/o the intermediate bare repository, and all the ensues.
IOW, I think pushing into refs/remotes makes sense in the situation
where the user has two non-bare repos that they want to exchange
commits between.
j.
From: Johannes Schindelin <hidden> Date: 2016-06-15 22:46:13
Hi,
On Mon, 16 Feb 2009, Sergio Callegari wrote:
Johannes Schindelin wrote:
quoted
Wrong. It cries out loud when you detach, not when you commit to a
detached HEAD. For good reason: Already at the second commit it would
stop being funny.
Right, I was wrong in expecting complaints. But... if it cried out at
the first commit, for many people there would probably not be a second.
What you are suggesting, though, is that the _pusher_ detaches the HEAD.
So the _local_ user will never know.
Btw, I am ignorant on this: is there some case where one wants and has
reasons to commit to a detached head before making a temporary branch on
it?
Yes. When you try fixups on a commit you just jumped to, for example. Or
when bisecting.
I often use the detached HEAD as kind of a stash during a bisect. I try
to fix it there, at the bad commit, and then cherry-pick HEAD@{1} into
the branch after resetting the bisect.
quoted
quoted
Furthermore, one could do just a bit more than detaching, namely
store the fact that head got detached and the name of the branch
where the head was. With this, when the unconscious user types git
status or git commit the system could alert him that head got
detached because someone updated the branch behind his shoulders
from remote...
And of course, you need a way to show the user all the updates the branch
went through while the HEAD was detached, so that the user has a chance of
understanding what happened in the meantime.
So much additional work, just to fix up the shortcomings of the
'detach' paradigm? I take it as a clear mark of a not-so-elegant
design.
Well not that much additional work...
when you push to the checked out branch, head gets detached and branch name
(say /ref/heads/master) gets stored (say in .git/pre_push_branch).
when you run status or commit, you realize that there is a pre_push_branch and
you give the warning, saying what the pre_push_branch was.
Of course, you assume there that it was only one push between detaching
the HEAD and inspecting the mess.
Now, since before the push you were at the tip of that branch, to know
what happened it should be enough to ask the log (or the diff) from
pre_push_branch to HEAD. At the first user command that moves HEAD,
pre_push_branch should get deleted.
And you call that not much work?
Btw, what does happen now if you delete the branch the remote worktree
is on?
See the related discussion of receive.denyDeleteCurrent.
Ciao,
Dscho
From: Jay Soffian <hidden> Date: 2016-06-15 22:46:13
On Mon, Feb 16, 2009 at 3:09 PM, Johannes Schindelin
[off-list ref] wrote:
What you are suggesting, though, is that the _pusher_ detaches the HEAD.
So the _local_ user will never know.
I'm going to be presumptuous here and say that I think that you're
thinking about this the wrong way.
I would wager that when someone is pushing into a non-bare repo, it is
very likely that the pusher and the local user are the same person.
i.e., there are two common combinations: 1) a shared bare repo; 2) an
individual (non-shared) non-bare repo.
I think it is the shared non-bare repo which is rather uncommon, and
used mostly by advanced users or for specialized situations like
publishing web-roots.
If I'm right, then I still think that what might better sense is:
non-bare repo non-bare repo
------------------- ---------------------
refs/heads ---push--> refs/remotes/incoming
^ |
| merge
merge |
| v
refs/remotes/origin <--fetch-- refs/heads
Yes, you can set this up, but it is quite a few extra steps to do so.
The defaults assume there is a bare repo that you're pulling/pushing
from/to, hence the confusion for new users when that's not the
scenario they are in.
But instead of all this talk, maybe I should pony up some RFC patches. :-)
j.
From: Junio C Hamano <hidden> Date: 2016-06-15 22:46:13
Sergio Callegari [off-list ref] writes:
... is there some case where one wants
and has reasons to commit to a detached head before making a temporary
branch on it?
Absolutely. I do it all the time for minor fix-ups after applying other's
patches on a newly created topic branch.
If you want a push to the current branch of _your_ repository detach HEAD
automatically and record which branch it was pointing at before you
detached, I am reasonably sure you can do that in post-receive hook, no?
I do not think it is such a bad thing to have a new value 'detach' to
receive.denyCurrentBranch as a possible non-default choice per-se, but the
earlier discussion Jeff pointed out is only showing that detaching alone
is not enough to help the user recover from the resulting state, and Dscho
discussed in this thread that detaching and recording the original branch
may not be enough either. IOW, we do not know yet precisely what needs to
happen other than detaching HEAD when the configuration tells us to
'detach' to be useful.
So how about you experiment the workflow by setting the configuration to
'ignore', setting up a hook to detach _and do some other useful things_ as
necessary, and help all of us figuring out what other information is
useful to record when you receive such a push, and what new indications
you could give users to reduce the possibility of confusion? Once we know
what we want to happen, we can have it as one of the canned choices and it
would help users.
From: Jay Soffian <hidden> Date: 2016-06-15 22:46:13
On Mon, Feb 16, 2009 at 4:15 PM, Johannes Schindelin
[off-list ref] wrote:
quoted
Not consistent with what?
With pushing into bare repositories. And worse, with the existing mode of
operation.
I don't understand why pushing into a bare repo should have the same
behavior as pushing into a non-bare repo. They are different workflows
after-all.
j.
From: Jeff King <hidden> Date: 2016-06-15 22:46:13
On Mon, Feb 16, 2009 at 01:43:03PM -0800, Junio C Hamano wrote:
Sergio Callegari [off-list ref] writes:
quoted
... is there some case where one wants
and has reasons to commit to a detached head before making a temporary
branch on it?
Absolutely. I do it all the time for minor fix-ups after applying other's
patches on a newly created topic branch.
This question got me thinking. At the time that detached HEAD was
introduced, I argued for a loud warning message, claiming that for most
users, commiting on a detached HEAD was dangerous and unintentional and
there _should_ be a big warning message. And like then, committing on a
detached HEAD is still not something I generally do.
But then I realized there is actually one time: during interactive
rebase, which detaches HEAD during the rebase processs, and then puts
the final detached value back into the branch ref for you (or not, if
you abort).
Which made me think how such a process interacts with pushing into a
non-bare repo. If we are detached, the push cannot, by definition, touch
the ref pointed to by HEAD, since ther isn't one. But there is still
some sense of "current branch" recorded by rebase; after the rebase is
completed, it attempts to put a new value in the ref.
So this is still some conflict possible even with the current safety
valves. Fortunately, the ref update is smart enough to realize the value
has changed behind our back:
$ git rebase --continue
error: Ref refs/heads/master is at 5836aa51b217a1c88f32107cbcd606bece018657 but expected d2d7bf3fcaa927ef997dbcdaf9d9a9e176d6a8d0
fatal: Cannot lock the ref 'refs/heads/master'.
But that doesn't give any hint to the user about what happened, or how
to fix it.
So:
1. How can we improve this situation?
One option is including "the branch we are rebasing on" in the list
of refs to deny. I don't like that, though, because that becomes an
ever-growing list of places for receive-pack to look, some of which
are not even part of core git.
I think the best bet is just detecting the situation (which we
already do) and giving a sane recipe for resolution. Probably
something like:
git branch incoming master ;# stash newly pushed changes
git branch -f master $old_sha1 ;# restore previous state
git rebase --continue ;# finish the rebase
git merge incoming ;# pull in the pushed changes
2. Are there other "we are implicitly assuming $ref won't change
behind our backs" long-term commands?
-Peff
From: Jeff King <hidden> Date: 2016-06-15 22:46:13
On Mon, Feb 16, 2009 at 05:28:38PM -0500, Jay Soffian wrote:
On Mon, Feb 16, 2009 at 4:15 PM, Johannes Schindelin
[off-list ref] wrote:
quoted
quoted
Not consistent with what?
With pushing into bare repositories. And worse, with the existing mode of
operation.
I don't understand why pushing into a bare repo should have the same
behavior as pushing into a non-bare repo. They are different workflows
after-all.
Actually, I think it is pulling from the non-bare repo that will get
confusing.
You are proposing to push, when pushing into a non-bare repo, into a
push refspec like refs/incoming/ (for example). But what is your fetch
refspec?
If it fetches as usual from refs/heads/, then you have an asymmetry.
That is, if I do "git push" on one client, then "git pull" on another
won't fetch the changes. I have to wait for the non-bare repo to pull
them into its refs/heads/ hierarchy (one by one, if there are multiple
branches).
So you can try putting refs/incoming into your fetch refspec if it is a
non-bare repo. But there are two issues there:
- how do you know the remote is non-bare?
- now you have to "push" in the non-bare upstream in order to make
commits available. So it no longer works to do:
workstation$ cd repo && hack hack hack && commit commit commit
laptop$ git clone workstation:repo
since you will silently end up with stale results.
In some ways, this is nicely rigorous: non-bare repos become
essentially "uncontactable" remotely, and you have a de facto bare
repo in the form of refs/incoming sitting in between. But I'm not
sure it matches what most users want to do, and certainly it causes
more breakage to their workflows than receive.denyCurrentBranch.
-Peff
What you are suggesting, though, is that the _pusher_ detaches the HEAD.
So the _local_ user will never know.
I am not sure that I get what you mean. But if I get it right, the only
reason why the local
user cannot know is precisely because "git commit" does not complain if
you call it from a detached head.
Otherwise the local user would find out that a push happened behind his
shoulder right at the first "status" or "commit", as he was expecting to
be on a branch and he finds himself off it.
quoted
Btw, I am ignorant on this: is there some case where one wants and has
reasons to commit to a detached head before making a temporary branch on
it?
Yes. When you try fixups on a commit you just jumped to, for example. Or
when bisecting.
I often use the detached HEAD as kind of a stash during a bisect. I try
to fix it there, at the bad commit, and then cherry-pick HEAD@{1} into
the branch after resetting the bisect.
Interesting. But it is sort of abusing the detached head thing, isn't
it? You use it as a temporary unnamed branch, and it becomes the tip of
a short-lived development burst... It is not anymore just a way to peek
at some status as I remember it was initially introduced, is it?
quoted
quoted
quoted
Furthermore, one could do just a bit more than detaching, namely
store the fact that head got detached and the name of the branch
where the head was. With this, when the unconscious user types git
status or git commit the system could alert him that head got
detached because someone updated the branch behind his shoulders
from remote...
And of course, you need a way to show the user all the updates the branch
went through while the HEAD was detached, so that the user has a chance of
understanding what happened in the meantime.
So much additional work, just to fix up the shortcomings of the
'detach' paradigm? I take it as a clear mark of a not-so-elegant
design.
Well not that much additional work...
when you push to the checked out branch, head gets detached and branch name
(say /ref/heads/master) gets stored (say in .git/pre_push_branch).
when you run status or commit, you realize that there is a pre_push_branch and
you give the warning, saying what the pre_push_branch was.
Of course, you assume there that it was only one push between detaching
the HEAD and inspecting the mess.
After the first push, the head is already detached, so pre_push_branch
does not get touched by the second, the third, the forth push, etc...
Which I guess is what the local user should want. He expected to be at
some commit at the tip of some branch and he needs to find out what has
happened between that commit and the new tip of that branch. Does he
really need to know in how many and what precise push operations the
branch tip moved?
quoted
Now, since before the push you were at the tip of that branch, to know
what happened it should be enough to ask the log (or the diff) from
pre_push_branch to HEAD. At the first user command that moves HEAD,
pre_push_branch should get deleted.
And you call that not much work?
quoted
Btw, what does happen now if you delete the branch the remote worktree
is on?
I tried. With current git 1.6.1.3, head remains pointing at a non
existent branch and git status thinks that you need to do your initial
commit.
When you commit, the deleted branch is immediately recreated from
scratch and you loose the history that got you at that status.
Which brings me back to my former consideration.
I initially thought of detaching head because it looks like a way to
save a bit of info that I would like to see preserved. When someone
pushes in my repo, if my current branch tip moves, at the first action
that I attempt on the repo I would like to see a big alert that it did
and have an easy way to find out at what commit I was before the push
happened. Otherwise, I cannot really find out what the push precisely
changed, I cannot easily revert it if it was wrong, etc.
Sergio
From: Johannes Schindelin <hidden> Date: 2016-06-15 22:46:13
Hi,
On Tue, 17 Feb 2009, Sergio Callegari wrote:
Johannes Schindelin wrote:
quoted
What you are suggesting, though, is that the _pusher_ detaches the
HEAD. So the _local_ user will never know.
the only reason why the local user cannot know is precisely because "git
commit" does not complain if you call it from a detached head.
No, the only reason is that you sneakily detached the HEAD behind his
back. It is not possible in physical life -- at least not without the
owner of the head noticing -- and it should not be possible with Git,
either.
All this "we need more complaining" is just a fix up for a failed design.
quoted
quoted
Btw, I am ignorant on this: is there some case where one wants and
has reasons to commit to a detached head before making a temporary
branch on it?
Yes. When you try fixups on a commit you just jumped to, for example.
Or when bisecting.
I often use the detached HEAD as kind of a stash during a bisect. I
try to fix it there, at the bad commit, and then cherry-pick HEAD@{1}
into the branch after resetting the bisect.
Interesting. But it is sort of abusing the detached head thing, isn't
it? You use it as a temporary unnamed branch,
That is exactly what a detached HEAD is.
quoted
Of course, you assume there that it was only one push between
detaching the HEAD and inspecting the mess.
After the first push, the head is already detached, so pre_push_branch
does not get touched by the second, the third, the forth push, etc...
Oh, so the user should be really fscked for not realizing just how much
happened in the meantime?
quoted
quoted
Now, since before the push you were at the tip of that branch, to
know what happened it should be enough to ask the log (or the diff)
from pre_push_branch to HEAD. At the first user command that moves
HEAD, pre_push_branch should get deleted.
quoted
And you call that not much work?
That point is still valid. If you have to do too much to make your idea
work, if you have to bolt on this and that, it is a sure sign that the
design is borked.
quoted
quoted
Btw, what does happen now if you delete the branch the remote
worktree is on?
I tried. With current git 1.6.1.3, head remains pointing at a non
existent branch and git status thinks that you need to do your initial
commit. When you commit, the deleted branch is immediately recreated
from scratch and you loose the history that got you at that status.
As I remarked already, this is a bug that is actively being squashed.
Of course, you can go on and on and on with the detached HEAD ide, but so
far you haven't convinced me that this is a sensible thing to do.
Ciao,
Dscho
Of course, you can go on and on and on with the detached HEAD ide, but so
far you haven't convinced me that this is a sensible thing to do.
I will not... it's time to sleep where I am! And I am just a user of git
and you are a developer, which makes me think that you might know much
better.
But the exchange was insightful, thanks.
Rather, I'll turn again the question...
Let us assume that I am working on branch B and that my worktree is
based on commit XYZ. Let's also assume that someone pushes behind my
shoulders and moves the tip of B (or even deletes B alltogether) either
in one or in multiple pushes. Is there an easy way so that I can now
find out at what commit (XYZ) I was before the push(es)? That would
already make me quite satisfied, because with this I can write wrappers
or aliases that can check the HEAD against that commit on every
status/commit operation and warn the user just in case.
Sergio
From: Johannes Schindelin <hidden> Date: 2016-06-15 22:46:13
Hi,
On Tue, 17 Feb 2009, Sergio Callegari wrote:
Let us assume that I am working on branch B and that my worktree is based on
commit XYZ. Let's also assume that someone pushes behind my shoulders and
moves the tip of B (or even deletes B alltogether) either in one or in
multiple pushes. Is there an easy way so that I can now find out at what
commit (XYZ) I was before the push(es)?
Nope. There was code flying around at some stage to record in the index
what commit it was based on.
I forgot why it was thrown out again; you'll have to look up the
discussion yourself.
Ciao,
Dscho
From: Jay Soffian <hidden> Date: 2016-06-15 22:46:13
On Mon, Feb 16, 2009 at 5:52 PM, Jeff King [off-list ref] wrote:
Actually, I think it is pulling from the non-bare repo that will get
confusing.
You are proposing to push, when pushing into a non-bare repo, into a
push refspec like refs/incoming/ (for example). But what is your fetch
refspec?
If it fetches as usual from refs/heads/, then you have an asymmetry.
That is, if I do "git push" on one client, then "git pull" on another
won't fetch the changes. I have to wait for the non-bare repo to pull
them into its refs/heads/ hierarchy (one by one, if there are multiple
branches).
So you can try putting refs/incoming into your fetch refspec if it is a
non-bare repo. But there are two issues there:
- how do you know the remote is non-bare?
- now you have to "push" in the non-bare upstream in order to make
commits available. So it no longer works to do:
workstation$ cd repo && hack hack hack && commit commit commit
laptop$ git clone workstation:repo
since you will silently end up with stale results.
In some ways, this is nicely rigorous: non-bare repos become
essentially "uncontactable" remotely, and you have a de facto bare
repo in the form of refs/incoming sitting in between. But I'm not
sure it matches what most users want to do, and certainly it causes
more breakage to their workflows than receive.denyCurrentBranch.
My head is playing around with two ideas now that Dscho has mentioned:
receive.localBranches = (refuse | allow)
http://thread.gmane.org/gmane.comp.version-control.git/77955/focus=78065
And PUSH_HEAD.
The idea would be for side-pushes never to update a local branch, but
to be recorded in PUSH_HEAD. You'd be able to rebase/merge local
branch on-top of changes in PUSH_HEAD. I'm trying to figure out what
can make sense when pulling from such a repo.
j.
In the meantime, we have receive.denyCurrentBranch, which is much superior
to the localBranches design: it tackles the _real_ issue -- the only
reason why a current branch cannot be updated lightly is that it might
have a working directory which would be forced out-of-sync.
And PUSH_HEAD.
The idea would be for side-pushes never to update a local branch, but to
be recorded in PUSH_HEAD. You'd be able to rebase/merge local branch
on-top of changes in PUSH_HEAD. I'm trying to figure out what can make
sense when pulling from such a repo.
Sorry, I should clarify what I mean by PUSH_HEAD:
The idea is to have the _same_ as FETCH_HEAD, i.e. a simple file
(.git/FETCH_HEAD) listing all the branch tips that have been pushed, _no
matter_ if they were successfully stored as refs.
Just do this in a repository which is lagging behind origin a little:
$ git fetch origin
and then see that a file .git/FETCH_HEAD exists. As long as you are only
interested in the first rev, you can even use "FETCH_HEAD" as a rev name:
$ git show FETCH_HEAD
The important feature of this method is that FETCH_HEAD is not fetchable.
Neither 'ls-remote' nor 'branch' will show it.
BTW a PUSH_HEAD could also help the issue that when updating of a ref was
refused, all the objects will have to be transferred via the wire again
when pushing somewhere else.
Having said all that, I can easily live without PUSH_HEAD.
Ciao,
Dscho
In the meantime, we have receive.denyCurrentBranch, which is much superior
to the localBranches design: it tackles the _real_ issue -- the only
reason why a current branch cannot be updated lightly is that it might
have a working directory which would be forced out-of-sync.
Hmpfh.
So both you and Junio have changed your mind since that thread then.
Because in that thread, you propose receive.guardCurrentBranch, which
was quite similar to today's receive.denyCurrentBranch. Junio then
argues that treating just the checked-out branch as special, as
opposed to all local branches is not the right thing to do:
--- snip ---
http://thread.gmane.org/gmane.comp.version-control.git/77955/focus=78062
Step back a bit and think _why_ you wanted to prevent current branch tip
from getting updated in the first place. There are two issues:
* Why is it _current_ branch, and not _these branches_, that can be
configured by the user to be protected from a push from sideways?
* Why is it undesirable for the work tree and the index to go out of sync
with respect to the branch tip to begin with?
The latter is simpler to answer, so let's deal with it first. The reason
why it is bad is because allowing a push to the current branch interferes
with the work actively being done in the repository, using the work tree
contents. There is a person, you, who is actively editing the work tree
in order to advance the tip of the branch by making commits. If the
branch tip moves without your knowing, that destabilizes your working
environment. Your work tree wanted to make a new commit on top of some
known state, but that state was moved underneath you. Not good.
When you are using the repository for real work (i.e. advance the tips of
its branches), you want a stable environment. You do not want its HEAD
bobbing around outside your control, and silently detaching to cause your
later commits to go to unnamed branch without your knowing is just as bad
(which you already correctly objected to).
Now think. What if one of these operations you do in the repository to
advance the tip was to merge from one of _your_ local branches? Yes,
you end up merging something you did not expect to merge if you allowed
a push from sideways to affect that local branch, only because the
branch happened to be un-checked-out and you implemented this protection
to forbid only to current branch. Allowing a push from sideways to any
local branch destabilizes your work environment, not just the current
one.
Okay, I am starting to see the light.
How about
receive.localBranches = (refuse | allow)
--- snip ---
Then the thread died, with receive.localBranches going into TODO, but
never got an implementation. Sometime later, receive.denyCurrentBranch
came along, which is the original idea you proposed, Junio argued
against, and then you agreed.
So, I'm not sure what happened in the intervening time between the
receive.localBranches proposal and the receive.denyCurrentBranch
implementation that suddenly what is basically guardCurrentBranch
became a good idea.
But, I happen to agree with Junio's argument in gmane 77955.
j.
From: Jeff King <hidden> Date: 2016-06-15 22:46:13
On Tue, Feb 17, 2009 at 12:29:53PM -0500, Jay Soffian wrote:
So both you and Junio have changed your mind since that thread then.
Because in that thread, you propose receive.guardCurrentBranch, which
was quite similar to today's receive.denyCurrentBranch. Junio then
argues that treating just the checked-out branch as special, as
opposed to all local branches is not the right thing to do:
I have to admit, I found that thread a very interesting read, because I
somehow missed it the first time and it seemed the opposite of what
happened later.
So, I'm not sure what happened in the intervening time between the
receive.localBranches proposal and the receive.denyCurrentBranch
implementation that suddenly what is basically guardCurrentBranch
became a good idea.
I think what happened (partially) is that I never read the original,
then at GitTogether somebody (Sam?) was complaining about usability
issues, so I wrote the denyCurrentBranch patch. Why and how people
changed their minds is a mystery to me, though.
-Peff
PS I seem to have an uncanny knack for writing a patch, then finding out
that Dscho wrote the exact same patch months or years earlier. I think
this is the third time it has happened.
From: Junio C Hamano <hidden> Date: 2016-06-15 22:46:13
Jay Soffian [off-list ref] writes:
So both you and Junio have changed your mind since that thread then.
At least I didn't.
I personally was not too worried about protecting either local branches
nor the current branch (and I do not lose sleep over them now either).
Either is about forbidding an end user who knows from doing an operation
we have allowed so far, only because an abuse of the feature by other end
users who either don't know what they are doing or are careless can result
in confusing the latter. I do not particularly like that kind of safety
valve.
The current round of protecting only local branches is there because it is
of much lessor impact, with simpler code (and easier revertibility if
needed), than the full blown "protect these branches" one in which issues
in its design still has to be ironed out if we go that route (see my other
message from yesterday to Jeff --- we discuss exactly that in the context
of detached HEAD and other operations). The need for "current branch
protection" this round implements also comes from an observed confusions
in real world users Dscho and others saw on #git and other places. The
more general "protect these branches" is conceptually nicer but the need
for such safeguard is still under discussion as far as I understood what
was said in the recent discussions.
From: Jay Soffian <hidden> Date: 2016-06-15 22:46:13
On Tue, Feb 17, 2009 at 5:20 PM, Junio C Hamano [off-list ref] wrote:
Jay Soffian [off-list ref] writes:
quoted
So both you and Junio have changed your mind since that thread then.
At least I didn't.
Ah, I didn't mean to mischaracterize your intent from that thread then.
I personally was not too worried about protecting either local branches
nor the current branch (and I do not lose sleep over them now either).
Either is about forbidding an end user who knows from doing an operation
we have allowed so far, only because an abuse of the feature by other end
users who either don't know what they are doing or are careless can result
in confusing the latter. I do not particularly like that kind of safety
valve.
The current round of protecting only local branches is there because it is
of much lessor impact, with simpler code (and easier revertibility if
needed), than the full blown "protect these branches" one in which issues
in its design still has to be ironed out if we go that route (see my other
message from yesterday to Jeff --- we discuss exactly that in the context
of detached HEAD and other operations). The need for "current branch
protection" this round implements also comes from an observed confusions
in real world users Dscho and others saw on #git and other places. The
more general "protect these branches" is conceptually nicer but the need
for such safeguard is still under discussion as far as I understood what
was said in the recent discussions.