Sam Vilain [off-list ref] writes:
Now that git-stash is available, it is not so unsafe to push to a
non-bare repository, but care needs to be taken to preserve any dirty
working copy or index state. This hook script does that, using
git-stash.
Honestly, I am reluctant to do things that _encourages_ pushing
into a live tree.
- Who guarantees that the reflog is enabled for the HEAD?
- Who guarantees that a human user is not actively editing the
work tree files without saving? You would not see "dirty
state", the editor would notice "the file was modified since
you started editing it" and tell so to the user, but the user
cannot recover from the situation without knowing to do the
three-way merge between HEAD@{1}, HEAD and the index _anyway_.
+update_wc() {
+ ref=$1
+ echo "Push to checked out branch $ref" >&2
+ if (cd $GIT_WORK_TREE; git-diff-files -q --exit-code >/dev/null)
+ then
+ wc_dirty=0
+ else
+ echo "W:unstaged changes found in working copy" >&2
+ wc_dirty=1
+ desc="working copy"
+ fi
+ if git diff-index HEAD@{1} >/dev/null
Are you missing "--cached" here?
+ if [ "$wc_dirty" -ne 0 -o "$index_dirty" -ne 0 ]
+ then
+ new=$(git rev-parse HEAD)
+ git-update-ref --no-deref HEAD HEAD@{1}
+ echo "W:stashing dirty $desc - see git-stash(1)" >&2
+ (cd $GIT_WORK_TREE
+ git stash save "dirty $desc before update to $new")
+ git-symbolic-ref HEAD "$ref"
This part feels somewhat dangerous. What happens if we are
interrupted in the middle of these commands?
+ fi
+
+ # eye candy - show the WC updates :)
+ echo "Updating working copy" >&2
+ (cd $GIT_WORK_TREE
+ git-diff-index -R --name-status HEAD >&2
+ git-reset --hard HEAD)
+}
And I would have expected you would unstash the dirty state here.
Are there any reason not to?
Junio C Hamano wrote:
quoted
Now that git-stash is available, it is not so unsafe to push to a
non-bare repository, but care needs to be taken to preserve any dirty
working copy or index state. This hook script does that, using
git-stash.
Honestly, I am reluctant to do things that _encourages_ pushing
into a live tree.
I think a lot of people want this, and explaining why it doesn't work to
people is especially tiresome given that I know it can work, and the
caveats get smaller and smaller each time. I still think that the
operation can be made safe enough for general use.
- Who guarantees that the reflog is enabled for the HEAD?
Ok, so I guess if that's the case then the old behaviour is OK.
However, this would not be required if implemented in receive-pack, as
the only thing I'm using it for is to get the revision that the current
index is based on.
The other option, which was writing two hooks, both of which need to be
enabled, seemed far too ugly!
- Who guarantees that a human user is not actively editing the
work tree files without saving? You would not see "dirty
state", the editor would notice "the file was modified since
you started editing it" and tell so to the user, but the user
cannot recover from the situation without knowing to do the
three-way merge between HEAD@{1}, HEAD and the index _anyway_.
There seems to be a lot of focus on this. However I don't think it is a
showstopper; in this instance that the person who has their life ruined
by the incoming push can blame the person who did it, blame themselves
for giving that stupid user access to their working directory, and then
accept that the tool is doing the best that it can.
quoted
+ if git diff-index HEAD@{1} >/dev/null
Are you missing "--cached" here?
Ah, yes, good catch.
quoted
+ if [ "$wc_dirty" -ne 0 -o "$index_dirty" -ne 0 ]
+ then
+ new=$(git rev-parse HEAD)
+ git-update-ref --no-deref HEAD HEAD@{1}
+ echo "W:stashing dirty $desc - see git-stash(1)" >&2
+ (cd $GIT_WORK_TREE
+ git stash save "dirty $desc before update to $new")
+ git-symbolic-ref HEAD "$ref"
This part feels somewhat dangerous. What happens if we are
interrupted in the middle of these commands?
Heh. What seems to happen is that the local command is aborted and the
remote one continues. Nonetheless I'll add a trap statement, but again
if implemented in receive-pack it could probably be more resilient.
quoted
+ fi
+
+ # eye candy - show the WC updates :)
+ echo "Updating working copy" >&2
+ (cd $GIT_WORK_TREE
+ git-diff-index -R --name-status HEAD >&2
+ git-reset --hard HEAD)
+}
And I would have expected you would unstash the dirty state here.
Are there any reason not to?
If git-stash could support stashing conflicted merges, I don't think so.
However, if the user is a git-shell user, then they won't be able to
resolve the conflict and they won't be able to re-push as the stash will
fail (a condition not visited by the above).
Sam.
changes as you suggested are below;
diff --git a/templates/hooks--post-update b/templates/hooks--post-update
index 352a432..b15c711 100755
--- a/templates/hooks--post-update
+++ b/templates/hooks--post-update
@@ -25,6 +25,11 @@ fi
update_wc() {
ref=$1
echo "Push to checked out branch $ref" >&2
+ if [ ! -f $GIT_DIR/logs/HEAD ]
+ then
+ echo "E:push to non-bare repository requires a HEAD reflog" >&2
+ exit 1
+ fi
if (cd $GIT_WORK_TREE; git-diff-files -q --exit-code >/dev/null)
then
wc_dirty=0@@ -33,7 +38,7 @@ update_wc() {
wc_dirty=1
desc="working copy"
fi
- if git diff-index HEAD@{1} >/dev/null
+ if git diff-index --cached HEAD@{1} >/dev/null
then
index_dirty=0
else@@ -49,11 +54,13 @@ update_wc() {
if [ "$wc_dirty" -ne 0 -o "$index_dirty" -ne 0 ]
then
new=$(git rev-parse HEAD)
- git-update-ref --no-deref HEAD HEAD@{1}
echo "W:stashing dirty $desc - see git-stash(1)" >&2
- (cd $GIT_WORK_TREE
- git stash save "dirty $desc before update to $new")
+ ( trap 'echo trapped $$; git symbolic-ref HEAD "'"$ref"'"' 2 3 13 15 ERR EXIT
+ git-update-ref --no-deref HEAD HEAD@{1}
+ cd $GIT_WORK_TREE
+ git stash save "dirty $desc before update to $new";
git-symbolic-ref HEAD "$ref"
+ )
fi
# eye candy - show the WC updates :)
Junio C Hamano wrote:
Sam Vilain [off-list ref] writes:
quoted
Now that git-stash is available, it is not so unsafe to push to a
non-bare repository, but care needs to be taken to preserve any dirty
working copy or index state. This hook script does that, using
git-stash.
Honestly, I am reluctant to do things that _encourages_ pushing
into a live tree.
"Live" and "living" are perhaps two different things here. I for one have
something similar, but only for repositories residing on certain servers,
where there really must be zero local changes to the working tree.
- Who guarantees that the reflog is enabled for the HEAD?
I disable reflogs on that server. There's (hardly ever) any human interaction
with the scripts in that repo, so I really, really don't care about reflogs.
- Who guarantees that a human user is not actively editing the
work tree files without saving?
There are times when one simply doesn't care.
I realize that for my situation, a much simpler script can (and is) used, so
I agree with your concerns. The idea that every git repo has a human hacking
on it isn't true though, so doing things like this are sometimes useful,
timesaving and a real help.
--
Andreas Ericsson andreas.ericsson@op5.se
OP5 AB www.op5.se
Tel: +46 8-230225 Fax: +46 8-230231
Andreas Ericsson wrote:
quoted
- Who guarantees that a human user is not actively editing the
work tree files without saving?
There are times when one simply doesn't care.
I realize that for my situation, a much simpler script can (and is)
used, so
I agree with your concerns. The idea that every git repo has a human
hacking
on it isn't true though, so doing things like this are sometimes useful,
timesaving and a real help.
Yeah, that's absolutely true. My use cases would be twofold. First, a
public reference tree on a shared development server where people can
look over my corner of the code base without having to check the whole
thing out for themselves.
Second, a Web server with a bunch of static text/image files and PHP
scripts. If I can deploy by just pushing to a "current release" branch,
that saves me from having to first push then ssh to the machine and do
"git reset --hard".
Neither one of those things is impossible to do with vanilla git. They
just require extra busywork steps at the moment if you don't use an
"update the working copy on push" hook.
-Steve