一、写在前面
我有一个 iOS SDK 工程,除了常规的初始化、登录支付等接口,还包含第三方相关的接口。这时候想分一个版本出来,要求这个版本移除第三方接口。但是因为这个工程还在不断的维护,因此要求后面的更新,需要覆盖原来的版本和分出来的不带第三方的版本,这种情况就可以通过 Git 分支来实现。大概思路就是:原来只有一个 main/master 分支,那么包含第三方的版本默认为 main 分支,新增一个 remove-ads 分支。在 remove-ads 分支中,删除或注释掉第三方接口。当 main 分支有更新时,再同步到 remove-ads 分支。这样就实现了区分,后面的更新也能覆盖两个分支。
二、分支操作
1、查看分支
git branch
查看本地的分支
% git branch
* master
git branch -r
查看远程仓库的分支
% git branch -r
origin/master
git branch -a
查看本地和远程所有分支
% git branch -a
* master
remotes/origin/master
可以看到,当前仓库的本地和远程仓库都是 master 分支,也就是 main 分支。(注意执行 Git 操作,都是在代码仓库的目录下进行的,Git 仓库下都有一个隐藏文件 .git
)
2、检查状态
git status
检查当前的状态,确保本地和远程的代码一致,以避免潜在的冲突。如果存在未提交的更改,Git 可能会拒绝切换分支。
% git status
位于分支 master
您的分支与上游分支 'origin/master' 一致。
无文件要提交,干净的工作区
3、本地创建并切换分支
git checkout -b remove-ads
本地创建并切换到 remove-ads 分支。如果你是第一次使用分支,担心操作出问题,可以先压缩备份下代码工程。
% git checkout -b remove-ads
切换到一个新分支 'remove-ads'
看星号,说明本地已经成功创建并切换到 remove-ads 分支:
% git branch
master
* remove-ads
而远程仓库依旧只有 master 分支。
% git branch -r
origin/master
4、将本地分支推送到远程仓库
为了在远程仓库上同步这个新分支,并与其他开发者共享,我们需要将它推送到远程仓库。
使用 git push origin remove-ads
会将 remove-ads 分支推送到远程仓库 origin,并创建一个同名的远程分支。
% git push origin remove-ads
总共 0(差异 0),复用 0(差异 0),包复用 0
remote:
remote: To create a merge request for remove-ads, visit:
remote: http://xx.xx.xxx.xxx/Vampire/SW_iOS_SDK_NEW/merge_requests/new?merge_request%5Bsource_branch%5D=remove-ads
remote:
To ssh://xx.xx.xxx.xxx:2333/Vampire/SW_iOS_SDK_NEW.git
* [new branch] remove-ads -> remove-ads
git branch -r
再次查看,remove-ads 分支已经成功推送到远程仓库。
% git branch -r
origin/master
origin/remove-ads
5、设置追踪分支(可选)
为了简化后续的操作,可以设置本地分支与远程分支的关联,以便后续使用 git push
和 git pull
时不需要指定远程分支名称。
% git branch --set-upstream-to=origin/remove-ads remove-ads
分支 'remove-ads' 设置为跟踪 'origin/remove-ads'。
如果不设置追踪分支,那么后续对分支执行 git push
和 git pull
操作就需要指定远程仓库分支:
% git push origin remove-ads
% git pull origin remove-ads
总的来说,还是设置追踪分支更方便,因为一般情况下,本地仓库和远程仓库会保持一致的分支情况和分支名称。
6、修改分支代码
上面的操作完成后,就可以在本地针对 remove-ads 分支进行代码的修改,例如我当前的需求:删除或注释掉第三方接口。修改完毕再同步推送到远程仓库。
% git add .
% git commit -m '移除第三方接口'
[remove-ads 9ffdc86] 移除第三方接口
1213 files changed, 80 insertions(+), 41489 deletions(-)
...
推送到远程仓库,注意这里直接使用 git push 是因为前面已经设置了分支追踪。
% git push
枚举对象中: 56, 完成.
对象计数中: 100% (56/56), 完成.
使用 8 个线程进行压缩
压缩对象中: 100% (29/29), 完成.
写入对象中: 100% (29/29), 91.14 KiB | 1.69 MiB/s, 完成.
总共 29(差异 20),复用 0(差异 0),包复用 0
remote:
remote: To create a merge request for remove-ads, visit:
remote: http://xx.xx.xxx.xxx/Vampire/SW_iOS_SDK_NEW/merge_requests/new?merge_request%5Bsource_branch%5D=remove-ads
remote:
To ssh://xx.xx.xxx.xxx:2333/Vampire/SW_iOS_SDK_NEW.git
e32bf32..9ffdc86 remove-ads -> remove-ads
7、切回主分支
git checkout master
切回主分支,可以在主分支上正常开发了,也不影响 remove-ads 分支的代码。
% git checkout master
正在更新文件: 100% (1213/1213), 完成.
切换到分支 'master'
您的分支与上游分支 'origin/master' 一致。
8、同步修改到分支
如果在主分支修改了一些公共的代码,需要同步到 remove-ads 子分支。那么需要先切换到子分支,再使用 git merge master
合并主分支的修改。
% git checkout remove-ads
切换到分支 'remove-ads'
您的分支与上游分支 'origin/remove-ads' 一致。
% git merge master
Merge made by the 'ort' strategy.
.../SWGame_Logical/SWGame_Public/SWGame_ViewControllerManager.m | 2 ++
1 file changed, 2 insertions(+)
同样的,本地合并完成后,再推送到远程仓库即可。
% git status
位于分支 remove-ads
您的分支领先 'origin/remove-ads' 共 2 个提交。
(使用 "git push" 来发布您的本地提交)
无文件要提交,干净的工作区
% git push
枚举对象中: 16, 完成.
对象计数中: 100% (16/16), 完成.
使用 8 个线程进行压缩
压缩对象中: 100% (6/6), 完成.
写入对象中: 100% (6/6), 576 字节 | 576.00 KiB/s, 完成.
总共 6(差异 4),复用 0(差异 0),包复用 0
remote:
remote: To create a merge request for remove-ads, visit:
remote: http://xx.xx.xxx.xxx/Vampire/SW_iOS_SDK_NEW/merge_requests/new?merge_request%5Bsource_branch%5D=remove-ads
remote:
To ssh://xx.xx.xxx.xxx:2333/Vampire/SW_iOS_SDK_NEW.git
9ffdc86..8d0c113 remove-ads -> remove-ads
从 Git 可视化工具 Sourcetree 也可以清楚的看到我们的切分支过程:
三、暂存操作
在切换分支的开发中,会遇到这样一种情况:
我正在主分支上进行开发,还未开发完成,因此不想提交代码。但是这时候接到一个需求,要求对 remove-ads 子分支进行修改,并导出 SDK 文件,这时候我需要切换到 remove-ads 分支进行开发。但是主分支代码不体检,Git 是不允许切换分支的。
% git checkout remove-ads
错误:您对下列文件的本地修改将被检出操作覆盖:
SWGameSDK/SWGameSDK/SWGame_Api/SWGame_Api.h
请在切换分支前提交或贮藏您的修改。
正在终止
那么就涉及到 暂存
的操作了。具体如下:
1、将未完成的代码暂存到 stash 中
在 main 分支上,使用 git stash
命令可以将当前未完成的代码暂存起来,不影响切换分支。git stash 会将当前分支上的未提交更改(包括已跟踪的文件和未提交的修改)存入一个临时区域,并恢复上一次提交的状态。
% git stash
保存工作目录和索引状态 WIP on master: 4806dee 主分支修改测试
2、切换到 remove-ads 分支进行修改
代码暂存后,可以自由地切换到 remove-ads 分支进行工作。
git checkout remove-ads
3、切换到 master 分支并恢复未完成的工作
完成 remove-ads 分支的工作后,切换回 master 分支。
git checkout master
然后使用 git stash pop
恢复之前暂存的代码。该命令会将之前的暂存内容恢复到工作区,同时从 stash 中移除该存储点,如果暂存过程没有冲突,未完成代码将会恢复。
% git stash pop
位于分支 master
您的分支与上游分支 'origin/master' 一致。
尚未暂存以备提交的变更:
(使用 "git add <文件>..." 更新要提交的内容)
(使用 "git restore <文件>..." 丢弃工作区的改动)
修改: SWGameSDK/SWGameSDK/SWGame_Api/SWGame_Api.h
修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
丢弃了 refs/stash@{0}(48769d4112625cc27e49c48a478afa1207034106
4、继续在 master 分支上开发
现在可以继续在 master 分支上完成之前未完成的开发。
需要注意的点:
- 如果
git stash pop
过程中出现冲突,Git 会提示手动解决冲突,解决冲突后再继续开发。 - 如果不想立即应用暂存的内容,可以先使用
git stash list
查看所有暂存点,然后稍后使用git stash apply stash@{n}
来恢复特定的暂存点。
当使用 git stash 时,Git 会将当前的修改保存到一个堆栈(stash stack)中,并按照顺序给这些暂存点编号。每次暂存的内容都会生成一个唯一的标识,如 stash@{0}、stash@{1},依次类推。
- stash@{0} 表示最新的暂存点。
- stash@{1} 表示倒数第二个暂存点,依次类推。
git stash apply stash@{n} 允许你选择应用特定的暂存点,而不仅仅是最新的一个。但是需要注意的是,git stash apply stash@{n} 不会删除暂存点。
% git stash list
stash@{0}: WIP on master: 4806dee 主分支修改测试
% git stash apply stash@{0}
位于分支 master
您的分支与上游分支 'origin/master' 一致。
尚未暂存以备提交的变更:
(使用 "git add <文件>..." 更新要提交的内容)
(使用 "git restore <文件>..." 丢弃工作区的改动)
修改: SWGameSDK/SWGameSDK/SWGame_Api/SWGame_Api.h
修改尚未加入提交(使用 "git add" 和/或 "git commit -a"
% git stash list
stash@{0}: WIP on master: 4806dee 主分支修改测试