TortoiseGit的使用
目录
2. 用Git Submodule方式将SDK链接到FW_TLC仓库中
1. Concept
HEAD:HEAD是一个指向你正在工作中的本地分支的指针。简单来讲,就是你现在在哪儿,HEAD就指向哪儿。例如当前我们处于master分支,所以HEAD这个指针指向了master分支。
working tree:实际操作的目录被称为工作树,也就是工作区域。
Index:索引是工作树和仓库之间的一个暂存区域。在这个区域放置了你想要提交给仓库的文件,如工作树的代码通过右键TortoiseGit → add添加到索引中,通过commit 则将索引区域的文件提交到本地仓库中。
2. 用Git Submodule方式将SDK链接到FW_TLC仓库中
为了降低代码维护成本,在YS8803项目开发中,计划将Flycode / LLF等Project共用同一份SDK代码,于是将原本存放在各个project下的SDK文件夹提取出来,单独建立一个SDK仓库,让Flycode / LLF Project都调用该SDK仓库下的SDK代码。在此我们将FW_TLC称为主项目,将SDK称为子项目。
2.1. 日常开发使用说明
代码clone:因为主项目FW_TLC和子项目SDK的包含关系在submodule中体现了,所以只需要clone FW_TLC仓库,clone Main Branch后FW_TLC下的SDK文件夹是空的,需在FW_TLC文件夹内右键TortoiseGit -> Submodule Update。switch branch时需要在switch完成界面点击Update Submodules。
2.2. 将SDK提升为项目(RD无需关注)
以下内容是将旧的代码仓库结构调整为SDK独立仓库,并通过submodule方式将子项目链接到主项目的操作步骤,开发人员在日常开发中无需关注。
完成上述步骤后,本地FW_TLC文件夹下就只剩下SDK文件夹,然后再在该目录下将文件推送到服务器端的SDK仓库,就可以将原本在FW_TLC文件夹下的SDK文件夹推送到外层的SDK仓库,并且能保留之前的所有log。
(2)将SDK仓库链接到FW_TLC仓库
FW_TLC文件夹内右键TortoiseGit -> Submodule Add,添加子仓库path。
3. gitlab远程子仓库配置为SSH
在gitlab main path下原本是链接了一个http的子仓库SDK,但是由于要使用持续集成工具Jenkins检查merge的代码是否编译通过、是否单元测试通过等,因此需要将子仓库SDK的链接引用改为SSH的。改链接引用很容易,将git main path下的.gitmodules文件里的url改为SSH的就好。
但是遇到了一个问题:重新在本地Git Clone main path,右键点击Submodules update,提示要输入gitlab的密码,输入密码后还是弹出输入密码的框。此时需要配置下子仓库,
3.1. Flow
- win+r输入cmd打开cmd运行窗口输入,git config --global user.name "你的gitlab用户名",回车,输入git config --global user.email "你的gitlab邮箱",回车;
gitlab用户名和gitlab邮箱可以在这里看到
- 输入git config --global --list,回车,这一步知识看下前面的步骤有没有成功;
- 输入ssh-keygen,连续3次回车,成功之后id_rsa,id_rsa.pub两个文件默认在C:\Users\username/.ssh目录下,cmd运行窗口也显示了文件路径。
ps:如果输入命令ssh-keygen回车显示“ssh-keygen 不是内部或外部命令,也不是可运行的程序xxx”,那么在本地main code文件夹下右键选择Git Bash Here,输入ssh-keygen就可以了,盲猜可能是之前环境变量没配好。
- 打开id_rsa.pub,复制ssh key
法一:直接用UltraEdit打开id_rsa.pub,复制所有内容;
法二:在本地main code文件夹下右键选择Git Bash Here,输入cat ~/.ssh/id_rsa.pub,回车,
复制以ssh-rsa开头的这段ssh key;
- 将ssh key填写到gitlab SSH Keys上。
- 生成.ppk;打开PuTTYgen -> 点击load,选择.ssh/id_rsa -> 点击Save private key,保存ppk文件到.ssh目录下;
- 本地新建文件夹load ssh path,输入gitlab的个人密码,成功clone sdk到本地;
- clone main path到本地
(1)右键单击TortoiseGit → Git Clone,clone main path(http);
(2)将生成的.ppk加到Git putty key;
(3)在本地main仓库下右键pull;
(4)右键submodules update将sdk子仓库(ssh)拉取到本地。
3.2. Q&A
- clone代码报错:error: cannot spawn C:\ProgramData\Microsoft\Windows\Start Menu\Programs\TortoiseGit: Permission denied
原因:之前安装过TortoiseGit,但是残留文件没有清除
解决方法:打开C:\ProgramData\Microsoft\Windows\Start Menu\Programs\TortoiseGit,找到其快捷键,打开文件所在位置,复制其路径,粘贴到下图所示的位置应用即可。
- 配置了SSH仍要输入密钥
这种情况下,再应用一次ppk即可。
4. Revert
在TortoiseGit中,"Revert"文件 相当于git checkout HEAD--文件名(或git checkout-REVISION--文件名),用于将文件重置为其最后(或特定)提交状态。而git的revert仅由日志提交对话框中的revert更改引用。
4.1. Gitlab Revert
4.2. TortoiseGit Revert
如果要撤消自上次提交以来对文件所做的所有更改,则需要选择该文件,右键单击弹出上下文菜单,然后选择TortoiseGit → Revert 将弹出一个对话框,显示您已更改并可以还原的文件。选择要还原的对象,然后单击“OK”。
Revert将仅撤消本地更改。它不会撤消已push的任何更改。如果要撤消在特定修订中提交的所有更改,请阅读Reset这节内容。
撤消删除或重命名
需要在父文件夹(或commit或repository status dialog)上使用“Revert”,因为删除的项目不存在,无法右键单击。
撤消添加项目
5. Reset
如果你merge其它分支的代码到本地分支,但是你想回退到之前的节点,那么可以使用Reset。右键TortoiseGit → Show log → 选中要回退的节点 → 右键点击Reset "xxx" → 选择相应的Reset Type即可。
- Soft:保持工作树和索引不变。完全不接触索引文件和工作树(但将头重置为所选提交,就像所有模式一样)。这将使所有更改的文件保持“要提交的更改”不变。
- Mixed:同Abort Merge,保持工作树不变,重置索引,但不重置工作树(即保留更改的文件,但不标记为提交),并报告未更新的内容。
- Hard:同Abort Merge,重置工作树和索引(放弃所有本地更改),对工作树中跟踪文件的任何更改都将被丢弃。与TortoiseGit的revert或clean功能不同,Hard不使用Windows回收站,直接永久删除这些文件,未提交的更改可能会丢失!
上述Reset操作只能将本地仓库回退到之前的节点,并不能将远端节点回退。如果要将远端节点回退,在上述操作的基础上还需要进行一个步骤。右键点击Git Bash Here,输入git push --force -u origin 分支名,回车即可看到远端仓库已经回退到之前节点了;
注:developer只能回退远端分支,不能回退远端main;
5.1. Revert VS Reset
TortoiseGit revert aimed to revert effects of previous commit. For example,
A <- B <- C
^ HEAD
If I found B I committed before is wrong, and I want to "undo" its change, revert B will cause:
A <- B <- C <- B'
^ HEAD
其中B' 与B中所做的改变相反。
Reset is more straight-forward, it is simply setting the HEAD to a certain commit,
A <- B <- C
^ HEAD
git-reset-ting to B will give you
A <- B <- C
^ HEAD
6. rebase
Rebase相当复杂,它会改变/重写存储库的历史。在使用它之前,请确保您了解它的原理(有关Git和重新定基的一般提示,请参阅“阅读指南”部分,尤其是Git rebase(1)手册页)。
Squash:该提交与位于列表下方(ID较低)的前一个提交合并。
Force rebase -> 选中log右键Squash -> start rebase -> 修改commit log -> commit -> done
7. merge
由于用Git Submodule方式将SDK作为子仓库链接到FW_TLC仓库中,并且Ci Jenkins只能使用SSH Clone的方式下载代码,.gitmodules里的path由http改为了ssh,所以代码merge到主干的方式发生了改变,步骤稍微繁琐一些,但总体思想不变,即将其看作两个独立的仓库进行管理。
7.1. Flow
以开发一个新需求为例,从FW_TLC Main的最新节点上创建一个FW_TLC branch进行模块开发。若此模块涉及SDK的修改,则创建FW_TLC branch对应的SDK branch;当功能开发完成并通过研发内测后,将FW_TLC branch merge到Main,此时需按如下步骤进行。如果此FW_TLC branch不涉及SDK的修改,则从步骤7开始。
SDK源分支
:SDK branch
SDK目标分支
:SDK Main
FW源分支
:FW_TLC branch
FW目标分支
:FW_TLC Main
- 确认
SDK源分支
上的变更是否都已经commit了。(不是push) - pull 从远程仓库拉取最新版本到本地。
- merge
SDK目标分支
到SDK源分支
上。 - 如果有冲突的话,解决冲突,commit & push 到远程仓库。
如果没有冲突,直接push 到远程仓库。
- 在gitlab上创建SDK的merge request,等待直至merge通过。
SDK源分支
switch到SDK目标分支
,在FW源分支
下commit & push SDK的引用修改。- merge
FW目标分支
到FW源分支
上,进行步骤4。 - 在gitlab上创建FW的merge request,等待merge通过。
7.2. Edit conflict
在merge的时候,可能有冲突导致merge不成功,此时需要使用TortoiseGit来解决冲突。在本地FW_TLC branch右键merge from FW_TLC main(此时需要保证本地仓库是最新的),有冲突则点击点击resolve,双击打开冲突文件,此时会出现三窗格视图,即合并视图。
- merge操作涉及4个文件:mine file、theirs file、Mergedfile和Basefile。
- Base 是mine 和 theirs 的最后一个共同祖先,表示文件的最旧版本,从那里您和他们开始进行更改。
- theirs 代表了其他人对该文件所做的全部更改。左窗格显示了 theirs 相对于基本文件的更改。
- mine 代表了包含您所做的所有更改的基本文件,右窗格显示了 mine 相对于基本文件所做的更改。
- 底部窗格 Merged是您试图解决冲突的输出文件。
Merged file存在以下几种情况:
- 所有的修改 Mine 是最新的
- 所有的修改 Theirs 是最新的
- 一部分修改 Mine是最新的,一部分修改 Theirs是最新的
情况1选中文件右键,点击 Resolve conflict using "HEAD"即可
情况2选中文件右键,点击 Resolve conflict using "MERGE_HEAD"即可
情况3可以直接编辑底部窗格。或者使用上方工具栏的Use 'theirs' text block 、Use 'mine' text block、Use 'mine' text block then 'theirs'、Use 'theirs' text block then 'mine'。
8. Abort Merge
Merge:重置索引并且尝试重构merge之前的状态;
Mixed:保持工作树不变,重置索引,但不重置工作树(即保留更改的文件,但不标记为提交),并报告未更新的内容。
Hard:重置工作树和索引(放弃所有本地更改),对工作树中跟踪文件的任何更改都将被丢弃。与TortoiseGit的revert或clean功能不同,Hard不使用Windows回收站,直接永久删除这些文件,未提交的更改可能会丢失!
9. Stash changes
通常,当你在做项目的一部分时,事情处于一种混乱的状态,你想切换一下分支来做其他事情。问题是,你不想只做一半的工作,然后再回到这一点。那么可以通过Stash changes来解决。
Stash changes就是将当前未commit的修改存放在堆栈,需要使用时pop出来即可。
Stash change操作会获取工作目录的脏状态,即修改后的跟踪文件和暂存的更改,并将其保存在一堆未完成的更改中,你可以随时重新应用这些更改,即使在不同的分支上。
当你想记录工作目录和索引的当前状态,但又想返回一个干净的工作目录时,右键选择命令TortoiseGit → Stash changes将弹出一个对话框,你可以在其中选择输入此状态的消息:
- include untracked:将未跟踪文件也隐藏起来。
- --all:要隐藏所有文件,包括被忽略的文件和未跟踪的文件。
如果你需要应用Stash起来的更改,右键选择命令TortoiseGit → stash list → 选中要应用的修改 → 右键选择Stash Apply
- Stash List:提供了整个Stash堆栈的概览。你还可以删除并查看隐藏在那里的更改。
- Stash Apply:会将选中的那条Stash的更改应用到当前分支,应用后选中的Stash仍然在stash list中。
- Stash Pop:会将最新的那条Stash的更改应用到当前分支,并且会将此条stash从stash list中删除。
10. Clean up
要从工作树中删除未跟踪或忽略的文件,请使用TortoiseGit → Clean up。然后出现一个对话框,允许你从当前目录或整个工作树(取决于安装的git版本)开始,通过递归删除不受版本控制或被忽略的文件来清理工作树。
Remove all untracked files:这将删除所有未跟踪文件,包括Git忽略的文件。这是最干净的选择。
Remove non-ignore untracked files:这将删除未跟踪文件,但不包括Git忽略的文件。
Remove ignored files:只清除被忽略的文件这只删除Git忽略的文件
Remove untracked directories :删除未跟踪目录。
Do not use recycle bin:不要使用回收站,即直接永久删除这些文件。
Dry run:这只是给出了要删除的文件列表,但不执行任何删除。
Submodules :递归地清理子模块。
11. Ignore
编译后会产生一些不受版本控制的文件和文件夹。如用于存储可执行文件bin/、obj/、db、*table等等。每当提交更改时,TortoiseGit都会显示这些派生文件,这将填充提交对话框中的文件列表。当然,你可以关闭此显示,但可能会忘记添加新的源文件。
避免这些问题的最佳方法是将派生文件添加到项目的忽略列表中。这样,它们将永远不会出现在提交对话框中,但真正需要commit的源文件仍将被标记。
右键单击一个或多个未版本化的文件,并选择TortoiseGit→ add to ignore list,将出现一个子菜单,允许你选择按名称或扩展名忽略。如下图二所示,忽略对话框允许你选择忽略类型和忽略文件。
Ignore Type
- 仅忽略包含文件夹中的项目:仅忽略该文件夹中的选定pattern。
- 递归忽略项:忽略该文件夹和子文件夹中具有选定模式的项目。
Ignore File
- 存储库根目录中的.gitignore:在存储库根目录的.gitignore中写入忽略条目。这允许您将忽略列表与远程存储库同步。
- .gitignore位于项目的包含目录中:在包含项的目录中的.gitignore中写入忽略项。这允许您将忽略列表与远程存储库同步。
- .git/info/exclude:在存储库元数据中的.git/info/exclude中写入忽略条目。这允许您在本地存储忽略列表,但不能与远程存储库同步。
12. Amend
- 提交代码到远端仓库后,如果发现提交有遗漏或者提交有误,可以使用如下方法修改最后一条提交信息。
修改后,右键commit -> 选中Amend Last Commit -> 修改代码 or log -> 点击commit -> push的时候选中unknown changes。
13. Cherry Pick
Cherry-pick,即挑选一个需要的commit 进行操作。它可以将在源分支A上的commit修改移植到目标分支B。
(1)pull or fetch,确保本地仓库含有源分支A和目标分支B的最新内容。
(2)本地仓库切到目标分支B -> 右键TortoiseGit show log -> 点击右上角的目标分支,选中源分支A -> 选中所需的commit -> 右键,点击Cherry pick this comment -> 如果需要多个commit,点击add添加 -> 点击continue,即可在目标分支的log里看到刚刚cherry pick的commit。
14. Q&A
情形1:代码clone到本地,simstudio编译fail,但报错很奇怪,看起来代码没有问题,
情形2:编译pass,但是运行的时候断点没触发,表面看起来运行的不是这份代码生成的dll,但是remove、 rebuild工程都不行
以上两种情况很可能是文件的行尾造成的,不同操作系统使用不同的换行符表示行尾,例如Windows使用回车换行符(CRLF,\r\n),而Linux、Mac OS使用换行符(LF,\n)。代码行尾符的变化可能由于编辑器或者git的行尾符默认设置导致的。
配置git的行尾符默认设置,如果AutoCrLf为false(表示Git不会自动转换换行符),点击Edit global.gitconfig改为true,ture代表Git会自动将换行符转换为操作系统默认的换行符,如下图所示:
如果还存在行尾符不是PC行尾符的情况,可以使用git bash的unix2dos命令。
查看行尾符:使用beyonce compare打开文件,点击规则,选中比较行结尾即可。