啥是git
git是个分布式版本控制系统
有人问了,啥是版本控制,啥是分布式
这个我们可以从玩一个简单地RPG游戏开始,游戏可以是单机的,就是自己本地使用,我们经常在打的时候会死了,从而就不得不从头再来,所以游戏有了保存记录的功能,我们可以保存一个时间点之前玩的数据,后面挂了,或者中途断电什么的,可以继续从这里开始,当然一般的游戏可能不会看到什么区别,无非多了尝试的机会,可能你用别的方式可以无限条命。但是如果有个关卡,你可以选择和某个女主角同行,或者有个选择的通过地方,你不得不选择接下来的场景,或者是有个分支任务,你都想试试说不定有不同的奇遇和经验或是宝物,那么就有个记录就很好了,你可以建立新的分支保存,甚至玩着多个分支,当然前提是你要保存每次游戏记录,这也可以说是版本,你通过这种方式,保持自己的游戏版本可以多个分支,而且你可以重新从某个版本开始,覆盖后面的游戏,最终你玩的过程通关还是game over都可以有多个不同的版本了。
那分布式呢,我们如果玩的是网络版,这时候你想在本机离网也可以玩,或者任何地方都可以玩,那么数据就可以存在个地,我们只要能打开记录,就可以继续玩,这就有了分布式的概念了,主要是带来了方便。集中式就是记录都存在网络的服务器上,你只有登录那个服务才能玩。
当然对于很多网游这种是不大现实,因为要考虑和别人同时玩以及公平的问题,这样只有自己的记录会有很多冲突的。
那么从专业的讲版本控制就是对文件变更过程的管理,每个操作更新都可以是一个版本,而分布式就是文件记录都可以不止保存在服务器上,同时也完整的保存在本地计算机上,随时可以进行更新。
这真的是比传统svn集中式版本好的地方,带来了极大的便利性,而且配合github这一强大的web版本系统,我们除了文档,代码、图片都可以进行分布式版本控制,做什么都很方便,而且还有非常多开源带来的共享和学习资源,交流协作的机会,如果真的是会用的话真的是入门到入迷。
当然入迷还有可能是因为过多的操作方式而在操作时到处迷路了,接下来就可以开始我们的“游戏”之旅。
代码管理
- 领会:理解版本控制系统的思想及其在软件开发中的重要作用,理解分布式版本控
制系统的特点与优势。 - 熟知:Git 版本控制系统的基本工作原理,仓库、分支、合并等 Git 概念,熟练掌
握常用的 Git 命令。 - 应用:安装并使用 Git 进行代码与文档管理,部署与应用 GitLab 以实现私有 Git
服务,在 Github 上使用和发布开源代码。
登录github建立仓库
右上角的加号点开
然后输入仓库名称,一般和对应项目同名,勾选是否私有和生成README文件
点击创建
接着在实验环境,比如本地电脑或虚拟机上装好git,windows还有git for windows 版,
进入要部署项目的文件夹,右键点git bash here
输入git clone + 仓库地址获取仓库文件到本地,仓库地址在仓库页面可以看到
$ git clone https://github.com/yihui8776/SmartScientificResearchAssistant.git
进入仓库主目录,如下图所示,仓库主目录中有个 .git 隐藏目录,它里面包含了仓库的全部信息,删掉这个目录,仓库就变成普通的目录了。进入到仓库目录中,命令行前缀发生了一些变化,出现了红色的 master ,它就是当前所在的分支名:
当我们在 GitHub 上创建一个仓库时,同时生成了仓库的默认主机名 origin,并创建了默认分支 master。GitHub 可以看成是免费的 Git 服务器,在 GitHub 上创建仓库,会自动生成一个仓库地址,主机就是指代这个仓库,主机名就等于这个仓库地址。克隆一个 GitHub 仓库(也叫远程仓库)到本地,本地仓库则会自动关联到这个远程仓库,执行 git remote -v 命令可以查看本地仓库所关联的远程仓库信息:
Git 要求对本地仓库关联的每个远程主机都必须指定一个主机名(默认为 origin),用于本地仓库识别自己关联的主机,git remote 命令就用于管理本地仓库所关联的主机,一个本地仓库可以关联任意多个主机(即远程仓库)。
克隆远程仓库到本地时,还可以使用 -o 选项修改主机名,在地址后面加上一个字段作为本地仓库的主目录名
如果删除了.git 目录或是一个普通的文件夹目录想要再变成git仓库,可以使用git init命令。
原理介绍
使用的时候我们会接触各种命令和问题,但是场景很多,而我们一般的教程会先从它的存储来说,也就是可以想象几个具体的文件存储地方,然后来更好的理解git的结构和命令。
git的主要使用三个抽象概念,工作区、暂存区、版本区等。
在我们工作环境上的主要想象有一个工作区,一个暂存区
工作区上就是代码文件具体存储的地方,我们在上面编辑代码和文件。在进行 git add + 文件目录/名
后会进行打标记,也就是记录这次修改的加入到暂存区,先看下当前状态
$ git status
On branch master
Your branch is up to date with 'origin/master'.
这就是说明当前工作区和上游分支origin/master一致;
开始对工作区做修改,放入项目代码,修改README文件后再继续看status
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: README.md
Untracked files:
(use "git add <file>..." to include in what will be committed)
README.md.bak
显示的是README.md文件做了更改,但是还没跟踪。
跟踪记录到暂存区 git add
用git add 命令进行标记跟踪,说明这次更改要和前面进行对比然后把变更记录到缓冲里;
接下来要添加修改到暂存区以及撤销修改
使用 git add [文件名] 命令跟踪此新建文件,就是把新增文件添加到暂存区 stage,以备提交:
git add . 表示对当前目录所有修改增加到暂存区,也可以具体加文件名等,对具体的更改分别增加。
当我们修改了工作区,git add 命令是将这些修改添加到暂存区,暂存区记录的只是修改。如果要撤销暂存区的修改怎么办?
撤销跟踪
可以执行 git reset -- [文件名] 或者 git rm --cached [文件名] 命令即可
git reset -- README.md 或 git rm --cached README.md
看提交的变化 git diff :
它可以用来查看工作区被跟踪的文件的修改详情,此时新建文件 one.txt 并未被跟踪,而已被跟踪的文件 README.md 无修改,所以看不到。注意,只有在版本区中存在的文件才是被跟踪文件。
再看下跟踪后的status
$ git status
On branch master
Your branch is up to date with 'origin/master'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: README.md
看git diff
会显示增加和变更的内容
git add 进行跟踪后在看git diff
$ git diff --cached
diff --git a/README.md b/README.md
index cb4f9c1..36f78b1 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,64 @@
# SmartScientificResearchAssistant
-SmartScientificResearchAssistant
提交到版本区
将执行 git commit 命令把暂存区的修改提交到版本区,生成一个新的版本。
$ git commit -m 'mod README'
[master 9261336] mod README
1 file changed, 63 insertions(+), 1 deletion(-)
-m 表示标记,后面是标记的注释内容。这里显示增加了63行,少了1行
查看提交历史
git log
关于查看提交历史记录的命令,有些常用的选项介绍一下:
- git log [分支名] 查看某分支的提交历史,不写分支名查看当前所在分支
- git log --oneline 一行显示提交历史
- git log -n 其中 n 是数字,查看最近 n 个提交
- git log --author [贡献者名字] 查看指定贡献者的提交记录
- git log --graph 图示法显示提交历史
用git log 查看有两个提交的日志。
配置个人信息
user.email:写入你自己注册 GitHub 账号的邮箱
user.name:你自己的 GitHub 账号名字
如 git config --global user.email ‘yihui@github.com’
提交后我们可以查看具体分支等信息
git branch -avv
$ git branch -avv
- master 9261336 [origin/master: ahead 1] mod README
remotes/origin/HEAD -> origin/master
remotes/origin/master ab18665 Initial commit
第一行,开头的星号表示当前所在分支,绿色的 master 是分支名,之所以是绿色,也是因为它是当前所在分支。后面第二项是版本号,第三项中括号里面蓝色的字,表示此分支跟踪的远程分支的名字,当然啦,这也是克隆远程仓库到本地时的默认设置 -- 创建 master 分支并自动跟踪远程同名分支;冒号后面黑色文字表示本地分支领先其跟踪的远程分支一个提交。最后一项是提交时填写的备注信息。
第二行,是 Git 指针信息,它指向远程仓库的 master 分支,这行信息暂不重要。
第三行,远程分支信息,详见第一行的解释。
版本回退
如果发现提交错了,可以进行回退
首先执行 git reset --soft HEAD^ 撤销最近的一次提交,将修改还原到暂存区。--soft 表示软退回,对应的还有 --hard 硬退回,后面会讲到,HEAD^ 表示撤销一次提交,HEAD^^ 表示撤销两次提交,撤销 n 次可以简写为 HEAD~n。软退回一个提交后执行 git branch -avv 命令查看分支信息:
回退后可以看到 git diff已经没了, 执行 git status 查看仓库状态,果然上一个提交中的修改全部扔回了暂存区:
$ git status
On branch master
Your branch is ahead of 'origin/master' by 1 commit.
(use "git push" to publish your local commits)
nothing to commit, working tree clean
$ git diff
处理 commit 时间线分叉
执行 git status 和 git branch -avv 查看仓库状态和分支状态:
本地仓库的 master 分支与远程仓库的 origin/master 分支在提交版本上有了冲突,又叫做提交时间线分叉。因为刚才的提交操作不是基于远程仓库 origin/master 分支的最新提交版本,而是撤回了一个版本。这种情况下也是可以将本地 master 分支推送到远程仓库的,需要加一个选项 -f ,它是 --force 的简写,这就是强制推送。
本地仓库 commit 变化记录
git reflog 会记录本地仓库所有分支的每一次版本变化。
实际上只要本地仓库不被删除,随你怎么折腾,都能回退到任何地方。
可以直接执行命令 git reset --hard [版本号] ,如果记不清版本号,也可以根据上图第 3 行的信息,执行 git reset --hard HEAD@{2} 命令
git分支管理
git 还有更为重要的技能就是分支管理了,这样我们可以根据自己的计划和变更多个分支开发,比如原始分支和开发分支,开发一个新产品模块也可分支,也可开源和企业版本,或是客户不同做不同定制化等。
git fetch
将远程仓库的分支拉到本地仓库。
注意,仅仅是更新了本地的远程分支信息,也就是执行 git branch -avv 命令时,查看到的 remotes 开头的行的分支信息。
之前提交的README,可以在github界面看到commit次数
可以看到内容都有了,但是排版有问题。现在我们在远程的分支上面直接更改。直接在 github上编辑README文件。
编辑保存后直接提交
git fetch 将提交的信息获取到本地
看下分支信息
$ git branch -avv
- master 9261336 [origin/master: behind 1] mod README
remotes/origin/HEAD -> origin/master
remotes/origin/master da4c551 Update README.md
本地无改变,而远程加了dac551 的commit。
git fetch 只是获取信息,没有真的把代码拉下了,拉取代码需要 git pull。
另一种方式:
前面执行过 git fetch 命令,所以也可以执行 git rebase origin/master 命令来实现 “使本地 master 分支基于远程仓库的 master 分支”,rebase 命令在后面还会经常用到,相当于fetch再pull
yihui8776@DESKTOP-8K7I89U MINGW64 /e/workspace/SmartScientificResearchAssistant (master)
$ git rebase origin/master
First, rewinding head to replay your work on top of it...
Fast-forwarded master to origin/master.
yihui8776@DESKTOP-8K7I89U MINGW64 /e/workspace/SmartScientificResearchAssistant (master)
$ git branch -avv
* master da4c551 [origin/master] Update README.md
remotes/origin/HEAD -> origin/master
remotes/origin/master da4c551 Update README.md
在看本地工作区的文件,看到也更新了。
练习
下面关于git的叙述中,正确的是:
A. git 是通过服务器集中管理代码的版本控制系统
B. git commit 命令将代码的本地更新提交到远程仓库
C. 在git使用的传输协议中,HTTP协议和SSH协议通常是只读的
D. 如果在不同的分支中同一个文件的同一部分被修改,则git需要用户来解决冲突
如果在 feature/abcd 分支上运行 git status,返回如下结果:
On branch feature/abcd
Your branch and 'origin/feature/abcd' have diverged,
and have 2 and 1 different commits each, respectively.
此时更新本地分支应该使用哪个命令?
A. git git reset --hard feature/abcd
B. git pull --rebase feature/abcd
C. git rebase master
D. git fetch origin feature:featuregithub