阻止将简单合并推送到 git 服务器

发布于 2024-10-01 02:10:28 字数 1599 浏览 8 评论 0原文

不久前,我 要求我们的开发人员使用 rebase 而不是在推送之前合并。消除琐碎的合并使得更容易遵循提交图(即:gitk、git log)。

有时人们仍然会不小心进行简单的合并,然后推送。有谁有编写阻止简单合并的服务器端挂钩的方便或技巧吗?

我所说的“简单合并”是指没有冲突的合并。 这是一个示例这是 git 中简单合并的更好解释< /a>.

2010 年 11 月 10 日星期三 01:26:41 UTC 更新:大家都发表了精彩的评论!谢谢。

  • 考虑以下几点:我真正要求人们做的是:
    • 如果 git pull --ff-only 失败,请执行 git pull --rebase 而不是 git pull
  • git.git 仅具有一两个提交者,对吧?理论上,遵循提交图应该很容易,但对我来说它看起来很混乱。

2010 年 11 月 11 日星期四 23:49:35 UTC 更新

UTC 2010 年 12 月 15 日星期三 18:34:52 更新

  • adymitruk 已经接近了!只有一种情况尚未解决:重要的合并必须仍然有效。
  • 一个相当完整的 测试套件 可用,请查看。
  • 我在(?)git 邮件列表

A while back I asked our developers to use rebase instead of merge before pushing. Eliminating trivial merges makes for a much easier to follow commit graph (ie: gitk, git log).

Sometimes folks still accidentally do trivial merges, then push. Does anyone have handy or have tips for writing a server-side hook that blocks trivial merges?

By "trivial merge", I mean a merge without conflicts. Here's an example, and here's a better explanation of a trivial merge in git.

Update Wed Nov 10 01:26:41 UTC 2010: great comments, all! Thank you.

  • Consider the following: all I'm really asking folks to do is this:
    • if git pull --ff-only fails, do git pull --rebase instead of git pull
  • git.git only has one or two committers, right? In theory, it should be easy to follow the commit graph, but it looks pretty messy to me.

Update Thu Nov 11 23:49:35 UTC 2010:

Update Wed Dec 15 18:34:52 UTC 2010:

  • adymitruk is close! Just one case is still unresolved: non-trivial merges must still work.
  • A rather complete test suite is available, check it out.
  • I asked for help on a (the?) git mailing list.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

离去的眼神 2024-10-08 02:10:28

我在尝试寻找解决方案时遇到了这段代码。它并不完全符合您的要求,但应该可以在 if 语句上添加额外的分支名称。

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

所有学分均归原作者所有。

#!/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

I came across this piece of code, while trying to find a solution. It doesn't do exactly what you want, but it should be ez to add extra branch names on the if statement.

Works for me, so far. it forces pull --rebase for the same branch and lets regular merges with other branches go through.

All credits go to the original author.

#!/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
_失温 2024-10-08 02:10:28

这个更新挂钩将检查您是否正在推送到特定分支(它允许在 wip、主题和其他分支中进行简单合并)。

这不会影响 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

This update hook will check if you are pushing to specific branches (it allows trivial merges in wip, topic and other branches).

This does not bother with the rest of the parents on octopus merges as it only references the 2nd parent in each merge commit being pushed. Please feel free to update the script.

UPDATE: Reserved branches are required to exist on the remote.

#!/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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文