当前位置:   article > 正文

git submodule使用 解决同频操作分支难点_git submodule branch

git submodule branch


git submodule、git subtree 介绍及差异见:  submodule、subtree方案详解
 

一、子仓库难点,分支操作不同频

        子仓库分支与主仓库分支不会主动关联,不便管理,开发中需要较为小心
 

二、解决方式        

         增加node脚本,支持主仓库子仓库同频分支操作,保证主、子分支的一致性

        

三、同频操作分支源码及使用介绍
 

  •  介绍

    支持分支创建、切换、合并、拉取、创建Tags的同频操作
     
  • 操控面板

  • 脚本目录结构

  •  ⚠️使用步骤

    • 初始化子仓库
      git submodule add [子仓库git地址]

    • 增加packagen.json的script配置

      1. "scripts": {
      2. "branch": "node bin/branch.js"
      3. },
    • 修改bin/branchMode/index.js 内的submoduleName变量
      替换为子仓库的文件夹名称

    • 运行脚本

      npm run branch
  • bin/branch.js

    1. /**
    2. * 用于主仓库 & 子仓库 的分支同步
    3. */
    4. const {
    5. checkGitStatus,
    6. slcBranchType,
    7. BRANCH_CHECKOUT_TYPE
    8. } = require('./branchMode/index')
    9. const createBranch = require('./branchMode/createBranch.js')
    10. const toggleBranch = require('./branchMode/toggleBranch.js')
    11. const mergeBranch = require('./branchMode/mergeBranch.js')
    12. const pullBranch = require('./branchMode/pullBranch.js')
    13. const createBranchTags = require('./branchMode/createBranchTags.js')
    14. /**
    15. * 二、branch操作
    16. */
    17. const main = async() => {
    18. // 工作空间干净才允许执行操作
    19. await checkGitStatus()
    20. // git操作类型选择
    21. const featType = await slcBranchType()
    22. switch (featType) {
    23. // 创建
    24. case BRANCH_CHECKOUT_TYPE.create:
    25. createBranch()
    26. break
    27. // 切换
    28. case BRANCH_CHECKOUT_TYPE.toggle:
    29. toggleBranch()
    30. break
    31. // 合并
    32. case BRANCH_CHECKOUT_TYPE.merge:
    33. mergeBranch()
    34. break
    35. // 拉取
    36. case BRANCH_CHECKOUT_TYPE.pull:
    37. pullBranch()
    38. break
    39. // 创建Tags
    40. case BRANCH_CHECKOUT_TYPE.pushTags:
    41. createBranchTags()
    42. break
    43. default:
    44. break
    45. }
    46. }
    47. module.exports = main()
  • bin/util.js

    1. const inquirer = require('inquirer')
    2. const execa = require('execa')
    3. function log() {
    4. const str = [...arguments].join(', ')
    5. console.warn(
    6. `\n\u001b[33m ${str} \u001b[39m\n`
    7. )
    8. }
    9. function logGreen() {
    10. const str = [...arguments].join(', ')
    11. console.warn(
    12. `\n\u001b[32m ${str} \u001b[0m\n`
    13. )
    14. }
    15. function inputPrompt(msg, backup = null) {
    16. return inquirer.prompt([{
    17. name: 'detail',
    18. type: 'input',
    19. default: backup,
    20. message: msg
    21. }]).then(({ detail }) => detail)
    22. }
    23. function confirmPrompt(msg, backup = true) {
    24. return inquirer.prompt([{
    25. name: 'yes',
    26. type: 'confirm',
    27. default: backup,
    28. message: msg
    29. }]).then(({ yes }) => yes)
    30. }
    31. function selectPrompt(msg, list = [], backup = 0) {
    32. return inquirer.prompt([{
    33. name: 'select',
    34. type: 'list',
    35. choices: [
    36. new inquirer.Separator(' '),
    37. ...list,
    38. new inquirer.Separator(' ')
    39. ],
    40. default: backup,
    41. message: msg
    42. }]).then(({ select }) => select)
    43. }
    44. /**
    45. * 获取本地分支列表
    46. * @param {Boolean} isOrigin 查看远程分支
    47. * @param {String} cwd 执行路径
    48. * @returns branchList
    49. */
    50. const getBranchList = async(isOrigin = false, cwd = '') => {
    51. if (isOrigin) await execa.command('git fetch origin', { ...(cwd ? { cwd } : {}) })
    52. const currentBranch = execa.commandSync('git rev-parse --abbrev-ref HEAD', { ...(cwd ? { cwd } : {}) }).stdout
    53. let branchList = execa.commandSync(`git branch ${isOrigin ? '-r' : ''}`, { ...(cwd ? { cwd } : {}) }).stdout
    54. branchList = branchList.split('\n').map(item => {
    55. return item.split(' ').slice(-1)[0]
    56. })
    57. branchList = branchList.filter(item => item !== currentBranch)
    58. return branchList
    59. }
    60. const returnLog = (text = '') => {
    61. log(text)
    62. process.exit()
    63. }
    64. // 同步for运行Command
    65. const awaitForCommand = async(commandList = []) => {
    66. for (let i = 0; i < commandList.length; i++) {
    67. const item = commandList[i]
    68. await execa.command(item[0], { ...(item[1] ? { cwd: item[1] } : {}) })
    69. }
    70. }
    71. /**
    72. * 查看文件修改状态
    73. * @param {String} type 指定类型
    74. */
    75. const getStatusList = (type = '') => {
    76. let statusList = execa.commandSync('git status -s').stdout
    77. statusList = statusList.split('\n').map(item => {
    78. return item.split(' ').filter(item => item)
    79. })
    80. if (type) {
    81. statusList = statusList.filter(item => {
    82. return item?.[0]?.toUpperCase() === type.toUpperCase()
    83. })
    84. }
    85. return statusList
    86. }
    87. module.exports = {
    88. log,
    89. logGreen,
    90. inputPrompt,
    91. confirmPrompt,
    92. selectPrompt,
    93. getBranchList,
    94. returnLog,
    95. awaitForCommand,
    96. getStatusList
    97. }
  • bin/branchMode/index.js

    1. const execa = require('execa')
    2. const {
    3. selectPrompt,
    4. returnLog
    5. } = require('../util')
    6. // 子仓库目录
    7. const submoduleName = 'child-ui'
    8. // 当前分支
    9. const currentBranch = execa.commandSync('git rev-parse --abbrev-ref HEAD').stdout
    10. // 分支切换类型
    11. const BRANCH_CHECKOUT_TYPE = {
    12. create: 1,
    13. toggle: 2,
    14. merge: 3,
    15. pull: 4,
    16. pushTags: 5
    17. }
    18. // 枚举是否
    19. const ISOK_ENMU = {
    20. yes: 1,
    21. no: 2
    22. }
    23. // 选择是否
    24. const ISOK_OPTIONS = [
    25. { name: '是', value: ISOK_ENMU.yes },
    26. { name: '否', value: ISOK_ENMU.no }
    27. ]
    28. // (1)、检测当前工作空间是否有未提交的文件
    29. const checkGitStatus = async() => {
    30. const gitStatus = await execa.command('git status')
    31. if (!gitStatus.stdout.includes('nothing to commit')) {
    32. returnLog('检测到主仓库代码未提交, 请自行检查!')
    33. }
    34. const childStatus = await execa.command('git status', { cwd: `./${submoduleName}` })
    35. if (!childStatus.stdout.includes('nothing to commit')) {
    36. returnLog('检测到子仓库代码未提交, 请自行检查!')
    37. }
    38. }
    39. // (2)、选择分支操作类型
    40. const slcBranchType = async() => {
    41. const selectProjectName = await selectPrompt('branch操作类型选择',
    42. [
    43. { name: '创建', value: BRANCH_CHECKOUT_TYPE.create },
    44. { name: '切换', value: BRANCH_CHECKOUT_TYPE.toggle },
    45. { name: '合并', value: BRANCH_CHECKOUT_TYPE.merge },
    46. { name: '拉取', value: BRANCH_CHECKOUT_TYPE.pull },
    47. ...(
    48. currentBranch === 'master' ? [{ name: '创建Tags', value: BRANCH_CHECKOUT_TYPE.pushTags }] : []
    49. )
    50. ]
    51. )
    52. return selectProjectName
    53. }
    54. // (3)、子分支切换 & pull
    55. const toggleChildBranch = async(customBranch = currentBranch) => {
    56. const childBranch = execa.commandSync('git rev-parse --abbrev-ref HEAD', { cwd: `./${submoduleName}` }).stdout
    57. if (childBranch !== customBranch) {
    58. await execa.command(`git checkout ${customBranch}`, { cwd: `./${submoduleName}` })
    59. }
    60. await execa.command('git pull', { cwd: `./${submoduleName}` })
    61. }
    62. module.exports = {
    63. submoduleName,
    64. currentBranch,
    65. BRANCH_CHECKOUT_TYPE,
    66. ISOK_ENMU,
    67. ISOK_OPTIONS,
    68. checkGitStatus,
    69. slcBranchType,
    70. toggleChildBranch
    71. }
  •  bin/branchMode/createBranch.js

    1. /**
    2. * 创建分支(主 + 子)
    3. */
    4. const {
    5. logGreen,
    6. inputPrompt,
    7. getBranchList,
    8. returnLog,
    9. awaitForCommand
    10. } = require('../util')
    11. const {
    12. submoduleName,
    13. checkGitStatus,
    14. toggleChildBranch
    15. } = require('./index')
    16. const createBranch = async() => {
    17. // (1) 子分支切换 & pull
    18. await toggleChildBranch()
    19. // (1.1) 主pull
    20. await awaitForCommand([['git pull']])
    21. // (2) 检测暂存区
    22. await checkGitStatus()
    23. // (3) 输入分支名
    24. const createName = await inputPrompt(`请输入分支名:`)
    25. if (!createName) return
    26. const localBranchList = await getBranchList()
    27. if (localBranchList.includes(createName)) {
    28. returnLog('分支已存在')
    29. }
    30. // (4) 创建主分支
    31. const parentOriginList = await getBranchList(true)
    32. // (4.1) 远程分支存在,创建本地 & 关联远程
    33. if (parentOriginList.includes(`origin/${createName}`)) {
    34. await awaitForCommand([[`git checkout -b ${createName} origin/${createName}`]])
    35. // (4.2) 创建分支 & 推至远程
    36. } else {
    37. await awaitForCommand([
    38. [`git checkout -b ${createName}`],
    39. [`git push --set-upstream origin ${createName}`]
    40. ])
    41. }
    42. // (5) 创建子分支
    43. const childLocalList = await getBranchList(false, `./${submoduleName}`)
    44. const childOriginList = await getBranchList(true, `./${submoduleName}`)
    45. // (5.1) 本地存在
    46. if (childLocalList.includes(createName)) {
    47. await awaitForCommand([[`git checkout ${createName}`, `./${submoduleName}`]])
    48. // (5.2) 远程存在
    49. } else if (childOriginList.includes(`origin/${createName}`)) {
    50. await awaitForCommand([[`git checkout -b ${createName} origin/${createName}`, `./${submoduleName}`]])
    51. // (5.3) 都不存在
    52. } else {
    53. await awaitForCommand([
    54. [`git checkout -b ${createName}`, `./${submoduleName}`],
    55. [`git push --set-upstream origin ${createName}`, `./${submoduleName}`]
    56. ])
    57. }
    58. logGreen('已成功创建')
    59. }
    60. module.exports = createBranch

  •  bin/branchMode/mergeBranch.js

    1. 1/**
    2. * 合并分支(主 + 子)
    3. */
    4. const {
    5. logGreen,
    6. selectPrompt,
    7. getBranchList,
    8. awaitForCommand,
    9. getStatusList
    10. } = require('../util')
    11. const {
    12. submoduleName,
    13. currentBranch,
    14. checkGitStatus,
    15. toggleChildBranch
    16. } = require('./index')
    17. const mergeBranch = async() => {
    18. // (1) 主拉取
    19. await awaitForCommand([
    20. [`git pull`]
    21. ])
    22. // (2) 子分支切换 & pull
    23. await toggleChildBranch(currentBranch)
    24. // (3) 检测暂存区
    25. await checkGitStatus()
    26. // (4) 分支选择
    27. const localBranchList = await getBranchList()
    28. const branchKey = await selectPrompt('请选择合并分支', localBranchList)
    29. // (5) 主分支合并
    30. try {
    31. await awaitForCommand([[`git merge ${branchKey}`]])
    32. } catch (error) {
    33. // log(`主仓库merge异常: ${error}`)
    34. }
    35. // (6) 子分支合并
    36. await awaitForCommand([[`git merge ${branchKey}`, `./${submoduleName}`]])
    37. // (7) 自动提交commit同步文件
    38. const statusList = getStatusList()
    39. if (
    40. statusList.length === 1 &&
    41. // 暂存区 || 冲突
    42. ['M', 'UU'].includes(statusList?.[0]?.[0]?.toUpperCase()) &&
    43. statusList[0][1] === submoduleName
    44. ) {
    45. await awaitForCommand([
    46. [`git add ${submoduleName}`],
    47. [`git commit -m fix:子仓库commit同步`]
    48. ])
    49. }
    50. // (8) 提交远程
    51. await awaitForCommand([
    52. [`git push`, `./${submoduleName}`],
    53. [`git push`]
    54. ])
    55. logGreen('已合并')
    56. await checkGitStatus()
    57. }
    58. module.exports = mergeBranch
  •  bin/branchMode/pullBranch.js

    1. /**
    2. * 拉取分支(主 + 子)
    3. */
    4. const { logGreen, awaitForCommand } = require('../util')
    5. const { currentBranch, checkGitStatus, toggleChildBranch } = require('./index')
    6. const pullBranch = async() => {
    7. await awaitForCommand([
    8. [`git pull`],
    9. [`git submodule update`]
    10. ])
    11. // 子分支切换 & pull
    12. await toggleChildBranch(currentBranch)
    13. logGreen(`git pull 成功`)
    14. await checkGitStatus()
    15. }
    16. module.exports = pullBranch
  •  bin/branchMode/toggleBranch.js

    1. /**
    2. * 切换分支(主 + 子)
    3. */
    4. const { logGreen, selectPrompt, getBranchList, awaitForCommand } = require('../util')
    5. const { submoduleName, checkGitStatus, toggleChildBranch } = require('./index')
    6. const toggleBranch = async() => {
    7. const localBranchList = await getBranchList()
    8. const branchKey = await selectPrompt('请选择分支', localBranchList)
    9. // (1) 切换分支
    10. await awaitForCommand([
    11. [`git checkout ${branchKey}`],
    12. [`git checkout ${branchKey}`, `./${submoduleName}`]
    13. ])
    14. // (2) 检测暂存区
    15. await checkGitStatus()
    16. await awaitForCommand([
    17. [`git pull`],
    18. [`git submodule update`]
    19. ])
    20. // (3) 子分支切换 & pull
    21. await toggleChildBranch(branchKey)
    22. logGreen(`切换分支:${branchKey} 成功, 并执行git pull`)
    23. await checkGitStatus()
    24. }
    25. module.exports = toggleBranch
  •  bin/branchMode/createBranchTags.js

    1. /**
    2. * 创建Tags(主 + 子)
    3. */
    4. const { logGreen, selectPrompt, inputPrompt, awaitForCommand } = require('../util')
    5. const { submoduleName, ISOK_ENMU, ISOK_OPTIONS } = require('./index')
    6. const createBranchTags = async() => {
    7. // (1) 主仓库Tags选择
    8. // const isTags = await selectPrompt('是否需要打Tags', ISOK_OPTIONS)
    9. // if (isTags !== ISOK_ENMU.yes) return
    10. // (2) 输入TagsName
    11. let tagsName = await inputPrompt(`请输入Tags名称:`)
    12. if (!tagsName) return
    13. tagsName = `tags/${tagsName}`
    14. // (3) 创建主仓库Tags
    15. await awaitForCommand([
    16. [`git tag ${tagsName}`],
    17. [`git push origin ${tagsName}`]
    18. ])
    19. logGreen(`主仓库Tags已推: ${tagsName}`)
    20. // (4) 创建子仓库Tags
    21. const isChildTags = await selectPrompt('子仓库是否需要打Tags', ISOK_OPTIONS)
    22. if (isChildTags !== ISOK_ENMU.yes) return
    23. await awaitForCommand([
    24. [`git tag ${tagsName}`, `./${submoduleName}`],
    25. [`git push origin ${tagsName}`, `./${submoduleName}`]
    26. ])
    27. logGreen(`子仓库Tags已推: ${tagsName}`)
    28. }
    29. module.exports = createBranchTags


        到这里就大工告成了,有用的话麻烦关注收藏一下~

        欢迎留言探讨

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/459346
推荐阅读
相关标签