Git 的结构
- 工作区:我们书写代码的地方
- 暂存区:打算提交的东西,但是还没有提交,暂时存放的区域。里面的内容将来可以提交到本地库,也可以撤销出暂存区。
- 本地库:存储每一个我们提交过的历史的版本
git add
命令添加到暂存区准备提交,然后通过 git commit
提交到本地库Git 和代码托管中心
代码托管中心的任务:维护远程库
现有代码托管中心:
- 局域网环境下:GitLab 服务器
- 外网环境下:GitHub、码云
团队内协同开发
- 成员 A 为了管理代码,创建了本地库
- A 为了将本地库推送到代码托管中心,在代码托管中心创建了远程库
- A 在本地库使用
push
命令将本地库内容推送到远程库 - 成员 B 通过
clone
命令将远程库的内容克隆下来,此举不仅会下载远程库的代码,还会完成本地库初始化 - 成员 B 也想要通过
push
命令将他在本地库书写的内容推送到 A 创建的远程库,此时他必须加入 A 的团队,再完成推送 - 成员 A 需要通过
pull
命令将成员 B 对远程库所做的修改拉取到他(A)的本地库
- A 公司的 A1 和 A2 分别拥有各自的本地库,代码托管中心有 A1 创建的远程库
- B 公司的 B1 通过对 A1 创建的远程库执行
fork
操作,复制出来一个新的远程库。虽然库中的内容一样,但是这两个库分别属于 A 公司 和 B 公司 - B1 通过
clone
他fork
出来的远程库,作出修改后push
到了他自己的远程库(即复制出来的库)。此次修改仅仅修改了 B1 自己的远程库,是无法同时修改 A1 的远程库的 - 所以 B1 需要对 A1 创建的库发起一个
pull request
请求,由 A1 去对请求中的内容(即 B1 对远程库所做出的修改)进行审核,审核通过后即可点击Merge pull request
将其合并到 A1 的远程库中,此时 A1 的远程库中已经拥有了 B1 所修改过的内容 - 再由 A1 和 A2 通过
pull
拉取 A 公司远程库的内容到本地
- 本地库初始化
进入项目根目录,执行:
# 生成 .git 文件夹 git init
- 设置签名
签名的作用:仅用于区分开发人员的身份,与登陆远程库的账号无关
# 项目级别/仓库级别:仅在当前本地库范围内有效 git config user.name twinkleZz git config user.email twinkleZz@qq.com# 系统用户级别:对当前 windows 用户有效 git config --global user.name twinkleZz git config --global user.email twinkleZz@qq.com
项目级别的签名信息会保存到 .git 文件夹下的 config 文件
系统级别的签名信息会保存到 C:\Users\17380 目录下,即当前 windows 用户文件夹下的 .gitconfig 文件中
- 查看工作区、暂存区状态
红字提示是说明在工作区修改了,还未提交到暂存区
绿字提示是说明已经提交到暂存区了,还未提交到本地库
git status# 打印如下 On branch master # 当前处于 master 分支 No commits yet # 当前无任何提交 nothing to commit (use "git add" to track) # 暂存区无可提交内容
- 追踪文件
追踪文件就是将工作区的内容提交到暂存区
# 在项目根目录创建一个文件,此时再次使用 git status 命令,会多打印一段代码: Untracked files: (use "git add
..." to include in what will be committed)index.htmlnothing added to commit but untracked files present (use "git add" to track)# 告诉我们有未追踪的文件,现在我们根据提示对 index.html 文件进行追踪(添加至缓存区): git add index.html# 追踪所有工作区文件: git add .# 取消追踪(将文件从暂存区移除): git rm --cached index.html
- 提交文件
将暂存区的所有文件提交到本地库
git commit index.html
直接提交的话,系统会提示
Please enter the commit message for your changes. Lines starting with '#' will be ignored, and an empty message aborts the commit
该句意思是让我们对本次提交进行描述
可是我们该如何输入呢?
两种方式:
1) 其实显示这段话的时候 git 已经启用了 vim 编辑器,我们可以输入:set nu
显示行号
按i
键进入编辑模式,直接输入This is my first commit!
作为本次提交的说明信息,然后按下 ESC 键,键入:wq
即可自动提交并退出编辑
2) 在提交时直接添加注释:
git commit -m "This is my first commit!" index.html
假如我们对刚才提交的 index.html 文件作出一些修改,此时再次执行git status
会提示:
Changes not staged for commit: (use "git add
..." to update what will be committed) (use "git restore ..." to discard changes in working directory) modified:index.html
该段代码是要求我们对修改后的文件进行提交或撤回操作
因此我们要先使用git add
将修改后的文件添加至缓存区,再次使用git commit
提交
也可以直接git commit
,但无法执行撤回操作
- 查看版本历史记录
历史版本保存在本地库中
git log# 打印如下:commit 后的 hash 值是我们本次提交的索引,HEAD 指向的是当前版本 commit 4de01b82723d95b536f3da6682632bfc716b78a7 (HEAD -> master) Author: blueming
Date:Fri Aug 14 22:46:11 2020 +0800My first commit!
如果打印内容较多,可以使用空格向上翻页,B 向下翻页,Q 退出
以简明的形式打印历史记录:
git log --pretty=oneline# 打印如下 4de01b82723d95b536f3da6682632bfc716b78a7 (HEAD -> master) My first commit!git log --oneline # 打印如下,在 --pretty 的基础上,缩短了 hash 值的显示长度 4de01b8 (HEAD -> master) My first commit!git reflog # 打印如下,在 --oneline 的基础上,显示了切换到某个版本需要移动几步,如 HEAD@{1} 就是移动一步 4de01b8 (HEAD -> master) HEAD@{0}: commit: My first commit! 0f0b10d HEAD@{1}: commit (initial): This is my first commit!
版本的前进与后退就是通过移动HEAD
指针实现的
只有git reflog
命令可以显示所有历史版本,其他命令只显示当前所处版本之前的版本
- 基于索引值的版本切换
其实就是对HEAD
指向的操作
git reset --hard 索引值 # 索引值即 git log 打印的 hash 值,可以使用其缩减形式。打印结果如下: Updating files: 100% (15/15), done. HEAD is now at 0f0b10d This is my first commit!
- 使用
^
符号实现版本切换
此方式只能回退版本,不能前移版本
# 回退一个版本 git reset --hard HEAD^# 回退三个版本 git reset --hard HEAD^^^# 回退一百个版本 git reset --hard HEAD~100
reset
命令的三个参数对比:
--soft
:仅仅在本地库执行 HEAD 指针移动
该参数只将本地库往后退到了某个版本,与暂存区的版本不再一致,那么暂存区会认为是自己的版本靠前了,会提示绿色 modified--mixed
:不仅会移动指针,还会重置暂存区
该参数将本地库和暂存区都往后退到了某个版本,与工作区版本不再一致,那么工作区会认为是自己的版本靠前了,因此会提示红色 modified--hard
:
既移动指针,又重置暂存区,还重置工作区
该参数会同时移动工作区、暂存区和本地库的版本,是最常用的参数
- 删除文件找回
删除文件的找回其实就是利用历史版本的回退实现的,前提是该文件之前已经被提交到本地库,并且文件删除操作也被 commit 到了暂存区或本地库中
# 删除工作区中的某个文件 rm README.txt# 此时运行 git status,会报红色 delete: Changes not staged for commit: (use "git add/rm
..." to update what will be committed) (use "git restore ..." to discard changes in working directory) deleted:asd.txt# 将删除操作提交到了暂存区或本地库 git add README.txt git commit -m "README commit" README.txt# 回退历史版本 git reset --hard HEAD^
已经提交到暂存区或本地库中的文件删除操作可以通过回退历史版本来还原文件
- 比较文件差异
# 将工作区中的文件和暂存区进行比较 git diff 文件名# 将工作区中的文件和本地库历史记录进行比较 git diff 本地库历史版本 文件名# 不带文件名,比较工作区中所有文件 git diff
使用分支意味着可以把你的工作从开发主线上分离开来,多条线共同推进项目进度,避免免影响开发主线
各分支在开发过程中互不影响,分支开发完成后可以与主干进行合并
使用分支也可以方便的进行热修复(在项目上线运行期间修复 bug)
分支操作
- 查看目前所处分支
git status# 打印如下 On branch master # 当前处于 master 分支 ...
- 查看所有分支
git branch -v
- 创建新分支
git branch 分支名
- 切换所处分支
git checkout 分支名
- 合并分支
# 第一步:切换到将要被合并的分支上 git checkout 分支名# 第二步:将 A分支合并到当前所处分支 git merge A分支名
1. 合并分支
2. 产生冲突,跳转至 [分支名|MERGING] 分支上
3. 进入冲突文件:
<<<<<<< HEAD
abcde edit by 分支A# 当前分支内容
=======
12345 edit by 分支B# 另一分支内容
>>>>>>> master
4. 删除特殊符号,修改文件内容并保存退出,最终文件内容如下:
abcde # 最终保留内容
5. git add 文件名
6. git commit -m "message" # 此时的 commit 不要带文件名
GitHub 操作
- 创建远程库
进入 GitHub 主页,点击右上角的 + 号,选择 New Repository,填写相关信息即可创建
- 设置远程库地址别名
我们创建的 GitHub 仓库地址是非常长的,因此在执行 git 操作的时候使用起来很不方便,我们可以为其设置别名
# 设置别名,将下面的 git 仓库地址映射到 origin 别名: git remote add origin https://github.com/xinlanxiangsui/moGuJie.git# 移除别名: git remote rm origin
- 将本地库内容推送至远程库
# git push 远程库地址(别名) 分支 git push origin master
执行完本行命令后需要按提示输入 GitHub 的账号和密码
注意:如果不是基于远程库的最新版本所做的修改,则无法推送,必须先拉取下来。拉取下来后如果进入冲突状态,则按照分支合并冲突的解决方法去解决即可
- 克隆远程库
克隆命令完成了三件事:
- 完整得把远程库下载到本地
- 初始化本地库
- 创建 origin 远程地址别名
# git clone 远程库地址 git clone https://github.com/xinlanxiangsui/moGuJie.git
- 【【学习笔记】GitHub 基本使用】拉取远程库的修改内容
# 只将远程库更新的内容下载下来,但不与本地分支进行合并。 git fetch origin master# 将 fetch 下来的内容与本地分支进行合并,fetch 内容的分支以 [远程仓库地址/分支名] 表示 git merge origin/master# 直接将远程库的修改合并到本地分支 git pull origin master
- 打开 GitHub,在对应的项目仓库中点击 Settings
- 选择左侧 Manage access,点击 invite a collaborator,输入被邀请人的 GitHub 账号或用户名
- 被邀请人通过系统发送的邮件中的链接,进入到对应的页面确认接受邀请即可