Git教程

252 阅读25分钟

      初衷:之所以写Git系列教程,是因为自己在学习Git的过程走过许多的弯路,我曾经为学习Git在网上也找过很多的资源,但这些资源的质量良莠不齐,对Git进行系统和全面讲解的并不多,而且缺乏学习趣味性,导致我们学习者记住的只是一些命令,并没有了解Git作用范围和作用时机,但是初学者又不是经常使用Git,所以学了一段时间就很快忘记了

      针对上述问题,本教程从Git的历史入手介绍,逐层深入,图片和视频相结合,让你对学习过程一点也不枯燥,而且会让你记忆深刻。

如果你想快速了解Git或者只是为了应付面试需要了解版本控制系统的知识,看完该系列的文章你肯定会受益无穷。


Git简介

Git是什么

  • Git是一个版本控制系统,是目前最先进的分布式版本控制系统,在企业中使用的很多。

  • 那什么又是版本控制系统呢?

    举个栗子:想必大家都完成过自己的毕业论文(那是一个痛苦的过程),我们需要对内容改之又改,每一次改动都很小心,总是不会删除之前的那一版(因为你还可能需要找回之前的版本),所以你总是会加一些修饰符:...修改版、...最终版、...最终版2、...最终最终版......乱七八糟。。。

    这就是大家熟悉的版本概念,我们在开发软件的时候其实也是这样,比如软件有v1.0 、v1.0.1、v1.0.2、v2.0版本等等,在一个最终的版本发布之前,可能需要漫长的时间来修改前一版本,还需要团队合作开发,所以如果采用手工管理版本的方式,恐怕就有点鞭长莫及了。


 所以我们进入了版本控制的时代,使用版本控制系统(Git)来保存我们之前的版本,
 可以记录每一次修改的地方,方便的回退到之前的版本,还可以将别人的改定合并。
 
 使用了版本控制软件后最终可能是下面这个样子的:
版本 文件名 Author Commit Date(提交时间)
2.0 毕业论文修改版 me 19 - 11- 30 19:34
3.0 毕业论文最终版 me 19 - 11- 30 19:34
4.0 毕业论文最终最终版 me 19 - 11-30 19:35
5.0 毕业论文极限版 me 19 - 11-30 19:35

不仅有详细的版本的信息,还可以看到作者、提交时间以及本次提交与上次版本不同之处等内容。


安装Git

Git只是一款软件,目前可以在windows、linux、以及macOS这些操作系统上安装使用。


在linux上安装

首先你可以看自己的电脑上有没有安装Git, 输入命令: git :

$ git 
Commond 'git' not found , but can be installed with:
sudo apt install git

提示我们没有安装Git,但是可以使用命令 sudo apt install git 进行安装

(注意:我使用的是Ubuntu,其他的linux发行版的提示可能不一样,但只是命令稍微有点区别,如果系统没有给出提示,百度一下就可以)

所以我们在我的Ubuntu下输入上述命令安装:

$ sudo apt install git

安装成功后查看版本:(版本是2.17.1)

$ git --version
git version 2.17.1

很简单的在linux下就安装完成了!


windows下安装

window的安装可以直接在官网上下载安装包:Git官网:git-scm.com/

直接点击箭头指向的地方就可下载适合你电脑的最新版本Git,如下所示:

然后在电脑上看到下面的Git组件就说明安装成功了,包括Git bashGit GUI等:

然后打开Git bash,输入 git --version (类似于linux下的bash)查看 Git 版本号:

$ git --version!
git version 2.30.0 windows.1

可以看到你下载的版本是适合windows下的 2.30.0

至此windows下安装结束!


全局配置(必须项)

安装完成后还需要进行全局配置(相当于注册QQ号、微信号的操作):

$ git config --global user.name "name"
$ git config --global user.email "email@example.com"

注意:name是你自己取得名字,email是你自己的邮箱。至此整个配置就完成了。



创建版本库

首先,什么是版本库?

版本库就是仓库(Repository),说白了就是存储你的各个版本文件的地方,是可以使用Git进行管理的文件目录。目录下的任何文件都可以使用Git追踪到,包括文件的修改,删除等等操作可以使用Git。

创建仓库很简单:

(首先需要说明的一点是,以后我们的操作都是在linux上进行,但是你在windows下的Git bash是完全一样,命令也是一模一样)。

首先创建一个目录(仓库),在windows下就是一个文件夹:

(选择自己认为合适地方创建即可)

$ mkdir firstRep
$ cd firstRep

如上命令,我们就创建了一个目录 firstRep ,(此时还只是一个单纯的目录)

初始化为Git仓库,使用命令命令:git init

$ git init
Initialized empty Git repository in ./home/codercxf/Desktop/firstRep/.git

看到提示:已经初始化好了一个Git 仓库,在我的电脑上是如下位置:./home/codercxf/Desktop/firstRep/.git

然后输入命令:ll 或者ls -all,查看目前仓库下的所有文件:

$ ls -all
. .. .git

可以看到命令 git init 生成了一个.git 的文件,表明此时你的目录(文件夹)已经是一个Git仓库了。

为版本库添加一个文件

首先此时我们初始化的仓库是空仓库,可以往仓库中添加一个文件了,例如我们添加一个 readme.txt 的文本文件(任意添加):

$ vim readme.txt
//添加以下两句:
git is version control tool
git is the most advanced version control system

然后将readme添加至仓库,使用命令: git add :

$ git add readme.txt

没有任何提示,说明添加成功;

然后将readme提交至仓库, 命令: git commit :

$ git commit -m "first commit"
[master (root-commit) 9c93bb2] first commi
 1 file changed, 2 insertions(+)
 create mode 100644 readme.txt

注意:先跟着操作即可,后面就知道 git addgit commit 的内部原理。

说明:

 git commit 是提交的命令,-m是参数, 
 后面跟着是本次的提交说明"first commit",方便别人查看。

 git commit 成功后会提示你:1 file changed(1个文件改动,readme.txt),
                           2 insertions(+) (readme.txt有2行内容)。

总结:今天一共学习了以下几个内容:

1、初始化一个仓库:git init

2、向仓库中添加文件:git add <fiile name>

3、向仓库中提交文件:git commit -m '本次提交的说明信息'


工作区和暂存区

想要很好的使用Git,要非常清楚地一点就是Git暂存区和工作区的概念:

工作区就是我们的工作目录,比如我们的 firstRep 就是一个文件夹而已。

在我们的目录下有一个.git文件,它不属于工作区,而是我们的版本库。版本库中最重要的就是index(暂存区),还有Git自动为我们创建的第一个分支master分支,以及指向master的HEAD指针。

在这里插入图片描述
其实有了上述的概念,我们就很容易的知道创建仓库时候的两个命令的含义:

第一步: git add 其实是将文件添加到暂存区;

第二步: firstRep 就是将暂存区的文件提交至当前分支(这里是 master 分支,其实我们完全可以自己创建分支,什么是分支以及如何创建见后续内容)。

简单的说就是先将文件添加到暂存区,然后将所有在暂存区的文件一次性的提交至所
在的分支上(分支的概念后面会详细讲解)。

实践练习

首先,我们对 readme.txt 文件进行小修改,添加一句话至 readme.txt 中:

$ cat readme.txt //cat:linux 的基本命令,查看文件内容
git is a version control tool
git is the most advaced version control system
i learn git now

然后我们再创建一个文件叫 study.txt 然后随便添加一行文字:比如:I Love You:

$ cat study.txt
I Love You

现在在工作区(也就是我们的目录下有两个文件 :一个修改过的 readme.txt,还有一个是新文件 study.txt):

然后将修改过的readme.txt 和新文件study.txt 都添加至暂存区, 使用命令:git add :

$ git add readme.txt
$ git add study.txt

我们使用命令:git status 查看仓库当前的状态:

$ git status 
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	modified:   readme.txt
	new file:   study.txt
	

提示我们已经将两个文件添加至暂存区,等待着 commit (提交)。

现在两个文件的状态应该是这样:

我们使用 git commit 一次性将两个文件提交至当前分支:

$ git commit -m "commit two files one time"
[master 16e071a] commit two files one time
 2 files changed, 2 insertions(+)
 create mode 100644 study.txt

然后我们再来看仓库当前状态:

$ git status
On branch master
nothing to commit, working tree clean

告诉我们现在是 master 分支,没有东西等待提交(也就是暂存区没有文件了)。

小结: 今天学习了两个概念:工作区和暂存区

git add :其实是将文件添加到暂存区;

git commit : 就是将暂存区的文件提交至当前分支(这里是master分支)。

git status :查看当前的状态




Git版本操作

版本回退

在前面我们已经修改了 readme.txt 文件如下内容:

git is a version control tool
git is the most advaced version control system
i learn git now

这里我们再添加一行:

git is a version control tool
git is the most advaced version control system
i learn git now
i think git is better than SVN

然后提交至仓库:

$ git add readme.txt
$ git commit -m "Git better than SVN"

好,到现在,你还记得 readme 总共修改几次,提交了几次吗?

你可能会记得,总共三次是吧。但是如果一个文件我们需要修改几十次,上百次你还会记得吗?更别说记得每次具体修改哪里了。所以这就是Git发挥威力的时刻了,一个命令就告诉你readme 提交记录,以及每次的变化,命令:git log:

$ git log
codercxf@codercxf-virtual-machine:~/Desktop/firstRep$ git log
commit a7616face803479e0573ff35bc18d00439cf28ff (HEAD -> master)
Author: CoderCXF <18251716983@163.com>
Date:   Sun Dec 1 20:24:50 2019 +0800

    git better than SVN

commit 1ffeaf83cef2f3976dc3bb6fd1f17e2af2a4a94c
Author: CoderCXF <xxxxxxxxxxx@xxx.com>
Date:   Sun Dec 1 20:16:55 2019 +0800

    commit rwo files one time

commit 61de2ca94483b341f308338bf27f6628dc8d5757
Author: CoderCXF <18251716983@163.com>
Date:   Sun Dec 1 20:15:11 2019 +0800

    first commit

所以,同志们,看到什么奇迹发生了没!!!

可以看到总共有三次提交 :最近的一次是"git better than SVN" ,还有之前的两次"commit two files one time"以及"first commit"

git 已经详细的记录每次历史提交,包括commit号AuthorDate等等信息。


git log 只是一个花絮,别忘了主题:如何回退到之前的版

看到上面git log 命令返回的嘛,其中以一个是commit 号(版本号),就是 a7616face.. 很长的一点数字,每一次提交的commit号都不一样,很容易理解,就是为了区分每一次提交,数字很长才不会造成重复。

可以这样说,只要知道了版本号就很容易回退到之前的任何一个版本,问题解决,所以到底该怎样做呢?

假如我们现在并不认为Git要比SVN好(虽然是事实^ ^),也就是要回退到没有 "git is better than SVN"的版本,即 "commit two files one time "的版本

我们可以使用 git reset回退,前一个版本是 HEAD^ ,前前一个版本是 HEAD^^, 以此类推,但是要是前10个版本,难道要写10个上标?当然不会那么愚蠢,例如回退10个就可以使用 HEAD~10

现在回退到前一个版本:

$ git reset --hard HEAD^

此时来查看 readme.txt 文件内容是不是已经回退成功:

$ cat readme.txt  
git is a version control tool
git is the most advaced version control system
i learn git now

可以看到,果然 "git is better than SVN" 没有了,回退成功。我们也可以继续回退到前前一个版本,直接继续 git reset 即可。

但如果这时候,你还是觉得Git 比 SVN 好用,后悔之前的删除操作,还想要恢复到之前的版本,该怎么办?说分手了还能再说我爱你?是的,在Git的世界里是可以的:

可是我们使用 git log 查看的时候,已经没有了刚才删除的版本记录,该怎么办?

commit 1ffeaf83cef2f3976dc3bb6fd1f17e2af2a4a94c
Author: CoderCXF <xxxxxxxxxxxx@xxx.com>
Date:   Sun Dec 1 20:16:55 2019 +0800

    commit rwo files one time
commit 61de2ca94483b341f308338bf27f6628dc8d5757
Author: CoderCXF <xxxxxxxxxxx@163.com>
Date:   Sun Dec 1 20:15:11 2019 +0800

    first commit

我们之前说只要知道commit号(一大串字符)就可以办到任何事,于是你就回去找刚才删除的那个版本号:找到了,就是a7616f...于是就可以回到刚才的版本:

git reset --hard a7616f

版本号不用写全,Git会自动识别,但是也不能写的太过简单,否则就会产生冲突。 然后查看 readme.txt 中的内容是否恢复到上一版本:

cat readme.txt
git is a version control tool
git is the most advaced version control system
i learn git now
i think git is better than SVN

看到已经恢复了上一版本。


小结:

记住:HEAD指向的是当前的版本

1)如果要回退到前一个版本使用 : git reset --hard HEAD^,返回前前一个版本使用的是:git reset --hard HEAD^^

(tips:之前的版本并未被删除!只是HEAD指针的指向变化)

2)使用git log 查看提交记录(包括版本号等信息);

3)总之使用 git reset --hard <commmit id> 就能回退到指定的版本。




撤销修改

前一篇博客介绍了版本回退,回退到已经提交的版本。

但是,这里的修改和上一篇的回退概念不一样,修改要分两种情况讨论:

1、只是在工作区(目录)进行了修改,还没有提交至暂存区(也就是要丢弃工作区的
	                                                              修改)。
	
2、在工作进行了修改,并且已经提交至暂存区。

下面我们分别讨论这两种情况如何撤销修改:

针对第一种情况

比如我们在readme.txt后加了一行I dont like Git:

$ cat readme.txt
git is a version control tool
git is the most advaced version control system
i learn git now
i think git is better than SVN
i dont like git

这个时候你突然觉得不对,即使不喜欢也不能说出来啊,于是立刻想纠正它。

于是用 git status查看一下当前状态:

$ git status
On branch 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.txt

no changes added to commit (use "git add" and/or "git commit -a")

发现我们只是在工作区更改了 readme.txt 文件,还没有 add 或者 commit,Git提示我们可以使用git checkout --<file>-- 命令放弃在工作区进行的修改:于是乎,有了下面的一行代码:

$ git checkout -- readme.txt        //注意:--与文件名之间有空格

此时再来查看readme.txt 内容:

cat readme.txt
git is a version control tool
git is the most advaced version control system
i learn git now
i think git is better than SVN
解惑:此时可能就会有小伙伴们问:为什么要使用git checkout 命令,
我直接打开readme.txt 手动删掉最后一行不就行了嘛,当然可以。

但是,我们这里只是对一个文件增加了一行,相当于修改了某一处的某一个功能,如果你
在写代码的时候一次性修改(或者添加很多行),你自己都不记得自己改了哪里,怎样
手动恢复呢?而且你手动删除之后还必须要 add 以及 commit 之后版本库中的版本才是
最新版本。

所以使用 git checkout 就解决了你很大的问题


针对第二种情况

Please 记住:Git总是有办法的 !

假如现在已经是晚上九点了,而你还在公司摸鱼,996也该下班了不是,此时心里极其不爽,于是你在readme.txt 文档下写下:cccccccccccccc:还不小心添加到了暂存区:

$ cat readme.txt
gait is a version control tool
git is the most advaced version control system
i learn git now
i think git is better than SVN
cccccccccc

$ git add readme.txt

突然灵光乍现,你意识到这个问题,顿时心里一万个草泥马飘过,但是你应该庆幸的是还没有commit ,于是你使用git status 查看一下当前的状态:

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

Git 告诉我们等待着提交(changed to be committed),但是也同时提示你使用命令 git reset HEAD <file>... 可以撤销掉缓存区的修改。于是乎,又是一顿操作:

$ git reset HEAD readme.txt	
Unstaged changes after reset:
M	readme.txt

这时候再来查看一下状态:

$ git status
On branch 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.txt

no changes added to commit (use "git add" and/or "git commit -a")

这个时候提示我们没有文件等待着提交( Changes not staged for commit:) , 只是在工作区进行了修改,于是这就回到了第一种情况,还记得上面是什么命令吗?对,git checkout -- <file>(丢弃工作区的修改)

于是赶紧操作起来:

$ git checkout -- readme.txt

然后查看当前的状态:

$ git status
On branch master
nothing to commit, working tree clean

现在,终于结束了!这就是为自己的行为付出的代价,所以工作和生活上还是要谨言慎行!

小结:

本节课主要讲解了如何撤销修改的操作,分为两种情况:

1、只是在工作区(目录)进行了修改,还没有提交至暂存区(丢弃工作区的修改)git checkout -- <file>

2、在工作进行了修改,并且已经提交至暂存区,分为两步撤销:1)把在暂存区的内容回退到工作区git reset HEAD <file >;2)丢弃工作区的修改:git checkout -- <file>




删除文件

1、删除版本库中的某个文件 例如,我们在仓库中新建一个文件 :testRemove.txt,写一句话Test how to delete file from Git repository,并提交至版本库,随后将其删除:

$ cat testRemove.txt
Test how to delete file from Git repository

$ git add testRemove.txt
$ git commit -m "Test delete"

首先在工作区删除文件: rm <fileName>, 然后Git会提示你工作区的目录和版本库的不一样,并且提醒你使用 git rm <fileName> 从版本库中彻底删除:于是乎,有了如下操作:

$ rm testRemove.txt

$ git status
on branch master
Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

	deleted:    testRemove.txt

no changes added to commit (use "git add" and/or "git commit -a")

现在版本库提示你可以进行很多操作,就是有两种选择 1)确实是要从版本库删除,使用 git rm <fileName> ,就彻底删除了文件。2)放弃删除操作

$ git rm testRemove.txt
rm 'testRemove.txt'

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	deleted:    testRemove.txt
	
$ git commit -m "remove testRemove"
[master 19ff64a] remove testRemove
 1 file changed, 1 deletion(-)
 delete mode 100644 testRemove.tx

可以看到已经彻底的删除了testRemove.txt 文件。

2)放弃删除。你可能只是脑子抽筋,错删了此文件,悔恨的拍大腿,但是,请记住Git总是有办法解决的。

因为你只是删除了工作区的文件,版本库中还依然存在,所以不用害怕。使用命令git checkout -- <file>即可:

$ git checkout -- testRemove.txt //注意:--与文件名之间的空格

$ ll             
total 20
drwxr-xr-x 3 codercxf codercxf 4096 123 15:59 ./
drwxr-xr-x 3 codercxf codercxf 4096 121 20:13 ../
drwxr-xr-x 8 codercxf codercxf 4096 123 15:59 .git/
-rw-r--r-- 1 codercxf codercxf  124 123 15:06 readme.txt
-rw-r--r-- 1 codercxf codercxf   44 123 15:59 testRemove.txt

看到testRemove.txt又回来了。

注意:这里的删除文件指的是删除版本库中的某一文件,在工作区(文件夹下的)直接删除即可(是无法恢复的)。

总结: 1、从版本库中删除文件:

第一步:在工作区删除文件 rm <file>

第二步:确定删除版本库中的文件: git rm <file> ,然后重新提交:git commit -m "确认删除文件描述"

2、如果已经在工作区删除,但是想恢复,此时版本库中该文件存在的,使用命令 git checkout -- <file> 即可以恢复原文件。





远程仓库

到现在为止,我们已经完全懂得Git仓库的概念(本地计算机上的一个文件夹)以及如何对仓库进行添加、提交、修改、撤销修改等等操作,可以很好的实现版本控制。

但是,我们之前操作的仓库都是在本地机进行操作,我们通常叫这种仓库叫: 本地仓库 ,但是Git是分布式的版本控制系统,不只是你自己进行操作,整个软件项目的运行肯定是团队成员共同完成。所以团队中的每一个人的各自的计算机上都会有该项目的一个拷贝,这也就是分布式的概念。

其实,情况是这样的,找一台电脑当做你公司的Git服务器,24小时开机,然后上班的时候大家都从这台服务器上克隆一份项目仓库到自己的电脑上,然后干完活之后大家再把自己的工作成果推送到(push)这台服务器上,也可以拉取其他人的提交。

好了,远程仓库的概念就由此产生了,我们把服务器上的这个仓库就叫做: 远程仓库 。所以知道想要大家一起工作,并且能合并大家的项目就需要一台计Git服务器。现在我们是学习阶段,搭建一个服务器未免有点“杀鸡蔫用牛刀”的感觉,但是记得 github 这个神奇的网站存在,我们完全可以把它当做自己的Git服务器。

所以下面就需要学习如何使用github这个网站,并且把这个网站当做自己的Git服务器。请移步至下一篇!

github

百度释义:gitHub是一个面向开源及私有软件项目的托管平台,因为只支持git 作为
	 唯一的版本库格式进行托管,故名gitHub。

我们一直用gitHub作为免费的远程仓库,如果是个人的开源项目,放到gitHub上是完全没有问题的。其实gitHub还是一个开源协作社区,通过gitHub,既可以让别人参与你的开源项目,你也可以参与别人的开源项目。

github具体的使用方法不再详细叙述,看两篇文章就能熟练的使用github。这里我们只要学习设置SSH。


首先,设置SSH的原因:

SSH是传输协议(类似于FTP协议,但是SSH是加密传输)由于Git是支持SSH协议的,所以你往远程仓库提交或者从远程仓库下载就是通过该协议,所以,需要进行设置:

注意:Git也支持 https 协议,但是下载上传速度慢,所以还是建议大家设置SSH。以后就用SSH传输。

第一步,创建SSH。

在用户主目录下查看是否已经有.ssh目录,如果有,再查看是否有id_rsaid_rsa.public,例如在windos 下就是如下两个文件:

windows下的设置请看我的另一篇专门介绍如何设置的文章:

blog.csdn.net/weixin_4211…

下面详细介绍在了Linux下的如何操作:

$ sudo ps -e|grep ssh
[sudo] password for codercxf: 
  1884 ?        00:00:00 ssh-agent

上面就说明我们已经启动了SSH,

于是我们跳到下一步。

如果没有这个创建SSH key,则创建:

$ ssh-keygen -t rsa -C "youremail@example.com"

注意:上面括号“youremail@example.com”应该填写你自己注册github使用的邮箱。

第二步,登录github,进入到Settings界面,点击SSH and GPG keys

点击 New SSH key ,新建一个 SSH key , 这里 title 任意填写,在Key文本框里粘贴id_rsa.pub文件的内容,点击Add key 完成配置。

至此整个SSH的设置就完成了,很简单有没有!

有了github后我们就可以进行远程仓库的部分了。


附上github的标识符和吉祥物:

标识符:

吉祥物:




在github上创建远程仓库

设置好github的SSH key ,我们就可以在github上创建一个远程仓库,并且可以让这两个仓库同步(能从远程仓下载到本地仓以及将本地仓库推送至远程仓库)。

首先,创建一个远程仓库,远程仓库的名字最好与本地仓库一致,所以这里远程仓库的名字叫 firstRep,点击 New 创建:如下图所示:

我们填写仓库名,对仓库的描述即可,其他默认,点击 Creat repository,就创建成功了。如下所示:

现在这个仓库是空仓库,因为我们还没添加任何的文件。

现在我们要做的就是把这个远程仓库和我们的本地仓关联起来:

$ git remote add origin git@github.com:xxxxxxx/firstRep.git

注意:上面“git@gitgun.com: ***/”填写你自己的仓库地址。

是下面这个地址:

下面我们就可以把本地库的内容推送到远程库了,使用命令 git push :

$ git push -u origin master
Counting objects: 13, done.
Compressing objects: 100% (9/9), doneGit
Writing objects: 100% (13/13), 1.17 KiB | 299.00 KiB/s, done.
Total 13 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), done.
To github.com:xxxxxx/firstRep.git
 * [new branch]      master -> master
Branch 'master' set up to track remote branch 'master' from 'origin'.

这说明已经推送成功。此时再来查看(记得刷新一下页面)firstRep这个远程仓库:

在这里插入图片描述
就会有我们之前在本地仓库的 readme.txt 文件了。

在第一次推送的时候是使用命令 git push -u origin master , 因为此时远程仓库还是空的,所以需要加上-u参数,下一次提交就可以不加-u这个参数了。比如我们更改了 readme.txt 文件,再推送到远程库的时候就可以使用命令:git push origin master

解惑:origin: 是 Git 默认的远程库的名字,
      master是远程库的分支,也就是我们要推送到的分支,后面学到分支的时候你可以
      创建其他的分支,也就是你可以推送到其他的分支上,这个后面再说。

由于自己的开源项目很菜,暂时拿不出手,所以就把自己的github账号信息隐藏了,也没有了视频演示,多谢理解!


小结:

1、远程仓库和本地仓库关联:

git remote add origin git@github.com:xxxxxxx/firstRep.git

2、本地仓推送到远程仓:git push origin <branch name> ,其中 origin 是Git

默认的远程仓的名字,origin后面的 branch name 是远程仓库的分支,第一次提

交到空仓库加上-u 参数。




分支

之前我们提到过分支的概念,但是没有详细介绍,只知道 Git 会默认的给我们创建一个
master分支(我们一般将其称为主分支)。

下面我们将讲解如何创建分支以及如何删除修改分支等等操作,那么现在我们要先对分支
有个概念。

我们在本地仓中有 master 分支,所以通过命令 git push origin master推送到远程仓时候,即推送到远程仓中的 master 分支,可以在 github 上看到远程仓中只有 master 这一个分支。

这就是分支的概念。

但是在实际的开发中,通常是不会在 master 分支上进行工作的。

比如你将要开发一个新的功能,需要对项目文件进行修改,如果你在主分支上修改,为了自己代码的安全考虑,把自己还没有写完的代码推送到远程 master 分支上,但是代码还没有全部完成,不完整的代码导致别人没办法工作。

所以一般的情况是你在自己新创建的分支上进行修改,等到代码全部完成之后,再将自己分支上的代码合并到主分支上,然后推送,这样,既能保证自己的代码安全,又不耽误别人工作。

这也是Git的精髓所在。

分支操作见下面内容。




创建与删除分支

创建分支:git branch <name>,例如我们创建一个dev新分支::

$ git branch dev

没有任何提示,表明已经创建成功。

可以使用命令 git brach 查看当前仓库的所有分支:

$ git branch
  dev
* master

可以看到现在整个仓库有两个分支:devmaster, Git会使用 * 标记当前分支,所以现在是在主分支 master 分支上。

那么如何切换到dev 分支呢? 使用命令:git checkout <name> :

$ git checkout dev
Switched to branch 'dev'

此时Git告诉我们,已经成功切换到 dev 分支,再来查看一下当前所有分支:

$ git brach 
* dev
  master

可以看到,当前确实是在dev 分支(*标记)。

其实也可以一步实现创建新分支并切换到该分支,例如我们创建 feature 分支并切换到该分支:使用命令:git checkout -b <name>:

$ git checkout -b dev
Switched to a new branch 'dev'

其实就是相当于上面的两条命令的合并:git branch devgit checkout dev

如果这个时候你已经不需要除了主分支之外的其他分支,即需要删除分支,使用命令:git branch -d <name>即可, 比如我们要删除 dev 分支, 然后再查看删除后仓库的分支:

$ git branch -d dev
Deleted branch dev (was d6932d6).

$ git branch
* master

由上面的几行英文就可以知道 dev分支被删除,现在仓库只剩下了 master 分支。

现在假如你开始在新的分支上工作,正如我们之前所说,工作完成后怎样合并到主分支上呢? 现在给出解答:

比如现在在 dev 分支上修改了readme.txt文件,在末尾加上一句话:creat new branch and merge to master:

$ git checkout dev
Switched to branch 'dev'
...//为readme.txt添加一行

$ cat readme.txt
git is a version control tool
git is the most advaced version control system
i learn git now
i think git is better than SVN
creat new branch and merge to master

然后提交:

$ git add readme.txt
$ git commit -m 'test merge'
[dev d08d313] test merge
 1 file changed, 1 insertion(+)

这个时候我们切换到 master 分支查看 readme.txt 文件内容:

$ git checkout master
M	readme.txt
Switched to branch 'master'
Your branch is up to date with 'origin/master'.

$ cat readme.txt
git is a version control tool
git is the most advaced version control system
i learn git now
i think git is better than SVN

发现这个时候 master 添加的一行内容并不存在,这是因为你刚才是在dev分支,而此刻的 master 并没有改变。

现在我们将dev分支上的修改合并到master 分支,在master 分支上使用命令: git merge dev

$ git merge dev
Updating d6932d6..d08d313
Fast-forward
 readme.txt | 1 +
 1 file changed, 1 insertion(+)

可以看到,Git告诉我们已经更新,使用的合并方式是 Fast-forward,然后再来看 master 分支下的 readme.txt的内容:

$ cat readme.txt
git is a version control tool
git is the most advaced version control system
i learn git now
i think git is better than SVN
creat new branch and merge to master

合并后,再查看readme.txt的内容,就可以看到,和 dev 分支的最新提交是完全一样的。


git switch:

注意到:我们切换分支的时候是使用 : git checkout 命令,但是我们在撤销修改的时候也是用的这个命令,所以Git为了区分,新引出了一个 git switch 命令英语切换分支,效果和 git checkout是一样的:

切换分支:

$ git switch dev
Switched to branch 'dev'

创建并切换到该分支:

$ git switch -c feaature
git Switched to a new branch 'feature'
注意:新版本的才有git switch 命令,我的旧版本不存在这个命令,
	 所以我是在windows上较新的版本操作的,其实没有关系,只要
	 知道有 git switch 这回事就行,不能用就用 git checkout ,效果完全一样。

小结:

今天一共就学习了以下几个内容:

1)创建分支:git branch <name> ;

2)切换分支:git checkout <name> 或者是git switch <name>(旧版本没有);

3)创建并切换到该分支: git checkout -b <name> 或者是 git switch -c <name>(旧版本没有);

4)删除分支:git branch -d <name>;

5)合并分支:git merge <name>;




推送和抓取分支

推送分支

我们在本地仓库上有 master 分支,但是如何将本地分支推送到远程分支呢,使用命令git push 即可:

例如,现在我们的本地仓库中有两个分支:masterdev, 现在将两个分支推送到远程仓库(github)上:git push origin <local branch name>

$ git push origin master
$ git push origin dev
注意:`origin` 是默认的远程仓库名字,后面的分支名字是本地仓库中分支的名字,
       这样,Git就会把本地分支推送到远程仓库对应的分支上(远程仓库没有,则
       Git会默认创建一个)

此外,并不是所有的分支都需要推送到远程仓,分支是否需要推送到远程仓,视自己的情况需要而定。


抓取分支:

你可以往远程仓推送自己的分支,同时也可以从克隆远程仓到本地(相当于下载),现在,我们在另外一台电脑上克隆仓库 firstRep ,使用命令git clone <repository name>:,现在我在windows上使用Git bash模仿你的一位同事:

$ git clone git@github.com:xxxxx/firstRep.git
Cloning into 'firstRep'...
remote: Enumerating objects: 16, done.
remote: Counting objects: 100% (16/16), done.
remote: Compressing objects: 100% (8/8), done.
remote: Total 16 (delta 3), reused 16 (delta 3), pack-reused 0
Receiving objects: 100% (16/16), done.
Resolving deltas: 100% (3/3), done.

然后我们进入到仓库,然后再来查看克隆到本地的分支情况,使用命令git branch:

$ cd firstRep

$ git branch
* master

ok,发现远程仓中的 dev分支并不存在,其实在默认情况下,你的小伙伴使用git clone命令只能看到本地的 master 分支。

现在你的小伙伴想要在 dev 分支上开发,就必须创建远程 origindev 分支到本地,使用下面的命令即可创建远程分支到本地:

$ git checkout -b dev origin/dev
Switched to a new branch 'dev'
Branch 'dev' set up to track remote branch 'dev' from 'origin'.

看到Git此时告诉我们,我们可以使用这个本地分支 dev 分支来追踪远程库中的 dev 分支。

现在他就可以在这个dev分支上工作,并且推送到远程的 dev 分支。

例如:我们新创建一个 a.txt 文件添加并提交至仓库中:

$ cat a.txt
test dev

$ git add readme.txt
$ git commit -m 'commit a.txt'
$ git commit -m 'commit a.txt'
[dev ca21716] commit a.txt
 1 file changed, 1 insertion(+)
 create mode 100644 a.txt

然后可以推送到远程库中的 dev 分支。

$ git push origin dev
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 12 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 276 bytes | 276.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To github.com:xxxxxx/firstRep.git
   a688f95..ca21716  dev -> dev

现在我们在远程仓中的 dev 分支看到的最新的提交是你的小伙伴提交内容。一切都是那么优雅,如丝般顺滑,但是到你这就可能会出错了,继续往下看。

碰巧你也新建了一个文件名一样的文件 a.txt ,添加了一些内容,然后想要推送至远程仓的 dev 分支:

$ cat a.txt
$ git add a.txt
$ git commit -m 'commit this txt'
[master 0ac9d23] commit this txt
 1 file changed, 1 insertion(+)
 create mode 100644 a.txt

然后试图推送到远程仓:

$ git push origin dev
To github.com:xxx/firstRep.git
 ! [rejected]        dev -> dev (fetch first)
error: failed to push some refs to 'git@github.com:xxx/firstRep.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.

可以看到推送失败了,仔细的读一下Git告诉我们失败的原因:通常是因为另外一个仓库推送了同样的文件至该分支上。

并且Git提示我们可以使用 git pull 抓取分支然后再推送:所以我们试着使用它提示的方法来抓取分支:

$ git pull origin dev
From github.com:xxxx/firstRep
 * branch            dev        -> FETCH_HEAD
Auto-merging a.txt
CONFLICT (add/add): Merge conflict in a.txt
Automatic merge failed; fix conflicts and then commit the result.

可以看到出现冲突,于是我们可以解决冲突: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)

You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add <file>..." to mark resolution)

	both added:      a.txt

no changes added to commit (use "git add" and/or "git commit -a")

可以看到存在冲突:查看 a.txt 文件的内容:

$ cat a.txt
<<<<<<< HEAD
test pull
=======
test dev
>>>>>>> ca217161af9b857fdede6699404ad322a0bb17b2

可以看到Git使用不同的符号:<<<<<<<=======>>>>>>>,来标记出当前版本的a.txt 和 你的某个小伙伴提交的版本的 a.txt 的不同内容。

我们必须手动解决冲突:

//手动更改为:test pull and dev
$ cat a.txt
test pull and dev

然后再提交修改然后推送:

$ git push
Counting objects: 2, done.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (2/2), 337 bytes | 168.00 KiB/s, done.
Total 2 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), done.
To github.com:CoderCXF/firstRep.git
   c869bd5..fc6a2fd  dev -> dev

推送成功。在github 上也可以看到文件 a.txt 合并后的内容。

$ cat a.txt
test pull and dev

ok, 至此所有的问题都已经成功解决。


小结:

1、推送分支至远程仓:git push origin <branch name>,如果推送失败的话,先使用git pull 抓取分支,然后合并内容;

2、本地新建的分支如果不推送到远程,对其他人就是不可见的;

3、如果需要自己关联到别人创建的另一个分支,使用命令: git checkout -b <branch name> origin/<branch name>,最好自己本地创建的分支和远程分支名称一样;

4、建立远程分支和本地分支的关联:使用命令: git branch --set-upstream branch-name origin/branch-name




标签(tag)

我们很早就介绍过 commit id(提交号)的概念,那是一串很长的数字,我们提交的每一个版本都会有一个commit id,很难找,所以,我们在发布每一个版本的时候经常都会打上一个标签(tag),比如v1.0版本、v1.0.1版本等等。

有了tag就不再需要 commit id了,tag就是commit id 的一个别名,一个tag和一个commit id绑定。

所以怎样打标签呢?

请看下一篇文章:创建标签。




创建标签

首先,我们切换到需要打标签的分支上:

$ git branch
* master
  ver

$ git checkout ver
Switched to branch 'ver'

现在我们已经切换到分支ver上了。 使用命令 git tag <tagname>打上一个标签:

$ git tag v1.0

使用 git tag 查看所有的标签:

$ git tag
v1.0

这个时候就已经创建好了一个标签。

但是可能有人说,不对啊,之前你说 tag 就是 commit id 的一个别名,一个 tag 和一个 commit id 绑定,但是现在好像是凭空就打上一个标签,这不是骗人吗?这个标签打到哪个commit号上了呢?

不用着急,我们来查看一下历史版本记录:

$ git log 
commit d6932d659f2b26c260760c85ecdcc576dedceb4c (HEAD -> ver, 
tag: v1.0, origin/master, master)
Author: CoderCXF <18251716983@163.com>
Date:   Tue Dec 3 19:03:22 2019 +0800

    the file has been deleted

commit 1d79486fe56604ce595433ad35aafc16cace4e97
Author: CoderCXF <18251716983@163.com>
Date:   Tue Dec 3 18:58:03 2019 +0800

    Test delete

commit f67aa75996c776f6ac41328a0f553513fe75df1e
Author: CoderCXF <18251716983@163.com>
Date:   Mon Dec 2 21:09:54 2019 +0800

    git is better than SVN

commit 1ffeaf83cef2f3976dc3bb6fd1f17e2af2a4a94c
Author: CoderCXF <18251716983@163.com>
Date:   Sun Dec 1 20:16:55 2019 +0800

    commit rwo files one time

commit 61de2ca94483b341f308338bf27f6628dc8d5757
Author: CoderCXF <18251716983@163.com>

可以看到在最近的一次提交上出现了一个 tag:v1.0 ,说明我们把标签打在了这次提交上面,即Git默认是打在最近的一次提交。

所以,如果我想在其他的commit后打上一个标签怎么搞呢,很简单,只要知道commit id 即可。

例如,我想在 Test delete 版本上打上一个标签,此版本的版本号是 1d79486...,于是有下面的命令:

$ git tag v0.0 1d79486

再用命令查看一下所有标签:

$ git tag
v0.0
v1.0

此时标签已经打上了,查看一下标签的具体信息,使用 git show <tagname>:

$ git show v0.0
Author: CoderCXF <xxxxxxxxxxx@xxx.com>
Date:   Tue Dec 3 18:58:03 2019 +0800

    Test delete

可以看到标签确实是打在了Test delete这一版本之上。

还可以创建带有说明的标签,用-a指定标签名,-m指定说明文字:

$ git tag -a v0.0.1 -m "0.0.1 version" f67aa

这样就为 git is better than SVN 打上了标签,不信可以查看一下:

$ git show v0.01
Author: CoderCXF <18251716983@163.com>
Date:   Mon Dec 2 21:09:54 2019 +0800

    git is better than SVN

看到果真如此。以上就是创建一个标签的过程。


小结:

1)创建标签:git tag <tagname>

2)为指定的版本创建标签:git tag <tagname> <commit id>

3)创建带有说明的标签:

git tag -a <tagname> -m "tag描述信息" <commit id>

4)查看仓库中所有的标签:git tag

5)查看某一标签的信息: git show <tagname>




标签管理

上一篇文章介绍了什么是标签以及如何创建标签,现在我们来看怎样具体的操作标签才能使得标签发挥其作用。


比如删除标签的操作:git tag -d <tagname>

现在我们删除标签 v0.0.1:

$ git tag -d v0.0.1
Deleted tag 'v0.0.1' (was 413cd70)

Git告诉我们 v0.0.1 已经删除了。

其实可能有的小伙伴们会看出来,我们创建的标签只是在本地仓,而对远程仓库毫无影响,所以其实我们是需要把标签推送到远程仓库的:使用命令:git push

比如现在我们把标签 v1.0 推送到远程仓:

$ git push origin v1.0
Warning: Permanently added the RSA host key for IP address 'xxxx.xxxx.xxxx.xxxx' to the list of known hosts.
Total 0 (delta 0), reused 0 (delta 0)
To github.com:CoderCXF/firstRep.git
 * [new tag]         v1.0 -> v1.0

这个时候你登录github就可以看到 1 release :

如果你再推送一个标签至远程仓,就会看到 2 releases:

$ git push origin v0.0
Warning: Permanently added the RSA host key for IP address 'xxxx.xxxx.xxxx.xxxx' to the list of known hosts.
Total 0 (delta 0), reused 0 (delta 0)
To github.com:CoderCXF/firstRep.git
 * [new tag]         v0.0 -> v0.0

如果你已经把标签推送到远程仓库,还想删除,就得分两步进行了:

第一步:先从本地删除:git tag -d <tagname>:

$ git tag -d v0.0
Deleted tag 'v0.0' (was 1d79486)

然后从远程删除:git push origin :refs/tags/<tagname>:

$ git push origin :refs/tags/v0.0
To github.com:xxxxxx/firstRep.git
 - [deleted]         v0.0

这个时候完全删除干净了,登录github查看是否只剩下了 v1.0 这个标签:

看到确实v0.0标签被删除了。删除完成。




参考:

【1】Git 官网:安装Git

【2】廖雪峰Git教程

【3】简书:Git创建和删除分支

【4】如何利用Git中的tag管理项目版本号

【5】Git标签管理-添加、查看、删除Git标签

【6】Git 标签管理