共计 7503 个字符,预计需要花费 19 分钟才能阅读完成。
简介
Git 是目前世界上最先进的分布式版本控制系统,由 C 语言进行开发
在 2022 年之前,Linux 构建的形式是世界各地的志愿者把源代码文件通过 diff 的形式发送给 Linus,而后由 Linus 自己通过手工形式合并代码
Linus 痛恨的 CVS 和 SVN 都是集中式的版本控制系统,而 Git 是分布式的版本控制系统,这两者有何区别?
集中式:版本库是集中寄存在地方服务器的,开发的时候用的都是开发机(本地机器),所以要先从地方服务器获取最新的版本,而后进行开发之后将代码推送给地方服务器。最大的问题是必须联网才可能进行工作,在网速慢的时候,提交大文件就会十分耗时。
分布式:分布式管制版本是没有“地方服务器”这个概念的,每个人的电脑上都是一个残缺的版本库,这样在开发的时候就不须要联网,因为版本库在本人的电脑上。既然每个人的电脑上都有一个残缺的版本库,那多集体如何合作呢?这时候就须要将各自对文件的批改推送给对方,就能够相互看到对方的批改了。和集中式版本控制系统相比,分布式版本控制的安全性会高很多。因为每个人的电脑里都有残缺的版本库,某个人的版本库出问题了没有关系,而集中式版本控制只有一个版本库。通常分布式版本控制系统也有一台充当“地方服务器”的电脑,当然这个服务器的作用只是不便“替换批改”,没有它也一样可能干活,只是替换批改不不便。
Git 与 svn 的区别
- 历史记录:Git 更加轻量级,每次提交只记录变动,而 SVN 每次提交都会存储残缺的文件
- 版本治理:Git 更加灵便,容许分支和分支合并,而 SVN 只有骨干
- 安全性:Git 分布式存储,一个服务器挂掉不会影响其余服务器,而 SVN 繁多服务器容易呈现平安问题
- 开发流程:Git 的开发流程更加快捷,能够疾速的实现拉取、提交,而 SVN 开发流程繁琐
- 部署:Git 无需平安客户端,反对跨平台,而 SVN 必须装置客户端能力应用
-
应用:Git 更加简略,学习老本更低,而 SVN 略显简单
操作
创立版本库
版本库:仓库 repository,能够简略了解为一个目录,这个目录中的所有文件都能够被 Git 治理起来,每个文件的批改、删除,Git 都可能进行跟踪,以便任何时刻都能够追踪历史,或者在未来某个时刻能够“还原”。
创立一个版本库很简略
//1. 创立目录
mkdir learngit
cd learngit
pwd
//2. 通过 git init 将这个目录变成 Git 能够治理的仓库
执行完 git init 命令之后,当前目录会多出一个.git 目录
这个目录是 git 用来跟踪版本库的,默认是一个暗藏文件
//3. 将文件放到 Git 仓库中
vim readme.txt // 轻易写点什么
git add readme.txt // 将 readme.txt 文件增加到仓库
git commit -m “this is a readme.txt”
为什么 add 和 commit 要分成两步呢?因为一次 commit 能够提交很多文件,而能够屡次 add 不同的文件
状态查看
当初咱们将 readme.txt 文件批改为如下内容
Git is a distributed version control system.
Git is free software.
能够通过 git status 来查看后果
git status 通知咱们 readme.txt 文件曾经被批改了,然而还没有筹备提交的批改
怎么查看到底该了什么内容呢?
能够通过 git diff 命令来查看 difference,显示的格局正是 Unix 通用的 Diff 格局
通过 git add readme.txt 进行提交
再通过 git status 查看以后状态
这是通知咱们,被提交的批改有 readme.txt 文件
- 如果想要查看工作区的状态,应用 Git status 命令
-
如果 git status 通知你有文件被批改过,用 git diff 能够查看批改内容
回退
咱们再次批改 readme 文件
以下是新内容
Git is a distributed version control system. Git is free software distributed under the GPL.
之后尝试提交
像这样,一直对文件进行批改,而后一直提交批改到版本库里,就相似于把 git 的状态存盘,每当文件批改到肯定水平的时候,就能够『保留一个快照』,这个快找在 Git 中被称为 commit
,一旦把文件弄乱了或者误删了文件,能够从最近的一个commmit
中复原 git log
可能帮忙咱们看到 git 的历史记录
显示的是从最近到最远的提交日志,如果嫌输入信息太多,能够加上 --pretty=online
参数
在 Git 中,用 HEAD
来示意以后版本,上一个版本为 HEAD^
,上上一个版本为HEAD^^
,
咱们能够通过 git reset --hard HEAD^
来将文件回退到上一个版本
在底层,Git 在外部有一个指向以后版本的 HEAD
指针,当进行回退版本的时候,GIT 仅仅是将 HEAD 的指向进行了扭转
一个新的问题:如果这个时候我又想回到 GPL 的那个版本该怎么办呢?
能够看到这时候咱们通过 Git log 进行日志查看,曾经没有那个版本的记录了
咱们能够通过 git reflog 看到之前提交的 id
通过 git reset –hard 参数 +ID 进行回退
工作区与暂存区
Git 与其余版本控制系统的一个不同之处就是有暂存区的概念
工作区
就是电脑里可能看到的目录,比方 learngit 文件夹
版本库
工作区有一个暗藏目录.git,这个不算是工作区,而是 Git 的版本库。Git 的版本库外面有很多货色,其中最重要的就是称为 stage(index)的暂存区,还有 Git 为咱们主动创立的第一个分支 master,以及指向 master 的一个指针叫做 HEAD
咱们将文件往 Git 版本库增加的时候,是分两步执行的
- git add 把文件增加进去,实际上就是把文件增加到暂存区
- git commit 提交更改,实际上就是把文件去的所有内容提交到以后分支
因为在创立 GIT 版本库的时候,GIT 主动为咱们创立了惟一一个分支 master,所以 git commit 就是往 master 分支上提交更改
git commit 之后
治理批改
每一次的批改都必须应用 git add 增加之后,才会放到暂存区,在 git commit 的时候才会提交到分支。如果批改了之后没有应用 git add 命令,那么是不会提交到分支中的
撤销批改
当咱们将文件批改成以下内容,然而未提交的时候,git 会进行以下提醒
Git is free software distributed under the GPL. Git has a mutable index called stage. Git tracks changes of files. My stupid boss still prefers SVN.
能够应用 git checkout — readme.txt 进行把 readme.txt 文件的工作区的批改全副撤销
切记,肯定要增加 – 标签,不然这个命令会变成切换到另一个分支
这里的撤销有两种状况
- readme.txt 自批改之后还没有被放到缓存区中,当初,撤销批改就回到和版本库截然不同的状态
- readme.txt 曾经增加到暂存区之后,又做了批改,撤回批改就回到增加到暂存区之后的状态
当然 当初举荐的命令是 git restore readme.txt
当曾经把批改通过 git add
命令增加到暂存区之后,想要抛弃批改,分成两步
- git reset HEAD <file>
-
git checkout –file
删除文件
当咱们在工作区下增加一个文件
vim test.txt
内容如下:
hello world.
而后通过 git add test.txt 与 git commit -m “add test.txt” 进行提交
这个时候咱们把 test.txt 文件进行删除
再通过 git status 查看会发现
当初咱们有两种抉择
1. 确定删除 应用 git rm test.txt,而后 git commit -m “remove test.txt”
2. 删错了 应用版本库里的版本替换工作区的版本 git checkout — test.txt
近程仓库
增加近程仓库 git remote add origin git@xxx
git push // 将本地库的内容推送到近程库上
-u 参数岂但可能实现近程推送 还可能将本地分支与远端分支关联起来 之后的推送或者拉取就可能简化命令git remote -v
查看近程仓库信息 git remote rm origin
删除近程仓库(解除本地和近程的绑定关系)git clone
克隆远端代码 ssh 协定的速度 >https
分支治理
HEAD 是一个指针,指向的分支就是以后分支,在一开始的时候,master 分支是一条线,Git 应用 master 指向最新的提交,再用 HEAD 指向 master,就能确定以后分支以及提交点
每次提交,master 分支都会向前挪动一步,这样随着一直提交,master 分支的线也会越来越长
当咱们创立了一个新的分支,其实也就是一个新的指针 dev,指向的是 master 雷同的提交,再把 HEAD 指向 dev,示意以后分支在 dev 上
因为 git 的新建分支是创立一个指针以及批改 HEAD 的指向,而文件自身内容不变,所以速度很快
从当初开始,对工作区的批改和提交就是针对 dev 分支了,新提交之后 dev 指针向前挪动,然而 master 指针不变
分支治理
git branch dev 创立 dev 分支
git checkout dev 切换到 dev 分支
增加一个内容为 hello world 的 test 文件
git add + git commit 提交成绩
git checkout master 切换回主分支
git merge dev 将 dev 分支合并到以后分支
而后再通过 git branch -d dev 将 dev 分支进行删除
git 举荐当初的分支操作应用 switch 命令git switch -c
创立并切换到新分支git switch master
创立到已有分支
抵触
git 应用 <<<<<<<,=======,>>>>>>> 标记出不同分支的内容标记出不同的分支
更改抵触文件为想要的内容后提交
分支治理
在合并分支的时候,如果可能,git 会应用 fast forward
模式,在这种模式下,删除分支之后就会丢掉分支信息
合并分支的时候,加上 –no-ff 参数就能够应用一般模式合并,合并后的历史有分支,可能看进去已经做过合并git merge --no-ff "merge dev" dev
bug
个别每个 bug 都会新建一个分支来批改,修复之后合并分支,而后将长期分支删除
git stash 将当前工作区进行存储
一是用 git stash apply 复原,然而复原后,stash 内容并不删除,你须要用 git stash drop 来删除;
另一种形式是用 git stash pop,复原的同时把 stash 内容也删了:
因而,多人合作的工作模式通常是这样:
- 首先,能够试图用 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 tag 给 commit 打标签
git show 查看标签信息
git tag -a 查看所有标签
git tag -d 删除标签
git push origin <tagname> 推送本地标签
github
1.fork 一个仓库 而后 clone 仓库 因为没权限 clone 原仓库
2. 开发 往本人的仓库推送
3. 推送 pr 给原仓库
Git 进阶操作
git pull
拉取胜利但不更更新
这个因为本地有更改,和仓库对应不上,解决形式如下
1.git stash 将本地批改存储起来
2.git pull // 倡议应用残缺的 git pull origin branchname
git pull 外部执行原理
pull 蕴含两个操作,fetch 和 merge
fetch: 将近程仓库拉取到本地仓库
merge: 将本地仓库和分支进行 merge
git pull 的时候会向远端发送 git-upload-pack 申请,携带的是本地仓库 commit 的记录,如果统一则不须要拉取,不一样就将远端仓库拉下来
push 之前 pull 的起因
git commit 的时候,仓库并不会将本地和近程仓库代码进行比拟,不会辨认出代码是否存在抵触,必须进行 pull 命令之后,才会将本地代码和近程仓库的代码进行比拟,如果二者的代码存在抵触,必须要解决抵触后从新 commit push,如果不存在抵触,则 pull 的时候间接合并代码,不会将本地代码笼罩掉
git status 中的 untracked file
在 Git 中,未被跟踪的文件(untracked file)是指存在与 Git 治理的目录中,然而尚未被增加到 Git 版本控制中的文件。这些文件没有被 Git 追踪,因而它们不受 Git 版本控制的治理。
当应用 git status
命令查看 git 存储库的状态,个别日志文件就会是 untracked file,因为没必要对日志进行追踪,日志也不会提交到代码库中
如果想把未被追踪的文件增加到 Git 版本控制中,能够应用 git add 命令将它们增加到 Git 的暂存区中,而后应用 git commit 提交到存储库中
git add 提交了多余的文件,并且曾经 git commit 了,怎么撤销
如果只是 git add 了,然而还没有 git commit,也就是说这些文件只是增加到了暂存区,还没有进行提交,那么能够通过 git reset + filename,将文件从暂存区中删除,或者 git reset 间接将所有文件都从暂存区中撤销
第一步得撤销 git commit
git revert sha 值 撤销你的某一个提交
或者间接 git revert HEAD 撤销最近一次提交,并创立一个新的提交来记录这个撤销操作,这个操作能够用来修复一个谬误的提交或者撤销一个不必要的提交
如果报错 error:commit sha is a merge but no -m option was given
这是因为正在尝试通过 git revert 命令撤销一个合并提交,然而没有指定用于撤销的父提交。要解决这个问题,须要应用 - m 选项来指定父提交,该选项前面须要指定一个数字,标识用于撤销提交的父提交的编号
假如想撤销最近的一次合并提交,能够应用 git revert -m 1 HEAD
应用合并提交的第一个父提交来撤销该提交
git commit 错分支了怎么办
1.git log 命令查找刚刚提交的 SHA 值
2.git branch + git checkout 切换到你想提交的分支
3.git cherry-pick + sha 讲提交利用到以后分支
git revert 后工作区代码隐没
git reset –hard HEAD 该命令会将工作区和暂存区都重置为最新的提交,并革除所有未提交的批改。须要留神的是,这个命令会革除本地未提交的更改,因而在应用前请确认这些更改曾经备份或者提交到了其余分支上。如果依然无奈复原更改,能够应用 git reflog 命令查找之前的提交记录,应用 git reset –hard +sha 指向指定的提交
批改 git commit 提交信息
当咱们 cr 被打回来的时候,就不须要从新 git commit,而是间接 git commit –amend 批改之前的提交信息,这会被 git 认为是一次新的提交
1.git commit –amend 关上编辑器
2. 批改提交信息
3.git push
查看 git 信息
1.git log 查看所有的提交历史记录 例如提交 ID 作者 日期 提交阐明等等,罕用于查看 Git 仓库的历史提交记录以及比照和合并分支
2.git reflog 记录了 Git 仓库的每一次操作,包含分支和标签的创立、删除、挪动等操作,这个命令能够用来找回曾经删除的分支或者标签
git diff
1.git diff –cached 查看暂存区和最初一次提交之间的差别 也就是 git add 离上一次的更改
2.git diff filename 查看文件的更改
3.git diff 查看曾经批改然而未暂存(没有 add)的更改
工作区、暂存区、本地仓库、近程仓库
1. 工作区:理论写代码的中央,电脑上的文件夹,外面放着咱们的代码文件
2. 暂存区:git 提供的一个长期的存储取余,能够临时存储咱们批改过的文件,期待提交到本地仓库,对应的是某一个分支
3. 本地仓库:存储代码版本历史记录的中央,能够看作是 Git 保护的一个数据库,存储了我的项目的所有历史版本
4. 近程仓库:一个在网络上的 Git 仓库,通常由代码托管服务商提供,能够把本地仓库的代码推送到近程仓库中,也能够从近程仓库中拉取代码到本地仓库进行应用
根本工作流:通过 git add 将文件增加到暂存区,而后通过 git commit 提交到本地仓库,最初通过 git push 提交到近程仓库
为什么须要本地仓库:
- 安全性:本地仓库能够在本地保留代码的历史版本,即便在近程仓库数据失落或者被毁坏的状况下,本地仓库中的代码依然是平安的
- 离线操作:没有网络的状况下,本地仓库容许开发人员持续对代码进行批改和提交
-
提高效率:因为本地仓库不须要每次从近程仓库拉取代码,能够大大减少代码拉取的工夫和网络带宽
git 工作区批改后切换到新分支,保留批改
如果在工作区有未提交的批改,并且切换到新分支,那么这些批改是不会被保留的,因为一个暂存区对应的是一个分支
这个时候咱们就须要
1.git stash // 将工作区的批改保留到一个长期区
2.git checkout
3.git stash pop 或者 git stash apply
4. 如果有抵触的话,解决对应的文件<<<<<<< HEAD // 这里是以后分支的批改内容 ======= // 这里是合并分支的批改内容 >>>>>>> merge-branch
二者区别
apply 从 stash 中复原最近的一次批改,但不会将这些批改移出
pop 从 stash 中复原最近的一次批改,同时将批改弹出
git merge 和 git rebase 的区别
merge 是合并的意思
rebase 是复位基底的意思
举荐是应用 git rebase 因为 rebase 的代码历史十分清晰
比方有一个 master 分支,同时 6 集体进行开发,须要创立六个独自的集体分支,而后应用 merge 的话就会有六个 branch 和主分支交错在一起,也就是 master 的 commit 历史是网状的.master 是创立一个新的结点,而后将两个分支的历史分割在一起
而 rebase 会把提交挪动到 master 的最后面,造成一条线
本文由 mdnice 多平台公布