Open esaborg opened 5 years ago
@esaborg: what kind of data you want to pass from git push?
@seletskiy: Here's my use case. With certain criteria I want to lock develop
branch from all pushed and merges. This is trivial, but I need a way to bypass the lock with some key and that's where the push options would help. That would allow me prevent all unwanted accidental pushes but enable to push with some key.
I know this is likely quite niche use case, but I believe there could be also other cases where which would benefit from the ability to add extra string info to the push.
Hi, I see now, the use case is pretty simple and reasonable.
Unfortunately, I don't see any way to pass any variable with git push
, because git-send-pack and git-receive-pack just don't support it.
I think you can implement a workaround by adding a git tag on your branch and then pushing it to the remote repository with --follow-tags
flag, then in your hook, you can obtain a list of tags on the pushed branch and decide either allow it or no.
Or you can push any file with special contents and check that file in your hook. (a dirty way, in my opinion)
Please let me know if it is working for you or no.
@esaborg: another way for your specific case is to create another user and push sensitive changes using key assigned to this username. In the hook itself you can add logic to restrict changes for given username only.
@kovetskiy As I understand, git push supports --push-options
(https://git-scm.com/docs/git-push#git-push--oltoptiongt) which would be quite suitable for this.
Adding a special file or tag would work as a dirty workaround. Creating a special user for this as @seletskiy suggests doesn't work as nicely since I would like any user to be able to push the changes. The trick is that having a hook like this would prevent the accidental pushed when develop
branch is supposed to be more or less locked.
@esaborg
I beg your pardon, git push indeed supports push options.
I made small research and you even can do it in bitbucket with External Hooks plugin.
Let's imagine some simple PreReceive hook:
#!/bin/bash
set -euo pipefail
enforced=false
if [[ "${GIT_PUSH_OPTION_COUNT:-}" && "${GIT_PUSH_OPTION_COUNT}" != "0" ]]; then
for (( index=0; index<$GIT_PUSH_OPTION_COUNT; index++ )); do
option_env="GIT_PUSH_OPTION_${index}"
option=${!option_env}
echo "option #${index}: ${option}"
if [[ "$option" == "enforce" ]]; then
enforced=true
fi
done
fi
if $enforced; then
exit 0
fi
echo "Sorry, git push to this repository is temporarily disabled." >&2
exit 1
The script will not allow a user to push unless -o enforce
specified while running git push
Variables that user passes specified in GIT_PUSHOPTION variables as it's specified in manual page:
The number of push options given on the command line of git push --push-option=... can be read from the environment variable GIT_PUSH_OPTION_COUNT, and the options themselves are found in GIT_PUSH_OPTION_0, GIT_PUSH_OPTION_1,… If it is negotiated to not use the push options phase, the environment variables will not be set. If the client selects to use push options, but doesn’t transmit any, the count variable will be set to zero, GIT_PUSH_OPTION_COUNT=0.
The only problem is that by default git push options are not allowed in repositories, so when you push you will receive the following error:
fatal: the receiving end does not support push options
fatal: the remote end hung up unexpectedly
error: failed to push some refs to 'http://admin@desktop:7990/bitbucket/scm/project_1/rep_1.git'
I didn't find any more elegant way to allow it except modifying file in $BITBUCKET_HOME/shared/config/git/system-config and adding following lines at the end of file:
[receive]
advertisePushOptions = true
With this configuration it's possible to do what you want.
Push without options:
→ rep_1 b✓ git push origin b
Enumerating objects: 7, done.
Counting objects: 100% (7/7), done.
Delta compression using up to 16 threads
Compressing objects: 100% (6/6), done.
Writing objects: 100% (6/6), 611 bytes | 611.00 KiB/s, done.
Total 6 (delta 3), reused 0 (delta 0)
remote: Push rejected by External Hook
remote: Sorry, git push to this repository is temporarily disabled.
remote:
To http://desktop:7990/bitbucket/scm/project_1/rep_1.git
! [remote rejected] b -> b (pre-receive hook declined)
error: failed to push some refs to 'http://admin@desktop:7990/bitbucket/scm/project_1/rep_1.git'
Push with a few but push options:
→ rep_1 b✓ git push origin b -o test_a -o test_b
Enumerating objects: 7, done.
Counting objects: 100% (7/7), done.
Delta compression using up to 16 threads
Compressing objects: 100% (6/6), done.
Writing objects: 100% (6/6), 611 bytes | 611.00 KiB/s, done.
Total 6 (delta 3), reused 0 (delta 0)
remote: Push rejected by External Hook
remote: option #0: test_a
remote: option #1: test_b
remote: Sorry, git push to this repository is temporarily disabled.
remote:
To http://desktop:7990/bitbucket/scm/project_1/rep_1.git
! [remote rejected] b -> b (pre-receive hook declined)
error: failed to push some refs to 'http://admin@desktop:7990/bitbucket/scm/project_1/rep_1.git'
And finally, push with enforce flag:
→ rep_1 b✓ git push origin b -o enforce
Enumerating objects: 7, done.
Counting objects: 100% (7/7), done.
Delta compression using up to 16 threads
Compressing objects: 100% (6/6), done.
Writing objects: 100% (6/6), 611 bytes | 611.00 KiB/s, done.
Total 6 (delta 3), reused 0 (delta 0)
remote:
remote: Create pull request for b:
remote: http://desktop:7990/bitbucket/projects/PROJECT_1/repos/rep_1/compare/commits?sourceBranch=refs/heads/b
remote:
To http://desktop:7990/bitbucket/scm/project_1/rep_1.git
9184775..81f94ec b -> b
Hope it is helpful for you.
@kovetskiy
Thank, that's exactly what I was looking for.
For some reason that script does not work on my environment. To be more specific, the environment variables remains unset for some reason. Adding the advertisePushOptions = true
line enabled the possibility to pass the variables, but I'm not seeing any values on server end.
I'm running git
version 2.18.0
, so that shouldn't be the problem.
@esaborg did you resolve the issue?
I would find it very useful to be able to send extra strings to pre receive hook from git push command.