带你过一遍:廖雪峰大神Git教程(建议收藏)

这里是带你过一遍第一期,我来带你过一遍很出名的Git(廖雪峰版)教程,想要查看前面的笔记请翻阅我的CSDN博客,作者码字不易,喜欢的话点赞,加个关注吧,后期还有很多干货等着你!

初识Git

Git的诞生

2005的时候,linus使用2周时间用C语言写出来了一个Git,供全世界Linux开发者使用

集中式VS分布式

集中式版本控制:版本库是集中存放在中央服务器的,而干活的时候,用的都是自己的电脑,所以要先从中央服务器取得最新的版本,然后开始干活,干完活了,再把自己的活推送给中央服务器。中央服务器就好比是一个图书馆,你要改一本书,必须先从图书馆借出来,然后回到家自己改,改完了,再放回图书馆。
在这里插入图片描述
分布式版本控制:是Git使用的版本管理方式;每个人都各自管理版本库,当双方都有修改的时候,就会将自己的修改推送给对方就行了
在这里插入图片描述

安装Git

Git官网:https://git-scm.com/downloads

按照对应方式下载就行:Git下载
在这里插入图片描述

创建版本库

  1. 创建一个文件夹,不管你是Linux,Windows,Mac 请使用你新建文件夹的方式,建立一个文件夹(注意:避免莫名其妙的问题,请不要使用中文路径
  2. 请打开你系统对应的控制台,(如:Windows请右键选择Git Bash Here)输入:git init(这时候,目录下,会出现一个隐藏文件夹:.git文件夹)
  3. 这时候,你已经建立了一个空的版本库了

把文件添加到版本库

这里有一个特别注意:

使用Windows的童鞋要特别注意:
千万不要使用Windows自带的记事本编辑任何文本文件。原因是Microsoft开发记事本的团队使用了一个非常弱智的行为来保存UTF-8编码的文件,他们自作聪明地在每个文件开头添加了0xefbbbf(十六进制)的字符,你会遇到很多不可思议的问题,比如,网页第一行可能会显示一个“?”,明明正确的程序一编译就报语法错误,等等,都是由记事本的弱智行为带来的。建议你下载Notepad++代替记事本,不但功能强大,而且免费!记得把Notepad++的默认编码设置为UTF-8 without BOM即可:

  1. 建立一个文件在刚刚你创建的文件夹中:
  2. 使用git add 文件名 告诉git,将这个文件加入仓库(这里廖老师说两句搞笑的话:执行上面的命令,没有任何显示,这就对了,Unix的哲学是“没有消息就是好消息”,说明添加成功。)
  3. 使用git commit -m ‘第一次提交’ 将文件提交到仓库(git commit命令执行成功后会告诉你,1 file changed:1个文件被改动(我们新添加的readme.txt文件);2 insertions:插入了两行内容(readme.txt有两行内容)。)

小贴士:可以一次性多次添加(也就是git add)后,使用commit一次性全部提交到仓库

疑难解答:

Q:输入git add readme.txt,得到错误:fatal: not a git repository (or any of the parent directories)。
A:Git命令必须在Git仓库目录内执行(git init除外),在仓库目录外执行是没有意义的。
Q:输入git add readme.txt,得到错误fatal: pathspec ‘readme.txt’ did not match any files。
A:添加某个文件时,该文件必须在当前目录下存在,用ls或者dir命令查看当前目录的文件,看看文件是否存在,或者是否写错了文件名。

时光穿梭机

版本退回

这里廖老师举了个例子,关于打游戏的:我拿精灵宝可梦红宝石(就是我们看得:宠物小精灵)来举例吧,当你想获得想要的道具,或者想抓捕你想要的小精灵的时候,我们就会不停的存档,读档,一直到获得自己想要的才停止;git也有相对应的方式保存你每一次提交到仓库的状态,git将你每一次commit都保存一个状态,你可以恢复到任意一个commit节点;
游戏中你不需要自己记下来上一次保存的时间,而是直接去存档列表中挑选你回到的位置;
git中也有这么个存档列表

  • git log 查看你提交(commit)的历史(如果嫌输出信息太多,看得眼花缭乱的,可以试试加上–pretty=oneline参数:)

这里进一步解释一下,git生成的版本号(commit id)
需要友情提示的是,你看到的一大串类似1094adb…的是commit id(版本号),和SVN不一样,Git的commit id不是1,2,3……递增的数字,而是一个SHA1计算出来的一个非常大的数字,用十六进制表示,而且你看到的commit id和我的肯定不一样,以你自己的为准。为什么commit id需要用这么一大串数字表示呢?因为Git是分布式的版本控制系统,后面我们还要研究多人在同一个版本库里工作,如果大家都用1,2,3……作为版本号,那肯定就冲突了。

在git中,使用HEAD来表示当前版本,也就是最新提交的版本,那么上一个版本就是HEAD^ ,上上个版本是HEAD^ ^ ,那么一百个版本以前是什么 ,肯定不 是HEAD ^ 后面跟100^,而是使用HEAD~100的方式退回到100个版本以前

  • 那么现在我们针对这个文件夹进行回退

git reset --hard HEAD^

将版本库返回上一个版本,这时候,我们使用git log来查看版本库的状态;
你会发现,回退的版本不见了,你的存档删除了,当然你现在还没有关掉你的窗口,你还可以用使用

git reset --hard 版本号(commit id 进行回退)

注意这里commit id 可以不用写全 git会自动去寻找

追寻版本回退原理

其实你可以把HEAD想象成一个指针:

┌────┐
│HEAD│
└────┘
   │
   └──> ○ append GPL
        │
        ○ add distributed
        │
        ○ wrote a readme file

他仅仅是从上一个位置,移动到你指定的位置

┌────┐
│HEAD│
└────┘
   │
   │    ○ append GPL
   │    │
   └──> ○ add distributed
        │
        ○ wrote a readme file

然后顺便将你的文件更新了~
那么当你后悔了,但是你已经将窗口关闭了,这时候你已经找不到前面的commit id了你该怎么办:

也是有办法的;可以使用git reflog命令,这个命令记录了你所有的命令,这样你就可以找到对应的commit id了

工作区与暂存区

工作区

也就是你的使用 git init 的文件夹

版本库

你使用git init 后会在文件夹中产生一个.git的文件夹,这个就是版本库,其中最为重要的就是称之为“stage”的暂存区;git创建版本库后,会自动创建master分支,以及指向master的指针HEAD
git关系

暂存区

其实是版本库中的一个重要区域,如上图所示,文件会先git add到暂存区

文件提交的步骤

前面讲了我们把文件往Git版本库里添加的时候,是分两步执行的:

  • 第一步是用git add把文件添加进去,实际上就是把文件修改添加到暂存区;
  • 第二步是用git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支。
    因为我们创建Git版本库时,Git自动为我们创建了唯一一个master分支,所以,现在,git commit就是往master分支上提交更改。
    你可以简单理解为,需要提交的文件修改通通放到暂存区,然后,一次性提交暂存区的所有修改。

我们可以使用git status 来查看当前工作区中文件的状态

当我们将暂存区的文件进行commit 提交到分支上的时候,再使用git status 的时候 就会是空的;你会看到:
On branch master
nothing to commit, working tree clean

管理修改

这里就是一个需要理解的小概念:git管理的是修改,而非文件

当你这样执行修改一个文件后:第一次修改 -> git add -> 第二次修改 -> git commit
git只会将第一次修改去进行提交到版本库,git只会去跟踪你的修改,文件变化是没有监视的,也就是说没有提交到暂存区的文件,可能会与真实文件不一致,这大大提升了协同工作;

撤销修改

这里就是针对你犯错误的时候,请认真观看

我这边分为以下几种情况:

  1. 当你写错了东西,但是你没有git add也没有git commit 的情况下:

那么恭喜你了!你发现的很早,你现在只需要把错误修改了,神不知鬼不觉的提交就好了,
或者使用git checkout – 文件名 就可以回到和版本库中一样的文件了(这个文件,全部会覆盖嗷)

  1. 当你写错了东西,但是你使用git add已经提交到暂存区了,但是没有使用git commit提交到版本库中

git reset HEAD 以把暂存区的修改撤销掉(unstage),重新放回工作区:

  1. 当你写错了东西,上一次的暂存区里有你这个文件,你还没 git add 也没有 git commit

使用git checkout – 文件名 就可以回到和暂存库中一样的文件了(这个文件,全部会覆盖嗷)

  1. 当你写错了东西,但是你使用git add已经提交到暂存区了,也使用git commit提交到版本库中了

那么直接使用 git reset --hard HEAD^撤回到上一个commit就行了(这个文件,全部会覆盖嗷)

  1. 当你提交到远程了

你就真的惨了……

特别注意

git checkout – file命令中的–很重要,没有–,就变成了“切换到另一个分支”的命令,我们在后面的分支管理中会再次遇到git checkout命令。

删除文件

使用git rm 删除暂存区的文件

  • 如果你是真的想删除,请使用git rm 或者git add 后使用git commit删除版本库
  • 如果是误删,请使用git checkout – test.txt将文件夹恢复到与版本库一致

远程仓库

先有本地仓库,再创建远程仓库

创建远程仓库:不管你是什么平台(GitHub,GitLab,Gitee)
创建完成后你会获得一个连接:git@*******/.git**
这时候,你在你的版本库中执行

git remote add origin git@*******/**.git

这时候相当于连接上了远程仓库:这时候你的远程仓库的名字就是origin,这是git默认对于远程版本库的叫法
下一步就是将你的本地库推送到远程库上:

git push -u origin master
由于远程库是空的,我们第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。

这里贴上一个小问题;以便大家以后遇到排查

我也遇到了fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists.的问题
廖老师是通过 [email protected]:michaelliao/learngit.git 关联的,我在win7和win10上测试推送时都不能成功,https的才可以。如果已经用git@关联,则可以在.git目录下的config文件中,把 url = 后面的内容改为https类型的即可。 https类型的格式为: $ git remote add origin https://github.com/daoke0818/testGit2.git
另外我发现:
如果在第一步中创建时已经初始化过项目,则这时会提醒 error: failed to push some refs to ‘https://github.com/daoke0818/testGit2.git’ hint: Updates were rejected because the remote contains work that you do hint: not have locally. This is usually caused by another repository pushing hint: to the same ref. You may want to first integrate the remote changes hint: (e.g., ‘git pull …’) before pushing again. hint: See the ‘Note about fast-forwards’ in ‘git push --help’ for details.
因为远程库中已经存在readme文件了,所以需要先pull下来。命令如下: $ git pull origin master
这时又会报错: From https://github.com/daoke0818/testGit
branch master -> FETCH_HEAD fatal: refusing to merge unrelated histories 说这两个库有不相干的历史记录而无法合并,这时我们可以加上一个参数 --allow-unrelated-histories 即可成功pull: $ git pull origin master --allow-unrelated-histories
但是这时会可能会提示必须输入提交的信息,默认会打开vim编辑器,先按 i 切换到插入模式,写完后 Esc→:→wq 即可保存退出编辑器。如果不进入vim编辑器,则会自动生成一个合并代码的commit。然后再使用前面的命令push将本地提交推送到远程仓库。后面如果本地还有commit,就可以直接用 git push origin master 推送。

先有远程仓库,再创建本地仓库

使用git clone git@*******/**.git 可以直接从远程仓库克隆一个本地库

如果有多个人协作开发,那么每个人各自从远程克隆一份就可以了。
你也许还注意到,GitHub给出的地址不止一个,还可以用https://github.com/michaelliao/gitskills.git这样的地址。实际上,Git支持多种协议,默认的git://使用ssh,但也可以使用https等其他协议。
使用https除了速度慢以外,还有个最大的麻烦是每次推送都必须输入口令,但是在某些只开放http端口的公司内部就无法使用ssh协议而只能用https。

分支管理

创建与合并分支

先解释一下分支的概念
在版本回退里,你已经知道,每次提交,Git都把它们串成一条时间线,这条时间线就是一个分支。截止到目前,只有一条时间线,在Git里,这个分支叫主分支,即master分支。HEAD严格来说不是指向提交,而是指向master,master才是指向提交的,所以,HEAD指向的就是当前分支。

一开始的时候,master分支是一条线,Git用master指向最新的提交,再用HEAD指向master,就能确定当前分支,以及当前分支的提交点:

git-br-initial

每次提交,master分支都会向前移动一步,这样,随着你不断提交,master分支的线也越来越长。

当我们创建新的分支,例如dev时,Git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev上:

git-br-create

你看,Git创建一个分支很快,因为除了增加一个dev指针,改改HEAD的指向,工作区的文件都没有任何变化!

不过,从现在开始,对工作区的修改和提交就是针对dev分支了,比如新提交一次后,dev指针往前移动一步,而master指针不变:

git-br-dev-fd

假如我们在dev上的工作完成了,就可以把dev合并到master上。Git怎么合并呢?最简单的方法,就是直接把master指向dev的当前提交,就完成了合并:

git-br-ff-merge

所以Git合并分支也很快!就改改指针,工作区内容也不变!

合并完分支后,甚至可以删除dev分支。删除dev分支就是把dev指针给删掉,删掉后,我们就剩下了一条master分支:

git-br-rm

下面我使用git命令进行操作

  • 首先,我们创建dev分支,然后切换到dev分支:
    git checkout -b dev
  • git checkout命令加上-b参数表示创建并切换,相当于以下两条命令:
    git branch dev
    git checkout dev
  • 然后,用git branch命令查看当前分支:
    git branch
  • 修改文件并添加到暂存库
    git add 文件
  • 添加到版本库库
    git commit -m ‘提交文件’
  • 切换回到master
    git checkout master
  • 合并master和dev
    git merge dev
  • 完成合并master和dev后,删除dev分支
    git branch -d dev

注意这些点

对于所有分支而言, 工作区和暂存区是公共的。
分支修改后没有提交是无法切换到另一分支的
$ git checkout master
error: Your local changes to the following files would be overwritten by checkout:
README.md
Please commit your changes or stash them before you switch branches.
但是我看到有些人是可以违规切换到其他分支的,不太清楚这是怎么操作的

解决冲突分支

当你处理分支冲突的时候,合并后使用git会告诉你哪些文件冲突了,你可以打开这些冲突文件,你会看到git已经帮你预处理了一下
比如:

Git tracks changes of files.
<<<<<<<HEAD
Creating a new branch is quick & simple.
=======
Creating a new branch is quick AND simple.

>>>>>>>dev

这时候你就明白上面的是现在指向的分支内容,下面是你提交的分支内容
你只需要将这个文件处理一下
比如你想保留你在dev分支的内容:

Git tracks changes of files.
Creating a new branch is quick AND simple.

这时候你再提交,冲突已经被你解决了
以下为流程图:
在这里插入图片描述
在这里插入图片描述
如上图,你解决后的文件被提交到下一个commit节点上去了

分支管理策略

这里提到一个概念:
git会默认使用Fast forward模式,这种模式会丢掉分支信息

我的理解:在你合并后,查看分支历史git log,你只会看到你当前分支的信息

但是当你merge的时候添加–no-ff参数,就会保留你分支的信息
比如:git merge --no-ff -m “merge with no-ff” dev
这时候git log;你还可以在这个分支上,看到dev的分支历史

在实际开发中,我们应该按照几个基本原则进行分支管理:

  • 首先,master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;
  • 那在哪干活呢?干活都在dev分支上,也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本;
  • 你和你的小伙伴们每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了。
  • 所以,团队合作的分支看起来就像这样:
    git-br-policy

Bug分支

这一节点主要讲述的内容是,当你正在开发dev分支,但是突然需要你修改一个bug,但是你目前的改动还不能提交(commit),怎么办?
可以使用git stash将现在工作区的操作全部保存下来
这时候你修改完成bug后:回到dev分支,可以使用git stash list查看你的保存的状态
工作现场还在,Git把stash内容存在某个地方了,但是需要恢复一下,有两个办法:

  • 一是用git stash apply恢复,但是恢复后,stash内容并不删除,你需要用git stash drop来删除;
  • 另一种方式是用git stash pop,恢复的同时把stash内容也删了:

当你多次使用git stash想要恢复到指定的状态时
可以使用git stash apply { {stash id}}
也可以回到你开发时的状态

注意,当你在其他分支进行提交,但你又不想将整个分支都合并到你现在发分支:可以使用git cherry-pick 命令
真实场景:在主分支上修改bug,提交后,你的dev上分支肯定没有修改好这个bug,但你又不想将主分支上的代码全部都移交过来,这时候你就可以使用git cherry-pick 只将主分支的这次提交合并过来;注意,这里的commit id指的是你想要合并过来的操作的commit id

未来分支

这一节点主要讲:如果要丢弃一个没有被合并过的分支,可以通过git branch -D 强行删除。

多人协作

这里,本人使用idea系列产品和vscode并没有遇到特别多的困难
我阐述一下多人协作的模式:

因此,多人协作的工作模式通常是这样:

  1. 首先,可以试图用git push origin 推送自己的修改;

  2. 如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并;

  3. 如果合并有冲突,则解决冲突,并在本地提交;

  4. 没有冲突或者解决掉冲突后,再用git push origin 推送就能成功!

如果git pull提示no tracking information,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream-to origin/。

这就是多人协作的工作模式,一旦熟悉了,就非常简单。

标签管理

使用git tag 就可以打一个新标签:
可以用命令git tag查看所有标签:
用命令git show 可以看到说明文字:
命令git push origin 可以推送一个本地标签;
命令git push origin --tags可以推送全部未推送过的本地标签;
命令git tag -d 可以删除一个本地标签;
命令git push origin :refs/tags/可以删除一个远程标签。
命令git push origin --delete 也可以删除一个远程标签。
我对于标签的理解:其实就是针对特定节点的一个记录,类似于app的版本号,标签创建完成后,使用git show tagname就可以看到对应的commit id还有相关提交人信息,其实可以理解成时标签绑定到一个commit id之上

最后附上基本操作图

在这里插入图片描述

Guess you like

Origin blog.csdn.net/weixin_42842069/article/details/112394447