Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/git/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Git Don';不允许分支合并到另一个分支_Git_Merge_Workflow_Branch_Git Branch - Fatal编程技术网

Git Don';不允许分支合并到另一个分支

Git Don';不允许分支合并到另一个分支,git,merge,workflow,branch,git-branch,Git,Merge,Workflow,Branch,Git Branch,我有一个分支,我想允许它从另一个分支合并。但我不允许它合并到另一个分支(例如Dev、master) 感谢您的帮助您将发现没有简单的方法可以做到这一点。我可以粗略地告诉你,你需要做什么;但是,你必须克服一些重大障碍,对于那些障碍,你只能靠自己,因为我没有花足够的时间来充分发展我认为糟糕的想法 唯一可能的解决方案是设置git挂钩。您可以在原始回购上设置预接收挂钩,这样,如果有人尝试包含您不喜欢的合并的推送,推送可能会被拒绝。(挑战在于找出你不喜欢的合并;我会回来讨论。) 当然,当有人推的时候,他们可

我有一个分支,我想允许它从另一个分支合并。但我不允许它合并到另一个分支(例如Dev、master)


感谢您的帮助

您将发现没有简单的方法可以做到这一点。我可以粗略地告诉你,你需要做什么;但是,你必须克服一些重大障碍,对于那些障碍,你只能靠自己,因为我没有花足够的时间来充分发展我认为糟糕的想法

唯一可能的解决方案是设置git挂钩。您可以在原始回购上设置预接收挂钩,这样,如果有人尝试包含您不喜欢的合并的推送,推送可能会被拒绝。(挑战在于找出你不喜欢的合并;我会回来讨论。)

当然,当有人推的时候,他们可能有大量的工作要重做。因此,您的开发人员知道他们不能推送违反您规则的引用,可能希望安装与预提交挂钩相同的脚本以避免错误。(也就是说,假设他们不只是认为有这种约束的项目不值得去做。)

棘手的部分是如何检测要进行的合并类型。您的脚本必须分析任何新合并,以查看第一个和第二个父级是什么。因此,您可以这样开始:如果合并的第二个(或后续)父级等于
主级
,则拒绝推送。那么如果你有

x -- x -- A <--(master)
 \
  x -- x -- B <--(dev)
x -- x -- x -- M -- x <--(master)
 \    \       /
  \    x --- A <--(hotfix)
   \
    x -- x -- B <--(dev)
因为脚本看到新合并提交的第二个子项是
A
,即
master
。所以他们不能推

x ----- x ---- A <--(master)
 \              \
  x -- x -- B -- M <--(dev)
开发人员必须不遗余力地将master合并到dev,但仍然可以这样做。而且,由于您显然希望将其作为一个规则,这意味着您的开发人员看到了这些合并的价值,即使您没有看到,您可以预期您将需要更严格地执行该规则。因此,脚本实际上需要查找其第二个(或后续)父级可从
master
访问的任何合并

因此,您可以使用类似于
git rev list
的方法来构建一个无法合并的修订列表,并检查每个新的合并,查找第二个(或后续)父项是否在该列表中

但这可能会产生一些意想不到的后果。如果有呢

x -- x -- A <--(master)
 \
  x -- x -- B <--(dev)
x -- x -- x -- M -- x <--(master)
 \    \       /
  \    x --- A <--(hotfix)
   \
    x -- x -- B <--(dev)

<代码> X-X-X-MX-P>你可以通过在本地修改一个<代码>预推< /COD>钩子来接近一个解决方案(在这种情况下,所有的DVS都需要安装钩子,所以你也可以考虑让你的DEVS安装更容易)。您可以将解决方案重新格式化为原点上的
预接收
钩子,以便更严格地执行

我们的想法是使用一个标记来识别一个很久以前的“坏”提交(标记“坏”分支上的第一个提交),该提交永远不应该被合并到干净的分支中,然后钩子查看您正在推送的ref和“坏”标记之间的
git merge base
,如果它们一致,则拒绝推送

下面是我对该答案的改编,用作
预推
挂钩。它包含一些逻辑,允许推送应该包含错误提交的分支,并且不必检查推送标记和其他非分支引用

#!/bin/bash
#
# This prevents a push to the named remote if the push has any "forbidden"
# commits (indicated by a tag matching the forbidden_pat variable) as any
# ancestors. It prevents a known-bad branch from having its history
# intermingled with other branches.
#
# Adapted from http://stackoverflow.com/a/13384768

# which remote should we protect?
protected_remote="origin"

# which branch should allow forbidden commits?
skip_branch_regex='^test[1-3]$'

# what do our forbidden tags look like?
forbidden_pat="forbidden/*"

# only check if this is the remote we care about
if [ "$1" != "$protected_remote" ]; then
  exit 0
fi

# we might be trying to push multiple branches (e.g. push.default = matching).
# See http://git-scm.com/docs/githooks#_pre_push for the format
while read line
do
  words=($line)
  branch="${words[0]##refs/heads/}"
  ref="${words[1]}"

  # don't proceed if this is not a branch (IOW, if our substitution didn't
  # change anything; we only want to check pushing branch pointers, not tags or
  # other refs
  if [ "$branch" = "${words[0]}" ]; then
    continue
  fi

  # don't proceed if we're trying to push a branch that can receive the bad
  # commit
  if [[ "$branch" =~  $skip_branch_regex ]]; then
    continue
  fi

  # check each forbidden tag to see if it's an ancestor of the ref we're
  # trying to push; reject if it is.
  for forbidden in $(git tag -l "$forbidden_pat"); do
    if [ $(git merge-base "$forbidden" "$ref") = $(git rev-parse "$forbidden") ]; then
      echo "Push to $branch contains BAD commit $forbidden." >&2
      exit 1
    fi
  done
done
exit 0
这在一个多开发者的环境中是可以接受的


尽管如此,我同意他的回答,即这不是一个需要通过编程解决的问题,而是一个应该通过其他方式解决的问题(培训、自动化测试、简化的分支工作流程等).

您可以在预接收钩子中拒绝此类合并的推送。第一个父级的想法很容易被打破:在一个临时分支上进行一次性提交,然后从中进行合并,这与热修复程序是无法区分的。我认为最好的可能是标记提交到第二个父级祖先的钩子,这些祖先可以到达
master
,但是,请咨询当地回购白名单,这样,如果有人批准了这个不寻常的案例,他们仍然可以推动/承诺,但我得说,我同意这个想法很糟糕。这样的工作流程不仅仅是一场灾难,它已经是一场灾难。注意:我欢迎对此答案进行更改/编辑,以便更好地将我的脚本改编的原始答案属性化。我不确定是否有这样的最佳实践来管理这一点。
#!/bin/bash
#
# This prevents a push to the named remote if the push has any "forbidden"
# commits (indicated by a tag matching the forbidden_pat variable) as any
# ancestors. It prevents a known-bad branch from having its history
# intermingled with other branches.
#
# Adapted from http://stackoverflow.com/a/13384768

# which remote should we protect?
protected_remote="origin"

# which branch should allow forbidden commits?
skip_branch_regex='^test[1-3]$'

# what do our forbidden tags look like?
forbidden_pat="forbidden/*"

# only check if this is the remote we care about
if [ "$1" != "$protected_remote" ]; then
  exit 0
fi

# we might be trying to push multiple branches (e.g. push.default = matching).
# See http://git-scm.com/docs/githooks#_pre_push for the format
while read line
do
  words=($line)
  branch="${words[0]##refs/heads/}"
  ref="${words[1]}"

  # don't proceed if this is not a branch (IOW, if our substitution didn't
  # change anything; we only want to check pushing branch pointers, not tags or
  # other refs
  if [ "$branch" = "${words[0]}" ]; then
    continue
  fi

  # don't proceed if we're trying to push a branch that can receive the bad
  # commit
  if [[ "$branch" =~  $skip_branch_regex ]]; then
    continue
  fi

  # check each forbidden tag to see if it's an ancestor of the ref we're
  # trying to push; reject if it is.
  for forbidden in $(git tag -l "$forbidden_pat"); do
    if [ $(git merge-base "$forbidden" "$ref") = $(git rev-parse "$forbidden") ]; then
      echo "Push to $branch contains BAD commit $forbidden." >&2
      exit 1
    fi
  done
done
exit 0