一、版本控制概念
版本控制是一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统。采用版本控制系统,可以将选定的文件回溯到之前的状态,甚至将整个项目都回退到过去的某个时间点的状态,可以通过比较文件的变化,查出最后是谁修改了文件的哪些内容,从而找出问题出现的原因,轻松恢复到原来的样子,使因修改带来的额外工作量微乎其微。
版本控制历程:本地版本控制系统—>集中化的版本控制系统(满足在不同系统上的开发者协同工作)—>分布式版本控制系统(满足将代码仓库完整地镜像下来,可以指定和若干不同的远端代码仓库进行交互)
二、GIT工具安装与入门
Git官方下载安装:https://git-scm.com/download/win
使用git来获取Git的更新:
$ git clone git://git.kernel.org/pub/scm/git/git.git
查看所有的配置以及他们所在的文件:
$ git config --list --show-origin
安装后,设置用户名和邮箱地址,每一个Git提交都会使用这些信息,它们会写入你的每一次提交中,不可更改;如果想针对特定项目使用不同的用户名称与邮件地址时,可以在那个项目目录下运行没有 --global
选项的命令来配置:
$ git config --global user.name "yaxin.liang"
$ git config --global user.email yaxin@example.com
设置文本编辑器:
$ git config --global core.editor 文本编辑器名称
检查配置信息:
$ git config --list
检查 Git 的某一项配置:
$ git config user.name
获取帮助:
$ git help <verb>
$ git <verb> --help
$ man git-<verb>
三、git版本库创建
两种获取Git项目仓库方式:
1、将尚未进行版本控制的本地目录转换为Git仓库
2、从其他服务器克隆一个已存在的Git仓库
在已存在的目录中初始化仓库:
步骤一:进入项目目录中,执行以下命令对目录进行初始化,生成一个.git的子目录,该目录包含初始化的Git仓库中所有的必须文件
$ git init
步骤二:执行以下命令,建立跟踪,并进行初始提交
$ git add *
$ git add LICENSE
$ git commit -m 'initial project version'
克隆现有的仓库:
$ git clone <url> <自定义本地仓库名字>
手动添加远程仓库:
步骤一:添加远程仓库
$ git remote add <shortname> <url>
步骤二:从远程仓库中抓取与拉取:只会将数据下载到你的本地仓库,并不会自动合并或修改你当前的工作
$ git fetch <remote>
自动抓取后合并远程分支到当前分支
$ git pull
四、克隆、pull、push、commit命令使用
自动抓取后合并远程分支到当前分支
$ git pull
查看当前文件状态:
$ git status <-S>
查看未暂存文件具体更改信息:-staged为查看已暂存未添加到下次提交里文件与最后一次提交的文件差异
$ git diff <-staged>
新建文件 README:
$ echo <文件夹名称> > README
跟踪新建文件 README:将修改后的文件放入暂存区
$ git add README
提交更新:将暂存区的文件提交(相当于对项目作一次快照)
$ git commit -m <提交的信息>
跳过使用暂存区域,直接提交所有修改过的文件:
$ git commit -a -m <提交的信息>
推送到远程仓库:将master分支推送到origin服务器
$ git push origin master
五、相关文件
创建忽略文件.gitignore
记录无需纳入git管理的文件名,也不希望他们总出现在为跟踪文件列表中,如日志文件,编译过程中出现的临时文件等
文件.gitignore的格式规范:
-
所有空行或者以
#
开头的行都会被 Git 忽略 -
可以使用标准的 glob 模式(shell所使用的简化了的正则表达式)匹配,它会递归地应用在整个工作区中
- 星号(
*
)匹配零个或多个任意字符 - [abc] 匹配任何一个列在方括号中的字符 (这个例子要么匹配一个 a,要么匹配一个 b,要么匹配一个 c)
- 问号(
?
)只匹配一个任意字符 - 方括号中使用短划线分隔两个字符, 表示所有在这两个字符范围内的都可以匹配(比如
[0-9]
表示匹配所有 0 到 9 的数字) - 使用两个星号(
**
)表示匹配任意中间目录,比如a/**/z
可以匹配a/z
、a/b/z
或a/b/c/z
等
- 星号(
-
匹配模式可以以(
/
)开头防止递归eg: /TODO 只忽略当前目录下的 TODO 文件,而不忽略 subdir/TODO
-
匹配模式可以以(
/
)结尾指定目录eg: build/ 忽略任何目录下名为 build 的文件夹
-
要忽略指定模式以外的文件或目录,可以在模式前加上叹号(
!
)取反eg: !lib.a 跟踪所有的 lib.a
六、相关操作
移除文件
$ git rm <f 强制性移除,会删除之前修改过已经防止暂存区的文件> <--cached 文件仍保留在磁盘,但是Git不再跟踪> <文件名>
移动文件(重命名)
$ git mv <原文件名> <现文件名>
查看提交历史
按时间先后顺序列出所有的提交:列出每个提交的 SHA-1 校验和、作者的名字和电子邮件地址、提交时间以及提交说明
$ git log
git log 的常用选项:
–pretty=format : <自定义显示信息格式> : 定制记录的显示格式
撤消操作
重新提交,将会覆盖第一次提交操作:
$ git commit --amend
取消暂存文件:
$ git reset HEAD <需要撤消的文件名>
撤消对文件的修改:
$ git checkout -- <需要撤消修改的文件名>
远程仓库
添加远程仓库
$ git remote add <shortname> <url>
查看远程仓库:
$ git remote -v
查看某个远程仓库:
$ git remote show <remote>
远程仓库重命名:
$ git remote rename <原名> <修改后的名称>
远程仓库移除:一旦使用这种方式删除了一个远程仓库,那么所有和这个远程仓库相关的远程跟踪分支以及配置信息也会一起被删除
$ git remote remove <远程仓库名>
$ git remote rm
打标签
创建标签:
-
轻量标签 :将提交校验和存储到一个文件中——没有保存任何其他信息
$ git tag <标签名>
-
附注标签 :存储在 Git 数据库中的一个完整对象,包含打标签者的名字、电子邮件地址、日期时间、标签信息
$ git tag -a <标签名> -m <标签描述信息> $ git show <标签名>
列出标签:
$ git tag -l <通配符>
共享标签:创建完标签后必须显式地推送标签到共享服务器上
$ git push origin <tagname /--tags一次性推送所有标签>
删除标签及更新删除:
$ git tag -d <tagname>
$ git push origin --delete <tagname>
$ git push <remote> :refs/tags/<tagname>
检出标签:查看某个标签所指向的文件版本(会使仓库处于“分离头指针(detached HEAD)”的状态,该状态下做了某些更改然后提交它们,标签不会发生变化)
$ git checkout
Git别名
$ git config --global <别名> <命令>
生成SSH公钥
默认情况下,用户的 SSH 密钥存储在其 ~/.ssh
目录下
查看速确认自己是否已拥有密钥,id_dsa.pub / id_rsa.pub存放公钥,id_dsa / id_rsa存放私钥
$ cd ~/.ssh
$ ls
创建ssh公钥和私钥: ssh-keygen
会确认密钥的存储位置(默认是 .ssh/id_rsa
),然后它会要求你输入两次密钥口令。 如果你不想在使用密钥时输入口令,将其留空即可
$ ssh-keygen -o
查看并复制公钥信息,粘贴进相关Git服务器中:
$ cat ~/.ssh/id_rsa.pub
七、Git分支
使用分支可以把工作从开发主线上分离开来,以免影响开发主线。Git 的分支,其实本质上仅仅是指向提交对象的可变指针,Git 的默认分支名字是 master
,master
分支会在每次提交时自动向前移动
创建分支
创建分支:在当前所在的提交对象上创建一个指针 (git branch
命令仅仅 创建 一个新分支,并不会自动切换到新分支中去)
$ git branch testing
查看各个分支当前所指的对象: HEAD 指向当前所在的分支
$ git log --oneline --decorate
查看每一个分支的最后一次提交:分支前的 *
字符代表目前检出的那一个分支(也就是说,当前 HEAD
指针所指向的分支)
$ git branch -v
查看已经合并到当前分支的分支:在这个列表中分支名字前没有 *
号的分支通常可以使用 git branch -d
删除掉;你已经将它们的工作整合到了另一个分支,所以并不会失去任何东西
$ git branch --merged
查看所有包含未合并工作的分支:
$ git branch --no-merged
切换分支:
$ git checkout <需要切换到的分支>
创建新的分支并切换到新的分支:
$ git checkout -b <newbranchname>
查看分叉历史:
$ git log --oneline --decorate --graph --all
合并分支
场景一:
快进 fast-forward :合并两个分支时, 如果顺着一个分支走下去能够到达另一个分支,那么 Git 在合并两者的时候, 只会简单的将指针向前推进(指针右移),因为这种情况下的合并操作没有需要解决的分歧
合并master和hotfix
先切换到需要合并到的分支,再将需要合并的分支合并
$ git checkout master
$ git merge <需要合并的分支名>
场景二:
一次合并提交:将此次三方合并的结果做了一个新的快照并且自动创建一个新的提交指向它
合并master和iss53
先切换到需要合并到的分支,再将需要合并的分支合并
$ git checkout master
$ git merge <需要合并的分支名>
场景三:
变基:使用 rebase
命令将提交到某一分支上的所有修改都移至另一分支上
注意:如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基
对比当前分支相对于两个分支最近的共同祖先的历次提交,提取相应的修改并存为临时文件, 然后将当前分支指向目标基底
回到 master
分支,进行一次快进合并
先切换到修改的分支上,再将它变基到master分支:
$ git checkout <需要合并的分支名>
$ git rebase master
或 直接将主题分支 变基到目标分支:省略了先切换到主题分支
$ git rebase <basebranch> <topicbranch>
复杂的多分支变基:取出 client
分支,找出它从 server
分支分歧之后的补丁, 然后把这些补丁在 master
分支上重放一遍;再进行快进合并
$ git rebase --onto master server client
$ git checkout <需要合并的分支名>
$ git rebase master
其它:
删除合并后不需要的分支
$ git branch -d <分支名>
遇到冲突时的分支合并:
查看那些因包含合并冲突而处于未合并(unmerged)状态的文件:
$ git status
解决冲突,通常是保留其中一个分支的修改,或者两个文件内容合并成一样,再将文件标记为冲突已解决:
$ git add
使用图形化工具解决冲突:
$ git mergetool
远程分支
Git 的 clone
命令会自动远程Git服务器当前分支命名为 origin
,拉取它的所有数据, 创建一个指向它的 master
分支的指针,并且在本地将其命名为 origin/master
。 Git 也会给你一个与 origin 的 master
分支在指向同一个地方的本地 master
分支
如果你在本地的 master
分支做了一些工作,在同一段时间内有其他人推送提交到远程服务器,并且更新了它的master分支,则:
显式地获得远程引用的完整列表:
$ git ls-remote <remote>
获得远程分支的更多信息:
$ git remote show <remote>
与给定的远程仓库同步数据:这个命令查找 remote 是哪一个服务器, 从中抓取本地没有的数据,并且更新本地数据库,移动 <remote>/master
指针到更新之后的位置
$ git fetch <remote>
将本地分支推送到远程分支:
$ git push <remote> <branch>:<远程分支名>
查看设置的所有跟踪分支:
$ git branch -vv
统计最新的领先与落后数字,需要在运行此命令前抓取所有的远程仓库:
$ git fetch --all; git branch -vv
拉取:
git pull 相当于 git fetch + git merge
删除远程分支:
$ git push <remote> --delete <branch>