我的练习地址:D: learngit ode.txt
Git的诞生
- Git是用C语言开发的;
- Git是分布式版本控制系统:没有“中央服务器”、不需要联网、安全性高很多(每个人电脑里都有完整的版本库);
- Git有极其强大的分支管理。
安装Git后创建版本库(又名仓库,repository)
选择一个合适的地方,创建一个空目录:
$ cd D:/ // 切换盘符,我这里进入D盘
$ cd .. // 回到文件上一层(注: cd与..中间有个空格)
$ cd ~ // 回到当前目录的主目录
$ mkdir Git // 创建文件夹Git
$ touch fileName // 新建文件
$ vi fileName // 编辑文件
$ press i button // 开始进入编辑状态
$ press the Esc button // 退出vim编辑区(一直按住ESC,按两次大写的Z;或者按ESC键然后输入::q!即可不保存退出)
$ :wq // 退出编辑状态, 回到命令窗口(这是保存退出)
$ mkdir learngit // 创建文件夹learngit(我的在D盘中创建)
$ pwd // 显示当前路径/e/Git/learngit
$ git init // 将当前目录变成一个Git可以管理的仓库
$ touch+文件名 // 直接新建一个文件(node.txt)
$ git add node.txt // 将文件node.txt添加到Git仓库(把文件修改添加到暂存区)
$ git commit -m "wrote a node.txt." // 将文件提交到仓库(把暂存区的所有内容提交到当前分支),命令执行成功会告诉你1 file changed: 1个文件被改动(我们新添加的node.txt文件);2 insertions: 插入了两行内容(node.txt有两行内容)。
$ git add file1.txt // 添加file1.txt文件
$ git add file2.txt file3.txt // 同时添加file2.txt和file3.txt两个文件(可多次)
$ git commit -m "add 3 files." // 一次性提交3个文件(commit可以一次提交很多文件)
时光机穿梭
2.1 版本回退
$ git status // 查看当前仓库状态(仓库下的工作区文件是否被修改过)
$ git diff readme.txt // 查看工作区的node.txt与缓存区的node.txt的区别
$ git log // 查看最近到最远的提交记录(详情: commit id + Author + Date + comment)
$ git log --pretty=oneline // 如果嫌输出信息太多,可以试试查看最近到最远的提交记录(简写:commit id + comment)。看到的一大串类似10c7e...的是commit id(版本号)
$ git reset --hard HEAD^ // 回到上一个版本(HEAD: 当前版本,HEAD^: 上一个版本,HEAD^^: 上上一个版本,HEAD~100: 往上100个版本)
$ git reset --hard 1234567 // 回到指定版本号commit id(此处:commit id 假设为1234567******,版本号不需要写全,Git会根据commit id的前几位自动寻找对应的版本)
$ cat readme.txt // 查看readme.txt的内容
$ git reflog // 查看每一次命令记录历史,确保能回到任意版本
2.2 工作区与暂存区
$ git diff readme.txt // 比较工作区(working directory)和暂存区(stage/index)的区别;工作区即电脑里能看到的目录,例如learngit文件夹。
版本库:工作区有一个隐藏目录.git,这个不算是工作区,而是Git的版本库。
Git的版本库里存了很多东西,最重要的就是stage(或叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD。
前面讲了我们把文件往Git版本库里添加的时候,是分两步执行的:
第一步是用git add把文件添加进去,实际上就是把文件修改添加到暂存区;
第二步是用git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支。
因为我们创建Git版本库时,Git自动为我们创建了唯一一个master分支,所以,现在,git commit就是往master分支上提交更改。
你可以简单理解为,需要提交的文件修改通通放到暂存区,然后,一次性提交暂存区的所有修改。
$ git diff --cached // 比较暂存区(stage/index)和分支(master)的区别
2.3 管理修改(详见1. 创建版本库中的命令)
2.4 撤销修改
$ git checkout -- node.txt // 撤销修改:1. 文件在添加到缓存区前修改,则回退到原工作区状态;2. 文件在添加到缓存区后修改,则回退到原缓存区状态。也即是将node.txt撤回到最近一次git add或git commit状态(注:--表示在当前分支,如果没有,则切换到另一个分支)
$ cat node.txt // 查看文件内容
$ git reset HEAD node.txt // 1. 回退到最新版本;2. 将暂存区的修改回退到工作区
2.5 删除文件
$ rm test.txt // 删除工作区文件(类似于手动删除)
$ git status // 查看当前工作区与缓存区状态
$ git rm test.txt // 情况1:确认删除
$ git commit -m "remove test.txt" // 情况1:确认删除后,提交到版本库
$ git checkout -- test.txt // 情况2:误删,需要回退(即:用版本库里的版本替换工作区的版本)
远程仓库
注册GitHub账号(因为你的本地Git仓库和GitHub仓库之间的传输是通过SSH加密的,所以需要创建SSH kEY):
- 创建SSH Key。在用户主目录下,看看有没有.ssh目录,如果有,再看看这个目录下有没有id_rsa(私钥,不能泄露)和id_rsa.pub(公钥)这两个文件,如果已经有了,可直接跳到下一步。如果没有,打开Shell(Windows下打开Git Bash),创建SSH Key:
$ ssh-keygen -t rsa -C "youremail@example.com"
- 把邮件地址换成自己的邮件地址,一路回车,使用默认值即可。
- 登录GitHub,打开“Account settings”,“SSH Keys”页面;
然后,点“Add SSH Key”,填上任意Title,在Key文本框里粘贴id_rsa.pub文件的内容;
点“Add Key”,你就应该看到已经添加的Key,这样就在本地创建了一个Git仓库,要想在GitHub创建一个Git仓库,并且让这两个仓库进行远程同步,这样,GitHub上的仓库既可以作为备份,又可以让其他人通过该仓库来协作。
首先,登陆GitHub,点击右上角"Create a new repo"按钮,创建一个新的仓库;
在Repository name填入learngit,其他保持默认设置,点击“Create repository”按钮,就成功地创建了一个新的Git仓库;
目前,在GitHub上的这个learngit仓库还是空的,GitHub告诉我们,可以从这个仓库克隆出新的仓库,也可以把一个已有的本地仓库与之关联,然后,把本地仓库的内容推送到GitHub仓库。
3.1 添加远程库
$ git remote add origin git@server-name:path/repo-name.git
// 关联一个远程仓库,如: git remote add origin git@github.com:GitHub用户名/learngit.git// 添加后,远程库的名字就是origin,这是Git默认的叫法,也可以改成别的,但是origin这个名字一看就知道是远程库。
下一步,就可以把本地库的所有内容推送到远程库上:
git push -u origin master // 第一次推送master分支的所有内容
注:在GitHub上创建新仓库时,如果勾选了README.md选项时,可能会出现下面错误,提示:远程仓库有readme.txt,而本地仓库没有README.txt,此时应该先进行合并文件,再进行推送。
$ git pull --rebase origin master // 推送之前,进行合并
合并文件之后,发现本地仓库中多了README.md文件,此时再进行推送修改到远程仓库就可以了。
再次执行:git push -u origin master, 即可推送本地仓库到远程仓库了
$ git push origin master // 以后每次本地修改更新后,推送最新修改
3.2 从远程库克隆
假设我们从零开发,那么最好的方式是先创建远程库,然后,从远程库克隆。
首先,登陆GitHub,创建一个新的仓库,名字叫gitskills,勾选Initialize this repository with a README,这样GitHub会自动为我们创建一个README.md文件。创建完毕后,可以看到README.md文件:
$ git clone git@github.com:Da0sy/gitskills.git // 以SSH方式克隆一个本地库,默认的git://使用ssh,但也可使用https等协议,看以下这种方式:
$ git clone https://github.com/Da0sy/gitskills.git // 以Https协议方式克隆
然后进入gitskills目录看,已经有README.md文件了。但这种方式没有上一种快。
分支管理
在版本回退里,你已经知道,每次提交,Git都把它们串成一条时间线,这条时间线就是一个分支。截止到目前,只有一条时间线,在Git里,这个分支叫主分支,即 master 分支。 HEAD 严格来说不是指向提交,而是指向 master , master 才是指向提交的,所以, HEAD 指向的就是当前分支。
一开始的时候, master 分支是一条线, Git 用 master 指向最新的提交,再用 HEAD 指向 master ,就能确定当前分支,以及当前分支的提交点:
每次提交, master 分支都会向前移动一步,这样,随着你不断提交, master 分支的线也越来越长。
当我们创建新的分支,例如 dev 时, Git 新建了一个指针叫 dev ,指向 master 相同的提交,再把 HEAD 指向 dev ,就表示当前分支在 dev 上:
Git 创建一个分支很快,除了增加一个 dev 指针,改改 HEAD 的指向,工作区的文件都没有任何变化!
不过,从现在开始,对工作区的修改和提交就是针对 dev 分支了,比如新提交一次后, dev 指针往前移动一步,而 master 指针不变:
假如我们在 dev 上的工作完成了,就可以把 dev 合并到 master 上。 Git 怎么合并呢?最简单的方法,就是直接把 master 指向 dev 的当前提交,就完成了合并:
合并完分支后,甚至可以删除 dev 分支。删除 dev 分支就是把 dev 指针给删掉,删掉后,我们就剩下了一条 master 分支:
4.1 创建与合并分支
git branch // 查看所有分支(当前分支以‘*’标记)
git branch name // 创建分支(如:git branch dev)
git checkout name 或者git switch name// 切换分支
git checkout -b name 或者git switch -c name// 创建切换分支(如:git checkout -b dev)
git merge name // 合并分支(name)到当前分支上
git branch -d name // 删除该分支
4.2 解决冲突
git log --graph // 查看分支合并图
git log --graph --pretty=oneline --abbrev-commit // 查看分支合并缩略图
4.3 分支管理策略
git merge --no-ff -m "注释" dev // 合并后的分支有历史记录,而Fast-Forward合并之后,分支没有历史记录
4.4 Bug分支
git stash // 隐藏分支工作现场,为修复bug准备
git stash list // 查看有哪些分支隐藏的工作现场,为恢复工作现场做准备
git stash apply // 恢复工作现场,但不删除存储的stash内容,结合git stash drop进行删除
git stash drop // 删除存储的stash内容,恢复到隐藏前的工作现场
git stash pop // 恢复到隐藏前的工作现场,相当于git stash apply和git stash drop
git stash apply stash@{0} // 可以多次stash,通过git stash list查看所有的stash,然后可以恢复到指定的隐藏的工作现场
4.5 Feature分支
注:当添加一个feature时,最好新建一个分支:git checkout -b name
git branch -D name // 强行删除一个没有被合并到主分支的分支
4.6 多人协作(最好结合工作场景理解)
git remote -v // 查看远程库详细信息
git push origin dev // push本地dev分支到远程dev
git push origin master // push本地master分支到远程master(时刻保持同步)
git pull // 将最新的pull/dev(master)爬下来
git checkout -b branch-name origin/branch-name // 在本地创建和远程分支对应的分支
git branch --set-upstream-to=origin/branch-name dev // 建立本地分支和远程分支的关联
4.7 Rebase
git rebase // 将本地未push的分支提交整理成直线,利于查看
标签管理
git tag tagname // 创建标签
git tag // 查看所有标签
git tag tagname commitId // 为某次提交创建指定标签
git show tagname // 查看指定标签具体内容
git tag -a tagname -m "v0.1 released" commitId // 为某次指定的提交创建标签,同时添加标签注释
git tag -d tagname // 删除某个标签
git push origin tagname // 推送某个标签到远程库
git push origin --tags // 一次性推送所有标签到远程库
git tag -d v0.9 // 删除远程库标签(第一步:删除本地库标签)
git push origin :refs/tags/v0.9 // 删除远程库标签(第二步:从远程库删除标签)
使用GitHub
在GitHub上,可以自己fork任意开源仓库,自己拥有fork后的仓库的读与写操作权限,可以推送pull request给官方仓库贡献代码。
使用码云(与GitHub类似,用到的时候,再注册使用练习,毕竟GitHub更加NB一些!)
自定义Git(这里只是简单入门)
git config --global color.ui true // 让Git显示颜色
8.1 忽略特殊文件
忽略某些文件时,需要编写.gitignore文件,文件本身要放到版本库中,Git可以对.gitignore做版本管理!(注:不需要从头写.gitignore文件,GitHub已经为我们准备了各种配置文件,只需要组合一下就可以使用了。所有配置文件可以直接在线浏览:https://github.com/github/gitignore)
8.2 配置别名
git config --global alias.st status // 将st作为status的别名,以后就可以git st查看暂存区与工作区的状态了(还有类似co:checkout, ci:commit, br:branch,--global:是针对于当前用户起作用的,如果不加,则只针对于当前仓库)
cat .gitignore // 查看当前文件所有配置信息(包括别名信息)