A bit of context
I am develloping a flow which will allow people to access a common environment.
The idea is to have a repository that should only be pushed in, but not a bare one as I want people to be able to read it. Let's call it COMMON
This is because I do not want people to have to clone the repository to be able to access the data.
To do it, I have the following structure:
- Local repository: where the ones who want to develop the flow can perform modifications, commit and push to the remote repository
- Remote repository: A bare repository that is also used as a gateway. Whenever a push is done to this bare repository it is repercuted to the COMMON repository
- COMMON repository: the public 'read' directory. Only a push can modify its history, even commit is forbidden(via the pre-commit hook)
Problematic
The COMMON repository should not have any direct modifications. However, as multiple users are sudoers, I cannot be 100% sure that someone will not directly modify it.
Or, accordingly with Murphy, I am 100% sure that someone will one day modify something locally in the COMMON repository...
To be sure that there is no conflict when someone rightfully pushes into the remote directory, and consequently in the COMMON repository, I thought about the following hooks for the COMMON:
- pre-receive
#!/bin/bash
#Stash local modifications if there are ones to avoid conflicts
echo "## Local modifications on the Product-Line are stashed with the tag: 'local modifications @ $(date)' "
git stash push -m "local modifications @ $(date)"
exit 0
- post-receive
#!/bin/bash
#Checks out the the branch that contains the last commit
git checkout $( git log --branches -1 --pretty=format:'%D' | sed -e 's/.*-> //g' -e 's/.*, //g' )
#Forces synchronization with the last commit
git stash
git stash drop stash@{0}
exit 0
However, the stash commands does not seem to work as expected. The log returned when a push is done in the local repository is the following :
$> echo toto >> stash_test ; git commit -am "test" ; git push
[tbranch f6e8fbb] test
1 file changed, 1 insertion(+)
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 48 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 351 bytes | 351.00 KiB/s, done.
Total 3 (delta 1), reused 0 (delta 0)
remote: remote: ## Local modifications on the Product-Line are stashed with the tag: 'local modifications @ Mon Dec 23 17:44:59 CET 2019'
remote: remote: No local changes to save
remote: remote: Already on 'tbranch'
remote: remote: M stash_test
remote: remote: Saved working directory and index state WIP on tbranch: f6e8fbb test
remote: remote: stash@{0}: WIP on tbranch: f6e8fbb test
remote: remote: Dropped stash@{0} (b29b76ceb2b2dfd2fcf6d0577c7200e517641328)
remote: To ../pl
remote: f75b5d1..f6e8fbb tbranch -> tbranch
To /home/usr/TEMP/remote
f75b5d1..f6e8fbb tbranch -> tbranch
Two issues here:
- To test the auto stashing in the COMMON repository, I modified a file. However when the pre-receive hook reaches the
git stash push -m "msg"
, it returnsNo local changes to save
- In the post-receive hook, the
git stash
plusgit stash drop stash@{0}
should emulate an update to the last commit of the current branch. In the log, it appears that the operation worked, however, if I get the status in the COMMON repository I obtain :
On branch tbranch
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: stash_test
modified: test
stash_test
is the file modified by the last committest
is the file locally modified to test the all procedure
Double dragon effect:
1. the git stash list
is empty, where it should contain the modification of test
. However the log is coherent with that as it did not stash test
in the pre-receive hook
2. stash_test
is not updated with the last commit... Here it is strange as the log indicates that everything was okay...
Where I am lost is that I tried to perform the steps manually and... it works as I expected.
I however am quite new in git administration so I could have missed something...
Questions
- Does the
git stash
command have a fancy behavior in the hooks that does not allow me to do what I want ? - Is there another (maybe better) way to achieve what I want to do ?
EDIT: Issue root cause identified
When a hook is executed, it is in the .git directory of my COMMON dir.
Hence, the git stash
does not detect the modifications.
If I perform a git status --porcelain
in the pre-receive hook I get:
?? HEAD
?? ORIG_HEAD
?? config
?? description
?? gitk.cache
?? hooks/applypatch-msg.sample
?? hooks/commit-msg.sample
?? hooks/fsmonitor-watchman.sample
?? hooks/post-receive
?? hooks/post-update.sample
?? hooks/pre-applypatch.sample
?? hooks/pre-commit
?? hooks/pre-commit.sample
?? hooks/pre-push.sample
?? hooks/pre-rebase.sample
?? hooks/pre-receive
?? hooks/pre-receive.sample
...
Which is expected as the content of the .git dir are not under version control.
In fact, even with the @knittl suggestion of using a git reset --hard
does not work as it is not done in the 'work' directory of common.
The trivial workaround I thought about is to encapsulate the operations in my hooks with:
pwd # returns COMMON/.git
pushd .. > /dev/null
pwd # returns COMMON
#hook operations
popd > /dev/null
Checking withs pwd
commands in the hooks I finally am in the correct directory to perform my stash/reset.
However, when doing it, the remote message returns me:
remote: remote: fatal: not a git repository: '.'
So now I am a bit confused as I am actually at the root of my COMMON so it should be considered as a git repository...
Even if, as suggested in by @knittl and @torek, it is not the golden way to deploy something, I would like to understand why there are these limitations and if there is a way to override them.
EDIT2: Stash in pre-commit
In the pre-commit hook I perform a stash to save the local modification and abort the commit so the 'reckless sudoer' cannot commit its changes but can later cherry-pick his modifications.
In this hook, the git stash
performs as expected.
I guess that the issue is related with the fact that pre/post-receive hooks are server-side hooks and should normally only be used for bare repository.