吾八哥博客

您现在的位置是:首页 > DevOps > 代码管理 > 正文

代码管理

实现gitlab下主干开发模式的CR流程

吾八哥2022-05-28代码管理42212

背景

GitLab下不具备gerrit那样的commit级别的CR的机制,多人在开发同一个功能的时候,往往是都大家拉出各自的分支,然后往开发分支上进行合并,如果开发过程中依赖对方实现的逻辑,那么这个合并过程就非常繁琐。要么就是开发过程中不做CR,大家都在一个分支上开发,最后在集中进行CR,那么这个时候功能开发得差不多了,CR的粒度就非常大,可能就会涉及到大量的代码逻辑调整。基于这种现状,这里尝试探索一种新的CR方式:边开发边CR,简化CR协同流程

实现思路

这里以master分支为例,来说下具体的流程:
1.master分支设置为保护模式:不允许任何人提交,需要通过MR的方式合入代码.
2.大家都在本地都在master分支上写代码,不需要拉出feature分支.
3.写完代码后,直接git push推送是不成功的,这个时候需要使用git cr命令来替代git push.
4.git cr命令执行后会先同步远端master代码带本地,若有冲突在本地解决,无冲突则将本地代码推送到远端临时分支,同时发起一个MR合并请求.
5.在MR里做CR,CR通过后即可合入master.

借助GitLab下的Push Options思路,来实现这种机制,Push Options详细介绍:https://docs.gitlab.com/ee/user/project/push_options.html

实现代码

package main

import (
	"fmt"
	"os/exec"
	"strings"

	"github.com/pkg/errors"
)

func gitBranch() (branch string, err error) {
	cmd := exec.Command("/bin/bash", "-c", "git rev-parse --abbrev-ref HEAD")
	out, err := cmd.CombinedOutput()
	if err != nil {
		err = errors.Wrap(err, "请在git仓库目录下运行!!!")
		return
	}
	branch = strings.TrimSpace(string(out))
	return
}

func gitUser() (username string, err error) {
	cmd := exec.Command("/bin/bash", "-c", "git config user.name")
	out, err := cmd.CombinedOutput()
	if err != nil {
		err = errors.Wrap(err, "请在git仓库目录下运行!!!")
		return
	}
	username = strings.TrimSpace(string(out))
	return
}

func gitPull(branch string) error {
	fmt.Printf("开始同步分支 %s 远端代码到本地...\n", branch)
	shell := `
#!/bin/bash

set -e

export TARGET_BRANCH="%s"
RES=$(git ls-remote --heads origin refs/heads/${TARGET_BRANCH})
if [[ "RES" == "" ]]; then
  echo "远端仓库里不存在分支:${TARGET_BRANCH},请先创建好该分支"
  exit 1
fi

git pull origin ${TARGET_BRANCH}
	`
	args := []string{"-c", fmt.Sprintf(shell, branch)}
	cmd := exec.Command("/bin/sh", args...)
	out, err := cmd.CombinedOutput()
	if err != nil {
		err = errors.Wrapf(err, "执行失败,错误信息如下:\n%s", string(out))
		return err
	}
	fmt.Println("同步远端代码到本地成功.")
	return nil
}

func gitPush(username, branch string) error {
	fmt.Println("推送代码到远端仓库并发起评审任务...")
	shell := `
#!/bin/bash

set -e

export USER_NAME="%s"
export TARGET_BRANCH="%s"
export SOURCE_BRANCH="cr/${USER_NAME}/${TARGET_BRANCH}"

git push origin HEAD:${SOURCE_BRANCH} \
-o merge_request.create \
-o merge_request.title="%s" \
-o merge_request.target=${TARGET_BRANCH} \
-o merge_request.source=${SOURCE_BRANCH} \
-o merge_request.remove_source_branch=true
	`
	args := []string{"-c", fmt.Sprintf(shell, username, branch, fmt.Sprintf("%s merge code into %s", username, branch))}
	cmd := exec.Command("/bin/sh", args...)
	out, err := cmd.CombinedOutput()
	if err != nil {
		err = errors.Wrapf(err, "执行失败,错误信息如下:\n%s", string(out))
		return err
	}
	fmt.Println("推送代码并创建评审任务成功,详情如下:")
	fmt.Println(string(out))
	return nil
}

func main() {
	branch, err := gitBranch()
	if err != nil {
		fmt.Println(err)
		return
	}
	username, err := gitUser()
	if err != nil {
		fmt.Println(err)
		return
	}
	if err = gitPull(branch); err != nil {
		fmt.Println(err)
		return
	}
	if err = gitPush(username, branch); err != nil {
		fmt.Println(err)
		return
	}
}

代码已提交到github,链接地址为:https://github.com/5bug/git-cr

使用方法

image.png