git实战
一. 入门
1.1 git、github、gerrit
git是版本控制软件,一般用来做代码版本控制。
GitHub和Gerrit都是基于Web的Git远程仓库,都提供了分享开源项目的平台,为开发大佬和团队提供了存储、分享、发布和合作开发项目的中心化云存储的场所。从代码的私有性上来看,Gerrit是一个更好的选择。但是对于开源项目而言,GitHub 依然是代码托管的首选。
1.2 初始化仓库
在当前目录执行命令:git init
,执行之后,会发现文件夹中多了一个隐藏的目录,目录名为.git。也就是说,git已经开始接管这个目录的版本控制工作了。
如果本来已有的目录不想再做版本控制,那么只需要删除掉.git文件即可。
1.3 仓库初始化后查看仓库状态
现在的文件夹里只有.git文件,此时可以使用git status
命令来查看当前仓库的状态。
终端窗口会输出:nothing to commit (create/copy files and use "git add" to track)
。
1.4 创建文件后查看仓库状态
仓库初始化后,再创建一个文件。此时再次使用git status
命令来查看当前仓库的状态。
此时文件的状态变为Untracked files,提示 (use "git add <file>..." to include in what will be committed)
。
即这个文件尚未被添加到git版本控制系统中,还未正式被git追踪,只是刚刚加入目录而已。
在git中这个文件可以说成是加入工作区(working directory)。
1.5 让git开始追踪文件
当开发完成后,此时使用git来生成一个版本。但是在生成版本前,应该先执行git add 文件名
命令,把文件加入暂存区,让git开始追踪文件。
可以执行如下命令:
git add login.html
通过该命令,即可把文件加入暂存区,git add
命令是检测文件的改动,并将改动添加到暂存区。新增文件、修改文件、删除文件,这些操作都属于文件的改动。。
此时再执行git status
命令,文件状态已经从Untracked变成new file,表示文件已经被放置到暂存区(Staging Area),稍后可以被存到存储库中。流程如下图所示:
1.6 生成版本
现在已经把一些改动存在了暂存区中,而如果想让这些改动存档,或者说是生成一个版本,那么需要使用git commit
命令把暂存区的内容移往存储库(repository)。
git commit -m '改动信息'
1.7 查看提交记录
可以使用git log
命令来查看提交记录。
终端输出:
commit 71f42eb8712ed659052b17a2b8e09ade4fc6316b (HEAD -> master)
Author: Echo <xxx@zte.com>
Date: xxx
改动信息
git log
其他使用
查看特定文件的commit记录:
git log 文件名
想找某个人提交的commit:
git log --author="someone's name"
想找commit信息中是否含有某些关键字:
git log --grep="some desc"
1.8 提交的信息写错了怎么办
git commit --amend -m '一些描述'
或是开发完成部分功能,如果想继续完善,那么可以使用:
git commit --amend -m '补充功能'
二. 协同开发
3.1 gerrit
Gitee.com(码云) 是一个基于 Git 的代码托管和研发协作平台,可以让你和其他人一起在远程或本地项目上进行协作。
3.5 把内容推送到远端仓库
小红首先进入文件夹执行git add .
和git commit -m 'init'
命令,将项目文件存进版本库。
接着执行git remote add origin https://gitee.com/foo/xiao-hong.git
,添加一个远程仓库。
这个命令有几点要说明:
git remote
命令主要进行与远端有关的操作。add
命令指的是要加入一个远端节点。- 命令中的
origin
是一个代名词,指的是后面那串服务器的位置,如本例中的https://gitee.com/foo/xiao-hong.git
。远端的节点默认使用origin
这个名称。如果是从服务器上Clone下来的,其默认名称就是origin
。
下一步,小红执行git push -u origin "master"
,这一步用于把本地仓库主分支推到远程仓库主分支。
这个命令帮我们做了下面的工作:
- 把master分支的内容推向远端的origin位置。
- 在origin远端服务器上,如果master分支不存在,则创建一个名为master的分支。
- 如果远端服务器上已存在master分支,则会把远端master分支更新到最新进度。
- 加入
-u
参数,下次再执行git push
命令时,就会用master分支作为默认的远端节点推送上去。
3.6 把内容从远端仓库拉到本地
用下述指令将远端仓库内容拉取到自己本地了:
git clone xxx
git clone
指令后面就是git仓库的地址。
3.7 成员之间互相推送和拉取
现在小红和小明的电脑都有了项目的文件,下面展示的是小红和小明推送和拉取的过程。
首先是小明在自己本地开发,为了方便讲解,我们假设小明新增了一个文件xiaoming.txt,并将这个文件加入暂存区,存进版本库,最终推送到远端仓库。执行的命令依次如下:
git add .
git commit -m '添加了xiaoming.txt'
git push origin master
这样就把变动的文件推送到了远端仓库。
接着是小红,小红执行下面的命令把远端最新的改动拉取下来:
git pull origin master
然后小红自己也在本地新增了一个文件xiaohong.txt,也将其推送到远端。过程如下:
git add .
git commit -m '添加了xiaohong.txt'
git push origin master
最后是小明,小明执行下面的命令把远端最新的改动拉取下来:
git pull origin master
3.8 使用分支的原因
上面的小节中,小红小明独自在自己的本地开发,然后提交代码到远程,再把远端的代码拉取到本地,这是一个最简单的协作流程。不过,这种做法容易导致混乱。设想一下这个场景,小明在本地开发了一个功能,并将其推送到远端仓库,但是小明的代码有bug。这个时候就很难受了,假如现在需要临时打包上线,那么现在master分支的最新代码是有bug的。所以,更好的做法是,采用分支来开发:master分支只推送经过测试的代码,项目成员开发的时候用自己的分支,测试通过后,再将分支代码合并到master分支,如此,便不会影响正在运行的产品线。
3.9 查看分支
如果git branch
命令后面没有跟任何参数,会输出当前在这个项目中有哪些分支。git默认会设置一个名为master的分支,前面的星号*表示现在正在这个分支上。
3.10 新建分支
git branch
后面跟上分支名称。
小红通过执行git branch xiaohong
创建了一条属于自己的分支,分支的名字最好是能够体现出这个功能,这里我们为了方便区分,用了小红的名字做为分支。
3.11 修改分支名字
修改分支名字:如git branch -m xiaohong xiao-hong。例如把分支的名字从xiaohong改为xiao-hong,这样并不会影响文件或目录。此时执行git branch
,输出:
* master
xiao-hong
3.12 切换分支
git checkout 分支名
。如果要切换到某个分支,则这个分支必须要先存在。
小红要切换到自己的xiao-hong分支开发,那么可以执行:
git checkout xiao-hong
还有另外一个方式:git checkout -b 分支名
。如果这个分支本来就存在,git会提示该分支已经存在;如果不存在,git会创建改分支后再切换过去。
3.13 删除分支
git branch -d 分支名
。要删除某一个分支,需要先切换到其他分支才能将其删除。
3.14 合并分支
3.14.1 Fast Forward快转模式
如:dev分支是从master分支分出去的,master合并dev的时候会直接使用快转模式
3.14.3 rebase变基
- a分支和b分支都是从master分出去的,且各自做了改动并commit。a和b都是从master分出来的,它们的base都是master。
- 切换到a分支,执行git rebase b命令。意思是使用b分支作为a分支的新的参考基准。
- rebase合并方式和merge方式的区别:使用rebase方式合并分支,git不会在做出一个专门用来合并的commit。
3.14.4 取消rebase
- 使用git reflog命令,用git reset rebase前的SHA-1值 --hard,
切换回rebase前的状态。 - 使用ORIG_HEAD。ORIG_HEAD会记录危险操作前HEAD的位置,可以方便地找到最后一次危险动作之前的SHA-1值。分支合并或reset之类的都是危险操作。通过这个记录点来取消这次rebase会更加简单:
git reset ORIG_HEAD --hard
3.15 合并发生冲突
- 不是改到同一个文件就一定会发生冲突,但改到同一行就会出现冲突
- 无论是使用merge还是使用rebase进行合并,都有可能产生冲突