组件化实践之:主工程抽离代码分支合并用

Posted by PaysonChen on October 7, 2023

组件化实践之:主工程抽离代码分支合并

1 背景

​ 组件化过程中不可避免的会遇到这样一个问题:

​ 组件化的过程一般周期比较长,此过程中不免会有业务需求的输入,这样就会导致一个情况:

​ 组件化分支已经将主工程里的类迁移到pod仓库,而在此期间的业务需求代码对这些被迁移的类有修改,

​ 合并主干(其他分支)代码时,主干(其他分支)有对移动之前的类做修改的情况下,会导致合并冲突,

​ 这种冲突是整个类都是新增符号(+),没有冲突符号,此时无法简单的通过工具,或者冲突的符号对其进行解冲突。

2 问题处理

​ 解决上述冲突,最开始想到的方案是通过xcode自带filemerge进行对比,这样比较容易导致遗漏且工作量大,无法充分利用git的冲突标志,

3 更优解决

​ 如果可以知道有哪些类在合并代码时,

  • ​ 有修改
  • ​ 且已经被迁移了(不存在主工程)

​ 那么就可以以这些类进行冲突检测

3.1 冲突解决方案

以下简述冲突检测设计思路

3.1.1 数据准备

  • 先进行一次预合并,通过首次合并,可以从sourcetree中看到冲突的类列表文件,查看冲突内容,出现整个文件都带+的变更内容,该文件即为被迁移且被其他分支修改的文件。

0

  • 将预合并产生的上述冲突的文件列表进行整理,将列表中符合迁移并修改的文件路径列表定义为数组存入文件:merge_project_files.txt

1

​ 通过选中类(可以全选之后一起移动【mv】)移动路径:

2

Tips:这里用移动mv,不用复制cp,为了主工程修改完之后,能恢复迁移后的样子,不至于多出一些已迁移但是还存在主工程的文件

即可获取主工程冲突文件路径,新建一个文本文件,将上述所有冲突类路径移动过去,

1
2
3
/Users/username/Documents/Project/git/Inner/Demo/127/Demo-IOS/ProjectDemoiOS/ProjectDemoiOS/Class/Main/Car/Model/PSCCarDetailInforModel.h
/Users/username/Documents/Project/git/Inner/Demo/127/Demo-IOS/ProjectDemoiOS/ProjectDemoiOS/Class/Main/Sites/View/PSCPowerPriceTableViewCell.m
.....
  • 将上述文件列表一一对应到组件库里本地clone路径了列表,定义为数组存入文件;merge_pods_files.txt
1
2
3
/Users/username/Documents/Project/git/CocoaPods/Private/ProjectCarModule/ProjectCarModule/Classes/Car/Model/DemoCarDetailInforModel.h
/Users/username/Documents/Project/git/CocoaPods/Private/ProjectExchangeMoudle/ProjectExchangeMoudle/Classes/Sites/View/DemoPowerPriceTableViewCell.m
.....

Tips:commond+option+c可以文件路径

3.1.2 算法编写

  • 步骤1:在一个全新的组件化分支(未进行预合并)上先从组件库将冲突的类文件拷贝回主工程,
  • 步骤2:提交本地仓库(不需要push远程仓库)后再进行合并
  • 步骤3:合并冲突则为可参考历史变更及可解决的冲突状态
  • 步骤4:合并解决完后再通过上述方案,反向将dest的主工程目录拷贝并覆盖到组件库文件

Tips:可能存在一些已经删除的文件,但是也出现在上述列表中,此时无法从组件库移动到主工程,需要确认是否是无用文件(不是误删)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# merge.sh
# 从外部文件中读取源文件路径和目标文件夹路径
#"source_paths.txt"
source_file=$1
#"destination_paths.txt"
destination_file=$2

# 检查源文件是否存在
if [ ! -f "$source_file" ]; then
    echo "源文件 '$source_file' 不存在。"
    exit 1
fi

# 检查目标文件夹文件是否存在
if [ ! -f "$destination_file" ]; then
    echo "源文件 '$source_file' 不存在。"
    exit 1
fi

#保证每条记录都有一个回车(最后一行如果没有回车,会被忽略)
while IFS= read -r source_path && IFS= read -r destination_folder <&3; do
    source_paths+=("$source_path")
    destination_paths+=("$destination_folder")
done < $source_file 3< $destination_file

# 输出数组长度
echo "源文件路径数组长度:${#source_paths[@]}"
echo "目标文件夹路径数组长度:${#destination_paths[@]}"

#exit 0
# 遍历索引
for index in "${!source_paths[@]}"; do
    echo "遍历目标文件夹路径数组,index="$index
    source_path="${source_paths[$index]}"
    destination_path="${destination_paths[$index]}"

    # 构建目标文件的完整路径
#    destination_path="${destination_folder}${source_path}"

    # 检查目标文件是否存在,如果存在则删除
    if [ -e "$destination_path" ]; then
        rm "$destination_path"
    fi

    # 确保目标文件夹存在
    mkdir -p "$(dirname "$destination_path")"

    # 移动源文件到目标路径
    mv "$source_path" "$destination_path"
done

echo "文件移动完成。"

3.1.3 执行

将pod仓库的文件移动回主工程的调用方式:

1
sh merge.sh merge_pods_files.txt merge_project_files.txt

解决完冲突后将主工程的上述文件移动回组件库

1
sh merge.sh merge_project_files.txt merge_pods_files.txt

3.1.4 收尾

  • 解决完冲突,Pod仓库会得到从主干(其他功能分支)合并的最新类的修改版本,需要提交到对应迁移Pod仓库
  • 主工程Project文件保留迁移后的版本,可以得到组件化改造后的Project的文件结构
  • 再执行一次之前提到的寻找Project未引用,但是还存在的类的脚本进行最后的清理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
function main() {
    
    # 设置项目目录
    project_directory=$1

    if [ -z "$1" ]; then
        #未传参为当前目录
        project_directory=.
    fi

    # 设置其他目录
    parent_path=$(dirname "$project_directory")
    echo "project 路径:"$parent_path
    
    current_dir=$(basename "$project_directory")
    echo "当前路径 文件夹名称:"$current_dir

    
    project_path=$(find "$parent_path"/$current_dir.xcodeproj -type f \( -name "*.pbxproj" \))
    echo "project 路径:"$project_path

    all_file_path=$(find "$project_directory" -type f \( -name "*.h" \))
    all_file_path_cnt=$(find "$project_directory" -type f \( -name "*.h" \) | wc -l)

    echo "主工程 头文件数量:"$all_file_path_cnt

    for src_file in $all_file_path; do
    #    echo $src_file
        filename=$(basename "$src_file" .h)
        if  ! grep -q "\b$filename\b" "$project_path";  then
            echo "project不包含:"$src_file
        fi
    done
}


main $1

传入工程(Project文件所在的目录)路径:

1
sh find_all_file_no_project.sh /Users/username/Documents/Project/git/Inner/Demo/Release/Demo-IOS/ProjectiOS/ProjectiOS