阻止将普通合并推送到git服务器

阻止将普通合并推送到git服务器,git,bash,git-branch,githooks,git-merge,Git,Bash,Git Branch,Githooks,Git Merge,不久前我。消除琐碎的合并使得提交图(即:gitk、git-log)更易于遵循 有时人们仍然会意外地进行一些琐碎的合并,然后推送。有没有人有写一个服务器端钩子阻止琐碎的合并的便捷方法或技巧 所谓“琐碎的合并”,我指的是没有冲突的合并,和 更新星期三11月10日01:26:41 UTC 2010:大家的评论真棒!多谢各位 考虑以下几点:我真正要求人们做的是: 如果git pull--ff only失败,请执行git pull--rebase而不是git pull git.git只有一两个提交者

不久前我。消除琐碎的合并使得提交图(即:gitk、git-log)更易于遵循

有时人们仍然会意外地进行一些琐碎的合并,然后推送。有没有人有写一个服务器端钩子阻止琐碎的合并的便捷方法或技巧

所谓“琐碎的合并”,我指的是没有冲突的合并,和

更新星期三11月10日01:26:41 UTC 2010:大家的评论真棒!多谢各位

  • 考虑以下几点:我真正要求人们做的是:
    • 如果
      git pull--ff only
      失败,请执行
      git pull--rebase
      而不是
      git pull
  • git.git只有一两个提交者,对吗?从理论上讲,遵循提交图应该很容易,但对我来说它看起来相当混乱
更新时间:2010年11月11日星期四23:49:35 UTC

  • 另一个想法是通过“git推送”防止客户端上的琐碎合并
更新星期三12月15日18:34:52 UTC 2010

  • 快到了!只有一个案例尚未解决:非平凡的合并必须仍然有效
  • 有一个相当完整的版本,请查看
  • 我在一个问题上寻求帮助

这个更新钩子将检查您是否正在推送到特定的分支(它允许在wip、topic和其他分支中进行琐碎的合并)

这并不影响octopus合并上的其他父级,因为它只在每次推送合并提交时引用第二个父级。请随时更新脚本

更新:远程服务器上必须存在保留分支

#!/bin/bash
refname="$1"
oldrev="$2"
newrev="$3"
branches="refs/heads/hotfixes refs/heads/dev refs/heads/qa refs/heads/master"
cont="no"
for branch in $branches ; do
  if [[ $refname == $branch ]] ; then
    cont="yes"
  fi
done
if [[ $cont == "no" ]] ; then
  exit 0
fi
echo "inspecting branch $refname for trivial merges" >&2
hashes="$(git log --format=%H --merges $oldrev..$newrev)"
for hash in $hashes ; do
  echo "checking merge commit $hash" >&2
  cont="no"
  for branch in $branches ; do
    if [[ $refname == $branch ]] ; then
      continue
    fi
    # if [[ "$(git log --format=%H $hash^2 ^$branch | wc -l)" == "0" ]] ; then
    if [[ "$(git log --format=%H $hash^2 ^$branch | wc -l)" == "    0" ]] ; then
      cont="yes"
    fi
  done
  if [[ $cont == "no" ]] ; then
    echo "No trivial merges allowed. Please rebase and push again." >&2
    exit 1
  fi
done
exit 0

我在试图找到解决方案时遇到了这段代码。它并不能完全满足您的需要,但在if语句中添加额外的分支名称应该是明智的

到目前为止,对我有效。它强制对同一分支进行拉-再基,并允许与其他分支进行常规合并

所有学分归原作者所有

#!/bin/bash
#
# This git update hook will refuse unnecessary merge commits caused by pulling
# from being pushed to a shared repository. These commits make following the
# history of a project difficult and are always avoidable with rebasing.
#
# by Scott Kyle (appden)
# modified by Olivier Refalo (orefalo)

refname="$1"
oldrev="$2"
newrev="$3"

# if this is not run as a hook, you may have messed up
if [ -z "$GIT_DIR" -o -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
    echo "Usage: GIT_DIR=<path> $0 <ref> <oldrev> <newrev>" >&2
    exit 1
fi

# if the new revision is all 0's then it's a commit to delete a ref
zero="0000000000000000000000000000000000000000"
# also check if the new revision is not a commit or is not a fast forward
# detect branch deletion, branch creation... and more
if [ "${refname#refs/heads/}" = "master" ] || [ "$newrev" = "$zero" ] || [ "$oldrev" = "$zero" ] || [ $(git cat-file -t $newrev) != "co
mmit" ] || [ $(git merge-base $oldrev $newrev) != "$oldrev" ]; then
    exit 0
fi

# loop through merges in the push only following first parents
for merge in $(git rev-list --first-parent --merges $oldrev..$newrev --); do
    # lazily create the revision list of this branch prior to the push
    [ -z "$revlist" ] && revlist=$(git rev-list $oldrev)
    # check if the second parent of the merge is already in this branch
    if grep -q $(git rev-parse $merge^2) <<< "$revlist"; then
        cat >&2 <<-EOF
            *** PUSH REJECTED ***
            *** TRIVIAL merge detected on local branch ${refname#refs/heads/}
            *** To fix: git rebase origin/${refname#refs/heads/}
            ***
            *** Next time use: git pull --rebase
            ***
            *** Permanent fix: git config [--global] branch.autosetuprebase always
            *** Then for existing branches: git config branch.<name>.rebase true
        EOF
        exit 1
    fi
done

echo -Info- Clean history successfully preserved!
exit 0
#/bin/bash
#
#这个git更新钩子将拒绝由拉取引起的不必要的合并提交
#从被推送到共享存储库。这些提交将执行以下操作:
#一个项目的历史是困难的,并且总是可以通过重新定基来避免。
#
#斯科特·凯尔(阿普登)
#由Olivier Refalo(orefalo)修改
refname=“$1”
oldrev=“$2”
newrev=“$3”
#如果这不是作为一个钩子运行,您可能已经搞砸了
如果[-z“$GIT_DIR”-o-z“$refname”-o-z“$oldrev”-o-z“$newrev”];然后
echo“用法:GIT_DIR=$0”>&2
出口1
fi
#如果新版本都是0,那么它是一个删除引用的提交
zero=“0000000000000000000000000000”
#还要检查新修订版是否不是提交版或快进版
#检测分支删除、分支创建。。。还有更多
如果[“${refname#refs/heads/}”=“master”]|[“$newrev”=“$zero”]|[“$oldrev”=“$zero”]|[$(git cat文件-t$newrev)!=“co
mmit“]|【$(git合并基$oldrev$newrev)!=“$oldrev”];然后
出口0
fi
#仅在第一个父级之后的推送中循环合并
对于合并到$(git rev list--第一个父项--合并$oldrev..$newrev--);做
#在推送之前惰性地创建此分支的修订列表
[-z“$revlist”]&&revlist=$(git rev list$oldrev)
#检查合并的第二个父级是否已在此分支中

如果grep-q$(git rev parse$merge^2)您如何定义“平凡合并?”您希望如何区分平凡合并和非平凡合并?我补充说,从“平凡合并”开始…有很多反对重定基址而不是合并的论点。就我个人而言,我不愿意被迫重新设定基准。只是说;)嗯,你不可能知道简单的“拉式”合并和没有主题/功能分支冲突的合并之间的区别。正如August所说,你真的应该三思而后行。您关于是否需要合并(存在冲突)的标准没有什么意义。您可以在合并或重新基准中解决合并冲突,也可以使用合并或重新基准合并内容而不产生冲突。重要的是犯罪的历史。如果您想做的是“合并在此功能分支上完成的工作”,那么表示这一点的方法就是合并。合并不一定会使历史难以理解-查看git.git@adymitruk-您应该使用
&
而不是
。它还将受益于
[[[
]
中的一些换行符。同意。。这是更多的伪代码。请建议替换if条件,我将编辑响应。即使将
替换为
&&
,删除一些换行符,并使用bash的
=~
运算符进行正则表达式匹配,也不能作为预接收挂钩。我创建了一个本地回购协议,克隆了它,并在“qa”分支上进行了一次简单的合并,但我仍然能够将简单的合并推回到原点。这是我到目前为止得到的信息:对不起。这意味着作为一个更新挂钩。如果您使用的是gitolite,请确保使用update.secondary并使用安装程序推动更改。我将更新答案以指定哪个钩子。我不确定您在那里使用while循环做什么。git更新钩子接收3个参数:分支名称、所在位置的提交sha、将所在位置的提交sha。当某个分支被推送到repo时,该钩子会被每个分支调用一次,这也会阻止非平凡的合并。看见我将这段代码添加到要点中,只需键入“make”即可运行测试。当部署到服务器(更新挂钩)上时,它会强制用户使用“pull--rebase”。来自另一个分支的常规合并工作正常,但来自同一个分支的常规合并将在一个微不足道的合并上失败,啊,我明白了。对不起,我应该仔细阅读你的描述。当我在一年前发布这个问题时,我想我正在寻找一种允许从源代码/主代码到主代码进行非平凡合并的方法,这样人们仍然可以