Bash 通过预接收挂钩在git push上测试推送冲突

Bash 通过预接收挂钩在git push上测试推送冲突,bash,git,githooks,git-push,Bash,Git,Githooks,Git Push,我正在BitBucket上制作一个预接收钩子,用来确认分支中的所有推送都是父分支的最新推送 我的意思是,在时间进化中,我们有几个分支: 对于上面的示例os 3分支,Dev、Feature1和my Local,我想在将本地推送到远程/origins/Feature1之前,将最新的特性1与最近的推送本地代码进行git合并。通过这种方式,我可以确认,无论是谁在推送,都在使用feature1的最新版本,不会有冲突。 如果有任何冲突,我会返回1,以避免推!并且要求开发人员在推送代码之前从特性中提取代码

我正在BitBucket上制作一个预接收钩子,用来确认分支中的所有推送都是父分支的最新推送

我的意思是,在时间进化中,我们有几个分支:

对于上面的示例os 3分支,Dev、Feature1和my Local,我想在将本地推送到远程/origins/Feature1之前,将最新的特性1与最近的推送本地代码进行git合并。通过这种方式,我可以确认,无论是谁在推送,都在使用feature1的最新版本,不会有冲突。 如果有任何冲突,我会返回1,以避免推!并且要求开发人员在推送代码之前从特性中提取代码

这是我在预接收钩子上的脚本

while read from_ref to_ref ref_name; do
    echo "Ref update:"
        echo " Old value: $from_ref"
        echo " New value: $to_ref"
        echo " Ref name:  $ref_name"
        echo " Diff:"
        git clone --progress -v $GIT_URL $CLONE_DIR1
        cd $CLONE_DIR1
        git checkout -b test remotes/origin/Feature1
        git merge --no-commit -m "Merging feature with local on-push code" $ref_name
        (....)
done
我试过使用ref_name,to_ref,但没有成功

有人能帮我吗


如何访问最近推送的代码,并按父分支与此代码合并?

这似乎是一件非常奇怪的事情,而且可能注定要失败。这肯定会很复杂,您需要根据正在更新的ref以及这些更新是否添加合并提交来更改测试行为

这就是说,预接收和更新挂钩有一些特殊规则,如果您遵守这些规则,您将获得更高的收益:

  • 不要
    chdir
    cd
    离开当前目录。或者,如果您这样做了,请确保返回
    chdir
    ,但通常不太难确保必须在另一个目录中运行的操作作为单独的进程运行:一个子shell或另一个脚本
  • 尝试使用需要使用其他存储库的GIT命令之前,请从环境中删除
    $GIT\u DIR
    。原因是钩子在顶级目录中运行,并且
    $GIT\u DIR
    设置为
    .GIT
    (非裸repo)或
    (裸存储库)
  • 将这两者结合在一起,您可以将所有验证程序代码移动到单独的脚本中,并执行如下操作:

    exitstatus=0
    while read from_ref to_ref ref_name; do
        ... maybe some setup code here to see if $ref_name
            is being created or destroyed ...'
    
        case "$ref_name" in
        ... add cases as needed to choose action based on ref ...
            if (unset GIT_DIR; /path/to/check_script arg1 arg2 ...); then
                echo "push being rejected because ..."
                exitstatus=1
            fi
        ...
        esac
        ...
    done
    exit $exitstatus
    
    这里还有一个很大的问题。您希望
    check\u script
    能够访问任何建议的新提交,如果钩子脚本退出0,则可以从
    $ref\u name
    访问这些提交,以便允许对其进行建议的更新。该更新尚未发生:
    $ref\u name
    仍然指向旧的SHA-1
    $from\u ref
    。同时,
    $to_ref
    中的新SHA-1可能没有任何名称指向它(尽管它仍然存在于基础存储库中)

    除此之外,如果
    $to_ref
    指向新提交(通常情况下),此时通过正常git操作进行的任何克隆都不会包含这些提交,因此您将无法使用它们

    有两种明显的方法来处理这个问题:

    • 创建一个指向
      $to\u ref
      的新(临时)引用。然后,您可以在克隆中看到建议的提交
    • 不要使用克隆。以其他方式复制存储库,或直接使用原始存储库本身,例如,作为“替代”,或通过创建临时工作树目录并将
      $GIT_work_tree
      指向该目录,或使用GIT 2.6+中出现的一些新的
      GIT worktree
      功能。(如果选择手动临时工作树方法,请务必同时考虑正常的共享
      $GIT_INDEX_文件
    还记得检查强制推送是否会从分支中删除提交,甚至在一次推送中删除一些并添加其他提交。

    更新: 这个问题为我解决了

    最后的代码是:

    #!/bin/bash
    DIR=xpto/external-hooks/code_review
    CLONE_DIR=$DIR/test_conflict_push-$(date +%s)
    GIT_URL=myGitUrl
    exitStatus=0
    
    read oldrev newrev refname
    feature_branch=${refname##refs/heads/}
    echo "Feature branch-> $feature_branch"
    #Clone feature branch from remote repo to be update via merged.
    git clone --progress -v $GIT_URL $CLONE_DIR
    currentDir=$PWD
    cd $CLONE_DIR
    #create branch named 'latest' to put new and modify files
    git checkout -b latest remotes/origin/$feature_branch
    #go back to PWD otherwise cant make git diff
    cd $currentDir
    # Get the file names, without directory, of the files that have been modified
    # between the new revision and the old revision
    echo "Getting files"
    files=`git diff --name-only ${oldrev} ${newrev}`
    echo "Files -> $files"
    # Get a list of all objects in the new revision
    echo "Getting objects"
    objects=`git ls-tree --full-name -r ${newrev}`
    echo "objects -> $objects"
    # Iterate over each of these files
    for file in ${files}; do
        # Search for the file name in the list of all objects
        object=`echo -e "${objects}" | egrep "(\s)${file}\$" | awk '{ print $3 }'`
        # If it's not present, then continue to the the next itteration
        if [ -z ${object} ]; 
        then
            continue;
        fi
        # Otherwise, create all the necessary sub directories in the new temp directory
        mkdir -p "${CLONE_DIR}/`dirname ${file}`" &>/dev/null
        # and output the object content into it's original file name
        git cat-file blob ${object} > ${CLONE_DIR}/${file}
    done;
    echo "Ready for start merging."
    cd $CLONE_DIR
    #add new files to branch
    echo $(git add .)
    #commit added and modify files to branch
    echo $(git commit -a -m "Merge latest to original feature")
    #get generated commit id
    echo $(git log -1)
    #create branch named 'merged' to merge above commited files
    echo $(git checkout -b merged remotes/origin/$feature_branch)
    #merge only occurs for madded and modify files!
    echo "Merging committed files to 'merged' branch with from 'latest' branch."
    mergeResult=$(git merge --no-commit latest)
    echo "Merge Result -> $mergeResult"
    ##to lower case
    if [[ "${mergeResult,,}" == *"conflict"* ]]
    then
    echo "Merge contains conflicts."
    echo "Update your $feature_branch branch!"
    exitStatus=1
    else
    echo "Merge don't contains conflict."
    echo "Push to $feature_branch can proceed."
    exitStatus=0
    fi
    #remove temporary branches
    echo $(git checkout master)
    echo $(git branch -D latest)
    echo $(git branch -D merged)
    #delete temporary clone dir
    rm -rf $CLONE_DIR
    exit $exitStatus
    
    非常感谢