git简介
集中式版本控制系统
版本库是集中存放在中央服务器的,而干活的时候,用的都是自己的电脑,所以要先从中央服务器取得最新的版本,然后开始干活,干完活了,再把自己的活推送给中央服务器。中央服务器就好比是一个图书馆,你要改一本书,必须先从图书馆借出来,然后回到家自己改,改完了,再放回图书馆。集中式版本控制系统最大的毛病就是必须联网才能工作。
分布式版本控制系统
首先,分布式版本控制系统根本没有“中央服务器”,每个人的电脑上都是一个完整的版本库,这样,你工作的时候,就不需要联网了,因为版本库就在你自己的电脑上。既然每个人电脑上都有一个完整的版本库,那多个人如何协作呢?比方说你在自己电脑上改了文件A,你的同事也在他的电脑上改了文件A,这时,你们俩之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。
和集中式版本控制系统相比,分布式版本控制系统的安全性要高很多,因为每个人电脑里都有完整的版本库,某一个人的电脑坏掉了不要紧,随便从其他人那里复制一个就可以了。而集中式版本控制系统的中央服务器要是出了问题,所有人都没法干活了。
其中git就是分布式版本控制系统的一种。
git入门
最常见的一套操作
git init
git pull --rebase origin master
git add .
git commit --all -m "first commit"
git remote add origin git@github.com:sustech-se2019/android-lab-tdx1997tdx.git
git push -u origin master
使用前配置
git config
git config可以配置git的参数,可以使用git config --list查看已经配置的git参数。其中有三个级别的保存位置,–system、–global、–local,分别表示所有用户(本系统)、当前用户(全局)、本地配置(当前目录),默认使用–local。
在使用Git提交前,必须配置用户名和邮箱,这些信息会永久保存到历史记录中。
git config --global user.name "Tocy"
git config --global user.email zyvj@qq.com
配置ssh(window版)
- 打开Git Bash查看电脑上是否已经存在SSH密钥
cd ~/.ssh
如果显示文件夹不存在,就需要创建秘钥。
- 创建秘钥
ssh-keygen -t rsa -C 798637048@qq.com
执行这条命令会如上图提示文件保存路径,可以直接按Enter,然后提示输入密码,输入两次(可以不输直接两次Enter),执行完之后会在 .ssh 目录生产两个文件:id_rsa和id_rsa.pub
- 添加SSH公钥到github和码云
用记事本打开.ssh目录下的id_rsa.pub文件,复制里面的内容,到github和码云主页上找到的SSH key的信息,添加即可。
- 测试是否成功
ssh -T git@github.com
配置ssh(linux版)
-
首先进入Linux系统的用户目录下的.ssh目录下,root用户是/root/.ssh,普通用户是/home/您的用户名/.ssh,我们以root用户为例:
cd .ssh #如果没有 自己创建 权限700 -
执行ssh-keygen命令创建密钥对
ssh-keygen -t rsa -C 798637048@qq.com
- 密钥生成后会在当前目录下多出两个文件,id_rsa和id_rsa.pub,其中id_rsa是私钥(敲黑板:这个很重要,不能外泄),id_rsa.pub这个是公钥.打开.ssh目录下的id_rsa.pub文件,复制里面的内容,到github和码云主页上找到的SSH key的信息,添加即可。
git常用命令
初始化git仓库
git init
命令的作用是在当前目录中初始化仓库,并且创建一个名为.git的子目录,该目录含有你初始化的Git仓库中所有的必须文件。
git仓库暂存区
git管理的文件有4种状态:
-
Untracked: 未跟踪, 此文件在文件夹中, 但并没有加入到git库, 不参与版本控制. 通过git add 状态变为Staged.
-
Unmodify: 文件已经入库, 未修改, 即版本库中的文件快照内容与文件夹中完全一致. 这种类型的文件有两种去处, 如果它被修改, 而变为Modified. 如果使用git rm移出版本库, 则成为Untracked文件
-
Modified: 文件已修改, 仅仅是修改, 并没有进行其他的操作. 这个文件也有两个去处, 通过git add可进入暂存staged状态, 使用git checkout 则丢弃修改过, 返回到unmodify状态, 这个git checkout即从库中取出文件, 覆盖当前修改
-
Staged: 暂存状态. 执行git commit则将修改同步到库中, 这时库中的文件和本地文件又变为一致, 文件为Unmodify状态. 执行git reset HEAD filename取消暂存, 文件状态为Modified
-
为什么要有暂存区域?
如果有多个修改文件,每个文件代表不同功能,而每一个功能应该单独做成一次提交,这样可以保证提交历史的清晰。否则,当你想要回滚历史的时候,你会无所适从,根本分不清每个版本包含了哪些功能,修复了哪些bug。而暂存区的作用就是为了,可以选择提交,这样就可以提高提交版本历史记录的清晰,方便回滚。而提交是原子性操作,文件的选择就交于暂存区去做,每一次提交都是一个完整的功能开发,保证commit的干净,降低commit的粒度。 -
暂存区如何判断文件是否被修改。
当执行git status查看状态时,会执行以下4件事件。
- 先根据.git/index文件中记录(用于跟踪工作区文件的)时间戳、长度等信息判断工作区文件是否改变。
- 如果工作区文件的时间戳改变了,说明文件的内容可能改变了,需要打开文件,读取文件的内容,与更改前的原始文件进行比较,判断文件内容是否被更改。
- 如果文件内容没有改变,则将文件新的时间戳记录到.git/index文件中。
- 因为如果判断文件是否更改,使用时间戳、文件长度等信息比较要比通过文件内容快得多。
查看仓库状态
git status
添加修改文件到暂存区
- 添加所有文件到暂存区
git add .
- 把所有跟踪文件中被修改过或已删除的文件信息添加至暂存区
git add -u
git本地仓库
添加修改文件到本地仓库
git commit命令的作用是将暂存区的修改提交到本地仓库,同时会生成一个commmit-id。
将暂存区的修改提交到本地仓库:
git commit -m "message"
"message"是本次提交的简述内容,比如添加新功能或修复bug等。
git commit –a –m "message"
该命令相当于以下两条命令:
git add . :把所有修改的信息添加到暂存区
git add -m “message”:将暂存区的修改提交到本地仓库
版本回退
git reset
可以使用git reset进行版本回退。
- 回退到指定版本[]为可选
git reset [--模式] commit_id [指定文件名]
- 回退到当前版本
git reset HEAD
Git Reset 三种模式:
- –soft:只改变HEAD指针指向,不影响暂存区和工作区
- –mixed(默认):改变HEAD指针,并且回退暂存区,不改变工作区
- –hard:改变HEAD指针并改变暂存区和工作区
例子:
- 使用 git log --pretty=oneline查看提交地址
- 输入以下命令彻底还原
git reset --hard 09ae29
- 这时候再使用git log --pretty=oneline可以看到已经还原成功
git revert
更多的使用git revert命令,head并不是回退到原来的版本,而是基于原来版本代码撤销后生成新的记录。具体见:
https://blog.csdn.net/yxlshk/article/details/79944535
版本回退撤销
第二天我后悔版本回退了怎么办?
- 使用git reflog查看历史命令
- 找到之前后悔之前的commit_id进行还原
git reset --hard a999115
git远程仓库
查看远程仓库
git remote
添加远程仓库
git remote add 仓库别名 远程仓库url
删除远程仓库
git remote rm 仓库别名
重命名别名
git remote rename [old_name] [new_name]
远程仓库抓取数据到本地
先用一张图来理一下git fetch和git pull的概念:
可以简单的概括为:
- git fetch是将远程主机的最新内容拉到本地,用户在检查了以后决定是否合并到工作本机分支中。
- git pull 则是将远程主机的最新内容拉下来后直接合并,即:git pull = git fetch + git merge,这样可能会产生冲突,需要手动解决。
git fetch
git fetch这个命令会把远程的commits拉取到本地的repo中,但是,它不是直接把commits接在分支的最后面,而是从你最后一次push的那个commit节点,再拉取一个新的分支出来。
理解 fetch 的关键, 是理解 FETCH_HEAD,FETCH_HEAD指的是: 某个branch在服务器上的最新状态。这个列表保存在 .Git/FETCH_HEAD 文件中, 其中每一行对应于远程服务器的一个分支。
一般来说, 存在两种情况:
- 如果没有显式的指定远程分支, 则远程分支的master将作为默认的FETCH_HEAD.
- 如果指定了远程分支, 就将这个远程分支作为FETCH_HEAD。
git fetch origin branch1
这个指令并不会在本地创建新的branch。设定当前分支的 FETCH_HEAD 为远程服务器的branch1分支。
git fetch origin branch1:branch2
首先执行上面的fetch操作,使用远程branch1分支在本地创建branch2(但不会切换到该分支),如果本地不存在branch2分支, 则会自动创建一个新的branch2分支。
git pull
git pull 的过程可以理解为:
git fetch origin master #从远程主机的master分支拉取最新内容
git merge FETCH_HEAD #将拉取下来的最新内容合并到当前所在的分支中
即将远程主机的某个分支的更新取回,并与本地指定的分支合并,完整格式可表示为:
git pull <远程主机名> <远程分支名>:<本地分支名>
推送到远程仓库
git push <远程主机名> <远程分支名>:<本地分支名>
git push origin master #将本地master分支的更新推送到远程主机上
git分支管理
分支管理操作(git branch)
- 查看本地分支:git branch
- 查看本地和远程分支:git branch -a
- 新建名字为test的分支:git branch test
- 将test分支名字改为dev:git branch -m test dev
- 删除名字为dev的分支:git branch -d dev
创建和切换分支以及撤销工作区的修改(git checkout)
- 将版本库的当前分支该文件版本替换工作区的该文件版本。
git checkout -- file
git checkout . #检出所有文件
- 切换分支
git checkout [分支名称]
- 检出某一分支代码,但HEAD还是当前分支
git checkout [分支名称] -- file
git checkout [分支名称] . #检出所有文件
使用场景之一:从master分支切换到test分支,并且将工作空间切换至test中的内容。
git checkout test
git checkout .
分支合并(merge&rebase)
- 将dev分支代码与当前分支合并
git merge dev
或者
git rebase dev
- rebase,你自己开发分支一直在做,然后某一天,你想把主线的修改合到你的分支上,做一次集成,这种情况就用rebase比较好.把你的提交都放在主线修改的头上
- merge,你如果想回退你分支上的某个提交就很麻烦,还有一个重要的问题,rebase的话,本来我的分支是从3拉出来的,rebase完了之后,就不知道我当时是从哪儿拉出来的我的开发分支
标签与日志
git tag
如果你达到一个重要的阶段,并希望永远记住那个特别的提交快照,你可以使用 git tag 给它打上标签。
- 查看已有的标签历史记录:git tag
- 给当前最新的commit打上标签:git tag <标签的定义>
- 给对应的commit id打上标签:git tag <标签定义>
git log
- 查看历史提交记录
git log
- 将每条历史提交记录展示成一行
git log --oneline
- 查看某个人的提交记录
git log --author="name"
- 显示前n条记录
git log -n
- 显示某个日期之后的记录
git log --after="2018-10-1" #包含2018年10月1号的记录
- 显示某个日期之前的记录
git log --before="2018-10-1" #包含2018年10月1号的记录
- 显示某两个日期之间的记录
git log --after="2018-10-1" --before="2018-10-7"