源代码管理
在第十四周的团队博客作业上,王老师让我们针对团队项目源代码管理提出了是个问题并进行了解析,我们根据自己的实际情况,给出了这十个问题的答案,并整理成了团队博客发布。
作为一个程序猿,源码的管理是一个头等大事来的,想象一下,修改完成却发现文件丢失了,该怎么办?有了源代码管理工具,能够帮助我们查看某个代码文件的修改内存及历史修改记录。
软件工程中,也有类似脚手架,塔吊这样的工程系统,工具和流程。 软件的源代码管理工具(source code control system),加上构建系统 (build system), 能保证一个复杂软件能在多个角色,多个团队的合作下,按时以合适的质量发布。 如果你写一个Hello World 程序, 当然不需要这些工具, 就像你用儿童积木搭房子过家家,你自己高兴,但这不是建筑工程。在经过(实际不到)一年的学习(入坑),我使用过Gitlab,GitHub,Gitee作为源代码管理器
源代码管理的10 个实践问题:
1.你的团队的源代码控制在哪里?用的是什么系统?如何处理文件的锁定问题?
场景:程序员1正在对几个文件进行修改,实现一个大的功能,这时候,程序员2也要改其中一个文件,快速修复一个问题,该怎么办?
一个代码文件被签出后,另一个团队成员可以签出这个文件,并修改,然后签入吗?
有几种设计?各有什么优缺点?
答:源代码的控制在github上,当一个人签出一个文件后,另一个人不可以签出这个文件,这样的优点是保证文件不会混乱,如果两个人修改了同一个地方,就不知道最后采取谁的方法,缺点是可能会影响程序开发的效率,因为如果两个人同时修改这个文件不同的地方便会加快开发的效率。
2. 如何看到这个文件和之前版本的差异?如何看到代码修改和工作项(work item),缺陷修复 (bug fix) 的关系。
答:每次push时在commit中的message部分注明修改内容,这样本次checkin做了什么改动一目了然;也可以在coding.net代码详情中查看具体做了哪些修改。另外我们小组的开发工具也支持版本控制,可查看具体的修改。
例如:
假设场景,例如当某团队程序员看到某个文件被修改了,并且想要阅读到这个文件在最近的修改酒精改动了哪些地方,或者说看到某个文件在最新版本被改动了几百行,那么这几百行对应的其他修改在何处文件中,这些修改所要解决的问题以及工作项,如何找寻到这些bug或是问题来源呢?
1、本团队发现很多开发工具都有show history(查看历史)的功能,那么我们点击此功能,就可以查询到历史改动痕迹或者是历史版本,就像一个时光穿梭机,对于文件的提交历史和提交修改也可以轻松的阅览到,例如由我们安卓开发软件Android studio我们就可以看到有的history查看功能:
2、当我们打开github的时候,我们也可以看到在github网页版主页中,当我们选中我们的其中一个项目之后,进入code界面,点击comparing changes,就会看到你的项目的改动
3、对于查询历史改动在何处的场景问题,基本是通过查看提交时候的comment来确定这次提交的修改原因是什么。Bug和功能列表通常在另外一个系统记录,比如:Excel,在Excel里面对Bug和功能进行标记(已完成,未完成,进行中),一般开会的时候大家对近期修复的Bug和功能按照这个Excel表的内容一起来过一遍。对于和这个几百多行的修改一起签入的其他修改,在Eclipse+SVN下可以查看相关修改的文件以及修改原因:
在某个文件上点击右键:Team->显示资源历史纪录:
也可以自动关联bug/issue和每次签入的修改之间的关系,用户可以提交Issue,并把Issue标记为bug,开发人员提交代码的时候,加上以下描述信息,对应的Issue就会被Close,fix #+Issue编号,如:fix #1 对应编号为1的Issue被关闭
3. 如果某个文件在你签出之后已经被别人修改,并且签入了,那么你在签入你的修改的时候, 如何合并不同的修改(merge)? 你用了什么工具来帮助你?
本团队想到可以使用GitBash工具更新本地仓库,有冲突时对比解决冲突,然后签入代码。又或者备份本地自己开发的一份代码,先把别人签入的代码更新到本地,然后在本地手动合并修改,用的工具是Beyond Compare。
4.你有20个文件都是关于同一个功能的修改,你要如何保证这些文件都同时签入成功,或者同时签入不成功?
场景:程序员1要签入20 个文件,他一个一个地签入, 在签入完5 个 .h 文件之后, 他发现一些 .cpp 文件和最新的版本有冲突,他正在花时间琢磨如何合并... 这时候, 程序员2从客户端同步了所有最新代码,开始编译,但是编译不成功- 因为有不同步的 .h 文件和 .cpp 文件! 这时候, 别的程序员也来抱怨同样的问题,程序员1应该怎么办?
答:在签入之前,一定要先对比处理有冲突的文件,这样可以方便他人使用修改
在签入的时候,先把冲突文件更新下来,与本地自己要签入的文件进行一轮合并。再去签入。
5、你的PC 上有关于三个功能的修改, 但是都没有完成,有很多文件处于半完工的状态,这时你要紧急修改一个新的 bug,如何把本地修改放一边,保证在干净的环境中修改这个 bug, 并成功地签入你的修改 --- changelist management。
答:1)在new分支上的时候在命令行输入:
git stash
或者
git stash save “修改的信息"。
这样以后你的代码就回到自己上一个commit了,直接git stash的话git stash的栈会直接给你一个hash值作为版本的说明,如果用git stash save “修改的信息”,git stash的栈会把你填写的“修改的信息”作为版本的说明。
2)接下来你回到old分支修改代码完成,你又再回到new分支,输入:
git stash pop
或者
git stash list
git stash apply stash@{0}
就可以回到保存的版本了。git stash pop的作用是将git stash栈中最后一个版本取出来,git stash apply stash@{0}的作用是可以指定栈中的一个版本
3)通过git stash list可以看到所有的版本信息:
stash@{0}: On order-master-bugfix: 22222
stash@{1}: On order-master-bugfix: 22222
4)然后你可以选择一个你需要的版本执行:
git stash apply stash@{0}
这时候你搁置的代码就回来了。
6、规范操作和自动化
你的团队规定开发者签入的时候要做这些事情:
- 运行单元测试,相关的代码质量测试。
- 代码复审 (要有别的员工的名字)
- 和这次签入相关的issue 编号, 任务/task, 缺陷/bug 编号,等等, 以备查询。
请问你的团队有这样的自动化工具让开发者方便地一次性填入所有信息然后提交么? (高级功能, 代码提交之后, 相关bug 的状态会改动为 “fixed”, 并且有链接指向这次签入。)
答:暂时没有。
8. 一个源文件,如何知道它的每一行都是什么时候签入的,为了什么目的签入的 (解决了哪个任务,或者哪个bug)?
场景: 一个重要的软件历经几年,几个团队的开发和维护,忽然出现在某个条件下崩溃的事故, 程序员果冻经过各种debug手段,发现问题是在某一个文件中有一行代码似乎显然出了问题, 但是这个模块被很多其他模块调用, 这行代码是什么时候,为了什么目的,经过谁签入的呢? 如果贸然修改, 会不会导致其他问题呢? 怎么办?
成员在Gitlab上提交修改过的代码,都会要求添加备注,比如修改的地方,还有修改的原因。这样,当代码出现问题之后,就可以很容易的找到当时的修改人,查看原因,有助于代码的修改。
下面的commit可以填写该项目需要备注的信息,比如可以编辑 人员/update/时间等信息 方便对项目进行管理
8. 一个源文件,如何知道它的每一行都是什么时候签入的,为了什么目的签入的 (解决了哪个任务,或者哪个bug)?
场景: 一个重要的软件历经几年,几个团队的开发和维护,忽然出现在某个条件下崩溃的事故, 程序员果冻经过各种debug手段,发现问题是在某一个文件中有一行代码似乎显然出了问题, 但是这个模块被很多其他模块调用, 这行代码是什么时候,为了什么目的,经过谁签入的呢? 如果贸然修改, 会不会导致其他问题呢? 怎么办?
1)查看分支
git branch 查看本地仓库
git branch -r 查看远程仓库
2)创建分支
git checkout -b feature-A
3)切换分支
git checkout master 切换到master分支
git checkout - 切换回上一个分支
4)获取仓库代码
git pull origin master
5)修改代码提交到feature-A分支上
git add . 添加文件
git commit -m 'add branch' 提交代码
git push -u origin feature-A 推送至远程仓库master以外的分支
6)合并代码到master分支
假设分支feature-A已经实现完成,想要将它合并到主干分支master中。首先切换到master分支
git checkout master
git merge --no-ff feature-A
7)以图表形式查看分支
git log --graph
也可以通过可视化工具进行创建分支
9. 如何给一个系统的所有源文件都打上标签,这样别人可以同步所有有这个标签的文件版本?
代码每天都在变, 有时质量变好,有时变差,我们需要一个 Last Known Good (最后稳定的好版本) 版本, 这样新员工就可以同步这个版本, 我们如果需要发布,也是从这个版本开始。 那么如何标记这个 Last Known Good 版本呢?
用户手册
meel@YLIN-VPC MINGW64 /t/Desktop/scrap_bilibili (master)
$ git tag -h
usage: git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] <tagname> [<head>]
or: git tag -d <tagname>...
or: git tag -l [-n[<num>]] [--contains <commit>] [--no-contains <commit>] [--points-at <object>]
[--format=<format>] [--[no-]merged [<commit>]] [<pattern>...]
or: git tag -v [--format=<format>] <tagname>...
-l, --list list tag names
-n[<n>] print <n> lines of each tag message
-d, --delete delete tags
-v, --verify verify tags
Tag creation options
-a, --annotate annotated tag, needs a message
-m, --message <message>
tag message
-F, --file <file> read message from file
-e, --edit force edit of tag message
-s, --sign annotated and GPG-signed tag
--cleanup <mode> how to strip spaces and #comments from message
-u, --local-user <key-id>
use another key to sign the tag
-f, --force replace the tag if exists
--create-reflog create a reflog
Tag listing options
--column[=<style>] show tag list in columns
--contains <commit> print only tags that contain the commit
--no-contains <commit>
print only tags that don't contain the commit
--merged <commit> print only tags that are merged
--no-merged <commit> print only tags that are not merged
--sort <key> field name to sort on
--points-at <object> print only tags of the object
--format <format> format to use for the output
--color[=<when>] respect format colors
-i, --ignore-case sorting and filtering are case insensitive
列出现有标签
命令:git tag
参数说明:
-l:接通配符表达式实现筛选
例子:
# 刚开始进入项目,发现没有标签,后面会逐一补充
meel@YLIN-VPC MINGW64 /t/Desktop/scrap_bilibili (master)
$ git tag
新建标签
命令:git tag -a v0.1.0 -m 'init'
参数说明:
-a/--annotated:注释,后接标签名,不需要引号
-m/--message:信息,后接注释说明文字,需带引号
结果:
meel@YLIN-VPC MINGW64 /t/Desktop/scrap_bilibili (master)
$ git tag -a v0.1.0 -m 'init'
meel@YLIN-VPC MINGW64 /t/Desktop/scrap_bilibili (master)
$ git tag
v0.1.0
meel@YLIN-VPC MINGW64 /t/Desktop/scrap_bilibili (master)
$ git show v0.1.0
tag v0.1.0
Tagger: unknown <545641826@qq.com>
Date: Mon May 27 04:58:08 2019 +0800
init
commit b30d3b3e00a93e43d8219ca584b4ce380c6f6be8 (HEAD -> master, tag: v0.1.0, origin/master, origin/HEAD)
Author: ylin <545641826@qq.com>
Date: Tue Dec 11 11:46:10 2018 +0800
first commit
diff --git a/.gitignore b/.gitignore
index 871bb87..8fbdcbe 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
cookie
+.idea*
注:git show 接标签名可查看当前项目指定标签具体信息
上传标签
命令:git push origin v0.1.0
参数说明:
需要在push时指定远程仓库(默认当前分支),后加标签名.
例子:
meel@YLIN-VPC MINGW64 /t/Desktop/scrap_bilibili (master)
$ touch test
meel@YLIN-VPC MINGW64 /t/Desktop/scrap_bilibili (master)
$ ls
headers memorandom.txt rename.py* scrap.py* test
meel@YLIN-VPC MINGW64 /t/Desktop/scrap_bilibili (master)
$ git add .
meel@YLIN-VPC MINGW64 /t/Desktop/scrap_bilibili (master)
$ git commit -m'test'
[master b57b583] test
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 test
meel@YLIN-VPC MINGW64 /t/Desktop/scrap_bilibili (master)
$ git push
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 32 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 255 bytes | 255.00 KiB/s, done.
Total 3 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
To https://github.com/545641826/scrap_bilibili.git
b30d3b3..b57b583 master -> master
回退到标签版本
新建文件模拟bug
此时远程仓库如图:
回退:
首先通过标签查看提交id
然后通过reset --hard 回退到指定提交版本.
最后提交
meel@YLIN-VPC MINGW64 /t/Desktop/scrap_bilibili (master)
$ git show v0.1.0
tag v0.1.0
Tagger: unknown <545641826@qq.com>
Date: Mon May 27 04:58:08 2019 +0800
init
commit b30d3b3e00a93e43d8219ca584b4ce380c6f6be8 (tag: v0.1.0)
Author: ylin <545641826@qq.com>
Date: Tue Dec 11 11:46:10 2018 +0800
first commit
diff --git a/.gitignore b/.gitignore
index 871bb87..8fbdcbe 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
cookie
+.idea*
meel@YLIN-VPC MINGW64 /t/Desktop/scrap_bilibili (master)
$ git reset --hard b30d
HEAD is now at b30d3b3 first commit
meel@YLIN-VPC MINGW64 /t/Desktop/scrap_bilibili (master)
$ ls
headers memorandom.txt rename.py* scrap.py*
1:测试相关代码和源代码都在同一个项目的同一个文件夹下,相当于是放在一起了。 修改了源代码,相关测试会自动更新。团队暂时没有部署自动构建任务
2:自动测试暂时还没有去做,所以这一步可能还未涉及到
3:还未涉及到服务器以及自动测试相关,所以这一步暂时没有
4:暂未配置服务器,所以暂时没有自动同步以及相关功能
心得体会:
在做这项作业的时候,我们团队一开始很多人都针对这些问题有许多不理解的点,和不理解的专业术语专业问题等等,但在我们探索的过程中和团队间的互相交流中我们了解了许多其他的辅助我们团队开发的软件,以及对于协助团队更改更新代码的软件,通过解答问题,我们团队对于这些软件的操作也愈加熟练起来,针对源文件签入,bug修改,查找历史修改文件,为所有源文件打上标签,同步所有有这个标签的文件版本,自动运行单元测试,从一开始的需求分析,到软件制作,到软件技术层面上的代码bug修改,到最后的测试环节,在本报告中所提及的问题中都有所涉及,我们在思考探索如果自动同步所有文件,自动构建,自动运行单元测试,碰到错误如何能够自动发邮件给团队,等等我们以往从未考虑到的问题,或者考虑到但从未想过该如何解决的问题时,通过这项作业我们每一个成员都有了新的思考和结果,我们也学会了如何运用软件协助我们完成一个新的项目,并监督每个成员期间的过程和操作,推动整项项目的顺利进展。