首先为何要写这篇文章?由于最近老是遇到有人在问一些关于代码管理的问题,好比怎么从 仓库拉代码,上传代码,也有彻底没用过代码管理系统的。所以这篇文章是结合这几年来使用 git 团队协做或我的的代码管理的使用心得。html
那 git 是什么呢?git 是一个分布式代码管理系统,可能不少人以前用过 svn 这样的代码管理系统。不过 git 的特色是分布式,以及更加便捷的协做方式。git 的使用也是十分普遍,好比程序员交友圈 github, gitlab, gogs 等等代码托管平台都是使用 git 做为代码管理工具。git
SSH加密认证原理: SSH(Secure Shell)是一种非对称加密与对称加密算法相结合的安全网络协议,用于计算机通讯加密。一个SSH会话的创建过程分为两个阶段:第一阶段,双方沟通并赞成创建一个加密链接通道以供后续信息传输用;第二阶段,对请求接入的用户进行身份验证以肯定服务器端是否要给该用户开放访问权限。详细的文章请参考理解SSH的加密与链接过程 。程序员
首先,若是主机本地没有创建秘钥对,就须要生成。生成方式:github
固然你可使用默认的方式,一路回车下去便可。或者也能够指定名称。例如 test,一路回车便可。算法
在当前目录下会看到生成的秘钥对以下,其中带后缀.pub 为公钥,没有后缀的为私钥。vim
这样就生成好了秘钥对,切记不要将私钥随意上传到能被网络访问、下载。我的的作法是用一套密钥对来管理全部的终端,好比云主机的 ssh 登录方式。缓存
这里以 github 举例,你将你的公钥拷贝后,登入 github, 而后找到 Settings -> SSH and GPG keys。 如图的所示的地方新建并粘贴。安全
点击进入,如图所示:bash
当搞定这个了就能够愉快的在 github 代码托管仓库建立你的项目了,这里我就一个测试的项目讲解个人使用过程。第一步新建项目:服务器
点击进入,填写项目名称以及项目的访问方式, 这里我以公开访问方式,也就是全部人均可以访问这个项目。
新建项目完成后第一个要作的就是将这个项目 clone(克隆) 到本地主机。
而后在终端中输入, 这是第一个命令。
git clone git@github.com:huangxiaojingCN/LearningGit.git
复制代码
在终端命令行中输入: ls -al 查看, 能够看到有一个隐藏的目录文件 .git, 在这个文件下就是记录这个代码仓库的全部信息,其中也有不少功能能够用以咱们对代码的自动化,代码检查等等。
接下来是第二个命令:git add 文件
// 建立一个新的空白文件,你可使用文本编辑器打开并编辑内容,也可使用 echo "This is a a.txt." >> a.txt
touch a.txt
// 将字符串 "hello world" 重定向到 a.txt
echo "This is a a.txt" >> a.txt
// 经过 git add a.txt 文件加入到本地代码管理
git add a.txt
复制代码
固然你也可使用 git add -p 命令来提交文件中的添加记录, 前提是这个文件以及在本地代码管理库中存在。稍后再说这个用法,很是实用。
第三个命令: git status, 查看当前代码库的状态
git status
复制代码
不难看到,咱们发现刚才执行了 git add a.txt 的命令被加入到了缓存区,即将要被提交 commit,固然你也能够删除它,执行 git rm --cached a.txt。
第四个命令: git commit -m "提交消息",只有在执行了 git add 将其加入到本地缓存区后才能使用 commit, 将其加入到本地代码仓库。
git commit -m "添加了 a.txt 文件,并加入了 hello world 文本内容."
复制代码
从上面的结果显示中能够看到,a.txt 被正确建立并加入到了本地代码管理库中。接着经过前面的命令 git status 查看下当前的代码库状态, 能够发现已经没有文件要被提交。
通过上面的两个步骤:git add、git commit 就已经代码加入到了本地代码仓库中,经过 git status 辅助查看本地代码仓库的状态。 这三个命令构成另外一次本地代码的的提交,比较基础可是很是经常使用。
第五个命令: git log, 从名字不难看出就是要看看咱们本地代码仓库的日志。
git log
复制代码
看到上面的截图是否是就发现,咱们刚才提交的信息也被展示出来啦!没错,这就是告诉你文件被正确提交并加入到了本地代码仓库中。可能你们发现了有一个 HEAD-> master,你只须要记住,当前 HEAD 所在的地方就是你的代码的版本。若是你发现你的截图跟我不一致,没有 Author 那是由于还没配置,这个后面再说,先说完整个 git 使用流程。
如今再来修改下 a.txt 的内容: 好比咱们加入其余文本内容以下, 笔者使用的 vim 编辑方式,固然你可使用你顺手的,好比编辑器等等。
编辑完后引入新的 git add 带参数的方式:
git add -p
复制代码
请你仔细看, 从第一行开始: diff --git a/a.txt b/a.txt 就是比较原来的 a.txt 和如今更改后的 a.txt 有啥区别。 绿色的 "+" 号表示新添加的,红色的 "-" 号表明删除的内容。最后一行方框中有选择[y, n,q,a,d, /, e, ?],而后让你填写一种,通常咱们使用最多的就是: y(yes)、n(no)、q(quit)。 这里咱们写入 y 后回车。
不知道还记不记得前面提到的 git status, 用来查看当前本地代码仓库的状态。你看出了什么变化吗?😄😄 前面添加的文件若是是新的, 那么看到的就是 new file, 若是是修改的是 modified。这也很好理解嘛!
那下一步咱们是否是又要提交啦!继续 git commit -m "提交信息"
而后查看一下 git log 日志吧!嗯嗯,是否是又看到了新修改的 a.txt 文件啦!
为了巩固前面的学到的知识,咱们将继续新建一个文件, 巩固 add、commit、status、log 的用法, 来来来
touch b.txt
echo "This is a b.txt" >> b.txt
git add b.txt
复制代码
按照管理,看看本地代码库的状态: git status
ok! 翻译一下吧!说的就是告诉你这个文件未被追踪,也就是未被加入本地代码仓库中。你可使用 git add file 的方式去添加。那就执行 git add b.txt, 而后经过 git status 看看。 是否是很熟悉啦!可是我写到想吐😄
到了这人咱们是否是就要提交了,从它的结果中也是能够看出的。继续执行:
git commit -m "添加了 a.txt 文件,加入了 This is a b.txt 文本内容."
复制代码
这个结果也是前面见过的,你应该有感受了吧!这里告诉咱们的是 b.txt 也被加入到本地代码仓库中。
快快使用 git status 和 git log 来瞅瞅吧!大佬!
又一个文件被添加到本地代码库管理了。可是这里你看看 log 的方式是不不够清晰,咱们能不能看看它的生长过程。这个时候咱们就要为 log 加上一些参数啦!
// --graph 图形化展现
// --decorate 查看当前提交的 commit 信息和其余的描述信息
// --all 查看全部的分支,分支的几率后面再说。
git log --graph --decorate --all
复制代码
看到区别了吧! 是否是旁边多了一条线,这个就比如咱们物流时间轴。后面的确定是包含前面的过程,在这里就是后面会包含前面提交的文件。好比当前 HEAD 所在的地方,执行 ls,能够看到即包含了 a.txt 又包含了 b.txt。
梳理一下前面的过程: 其无非核心的就是: add -> commit, 辅助 git status, git log 来完成提交到本地代码库的操做。
接下来就开始往远程仓库推代码和拉取代码啦!首先先来解释下前面老是提到的本地代码仓库,这个含义就是你的服务端代码仓库可能不包含你本地新建的文件,很简单嘛!你没有把信息同步给别人,别人是不知情你的本地的变化的。在这里我就引入远程代码仓库。接下来就是和远程仓库的交互。
再回顾下前面 log 日志打印内容, 你会发现有一串很长的数字。它表明了当前的提交的惟一标示,即咱们能够经过它找到任意一次提交的代码。
第七个命令: git push。 push 的单词意思就是推送,即客户端向远程仓库推送代码。那 origin 又是什么? 这个实际上是远程仓库的名字而已,它等效于前面克隆的地址。你能够经过 git remote show origin 来查看。
git push origin HEAD:分支
复制代码
从打印能够看到,Push URL: 即咱们要推送的地址,而 Fetch URL 就是咱们要拉取代码的地址。
好吧! 那咱们执行提交代码的命令看看效果。
// HEAD 即当前所在的分支
// : 冒号左边是本地分支, 右边是远程分支, 那这里的 huangsanyang/add_a_and_b 即为远程的分支名称
// 完整的理解就是: 将本地 HEAD 的分支推向远程仓库名为 huangsanyang/add_a_and_b 的分支
HEAD:huangsanyang/add_a_and_b
复制代码
使用 git log --graph --decorate --all 查看日志,这下多了点区别,能够看到当前 HEAD 所在地方,右侧还有一个红色的 origin/huangsanyang/add_a_and_b, 这就是告诉咱们这是一个远程分支, 从前面的 origin 就能够看出。
再次回顾: 一次完整的推送代码到远程仓库的流程为: add -> commit -> push。 再次 看看 github 代码仓库,是否是已经包含了咱们的提交啦!说明已经正确将本地的代码仓库提交到远程代码仓库。至关于作了一次远程备份。
到了这儿,咱们就将从零新建项目到推送代码到远程服务器仓库的流程啦!
拉取代码和多人协做一块儿讲解,如今假定你是项目组长,你拥有这个代码仓库的全部权,你能够删除、指定谁能协助项目开发、审核代码、合并代码。
这里我掏出了我本身使用的电脑,做为一个项目管理者的方式参与到协做开发中。由于我也是第一次克隆,各位请注意这是新的人员。因此你不是一我的在战斗....
老生常谈:查看一下 log 日志吧! 是否是和前面的 push 后同样。
接着我开始开发个人功能,好比我新建了 123.txt
touch 123.txt
echo "123456" >> 123.txt
git add 123.txt
复制代码
如今你还会忘记要干吗吗?若是忘记就该撞墙去。 git commit -m "添加了 123.txt "
再来看看 log, 是否是当前的 HEAD 指向了 huangsanyang/add_a_and_b, 这个也就是当前的本地分支啦!你还会看到后面一个分支有一个 origin/HEAD, 这个告诉咱们远程服务器的 HEAD 分支比咱们本地刚才提交分支少了一个 123.txt 文件。也就是说前面的开发者是无法拿到 123.txt, 那若是要拿到该怎么办呢?
继续提交吧!这一次提交是项目管理员,也是另外一个协做的开发者提交的代码。
别慌,苟住。继续来看 log 日志。这里我提交另外一个新的文件 123.txt, 推向了远程服务器分支 huangxiaojing/add_123。
OK, 让咱们回到前面的开发者,看他怎么获取最新的代码。这就很天然的过多到了 git fetch
git fetch --all
复制代码
sorry,可能仔细的你发现,我是用的是 git fetchall 而不是 git fetch --all, 那是由于我使用别名的方式简化了拉取指令。别名在后面的 git 补充篇讲解。
来看 log 日志,是否是拿到最新的代码了呢? 也就是管理员做者提交的代码 123.txt。
能够看到分支确实能看到了吧!不过你经过 ls 查看并无发现咱们想要的 123.txt。 那是由于你没有留意的你本地的 HEAD 指向的是哪里。能够看到当前的 HEAD 是要早于 123.txt 以前提交的。因此确定没有的。那怎么办?
啊哈!咱们就来看看怎么把分支切换到最新的版本上去。引入了新的命令:
// checkout 切换分支
// 分支名: huangsanyang/fetch_123_txt,固然也能够不指定,最好仍是带上。这样更好,更清晰
// 指定分支的哈希值: 这个前面说过,用来肯定惟一的提交记录。
git checkout -b 分支名 指定分支的哈希值
复制代码
来看 log 日志, OK! 切换过来了吧!经过 ls 看看
通过上面的过程,你已经能够和同事进行代码交换啦!你能够拿到同事的代码,经过 fetch -> checkout。可是这样其实也不是很好,咱们的代码仓库应该要有一个好的规范,在全部知名的 git 代码管理的项目中,都会经过维护一个 master 分支来保证稳定的版本。 master 分支应该遵循的原则是,必定要保证能编译经过,能正常部署运行。根据实际状况也能够增长 developer 分支来表示开发的过程的分支。那这里是否是就出现了两条分支了,一个是开发分支,一个是发布分支。 这个时候项目管理员的做用就来了,他务必保证 master 分支的代码必定是全部开发者的代码合体、保证代码稳定运行、代码质量审查。
接下来就要引入稍微高阶的内容:代码合并、审查。
如今回到项目管理者,他首要的就是要保证代码的 master 主干分支是最新的。
很显然不是,由于咱们并无看到 origin/master 是否在最后一次提交的分支。 这里先执行 git push origin HEAD:master 建立出远程 master 分支。
因为没有新的内容须要条,因此能够看到 Total 为 0。接着看看 log 日志,各位再次强调一下,善于使用 log 能让咱们清楚知道当前代码库的状态。
如今看到 origin/master, 咱们已经建立出这样一个用于项目发布的分支。所以做为管理员就要维护这个分支。接下来演示一次合并请求。也就是其余的开发者,编写了代码提交到远程非 master 的分支。开发者能够设置远程 master 分支为保护分支,那么别的开发者就不能往 master 推送代码。
如今切换到普通开发者,编写一个文件 utils.txt
touch utils.txt
echo "这是一个描述项目中使用工具的文件" >> utils.txt
git add utils.txt
复制代码
这里就再也不提供 git status 打印, 读者自行使用查看。经过 commit -> push 以下:
能够看到,开发者已经提交了新代码而且提交了指定分支 origin/huangsanyang/push_utils。 能够看出这样的提交代码风格很是好。由于让项目管理者,能够快速清晰的知道他干了什么。
让咱们切回到项目管理者,来看看他是如何合并代码的。请务必记住,必定要先执行 git fetch --all
git fetch -all
复制代码
再看 log 日志
到了这一步其实也是前面都用到的知识,知识不断的软磨硬泡,旨在让小白变成一个真正的高手。固然若是你看完不练习,当我没说。
在合并的时候,开发者应该要将分支切换到远程 master 所在的地方,而后再合并别的开发的代码。为何要这样,由于是将别的开发者代码往 master 合并,而不是把 master 往开发者合并。要分清那个分支才是最重要的分支。由于开发者写的功能也许有问题。因此必定要注意。
合并的命令:
// merge 合并分支
// --no-ff 不要强制解决冲突,由合并者自行处理
git merge --no-ff 指定合并的分支
复制代码
执行以下的合并指令:
git merge --no-ff c17c8f7e46b666ab84f3ba5b99efc57c1711baed
复制代码
最终的 log 截图, 请你仔细看看,分支走向发生了变化。能够看到有一个分支合并到了 5df2ffb37f131f93fc1db775e1a7dd36674814c9 分支。
若是确认无误,通过严格测试之后符合功能需求,再将其推送到远程 master 分支。
再查看 log
好了,正常合并流程已经讲完。可是你想一想,既然要成为一个高手,若是不去解决点冲突,这能符合高手的常规操做吗?
营造一个冲突环境,好比管理员开发的某个文件的一些代码被另外一个开发者改掉,那么开发者最终提交给管理员的代码和原来管理员的代码确定不一样的。这样是否是就要处理冲突了。
回到开发者,记得 fetch, 记得 checkout 切换分支。 而后修改一下 123.txt 文件, 能够看到他将新增了一些文件,而且修改了原来 12345 改成 1234 sdf6。而后提交。
1234 sdf6
故人西辞富士康
为学技术到蓝翔
蓝翔毕业包分配
尼玛仍是富士康
复制代码
来看看 log 日志,能够看到已经正确提交啦!
这个时候项目管理员就来合并代码啦!记得 fetch, 记得切换到 master 分支。
接着再来执行
git merge --no-ff 348a5e9987981d34ceea031c9cf442bd0aaa7c3c
复制代码
😄😄,你会发现并无冲突,哈哈这是否是很尴尬呀。 那是由于咱们是在 master 上将开发提交的分支往 master 合并。 而开发者实际上是包含了 master 的全部文件和记录。所以此次合并是正常的。其实我就是为了再一次巩固一下合并代码的流程。
其实冲突是多个开发者之间提交的代码中可能都修改同一个文件,且各自的代码都不一致。这个时候项目管理者就要作权衡,选择最好的结果。举个例子,如今代码管理者对 123.txt 进行修改后提交,普通开发者也修改了 123.txt 并提交。
先来看看普通开发者的修改,请注意必定要拉取代码 fetch, 而后 checkout。再次巩固这个两个命令的使用:
// 拉取远程代码仓库的全部分支
git fetch --all
// checkout 切换, branc_name 有意义的分支名, hash: 当前分支的惟一标示
git checkout -b branch_name hash
复制代码
而后使用文本编辑修改内容为:
111111111111111
asdfasdfsa;dlf
故人西辞富士康
为学技术到蓝翔
蓝翔毕业包分配
尼玛仍是富士康
复制代码
而后提交和推送代码到远程仓库。再次回顾命令的使用:
// 将其加入到本地缓存
git add 123.txt
// 提交代码到本地仓库
git commit -m "修改了 123.txt 内容"
// 将代码推送到远程仓库
git push origin HEAD
复制代码
使用 log 查看,命令回顾:
git log --graph --decorate --all
复制代码
不难看出,这一次提交要晚于远程代码仓库的 master 分支的。
接下来看项目管理者的修改, 请注意,这里并无将分支切换到开发者提交的分支上,而是在原来的老的分支上进行直接的修改。
看到下面的 log, 我没有骗你,我确实是在老的分支上,而开发者新提交的代码并无合并到 master
来看项目管理者修改内容变成了什么,是否是和以前的彻底不同,而且将以前的所有改掉啦!
接着又是熟悉的步骤, add、commit、push
OK, 提交成功后,尝试合并。并将最终分支合并到 master。
合并的命令回顾:
git merge --no-ff 被合并的分支
复制代码
看到执行 merge 后的打印了吗?
// 告诉咱们尝试自动合并失败,须要手动合并解决冲突
Automatic merge failed; fix conflicts and then commit the result.
复制代码
OK, 这里你应该选择你最使用方便的编辑器来进行代码的合并操做,好比你可使用 AS 自带的 git 插件。笔者这里使用的是 Emacs 的 git 插件。下面是本次合并信息,能够看出来是分段的,第一、2 行表示当前的分支,三、4两行表示要被合并的分支; 剩下的几行表示有哪些文件修改须要被合并。
咱们进入到未合并的文件 123.txt, 能够发现当前 HEAD 就是管理员提交的代码,而下面的就是要被合并的开发者提交的代码。
这里我就直接选择管理员的代码做为最终的代码,在实际开发中,审核着就是要承担这样的责任,须要合理的选择谁提交的代码可用,或者抽取各自好的代码进行合并。
最终选择的结果,能够看到我删除了开发者的代码,并将辅助的信息所有删除。好比有:
>> 开头的
<< 开头的
==== 开头的
复制代码
合并完成后又进入到熟悉的步骤, commit、push。看到下面的图,能够看到分支又被何在一块儿,你能够本身好好观察下分支走向。那些分支合到那个分支上,只要看懂了,遇到再复杂的分支也不会晕头转向。
好啦, 写到这儿就将整个 git 的常规操做所有讲完了。让咱们来再一次回顾一下,由于内容太长,为了让读者能熟悉命令,看完后能记住大部分。我给你再总结一次。
写在前面: 若是你的仓库已经存在提交,你第一步就须要 fetch, 而后切换到最新的版本上去,通常是 master 所在的分支
git fetch --all
2. 切换到指定 hash 的分支
git checkout -b branch_name hash
3. 新建一个文件后,须要将其加入到缓冲区,称为追踪文件
git add xxx
4. 将缓存去的文件加入到本地代码仓库
git commit -m "提交消息内容"
5. 提交到远程仓库
git push origin HEAD:branch_name
辅助命令:
1. 查看当前提交的状态
git status
2. 查看日志,分支树
git log --graph --decorate --all
管理者使用:
1. merge 合并代码,将指定分支合并到某一个分支,通常是 master
git merge --no-ff hash
复制代码
其实上面的是最多见的几个命令啦!基本上熟练使用这几个指令就能完成大部分工做。笔者用的最多也是这几个命令。下一篇做为补充,再增长几个命令,虽然不经常使用,可是也要知道。