简介

Git是目前世界上最先进的分布式版本控制系统,由C语言进行开发
在2022年之前,Linux构建的形式是世界各地的志愿者把源代码文件通过diff的形式发送给Linus,而后由Linus自己通过手工形式合并代码
Linus痛恨的CVS和SVN都是集中式的版本控制系统,而Git是分布式的版本控制系统,这两者有何区别?
集中式:版本库是集中寄存在地方服务器的,开发的时候用的都是开发机(本地机器),所以要先从地方服务器获取最新的版本,而后进行开发之后将代码推送给地方服务器。最大的问题是必须联网才可能进行工作,在网速慢的时候,提交大文件就会十分耗时。

分布式:分布式管制版本是没有“地方服务器”这个概念的,每个人的电脑上都是一个残缺的版本库,这样在开发的时候就不须要联网,因为版本库在本人的电脑上。既然每个人的电脑上都有一个残缺的版本库,那多集体如何合作呢?这时候就须要将各自对文件的批改推送给对方,就能够相互看到对方的批改了。和集中式版本控制系统相比,分布式版本控制的安全性会高很多。因为每个人的电脑里都有残缺的版本库,某个人的版本库出问题了没有关系,而集中式版本控制只有一个版本库。通常分布式版本控制系统也有一台充当“地方服务器”的电脑,当然这个服务器的作用只是不便“替换批改”,没有它也一样可能干活,只是替换批改不不便。

Git与svn的区别

  1. 历史记录:Git更加轻量级,每次提交只记录变动,而SVN每次提交都会存储残缺的文件
  2. 版本治理:Git更加灵便,容许分支和分支合并,而SVN只有骨干
  3. 安全性:Git分布式存储,一个服务器挂掉不会影响其余服务器,而SVN繁多服务器容易呈现平安问题
  4. 开发流程:Git的开发流程更加快捷,能够疾速的实现拉取、提交,而SVN开发流程繁琐
  5. 部署:Git无需平安客户端,反对跨平台,而SVN必须装置客户端能力应用
  6. 应用: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内容也删了:

因而,多人合作的工作模式通常是这样:

  1. 首先,能够试图用git push origin <branch-name>推送本人的批改;
  2. 如果推送失败,则因为近程分支比你的本地更新,须要先用git pull试图合并;
  3. 如果合并有抵触,则解决抵触,并在本地提交;
  4. 没有抵触或者解决掉抵触后,再用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多平台公布