相对纯软开发,一般对嵌入式小型项目的版本管理不会太重视。在一些中小厂可能还使用着U盘拷贝的方式去保存、转移代码。
但当项目的代码量增加、迭代速度加快、团队协作人数变多后,版本管理的重要性就很明显了。
所以掌握版本管理工具的使用可以说是资深开发者必备的技能之一。
版本管理的工具有很多,其中Git以其分布式和高效分支管理等特性成为了当前最主流。
以下是个人整理的Git学习笔记,仅供初学者学习,参考书籍是《Pro Git》,注意Git是一个工具,实践性较强,建议可以先简单学习了解其特性,具体指令可以遇到问题后再查阅学习使用,待使用较为熟练后再看《Pro Git》进行系统学习。
常用指令
git branch -a 查询所有分支;
git branch new_dev 创建new_dev分支;
git checkout new_dev 切换到new_dev分支;
git merged my_dev 把my_dev分支合并到当前分支;
git rebase last_dev 把当前分支的提交转移到last_dev分支最后面
git log 查看当前分支提交记录;
git status 查询文件状态;
git rm --cached 取消跟踪已暂存文件
git diff 查看文件改动;
git add 暂存文件;
git reset HEAD xxx 取消暂存的xxx文件
git commit -m "这是个备注" 提交更新,并提交信息“这是个备注”
git commit --amend 重新提交更新
git diff file1.c file2.c > my_change.patch 把指定文件的改动生成patch
git apply my_change.patch 应用patch
git tag -a v1.0 -m "my version 1.0" 打附注标签,后续可以用标签来代替分支名称
安装与配置
此过程不再赘述,请自行上网搜索。
Git基础
首先,我们先来介绍一下Git。
Git,是一个分布式版本控制系统(Distributed Version Control System,简称 DVCS)。是用来进行版本控制和管理的,管理代码的版本历史、支持本地和远程操作、分支、合并等。
有的会配合使用的Gerrit,则是基于 Git 的代码审查工具,主要用于代码审查、变更集管理和合并审批的,只是一个补充工具,帮助团队在提交更改前能对代码进行充分的审查。
Git中文件有三种状态:已提交(committed)、已修改(modified) 和 已暂存(staged)。
三个区域:工作区、暂存区以及 Git 目录(仓库)。
状态与区域的关系如下:
- 可以在工作区修改文件,修改后的文件变成已修改(modified)状态;
- 可以把修改的文件选择性的暂存到暂存区 ,在暂存区的文件变成已暂存(staged)状态;
- 可把暂存区的文件提交更新到Git目录(仓库),提交到仓库了的就变成已提交(committed)状态;
后续的基本操作实际就是修改文件的状态,不会有太深奥的东西。
获取仓库
通常有两种获取 Git 项目仓库的方式:
- 将尚未进行版本控制的本地目录转换为 Git 仓库,即自己创建仓库;
- 从其它服务器 克隆 一个已存在的 Git 仓库。
第一种比较少用到,当你需要用到时想必已经到了需要系统学习的阶段了,这里便不再展开了。
第二种方式是我们最常用的,因为一般项目都是团队协作的,最新的工程文件都是存放在远程服务器中。
这也是 Git 区别于其它版本控制系统的一个重要特性,从服务器上克隆下来的几乎是仓库的所有数据,那么当服务器损坏了,还能通过你克隆下来的本地仓库进行恢复。
克隆仓库的命令是 git clone 。 比如,要克隆 Git 的链接库 libgit2
$ git clone https://github.com/libgit2/libgit2
一般我们在GitHub中也用的这种方法克隆代码:
这样你就能看到出现了一个名为 “libgit2” 的目录,所有的项目文件已经在里面了。
Git 也支持多种数据传输协议。 上面的例子使用的是 https:// 协议,需要深入了解的可以自行查阅。
查看Git文件状态
上面已经介绍过,Git中文件有多种状态,那我们可以怎么查看哪些文件处于什么状态呢?
可以使用git status 命令查看:
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean
上面的信息表明,当前分支是“master”(分支后面再进行介绍),当前目录下没有出现过修改,相当干净。
我们创建一个新的 README 文件,使用 git status 命令,将看到一个新的未跟踪文件:
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Untracked files:
(use "git add <file>..." to include in what will be committed)
README
nothing added to commit but untracked files present (use "git add" to track)
未跟踪文件Untracked files,是指既不存在于上次快照的记录中,也还没有被放入暂存区的文件。
所以总的来说还有一种状态:未跟踪(Untracked),因为没有纳入Git区域中,所以不算是Git状态之一,加上上面提及的Git文件的三种状态,转换关系如下图
现在我们再来修改一个已被跟踪的文件。假设修改了一个名为 CONTRIBUTING.md 的已被跟踪的文件,然后运行 git status 命令:
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: README
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working
directory)
modified: CONTRIBUTING.md
文件 CONTRIBUTING.md 出现在 Changes not staged for commit 这行下面,说明已跟踪文件的内容发生了变化,但还没有放到暂存区。
再运行 git add 命令:
$ git add CONTRIBUTING.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: README
modified: CONTRIBUTING.md
现在在两个文件都已暂存了。
忽略文件
git status 会把所有修改过的文件都列了出来,但有时一些文件并不需要Git的管理,例如编译生成的文件,我们可以创建建一个名为 .gitignore的文件,文件内容如下:
$ cat .gitignore
*.[oa]
*~
第一行告诉 Git 忽略所有以 .o 或 .a 结尾的文件。一般这类对象文件和存档文件都是编译过程中出现的。 第二行告诉 Git 忽略所有名字以波浪符(~)结尾的文件。
设置好 .gitignore 文件可以让你后续提交文件更加干净方便一些。至于具体的正则表达式使用方式,请自行查阅。
查看未提交的修改
使用git status 命令可以查看哪些文件有过修改,如果还想看具体修改了什么地方,可以用 git diff 命令。
假如我们再次修改README 和CONTRIBUTING.md 文件,运行git diff 命令:
$ git diff
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 8ebb991..643e24f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -65,7 +65,8 @@ branch directly, things can get messy.
Please include a nice description of your changes when you submit your PR;
if we have to read the whole diff to figure out why you're contributing
in the first place, you're less likely to get feedback and have your
change
-merged in.
+merged in. Also, split your changes into comprehensive chunks if your
patch is
+longer than a dozen lines.
If you are starting to work on a particular area, feel free to submit a
PR
that highlights your work in progress (and note in the PR title that it's
此命令比较的是工作目录中当前文件和暂存区域快照之间的差异。
提交更新
需要提交的文件先git add,把文件暂存起来,然后运行提交命令:
$ git commit
可以添加-m选项,将提交信息与命令放一起:
$ git commit -m "Story 182: Fix benchmarks for speed"
[master 463dc4f] Story 182: Fix benchmarks for speed
2 files changed, 2 insertions(+)
create mode 100644 README
提交后会告诉你,当前是在哪个分支(master)提交的,本次提交的完整 SHA-1 校验和是什么(463dc4f),以及在本次提交中,有多少文件修订过,多少行添加和删改过。
查看提交历史
git log 命令可以回顾提交历史。
撤销操作
有时候我们提交完了才发现漏掉了几个文件没有添加,或者提交信息写错了。 此时,可以运行带有 --amend 选项的提交命令来重新提交:
例如,你提交后发现忘记了又需要修改其他地方,可以修改add后,再像下面这样操作:
$ git commit -m 'initial commit'
$ git add forgotten_file
$ git commit --amend
最终你只会有一个提交——即第一次提交和第二次提交的东西会合成一个提交。
取消暂存的文件
有时候我们会不小心add了不需要的文件,那如何取消暂存呢?
可使用git reset HEAD … 来取消暂存。
Git分支管理
在进行提交操作时,Git 会保存一个提交对象(commit object)。该提交对象会包含一个指向暂存内容快照的指针。每次修改提交后,产生的提交对象还会包含一个指向上次提交对象(父对象)的指针:
Git 的分支,其实本质上仅仅是指向提交对象的可变指针。Git 的默认分支名字是 master。 在多次提交操作之后,你其实已经有一个指向最后那个提交对象的 master 分支。 master 分支会在每次提交时自动向前移动。
分支创建
创建分支:
$ git branch iss53
切换分支:
$ git checkout iss53
Switched to a new branch "iss53"
如果想要新建一个分支并同时切换到那个分支上,你可以运行一个带有 -b 参数的 git checkout 命令:
$ git checkout -b iss53
Switched to a new branch "iss53"
分支合并
需要先切换到你要合并到的目标分支,然后执行合并命令:
$ git checkout master
Switched to a new branch "master"
$ git merge iss53
这样就能把iss53分支合并到你的master分支,合并效果图可以看下面的“变基”章节
远程分支
因为开发中经常会多人协作,所以一般会用远程仓库,需要再补充点远程仓库相关的。
假设有个名为git.ourcompany.com的远程仓库
可以使用git clone <remote_name>命令,下载到本地My Computer中:
当你拉下来之后,别人对远程的master分支提交,变成了:
而我们本地的电脑上则还是:
我们可以运行 git fetch <remote_name> 来抓取远程仓库有而本地没有的数据:
OK,咱们这边修改的提交也想同步到远程仓库,那该怎么办呢?
可以运行 git push 命令
变基
开发任务分叉不同分支:
若使用合并操作:
也可以使用rebase命令:
$ git checkout experiment
$ git rebase master
然后回到 master 分支,进行一次快进合并:
$ git checkout master
$ git merge experiment
变基还有一个好处,就是可以保持提交分支的干净,如下是不加变基的提交合并:
而使用变基的话如下:
显然,使用后者的方式合并代码更方便版本回退调试。
以上指令是初学者比较常用的指令,还是那句话,Git是一个工具,我们要在实践中学习才能事半功倍。