学习廖雪峰老师博客,一些关于 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 行规则忽略了该文件,于是我们就可以知道应该修订哪个规则。