学习廖雪峰老师博客,一些关于git的笔记。如有记录错误,望能不吝赐教。
1.git诞生
git是linus为了linux进行版本控制而自己用c写的分布式版本控制系统,在21世纪初,有cvs、svn这些免费的版本控制系统,这些集中式版本控制系统不仅速度慢,而且需要联网才能使用;还有一些商用的版本控制系统,比如linus后来选择的BitKeeper。
2.集中式vs分布式
集中式:
- 版本库是存放在中央服务器的,干活前,要先从中央服务器取得最新的版本,结束后,还要把自己的活推送给中央服务器。
- 集中式版本控制系统还需要联网才可以进行作业,所以网速慢的话,工作前后等待的时间就极其耗时。
分布式:
- 分布式根本没有”中央服务器“的概念,每台电脑都是一个完整的版本库,这样工作就不需要联网了,版本库在自己的电脑上。工作的时候,只需要把各自的文件互相推送给对方就行了。
- 与集中式相比,分布式更加安全。即使有一个人电脑坏掉了也没关系,因为每个人的电脑都有完整的版本库,可以从别人电脑里复制。但如果集中式版本控制系统的中央服务器坏掉了,那大家什么都不能做
- 分布式通常也将一台电脑充当”中央服务器“来进行方便电脑与电脑直接的信息推送,但是即使这台充当”中央服务器“的电脑坏了也没关系,因为每个人的电脑都有完整的版本库,只是信息互相推送比较麻烦,需要在同一局域网,两台电脑间才能互相访问。
3.安装git
- 在linux上安装git
$ git
The program ‘git’ is currently not installed. You can install it by typing:
sudo apt-get install git
输入git看有没有安装
sudo apt-get install git 如果没有,据说通过它就可以直接安装
- 在Mac OS X上安装git
一个通过homebrew (http://brew.sh/)
一个是通过Xcode:选择菜单“Xcode”->“Preferences”,在弹出窗口中找到“Downloads”,选择“Command Line Tools”,点“Install”就可以完成安装了
- 在Windows上安装git
在git官网直接下载安装程序,国内镜像( https://github.com/waylau/git…)
开始菜单里找到“Git”->“Git Bash”,蹦出一个类似命令行窗口的东西,就说明Git安装成功!
安装完成后,还需要最后一步设置,在命令行输入:
$ git config –global user.name “Your Name”
$ git config –global user.email “email@example.com”
4.创建版本库
- 版本库又名仓库,英文:repository,可以简单理解成一个目录,这个目录里面的所有文件都可以被git管理起来,每个文件的修改、删除,git都能跟踪。
- 所有的版本控制系统都只能跟踪文本文件的改动,比如TXT文件、网页、程序代码等等,而图片、视频这些二进制文件,虽然也能由版本控制系统管理,但不能跟踪文件的变化。
- 创建一个版本库 git init
先创建一个空目录,mkdir <fileName>
再通过git init命令把这个目录变成git可以管理的仓库。其中有一个.git的目录是git用来跟踪管理版本库的(这是一个隐藏目录,用ls -ah命令可以看见)。
- 把文件添加到版本库
第一步,用命令git add告诉git,把文件添加到仓库
第二步,用命令git commit告诉git,把文件提交到仓库
(git commit命令执行成功后会告诉你,1 file changed:1个文件被改动(我们新添加的readme.txt文件);2 insertions:插入了两行内容(readme.txt有两行内容))
添加文件到Git仓库,分两步:
- 使用命令git add <file>,注意,可反复多次使用,添加多个文件;
- 使用命令git commit -m <message>,完成
5.版本回退
- 在git中,用HEAD表示当前版本,用HEAD^表示上一个版本,用HEAD^^表示上上版本,HEAD~100表示往前100个版本
- git log显示从最近到最远提交(commit)的历史记录,也可以通过 git log —pretty=oneline 来简化信息
- git reflog显示命令历史,可以得知每一个提交的版本跟回退版本操作的版本号信息
- git reset –hard 回退版本
git reset –hard HEAD^ 回退到上一个版本
git reset –hard <commit id> HEAD指针指向指定版本号的版本 (这一点可以让我们坐时光机去向过去,也可以从过去回到现在)
(查看文档内容, cat <fileName>)
6.工作去和暂存区
- 工作区(working directory)
在电脑目录中可以看到的目录都是工作区
- 版本库(repository)
在工作区有一个隐藏目录.git,它是git的版本库,里面有暂存区(stage或者index);还有git为我们自动创建的第一个分支master,包括指向master的一个指针:HEAD
把文件往git版本库里添加的时候,分两步执行:
- 第一步,git add把文件添加进去,即把文件ongoing工作台添加到暂存区
- 第二步,git commit提交更改,即把暂存区所有内容提交到当前分支
7.管理修改
- git可以追踪并管理修改,因为有暂存区这个概念,将修改加入到暂存区,再次对文档进行修改,这时候把暂存区内容commit到分支上,那么前一次修改被提交了,而工作区里的修改(第二次修改)还在你的工作区中。
- 提交修改后(commit),可以用git diff HEAD — <fileName>来查看版本工作区和版本库里最新版本的区别。
8.撤销修改
- git checkout — file 让工作区文件回到最近一次git commit或者git add的状态
场景1:当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时。
撤销修改会出现以下两种状况:
一种是文件自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;
一种是文件已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。
- git reset HEAD <fileName> 将暂存区的内容撤销掉
场景2:当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步:
- 第一步,用命令git reset HEAD <fileName>,撤销暂存区fileName
- 第二步,通过git checkout — <fileName>, 拉最新版本
- git reset –hard HEAD^
场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,参考版本回退,不过前提是没有推送到远程库。
9.删除文件 rm <fileName>
- git rm
当我们在工作区删除了文件,造成工作区和版本库的版本不一致,我们可以通过git rm <fileName>删掉版本库的文件,并且git commit -m “xxx”。也可以通过git add <fileName>然后git commit -m “xxx”效果是一样的。
10.添加远程仓库
- 在GitHub上建一个Git仓库
登录GitHub —> create a repository —> 填写仓库信息 —> Git仓库创建成功
- 与本地关联
1.我们可以git clone从仓库克隆一个新的仓库
2.也可以把本地已有的仓库与之关联,然后把本地仓库的内容推送到GitHub仓库
git remote add origin git@github.com:xxjiayy/learngit_xjy.git
本地已有仓库与远程关联,origin就是远程仓库的名字
git push -u origin master
把本地库的内容推送到远程。由于远程库是空的,我们第一次推送到master分支时,加一个-u参数,GIt不但会把本地的master分支内容推送到远程新的master分支,还会把master分支和远程的master关联起来。
- 在GitHub中新建公钥
1.看一下 ~/.ssh文件中是否已存在id_rsa.pub和id_rsa文件
如果存在就不需要创建一个SSH key,当然也可以overwrite重新生成,如果要重写的话,之前关联过公钥的版本库都要重新关联。
2.创建SSH key
- 如果不存在id_rsa.pub和id_rsa文件,需要创建SSH key
ssh-keygen -t rsa -C “xxjiayy”
-t:指定密钥类型,默认是rsa,可以省略
-C:设置备注文字,例如:用户名
然后会出现:让你输入文件名,可以回车选择默认文件名
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/xiejiayun/.ssh/id_rsa):
然后,会提示输入密码:可以选择不输入
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
最后看到:说明你已经创建成功了
Your identification has been saved in /Users/xiejiayun/.ssh/id_rsa.
Your public key has been saved in /Users/xiejiayun/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:VnCyghzZ5jomXIKKFlqqnPyXFWHPjLqmob+Dj0PGRJQ xxjiayy
- 如果存在id_rsa.pub和id_rsa文件,你也可以选择重写
ssh-keygen -t rsa -C “xxjiayy”
然后会出现:让你输入文件名,可以回车选择默认文件名
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/xiejiayun/.ssh/id_rsa):
如果默认文件名的话,它就跟你之前已存在的文件冲突了,所以它出现:
Overwrite (y/n)? y
选择yes,开始重写之旅….然后下面的部分跟创建相同
3.添加SSH key到GitHub上去
- 将id_rsa.pub文件中的内容复制
- 登录GitHub —> 右上角settings进入 —> 点击SSH and GPD keys —> New SSH key —> 在Key里面把刚刚的文件内容复制进去,title随意填写(保存后系统也会默认生成)—> Add SHH key (这时候发现钥匙的图标还是灰色的)
4.本地测试SSH key
ssh -T git@github.com
如果创建SSH key的时候设置了密码,就会让你输入:(之后每次push都会让你输密码)
Enter passphrase for key ‘/Users/xiejiayun/.ssh/id_rsa’:
最后,恭喜已经成功了,钥匙图标也变成绿色了
Hi xxjiayy! You’ve successfully authenticated, but GitHub does not provide shell access.
如果看到“access denied”,表示拒绝访问,那么只能使用https去访问,而不是SSH
11.从远程克隆
- 创建一个新的仓库
勾选下面的选项,给这个新仓库添加README格式化
Initialize this repository with a README
- 克隆一个本地仓库
git clone git@github.com:xxjiayy/gitskillls.git
- SSH和https克隆的区别
git还支持https协议,但比起SSH,使用https除了速度慢以外,还有最大的麻烦是每次推送都必须输入口令。
12.创建与合并分支
查看分支:git branch
创建分支:git branch <name>
切换分支:git checkout <name>
创建+切换分支:git checkout -b <name>
合并某分支到当前分支:git merge <name>
删除分支:git branch -d <name>
- 在合并分支的时候,会出现Fast-forward信息,表示这次合并是“快进模式”,也就是直接把当前分支指向某分支
13.解决冲突
当Git无法自动合并分支时,就必须首先解决冲突。git status可以告诉我们冲突文件,解决冲突后,再提交,合并完成。
解决冲突就是把Git合并失败的文件手动编辑为我们希望的内容,再提交。
用git log –graph命令可以看到分支合并图。
14.分支管理策略
合并分支时,加上–no-ff参数就可以用普通模式合并,合并后的历史有分支,能看出来曾经做过合并,而fast forward合并就看不出来曾经做过合并。
git merge –no-ff -m “merge with no-ff” dev
因为本次合并要创建一个新的commit,所以加上-m参数,把commit描述写进去。
15.Bug分支
- git stash
现在的工作区工作并没有完成,无法commit,但现在需要切换分支,进行别的工作,可以把当前的工作现场“储藏”起来
- git stash list
查看储藏起来的工作区内容,可以多次stash
- git stash apply恢复stash内容,git stash drop删除stash的内容
- git stash pop恢复的同时把stash内容也删了
- git stash apply stash@{0} 可以恢复指定的stash内容
- git cherry-pick <commit>
cherry-pick 命令,复制某一个特定的提交到当前分支
在master分支上修复的bug,想要合并到当前dev分支,可以用git cherry-pick <commit>命令,把bug提交的修改“复制”到当前分支,避免重复劳动
16.feature分支
开发一个新的feature,最好新建一个分支
- git branch -d <branchName>
删除一个分支
- git branch -D <branchName>
如果丢弃一个没被合并过的分支,需要通过强行删除
17.多人协作
- git remote
查看远程库信息
- git remote -v
查看远程库更详细的信息
- git push origin master
- git push origin <branchName>
- 将该分支上所有本地提交推送到远程库
但是,并不是一定要把本地分支往远程推送,那么,哪些分支需要推送,哪些不需要呢?
- master分支是主分支,因此要时刻与远程同步;
- dev分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步;
- bug分支只用于在本地修复bug,就没必要推到远程了,除非老板要看看你每周到底修复了几个bug;
- feature分支是否推到远程,取决于你是否和你的小伙伴合作在上面开发。
- 抓取分支
你的小伙伴已经向origin/….分支推送了他的提交,而碰巧你也对同样的文件作了修改,因为你的小伙伴的最新提交和你试图推送的提交有冲突。
先有git pull 把最新的提交从origin/….上拉下来,然后本地合并,解决冲突
多人协作的工作模式通常是这样:
- 首先,可以试图用git push origin <branch-name>推送自己的修改;
- 如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并;
- 如果合并有冲突,则解决冲突,并在本地提交;
- 没有冲突或者解决掉冲突后,再用git push origin <branch-name>推送就能成功!
如果git pull提示no tracking information,则说明本地分支和远程分支的链接关系没有创建,用命令git branch –set-upstream-to <branch-name> origin/<branch-name>
- git checkout -b branch-name origin/branch-name
在本地创建和远程分支对应的分支,使用git checkout -b branch-name origin/branch-name,本地和远程分支的名称最好一致;
- git branch –set-upstream branch-name origin/branch-name;
建立本地分支和远程分支的关联,使用git branch –set-upstream branch-name origin/branch-name;
18.Rebase
变基
- git rebase
原本分叉的提交现在变成一条直线了!这种神奇的操作是怎么实现的?其实原理非常简单。我们注意观察,发现Git把我们本地的提交“挪动”了位置,放到了f005ed4 (origin/master) set exit=1之后,这样,整个提交历史就成了一条直线。rebase操作前后,最终的提交内容是一致的,但是,我们本地的commit修改内容已经变化了,它们的修改不再基于d1be385 init hello,而是基于f005ed4 (origin/master) set exit=1,但最后的提交7e61ed4内容是一致的。
这就是rebase操作的特点:把分叉的提交历史“整理”成一条直线,看上去更直观。缺点是本地的分叉提交已经被修改过了。
- rebase操作可以把本地未push的分叉提交历史整理成直线;
- rebase的目的是使得我们在查看历史提交的变化时更容易,因为分叉的提交需要三方对比。
19.创建标签
- git tag <name>
给当前分支最新提交的commit打一个标签(默认为HEAD)
- git tag
查看所有标签
- git tag <name> <commit id>
给指定的commit id 打标签
- git show <tagname>
查看标签信息命令
- git tag -a <tagname> -m “…..”
可以指定标签信息;用-a指定标签名,-m指定说明文字
20.操作标签
- 命令git push origin <tagname>可以推送一个本地标签;
- 命令git push origin –tags可以推送全部未推送过的本地标签;
- 命令git tag -d <tagname>可以删除一个本地标签;
- 命令git push origin :refs/tags/<tagname>可以删除一个远程标签。
21.使用GitHub
- 在GitHub上,可以任意Fork开源仓库;
- 自己拥有Fork后的仓库的读写权限;
- 可以推送pull request给官方仓库来贡献代码。
22.使用码云
- git remote add
使用该命令,把本地库和远程库关联起来
- git remote -v
查看远程库信息
- git remote rm origin
删除已有名为origin远程库
当然一个本地库,可以同步多个远程库信息
- git remote add github git@github.com:michaelliao/learngit.git
本地库和远程叫github的库关联起来
- git remote add gitee git@gitee.com:liaoxuefeng/learngit.git
本地库和远程叫gitee的库关联起来
- git push github master
已送到github远程库
- git push gitee master
推送到gitee远程库
23.忽略特殊文件
在Git工作区的根目录下创建一个特殊的.gitignore文件,然后把要忽略的文件名填进去,Git就会自动忽略这些文件
忽略文件的原则是:
- 忽略操作系统自动生成的文件,比如缩略图等;
- 忽略编译生成的中间文件、可执行文件等,也就是如果一个文件是通过另一个文件自动生成的,那自动生成的文件就没必要放进版本库,比如Java编译产生的.class文件;
- 忽略你自己的带有敏感信息的配置文件,比如存放口令的配置文件。
- git check-ignore
检查某个文件忽略的出处,例如:git check-ignore -v App.class
.gitignore:3:*.class App.class
Git告诉我们,.gitignore的第3行规则忽略了该文件,于是我们就可以知道应该修订哪个规则。