组件化实践之:主工程抽离代码分支合并
1 背景
组件化过程中不可避免的会遇到这样一个问题:
组件化的过程一般周期比较长,此过程中不免会有业务需求的输入,这样就会导致一个情况:
组件化分支已经将主工程里的类迁移到pod仓库,而在此期间的业务需求代码对这些被迁移的类有修改,
合并主干(其他分支)代码时,主干(其他分支)有对移动之前的类做修改的情况下,会导致合并冲突,
这种冲突是整个类都是新增符号(+),没有冲突符号,此时无法简单的通过工具,或者冲突的符号对其进行解冲突。
2 问题处理
解决上述冲突,最开始想到的方案是通过xcode自带filemerge进行对比,这样比较容易导致遗漏且工作量大,无法充分利用git的冲突标志,
3 更优解决
如果可以知道有哪些类在合并代码时,
- 有修改
- 且已经被迁移了(不存在主工程)
那么就可以以这些类进行冲突检测
3.1 冲突解决方案
以下简述冲突检测设计思路
3.1.1 数据准备
- 先进行一次预合并,通过首次合并,可以从sourcetree中看到冲突的类列表文件,查看冲突内容,出现整个文件都带+的变更内容,该文件即为被迁移且被其他分支修改的文件。
- 将预合并产生的上述冲突的文件列表进行整理,将列表中符合迁移并修改的文件路径列表定义为数组存入文件:merge_project_files.txt
通过选中类(可以全选之后一起移动【mv】)移动路径:
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