与googlecartographer类似的很多其他开源项目一样,PX4的源码也托管在GitHub上。
GitHub 是一个面向开源及私有软件项目的托管平台,只支持 Git 作为唯一的版本库格式进行托管。其提供了 Git 代码仓库托管及基本的 Web 管理界面。
简单的来说, Git 是一个分布式的版本控制系统。顾名思义,在你编辑程序代码的时候(特别是在多人协作一个项目时),它将会自动帮你实现代码以及版本的更新。这意味着你不必每次都手动地将自己修改的内容同步到云端。这些工作都可以由 Git 在适当的时候自动完成。这样既能避免手动同步的麻烦和风险,更能为程序员省下大量时间。
- Git是目前世界上最先进的分布式版本控制系统
- Git是协同开发的利器
- Git很有用
- 要掌握的知识很少,作用很大
开始之前不妨下载这个文档先了解一下基本的git操作及其相关的实际意义。对下图会有一个基本的认识。
接下来,笔者会针对PX4项目谈谈如何合理地使用git操作对PX4固件进行版本控制。
下载固件
PX4的源码托管在GitHub上,可以从这里找到。
PX4/Firmware
表示Firmware
这个仓库(repository)是由PX4
这个用户主管的。这是PX4的官方仓库,只有官方开发者能决定其中的内容。Fork
。点击这个按钮可以将Firmware
这个仓库fork到自己的用户下。例如,笔者的ID是FantasyJXF
,fork后笔者的Firmware
仓库显示如下图所示。这个仓库中保存了原Firmware
仓库从其创建开始到当前时间节点所有的信息。这是自己的仓库,其中的内容由自己决定。
master
代表当前显示的是仓库master
主分支上的内容。每一个git仓库都有一个master
分支,也可以新建其他分支并编写一些验证算法或者进行其他操作。一个新的分支开始默认都是将master
分支上的内容的复制过来的,在各个分支上的操作是互不影响的。点击master
按钮会看到一个仓库中可能会有很多的分支,如下图所示
同大多数 VCS 一样,Git 也可以对某一时间点上的版本打上标签。人们在发布某个软件版本(比如 v1.0 等等)的时候,经常这么做。
tags
在一定程度上可以与PX4的固件版本号(release)划等号。看下图更加直观
用户可以使用
git checkout xxx
指令在不同的版本、不同的分支下自由切换。据说带RC的不稳定。
clone
地址。git clone https://github.com/PX4/Firmware.git
上面这行指令相信看过PX4的人不会感到陌生。它的作用是将
PX4
这个用户的Firmware
这个仓库克隆(下载)到本地的硬盘上。但是由于Firmware
中还有类似于NuttX
、Mavlink
等子模块在其他的仓库,因此还需要使用以下的指令递归更新子模块git submodule update --init --recursive
完成以上操作后,用户就已经下载好了PX4开发所需要的、所有的、最新的固件了。
显然,以上不是本文的重点。本文要讲的是如何合理的使用git操作进行PX4的二次开发。
从这里正式开始。
下载自己的固件
在这之前需要读者先注册一个github的账号。然后按照上面2
所示的将PX4/Firmware
fork到自己的主目录中。
下载自己的固件
对于笔者来说,输入下列指令
git clone https://github.com/FantasyJXF/Firmware.git
后面的网址是自己的git仓库地址,可以从下图所示位置找到。
切换到特定的版本
由于git版本众多,目前最新已经到了
v1.6.0rc1
,有的版本存在不稳定的情况。使用git tag
指令可以查看历史标签$ git tag v1.0.0 v1.0.0-rc4 v1.0.0beta1 v1.0.0beta2 ... v1.5.1rc4 v1.5.2 v1.5.4 v1.5.5 v1.6.0rc1
读者可以选中一个特定的版本并在上面进行开发。例如下面的指令
git checkout v1.5.2
这句指令的意思是切换到1.5.2版本。然后默认分支为
master
分支。也就是说,当前电脑硬盘上的Firmware
文件夹中显示的是1.5.2版本固件master
分支上的内容。笔者更推荐新建一个自己的分支进行开发,如下
git checkout -b branch_name
这句指令的意思是新建一个
branch_name
分支并切换到该分支。上两句指令可以合成一句
git checkout -b branch_name tag_name
- 要查看当前本地仓库的版本,可以使用
$ git describe --always --tags v1.5.2-10-gf362f4056 # 笔者当前固件版本
- 要查看当前工作分支,可以使用
$ git branch * Fantasy # 笔者当前工作分支 master
到这里,Firmware
只下载了一部分,还是需要更新子模块
git submodule update --init --recursive
这里的子模块路径默认并不在你的用户目录中,因为没有fork子模块的仓库并且在源码中进行.git文件夹下config文件的配置,因此目前对子模块的修改最终无法push到自己的远程仓库中。
要配置的子模块太多,道理都是类似,此处不做过多说明。
关于.git文件夹,它是Git管理信息的目录,记录你每一次提交,保存快照,随着使用,占用内存越来越大。
更新于2017.5.7
子模块的修改需要切换到子模块目录下进行add、 commit 、 push。
必备git指令
经过前面的准备后,读者已经准备好了一套可以编译的PX4源码了。编译Pixhawk的固件的话执行下列指令即可
make px4fmu-v2_default
编译会在Firmware
目录下生成一个build_px4fmu-v2_default
构建文件夹。
接下来介绍几个必备的git指令
status # 显示工作区状态
使用这个指令可能查看当前工作分支,仓库的状态,修改了什么文件,与
origin/master
仓库的区别等等。origin
表示远程仓库,后面会提到。- 如果什么都没有改
$ git status On branch Fantasy nothing to commit, working tree clean
这里表示,在
Fantasy
这个分支下,并且没有要提交的内容。- 当修改了一些文件
$ git status On branch Fantasy 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: Makefile modified: src/drivers/mpu6500/mpu6500.cpp no changes added to commit (use "git add" and/or "git commit -a")
这里可以看到笔者修改了两个文件分别是根目录下的
Makefile
以及src/drivers/mpu6500/mpu6500.cpp
文件。diff #查看更改内容
$ git diff Makefile diff --git a/Makefile b/Makefile index c37610e65..165150b50 100644 --- a/Makefile +++ b/Makefile @@ -77,7 +77,7 @@ endif # in that directory with the target upload. # explicity set default build target -all: posix_sitl_default +all: px4fmu-v2_default # Parsing # --------------------------------------------------------------------
会显示文件具体哪里进行了修改,修改过什么。
很明显,关于Makefile文件,这里我将
all: posix_sitl_default
改成了all: px4fmu-v2_default
-
代表删除+
代表新添add #添加文件内容至索引
修改了文件后,可以将修改后的文件添加到索引
git add . # .表示添加所有修改过的文件 git add file_name # 表示只添加一个文件 git add file_name1 file_name2 # 添加多个文件
添加索引后再查看当前仓库状态
$ git status On branch Fantasy Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: Makefile modified: src/drivers/mpu6500/mpu6500.cpp
提示需要提交(commit)改变
commit #记录变更到版本库
$ git commit -m "modified sth" [Fantasy 3792adf42] modified sth 2 files changed, 6 insertions(+), 2 deletions(-)
使用
git commit
指令,使用-m
控制符,并在最后用双引号""
加入注释,可以说明修改过什么。$ git status On branch Fantasy nothing to commit, working tree clean
这里便保存好了本地的镜像到.git文件夹中
使用
git log
可以查看commit
的列表,看看到底由谁,更改过什么$ git log commit 3792adf429668af8039d7587dff000ed31d65a04 Author: FantasyJXF <931026752@qq.com> Date: Mon Apr 24 14:39:13 2017 +0800 modified sth commit b0ee5256d5ea0f40fe4e3dded9be27bbc3ffa871 Author: Michael Schaeuble <schaeuble.michael@gmail.com> Date: Fri Dec 9 12:46:59 2016 +0100 Disable LPE in px4fmu-v2_default With GCC 4.9 the binary is to large for the flash memory. This is why we disabled LPE on that platform. commit bdb76d013eb97c681aa2206e250adbb33c5ee9cb Author: Michael Schaeuble <schaeuble.michael@gmail.com> Date: Fri Dec 9 11:55:16 2016 +0100 ... :
可以看到刚刚由笔者完成了一次提交。
采用vi相应指令退出。q、wq! ……
push #更新远程引用和相关的对象
由于这里笔者是clone的自己的仓库,并且在自己的分支上(而不是默认的master)操作。可以将改变提交到自己的远程仓库的远程分支上。
使用
git remote
列出已经存在的远程分支$ git remote origin
可以看到这里有一个远程仓库
origin
,这是远程仓库的默认名称。使用
git remote -v|--verbose
列出详细信息,在每一个名字后面列出其远程url。$ git remote -v origin https://github.com/FantasyJXF/Firmware.git (fetch) origin https://github.com/FantasyJXF/Firmware.git (push) # or $ git remote --verbose origin https://github.com/FantasyJXF/Firmware.git (fetch) origin https://github.com/FantasyJXF/Firmware.git (push)
这里可以看到远程的
fetch
和pull
地址。使用下列指令可以将本地的提交push到远程github服务器上。
$ git push origin Fantasy Counting objects: 7, done. Delta compression using up to 4 threads. Compressing objects: 100% (6/6), done. Writing objects: 100% (7/7), 655 bytes | 0 bytes/s, done. Total 7 (delta 5), reused 1 (delta 1) remote: Resolving deltas: 100% (5/5), completed with 5 local objects. To https://github.com/FantasyJXF/Firmware.git * [new branch] Fantasy -> Fantasy
这样自己的修改就保存到了服务器上了,在自己的分支上,始终存在。
reset #版本回溯
使用
git reflog
可以详细的查看自己的每一次操作$ git reflog 3792adf42 HEAD@{1}: commit: modified sth b0ee5256d HEAD@{2}: checkout: moving from master to Fantasy 3ba3aff50 HEAD@{3}: clone: from https://github.com/FantasyJXF/Firmware.git
前面一串数字是hash值,每一次动作都会有唯一的hash值。记录你的每一次快照。
现在如果你进行了一些更改,并且已经提交,但是不想要了,想回到改之前的样子,那么久可以用
git reset
进行版本回溯了$ git reset --hard b0ee5256d HEAD is now at b0ee5256d Disable LPE in px4fmu-v2_default
这里笔者将版本回退到刚刚切换分支的时候,正好什么都没有改。
可以看到,之前的更改都已经舍去了。
不不确定的话先还可以使用
git log -p b0ee5256d
查看此次提交的改变内容
merge/rebase #合并与衍合
git作为一种版本控制工具在协同开发上发挥着巨大的作用。
许多用户可以在自己的分支上操作,然后将修改提交到上游,供主管合并。
一个简单的本地合并如下
首先由自己的分支切换到
master
分支$ git checkout master Switched to branch 'master' Your branch is up-to-date with 'origin/master'.
直接merge
$ git merge Fantasy Auto-merging src/drivers/mpu6500/mpu6500.cpp Auto-merging Makefile Merge made by the 'recursive' strategy. Makefile | 2 +- src/drivers/mpu6500/mpu6500.cpp | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-)
这个操作将
Fantasy
分支合并到了master
分支。在Fantasy
分支上的修改现在已经应用到了master分支上。关于
rebase
的作用是衍合指定分支到当前分支,有所图有所不同。读者请自行查阅
rebase
相当于是在本地将多次提交合并成了一个大的commit号,省略了中间的一些小提交。个人更加推荐直接merge
下一部分对于PX4意义不大,很难得会有提交代码的机会,不过作为追踪更新,看看也好。
同步远程仓库
一般笔者很少在
master
分支上操作,主要在该分支上跟踪远程master
仓库的更新。最开始用户在github上fork出一个项目后,如果原有的项目更新了,自己fork出来的项目需要与原有项目保持同步,需要做一些处理
- 首先添加你从github上fork的源仓库到本地的git工程
$ git remote add source_repository_name [url] # 对于PX4,则是 # git remote add Firmware https://github.com/PX4/Firmware.git
假设origin仓库和source_repository_name源仓库都有一个分支branch_name,你在该分支上进行开发,将本地修改commit后,在每次Push前做如下操作,即可实现和上游source_repository_name仓库同步:(需要注意的是在操作step2之前,一定要将checkout到branch_name所指定的branch)
- 同步源仓库的信息到本地
$ git remote update source_repository_name # 对于PX4,则是 # git pull Firmware master
现在使用
git remote
会发现多了一个远程仓库$ git remote Devguide origin
详细信息
$ git remote -v Devguide https://github.com/PX4/Devguide.git (fetch) Devguide https://github.com/PX4/Devguide.git (push) origin https://github.com/FantasyJXF/Devguide.git (fetch) origin https://github.com/FantasyJXF/Devguide.git (push)
- 将源仓库的信息merge到本地分支:
$ git checkout branch_name $ git rebase source_repository_name/branch_name # 对于笔者的分支,则是 # git checkout Fantasy # git rebase Firmware/master
- 提交代码
$ git push origin Fantasy
这一步将最新同步的代码和修改,提交到你的origin仓库
- PR
在Github网页上提出Push Request即可,将你的origin仓库的所有修改提交到source_repository_name仓库,完成贡献。
GitHub常用的开发协同流程为:将别人的仓库fork成自己的origin仓库 → git clone origin仓库到本地 → 本地添加fork源仓库 → 工作前先git remote update下fork源保持代码较新 → coding → push回自己 → github上提出Push Request即可
Tips
在使用Git 的时候,经常会遇到需要频繁输入密码的情况,每次git push 和 git pull 都要求输入用户名和密码,如果提交频繁的话就十分不方便。
那么怎么在Ubuntu下解决Git保存用户名和密码呢?
1、进入Git 配置文件。
~$ vim ~/.gitconfig
2、修改配置文件,添加下面这一行。
[credential]
helper = store
然后使用的时候,输入一次用户名和密码之后,就不会出现再提交用户名和密码。
总结
对于PX4的的git操作,笔者觉得可以是:将代码fork到自己的用户目录下;clone自己的仓库,并选定一个版本开发,在自己的分支开发;push到自己的远程仓库;添加源仓库地址,pull源仓库更新内容(这一步可有可无)。
最后要说的话:
以上涉及到的只有非常基本指令。git非常强大,功能很多,感兴趣的可以查阅资料深入了解。至少要熟悉仓库、版本库、暂存区的概念。
本文仅仅是抛砖引玉,只是想说明git真的很有用。
一张好图
By Fantasy