问题
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