问题
We have a master branch where the released production code lives, a dev branch where the code for the test server lives, and various feature branches (branched from master) as each developer sees fit.
Over the course of time the dev branch has diverged somewhat from master. In addition, there are some incorrect merges there that mess up parts of the code. Several times already we have tried to reset (force-push) dev to be the same as master. To start over with a clean slate, so to say.
Unfortunately this does not last long. Sooner or later someone merges the old dev into the new dev, bringing back all the mess with it. I suspect this might even happen automatically, where a naive git pull silently merges the old and new branch heads.
Is it possible to prevent this with a server-side commit hook? Something that would refuse to accept the git push if the wrong commit is merged in?
回答1:
It's possible with Git Hooks. Put the following POC script to .git/hooks/pre-receive on your remote (server-side) repository and give it right permission to execute.
Configure the branch you want to protect, for example master
$ git config hooks.protected-branch.refs master
File: .git/hooks/pre-receive
#!/bin/sh
read old_value new_value ref_name
refs=$(git config hooks.protected-branch.refs)
for ref in $refs; do
if [ "$ref_name" == "refs/heads/$ref" ]; then
if [ "$old_value" == "0000000000000000000000000000000000000000" ]; then
continue
fi
if ! git merge-base --is-ancestor "$ref_name" "$new_value"; then
echo "$ref_name is protected branch"
exit 1
fi
fi
done
When you try to reset master by force-push, You will get similar output like this:
Counting objects: 12, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (8/8), done.
Writing objects: 100% (12/12), 920 bytes | 153.00 KiB/s, done.
Total 12 (delta 4), reused 0 (delta 0)
remote: refs/heads/master is protected branch
To ../demo
! [remote rejected] master -> master (pre-receive hook declined)
error: failed to push some refs to '../demo
回答2:
GitHub has a feature called protected branches, which gives repository administrators the ability to disable force pushes to specific branches.
In addition to blocking force pushes, a protected branch can have required status checks.
for more information... Please check https://blog.github.com/2015-09-03-protected-branches-and-required-status-checks/
回答3:
Sooner or later someone merges the old dev into the new dev, bringing back all the mess with it.
This is a common problem when using the default git pull behavior. To
avoid it, it's possible to configure git pull to use rebase by
default instead of merge. That is, to rebase the current branch onto
the remote branch instead of merging it:
git config pull.rebase interactive
From the git-config man page:
pull.rebase
When
true, rebase branches on top of the fetched branch, instead of merging the default branch from the default remote when "git pull" is run. See "branch..rebase" for setting this on a per-branch basis.When
preserve, also pass --preserve-merges along to git rebase so that locally committed merge commits will not be flattened by running git pull.When the value is
interactive, the rebase is run in interactive mode.NOTE: this is a possibly dangerous operation; do not use it unless you understand the implications (see git-rebase(1) for details).
With that, whenever the remote branch is rewritten (with push -f),
whoever is pulling is responsible for identifying and dropping the "old"
commits during the rebase. This results in a clean history (i.e.: no
merges of "old" versions) on each branch.
来源:https://stackoverflow.com/questions/52968175/how-to-prevent-a-specific-branch-from-being-merged-in-git