Re: git push to a non-bare repository

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

Re: git push to a non-bare repository

From: Junio C Hamano <hidden>
Date: 2016-06-15 22:43:00

Theodore Tso [off-list ref] writes:
Is it at all possible to figure out <commit-id-before-the-push>?  It
seems the answer is no, and I suspect that's a bug.
Doesn't update hook get pre- and post- commit object name?

Re: git push to a non-bare repository

From: Shawn O. Pearce <hidden>
Date: 2016-06-15 22:43:00

Junio C Hamano [off-list ref] wrote:
Theodore Tso [off-list ref] writes:
quoted
Is it at all possible to figure out <commit-id-before-the-push>?  It
seems the answer is no, and I suspect that's a bug.
Doesn't update hook get pre- and post- commit object name?
Yes, and the same is true in the new post-receive hook.

-- 
Shawn.

Re: git push to a non-bare repository

From: Theodore Tso <tytso@mit.edu>
Date: 2016-06-15 22:43:00

On Sun, Mar 18, 2007 at 10:21:43PM -0400, Shawn O. Pearce wrote:
Junio C Hamano [off-list ref] wrote:
quoted
Theodore Tso [off-list ref] writes:
quoted
Is it at all possible to figure out <commit-id-before-the-push>?  It
seems the answer is no, and I suspect that's a bug.
Doesn't update hook get pre- and post- commit object name?
Yes, and the same is true in the new post-receive hook.
In my comments, I was observing that *after* the push had succeeded,
there was no way to find the commit-id-before-the-push, since neither
the reflog nor ORIG_HEAD is getting updated.  Is there a good reason
why not?  Would you accept a patch which caused the reflog and
possibly ORIG_HEAD to be updated on the remote side of the push?


When I was talking about a hook to enforce the BitKeeper semantics,
the question is whether we have enough to enforce the following:

	* Only accept the push if it will result in a fast-forward
		merge (and if not, tell the user to do a git pull, merge
		locally, and then redo the git push)
	* Only accept the push if there are no locally modified files
		that would be affected when the working directory is
		updated to reflect the new HEAD

I don't think there's any easy way to determine if these two criteria
would be met besides trying to actually do the merge, and if it fails
atomically back out to the original starting point, right?  Or am I
missing something painfully obvious?

Since one of the applications where I might want to do something like
this is a push a web site being maintained by git (where I don't want
any the result of the interim attempted to merge to accidentally get
seen by the web server), probably in order to do this right I'd have
to have the hook script do a cp -rl of the repository+working tree to
some scratch space, try to do the merge and update of the working
tree, and if it succeeds, allow it to happen for real in the "live"
tree, and if not, fail the merge.  This seems awfully kludgy; is there
some other way?

						- Ted

Re: git push to a non-bare repository

From: Shawn O. Pearce <hidden>
Date: 2016-06-15 22:43:00

Theodore Tso [off-list ref] wrote:
On Sun, Mar 18, 2007 at 10:21:43PM -0400, Shawn O. Pearce wrote:
quoted
Junio C Hamano [off-list ref] wrote:
quoted
Theodore Tso [off-list ref] writes:
quoted
Is it at all possible to figure out <commit-id-before-the-push>?  It
seems the answer is no, and I suspect that's a bug.
Doesn't update hook get pre- and post- commit object name?
Yes, and the same is true in the new post-receive hook.
In my comments, I was observing that *after* the push had succeeded,
there was no way to find the commit-id-before-the-push, since neither
the reflog nor ORIG_HEAD is getting updated.  Is there a good reason
why not?  Would you accept a patch which caused the reflog and
possibly ORIG_HEAD to be updated on the remote side of the push?
The reflog does update if the log file exists during a push (err,
actually during receive-pack).  Or if core.logAllRefUpdates is set
to true.  Now this isn't the default in a bare repository, but it
should be the default in a repository with a working directory.
So the case we are talking about should be seeing the reflog update.
 
When I was talking about a hook to enforce the BitKeeper semantics,
the question is whether we have enough to enforce the following:

	* Only accept the push if it will result in a fast-forward
		merge (and if not, tell the user to do a git pull, merge
		locally, and then redo the git push)
Yes, the update hook can detect this.  Actually receive-pack by
default rejects *all* non-fast-forward pushes, even if the client
side uses --force.
	* Only accept the push if there are no locally modified files
		that would be affected when the working directory is
		updated to reflect the new HEAD
The update hook could also perform this check; test if the ref
being updated is the current branch, and if so, verify the index and
working directory is clean.  That's a simple run of git-symbolic-ref
(to get the current branch) and git-runstatus (to check the index
and working directory), is it not?

If git-runstatus exits to indicate the tree is clean (nothing to
commit) then a simple `read-tree -m -u HEAD $new` should update
the working directory and index, right?

-- 
Shawn.

Re: git push to a non-bare repository

From: Theodore Tso <tytso@mit.edu>
Date: 2016-06-15 22:43:00

On Sun, Mar 18, 2007 at 10:56:03PM -0400, Shawn O. Pearce wrote:
The reflog does update if the log file exists during a push (err,
actually during receive-pack).  Or if core.logAllRefUpdates is set
to true.  Now this isn't the default in a bare repository, but it
should be the default in a repository with a working directory.
So the case we are talking about should be seeing the reflog update.
So I dug a little more deeply, and the problem is that the reflog for
master was getting updated, but not the reflog for HEAD, and that's
what "git reflog" was showing --- hence my confusion.

What are the rules for when HEAD's reflog should get updated, and is
this documented anywhere in the man pages?

						- Ted

Script started on Sun 18 Mar 2007 11:11:59 PM EDT
Top-level shell (parent script)
Using ssh-agent pid 7679
<tytso@candygram> {/home/tytso/talks/dscm/git}  
1% cp -r test1 test2 ; cd test2
<tytso@candygram> {/home/tytso/talks/dscm/git/test2}  
2% (cd r2; git-config core.logallrefupdates)
true
<tytso@candygram> {/home/tytso/talks/dscm/git/test2}  
3% cat r2/.git/refs/heads/master
f2e3cc0bb64c8c94b89ba07bfbdd1653584586f2
<tytso@candygram> {/home/tytso/talks/dscm/git/test2}  
4% cat r2/.git/logs/HEAD
0000000000000000000000000000000000000000 f2e3cc0bb64c8c94b89ba07bfbdd1653584586f2 Theodore Ts'o [off-list ref] 1174266825 -0400
<tytso@candygram> {/home/tytso/talks/dscm/git/test2}  
5% cat r2/.git/logs/refs/heads/master
0000000000000000000000000000000000000000 f2e3cc0bb64c8c94b89ba07bfbdd1653584586f2 Theodore Ts'o [off-list ref] 1174266825 -0400
<tytso@candygram> {/home/tytso/talks/dscm/git/test2}  
6% (cd r1 ; git push ../r2)
updating 'refs/heads/master'
  from f2e3cc0bb64c8c94b89ba07bfbdd1653584586f2
  to   37508dc11dbe274d021124057fd2d027f6ce9d17
Generating pack...
Done counting 5 objects.
Result has 3 objects.
Deltifying 3 objects.
 100% (3/3) done
Writing 3 objects.
 100% (3/3) done
Total 3 (delta 2), reused 0 (delta 0)
Unpacking 3 objects
  100% (3/3) done
refs/heads/master: f2e3cc0bb64c8c94b89ba07bfbdd1653584586f2 -> 37508dc11dbe274d021124057fd2d027f6ce9d17
<tytso@candygram> {/home/tytso/talks/dscm/git/test2}  
7% cd r2
<tytso@candygram> {/home/tytso/talks/dscm/git/test2/r2}  [master]
8% cat .git/refs/heads/master
37508dc11dbe274d021124057fd2d027f6ce9d17
<tytso@candygram> {/home/tytso/talks/dscm/git/test2/r2}  [master]
9% cat .git/logs/HEAD
0000000000000000000000000000000000000000 f2e3cc0bb64c8c94b89ba07bfbdd1653584586f2 Theodore Ts'o [off-list ref] 1174266825 -0400
<tytso@candygram> {/home/tytso/talks/dscm/git/test2/r2}  [master]
10% cat .git/logs/refs/heads/master
0000000000000000000000000000000000000000 f2e3cc0bb64c8c94b89ba07bfbdd1653584586f2 Theodore Ts'o [off-list ref] 1174266825 -0400
f2e3cc0bb64c8c94b89ba07bfbdd1653584586f2 37508dc11dbe274d021124057fd2d027f6ce9d17 Theodore Ts'o [off-list ref] 1174274004 -0400	push
<tytso@candygram> {/home/tytso/talks/dscm/git/test2/r2}  [master]
11% git reflog
37508dc... HEAD@{0}: 
<tytso@candygram> {/home/tytso/talks/dscm/git/test2/r2}  [master]
13% git version
git version 1.5.0.5.425.g9cec6-dirty
<tytso@candygram> {/home/tytso/talks/dscm/git/test2/r2}  [master]
14% exit

Script done on Sun 18 Mar 2007 11:14:28 PM EDT

Re: git push to a non-bare repository

From: Theodore Tso <tytso@mit.edu>
Date: 2016-06-15 22:43:00

On Sun, Mar 18, 2007 at 10:56:03PM -0400, Shawn O. Pearce wrote:
quoted
When I was talking about a hook to enforce the BitKeeper semantics,
the question is whether we have enough to enforce the following:

	* Only accept the push if it will result in a fast-forward
		merge (and if not, tell the user to do a git pull, merge
		locally, and then redo the git push)
Yes, the update hook can detect this.  Actually receive-pack by
default rejects *all* non-fast-forward pushes, even if the client
side uses --force.
Ah, so that's controlled by receive.denyNonFastForwards, right?  Cool,
I missed that.  Thanks!!

Documentation/config.txt doesn't say it defaults to true, but from
your comments that is the default?
quoted
	* Only accept the push if there are no locally modified files
		that would be affected when the working directory is
		updated to reflect the new HEAD
The update hook could also perform this check; test if the ref
being updated is the current branch, and if so, verify the index and
working directory is clean.  That's a simple run of git-symbolic-ref
(to get the current branch) and git-runstatus (to check the index
and working directory), is it not?

If git-runstatus exits to indicate the tree is clean (nothing to
commit) then a simple `read-tree -m -u HEAD $new` should update
the working directory and index, right?
What git-runstatus will allow me to do is to abort if there are any
local modifications, regardless of whether or not they would conflict
with the working tree update.  The key phrase in my criteria was no
locally modified files "THAT WOULD BE AFFECTED".

What I could do with BitKeeper is that I could modify some file like
schedule.html on my webserver, and then push a changeset from my
laptop to would update sermons.html, and it would allow the push ---
since it would change the file sermons.html, and not touch
schedule.html.

But if I modified schedule.html on my laptop and then committed it,
and *then* try to push that changeset to the webserver, it would abort
since in order to accept the changeset, it would have to update the
working tree, and that would clash with the locally modified
schedule.html file.  At thta point I'd have to login to the webserver,
revert the local modification and bring it back down my laptop and
include it in a proper changeset.

Yeah, I probably shouldn't have ever modified the file locally on the
webserver, but that would sometimes happen when I was in a rush, and
it was nice when it Just Worked.

						- Ted

Re: git push to a non-bare repository

From: Shawn O. Pearce <hidden>
Date: 2016-06-15 22:43:00

Theodore Tso [off-list ref] wrote:
Ah, so that's controlled by receive.denyNonFastForwards, right?  Cool,
I missed that.  Thanks!!

Documentation/config.txt doesn't say it defaults to true, but from
your comments that is the default?
Ah, my bad, it defaults to false:

  static int deny_non_fast_forwards = 0;

I should have known better, as I run a 1.5.x (aka 'next') server
for a workgroup and I never have that set, but use instead a complex
update hook that decides if a fast-forward is required or not.
 
quoted
quoted
	* Only accept the push if there are no locally modified files
		that would be affected when the working directory is
		updated to reflect the new HEAD
If git-runstatus exits to indicate the tree is clean (nothing to
commit) then a simple `read-tree -m -u HEAD $new` should update
the working directory and index, right?
What git-runstatus will allow me to do is to abort if there are any
local modifications, regardless of whether or not they would conflict
with the working tree update.  The key phrase in my criteria was no
locally modified files "THAT WOULD BE AFFECTED".
  git-diff $old $new | git-apply --index ?

If the patch does not apply, nothing gets updated.  If it does apply,
the index is also updated and stat data updated.

OK, it doesn't quite handle every case, as sometimes a patch will
reject but the internal 3-way merge from xdiff that is called by
merge-recursive will succeed, but this does protect your working
tree and doesn't require making a temporary copy.


Of course another possible approach is to stuff the entire working
directory into a temporary tree, and then merge.  If the merge
doesn't work, you can reset to the temporary tree.  Unfortunately the
working directory is "in flux" during that process... its not atomic.

-- 
Shawn.

Re: git push to a non-bare repository

From: Shawn O. Pearce <hidden>
Date: 2016-06-15 22:43:00

Theodore Tso [off-list ref] wrote:
So I dug a little more deeply, and the problem is that the reflog for
master was getting updated, but not the reflog for HEAD, and that's
what "git reflog" was showing --- hence my confusion.

What are the rules for when HEAD's reflog should get updated, and is
this documented anywhere in the man pages?
It is buried down in write_ref_sha1 (in refs.c).  The rule is if the
name of the ref given to us for update does not match the actual
ref we are about to change, we log to both the original ref name
given and the actual ref name.

This handles the case of HEAD being a symref to some actual branch;
we update the HEAD reflog and the actual branch reflog whenever
someone updates HEAD.  Which is what we are usually doing from
tools like git-checkout.

receive-pack isn't updating the HEAD reflog as its updating the
actual branch, not HEAD.  If you pushed instead to HEAD you should
see the HEAD reflog entry too.

Its a little ugly here as I'm not sure we should always update
HEAD's reflog if HEAD points at a branch we are actually updating.
Maybe we should though in receive-pack ?

-- 
Shawn.

Re: git push to a non-bare repository

From: Nicolas Pitre <hidden>
Date: 2016-06-15 22:43:00

On Sun, 18 Mar 2007, Shawn O. Pearce wrote:
Theodore Tso [off-list ref] wrote:
quoted
So I dug a little more deeply, and the problem is that the reflog for
master was getting updated, but not the reflog for HEAD, and that's
what "git reflog" was showing --- hence my confusion.

What are the rules for when HEAD's reflog should get updated, and is
this documented anywhere in the man pages?
It is buried down in write_ref_sha1 (in refs.c).  The rule is if the
name of the ref given to us for update does not match the actual
ref we are about to change, we log to both the original ref name
given and the actual ref name.

This handles the case of HEAD being a symref to some actual branch;
we update the HEAD reflog and the actual branch reflog whenever
someone updates HEAD.  Which is what we are usually doing from
tools like git-checkout.

receive-pack isn't updating the HEAD reflog as its updating the
actual branch, not HEAD.  If you pushed instead to HEAD you should
see the HEAD reflog entry too.
This is indeed a corner case.  And it was never considered before as 
great care was made at the time to be sure pushes wouldn't create any 
reflogs on the remote side, which is effectively done by not 
automatically enabling reflogs on bare repos.
Its a little ugly here as I'm not sure we should always update
HEAD's reflog if HEAD points at a branch we are actually updating.
Maybe we should though in receive-pack ?
If the meaning of HEAD changed (although indirectly) because HEAD 
happens to point to the branch that just got updated then logically the 
HEAD reflog should be updated too.  On the other hand the HEAD reflog 
should reflect operations performed on HEAD.  Since the push updates the 
branch directly it is not exactly performing some operation on HEAD 
since HEAD could point anywhere and that wouldn't change the push at 
all.

Meaning that for the discussion of pushing to a non-bare repository with 
a dirty working tree... If the branch being pushed into is not pointed 
to by HEAD then no consideration what so ever about the working tree 
should be made, and no update to the HEAD reflog made of course.


Nicolas

Re: git push to a non-bare repository

From: Theodore Tso <tytso@mit.edu>
Date: 2016-06-15 22:43:00

On Mon, Mar 19, 2007 at 12:08:47AM -0400, Nicolas Pitre wrote:
quoted
Its a little ugly here as I'm not sure we should always update
HEAD's reflog if HEAD points at a branch we are actually updating.
Maybe we should though in receive-pack ?
If the meaning of HEAD changed (although indirectly) because HEAD 
happens to point to the branch that just got updated then logically the 
HEAD reflog should be updated too.  On the other hand the HEAD reflog 
should reflect operations performed on HEAD.  Since the push updates the 
branch directly it is not exactly performing some operation on HEAD 
since HEAD could point anywhere and that wouldn't change the push at 
all.

Meaning that for the discussion of pushing to a non-bare repository with 
a dirty working tree... If the branch being pushed into is not pointed 
to by HEAD then no consideration what so ever about the working tree 
should be made, and no update to the HEAD reflog made of course.
Right, but if the branch being pointed to is pointed to by HEAD I
would argue that the reflog for HEAD should be updated, since
operations that reference HEAD will see a new commit, and and it will
be confusing when "git reflog" shows no hint of the change.

Of couse, if the branch being pushed to isn't one which is pointed by
HEAD, of course HEAD's reflog shouldn't be updated.

						- Ted

Re: git push to a non-bare repository

From: Nicolas Pitre <hidden>
Date: 2016-06-15 22:43:00

On Mon, 19 Mar 2007, Theodore Tso wrote:
On Mon, Mar 19, 2007 at 12:08:47AM -0400, Nicolas Pitre wrote:
quoted
If the meaning of HEAD changed (although indirectly) because HEAD 
happens to point to the branch that just got updated then logically the 
HEAD reflog should be updated too.  On the other hand the HEAD reflog 
should reflect operations performed on HEAD.  Since the push updates the 
branch directly it is not exactly performing some operation on HEAD 
since HEAD could point anywhere and that wouldn't change the push at 
all.

Meaning that for the discussion of pushing to a non-bare repository with 
a dirty working tree... If the branch being pushed into is not pointed 
to by HEAD then no consideration what so ever about the working tree 
should be made, and no update to the HEAD reflog made of course.
Right, but if the branch being pointed to is pointed to by HEAD I
would argue that the reflog for HEAD should be updated, since
operations that reference HEAD will see a new commit, and and it will
be confusing when "git reflog" shows no hint of the change.

Of couse, if the branch being pushed to isn't one which is pointed by
HEAD, of course HEAD's reflog shouldn't be updated.
I think we're saying the exact same thing.


Nicolas

Re: git push to a non-bare repository

From: Sam Vilain <hidden>
Date: 2016-06-15 22:43:00

Shawn O. Pearce wrote:
receive-pack isn't updating the HEAD reflog as its updating the
actual branch, not HEAD.  If you pushed instead to HEAD you should
see the HEAD reflog entry too.
  
What about splitting HEAD when you push to the underlying branch, and
making HEAD a non-symref?

Sam.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help