Git学习

关于Git

一种流行的分布式版本管理系统,其网页版为Github。只不过git要通过命令来实现,github则是可视化的并直接在远程仓库操作。github同时还是一个最大的全(同)球(性)远(交)程(友)仓(网)库(站)。

虽然生着一副程序员的面孔,但git的用途已远非为程序员管理代码了。事实上,它为我们一些其他文件(比如实习报告)的备份也提供了一个很好的解决方案。其具体流程大致如下图(很抱歉我也不知道为什么,我用"mermaid"写的流程图在这里识别不出来,然后我也不知道怎么删除文章中的代码块,大家烦请请移步到后面的图片吧)。

flowchart LR

D[远程仓库]

subgraph Local[本地]
A[工作区]-->|add|B[暂存区]-->|commit|C[本地仓库]-->|checkout|A
end
C-->|push|D
D--->|fetch|C
D==pull==>Local

要知道,很多编辑器都自带Git代码管理,而且都是可视化的(简单多了),比如VS Code、IntelliJ Idea,几乎不需要学习Git命令行,如果大家对命令行没有兴趣,可以直接去学这些可视化操作,等到一些需要用命令行配置的操作时再来。有一说一,不是程序员的我如果知道有这些东西也不会去学git命令(猛男落泪),虽然git命令窗的功能确实更加全面细致。

小白指路,辗转难决,多有不当,诚惶诚恐。如果像我一样第一次用这种管理系统,建议大家从创建本地仓库开始,先学习本地仓库的暂存提交从本地仓库同步,再学习远程仓库(github)的创建绑定推送拉取,然后再学习冲突解决、标签操作等比较而言细枝末节的东西。自然,下文有关github的配置还是不能跳过。

本文操作都以命令的形式在"Git Bash"上实现,事先需要下载"git"。

事实上,git下下来之后不仅有"Git Bash",还有"Git Gui",二者功能相同,但前者是命令行操作(有逼格),而后者是可视化操作(没有逼格)。

真实情况是,我还没学怎么用Git Gui操作。(超小声)

下载后,在项目文件目录下(或者桌面,随便哪里都行)右键"git bash"弹出黑窗口。为了使用github仓库,事先需要在窗口输入以下命令:

$ git config --global user.name "your_username"
$ git config --global user.email your_email@domain.com

两行命令中"$"是自带的命令开始的标志,不需要键入,这两行分别输入并回车之后,就把用户名与邮箱配置好了。

命令中"config"是配置的意思,"--global"表示全局。

想查看自己的所有配置,需要在git里面输入以下命令:

$ git config --list

回车之后,会出现一大串配置。在我的版本中,最后两行就是刚才配置的用户名与邮箱。

如果经常用github这个仓库,最好创建一个自己的github账户,码云同理;如果要使用SSH传输(gitee和github都能用),还需要生成"ssh key",使用以下代码:

$ ssh-keygen -t rsa -C "your_email@domain.com"

剩下它会有一些提示,默认回车即可。然后根据他的提示把这个".ssh"文件夹找到,打开里面的".pub"文件,全选复制这个密钥,到自己的github账户上的设置选项卡里选择"SST and SPS keys",如下图。点击添加"SST key",自拟名称,并将复制的密钥粘贴上去,就可以生成了。 检测是否连接成功用如下命令:

$ ssh -T git@github.com

此时不能一路回车,在"Are you sure..."这个第一个问句后面需要敲入"yes"确认之后再回车。

如果不想要SSH传输,以上操作不是必须的。

创建本地仓库

仓库就是管理本地版本的一个数据库。一套完整的本地仓库操作,包括“同步”、“修改”、“暂存”、“提交”四个步骤,这四个步骤本质上是文件在“仓库(repository)”、“工作区(working directory)”、“暂存区(staging area)”之间的处理与转移。 在一个新建的空文件夹里面右键选择"git bash",键入如下命令:

$ git init

回车之后会有初始化成功的提示,亦即在本目录下成功创建了一个仓库,是一个隐藏的文件夹。

查看

查看本地状态

在本命令框中输入以下命令:

$ git status

由此可以查看本地Git的“工作区”、“暂存区”的文件状态。如果发现没有预期的暂存与提交,git甚至会有技巧提示。

查看本地仓库

$ git ls-files

用来列举本地仓库里面当前分支下的所有文件。

"ls"意为"local storage"本地仓库

查看版本日志

在本命令框中输入以下命令:

$ git log

这是查看仓库里的版本日志,由此可以查看本地仓库的版本状态。

有时候日志信息过于庞杂,导致整个屏幕放不下,则会在左下角有一个冒号":",莫要惊慌,为了看到完整的信息,只需要不断键入回车即可。

为了解决上面日志信息过于庞杂的问题,日志查看命令行后面可以接--pretty=oneline使得所有日志信息只保留提交版本的日志ID与提交说明,并逐行显示。

在命令行后面加入--graph --pretty=oneline可以加入图形的形式显示分支操作。

查看操作日志

$ git reflog

这里将把所有的历史操作列举出来,并提供历史操作的日志ID,因此比版本日志更详细,常用来做版本回退与撤回回退的参考。

查看分支

分支可以理解为不同的版本,相当于把项目多拷贝几份,分别修改。

$ git branch

展示本地仓库里的分支,结果中带星号的为当前分支。

如果还想查看远程的分支,后面需要添加-a,顾名思义,"a"意为"all"。

查看标签

标签是啥?其实就是个装饰,对我这种初学者来说,多少有些可有可无,详见

$ git tag

用来查看本地的所有标签。

获取远程状态

$ git fetch

有时候远程仓库进行了更新但我们在本地查看分支并没有更新(git不会实时跟踪远程仓库,没有更新时,我们查看的远程分支总是之前从本地提交上去并创建所获得的,不会随便联网),我们为了得到最新的远程状态,需要命他获取。

比较文件

$ git diff HEAD -- file_name

使用本语句比较工作区的指定文件与仓库中的该文件。HEAD指针指向的是MASTER版本分支。

所显示的结果里面,"-"代表改动之前的文件,"+"代表改动之后的文件。 两个@@之间的内容代表下面比较展示的内容,在于原文件与改动之后文件的具体行数。
例如:@@ -1,2 +1,3 @@表示的是展示内容为原文件第一行之后的两行与改动后文件第一行之后的三行。
如果没有反馈结果,则说明两个文件通过比较没有发现区别。

检查文件

$ git checkout

将工作区的所有文件与仓库中当前分支的所有文件进行对比,说明是否被修改。

对比结果中,"M"代表被修改,"D"代表被删除,未显示的文件则没有发生改动。

查看文件内容

$ cat file_name

用于查看仓库内当前分支下"file_name"文件的内容。

本地流程

一套完整的本地流程有如下步骤:

  • 文件可以直接从仓库拉取至工作区,进行修改;

  • 修改之后的文件需要被添加到暂存区;

  • 将暂存区的文件提交到本地仓库里面(主干与分支)。

  • 建立分支,进行分支(主干)间的切换与合并

初次使用时,第一步可以理所当然的跳过。

随便在本目录下新建一个文件(就是一般的新建方式,别想多了),并向里面输入内容并保存。大家可以随时查看文件状态,此时,该文件的状态为“未被追踪(Untracked)”的文件,因为暂存盘里面并没有这个同名文件;如果暂存盘里面有,则状态应为“被修改(modified)”。

然后,开始我们下面的git命令。

暂存

$ git add new_filename

将被修改的"new_filename"从工作区添加到暂存区。其中,"new_filename"若是.则代表当前目录下的所有文件;若是绝对路径则代表绝对路径下的所有文件。

友情提醒:注意这个"new_filename"不要忘记加文件后缀名了。

提交

$ git commit -m '提交说明'

将暂存区的所有文件提交到本地仓库。

"-m"可以理解为"message"。单引号里面是本次提交的说明。需要注意的是,单引号是必须的,里面的内容也是必须要有的,否则会报错(事实上,每次都写提交说明是个好习惯,git是要强制你形成这个好习惯)。

至此,已实现一次完整的提交,但是,一套完整的流程还需要从仓库拉取,即同步一次工作区与仓库数据。

同步

从仓库拉取相应文件至工作区的命令:

$ git checkout file_name

切换分支(主干)的命令:

$ git checkout branch_name

个人猜测,此处的"checkout"意指检查工作区与仓库中的当前分支是否相同;然后根据"checkout"之后的规定内容(文件或者分支),实现工作区与规定内容的同步。因此将这几个命令归为一点。

暂存并提交

上面两步有时候会被嫌弃过于繁琐,其实也可以用一行命令将文件暂存并提交。

$ git commit -am '提交说明'

其中-am的"a"即为"add"的缩写。

这个命令即是将工作区的所有文件暂存并提交,但前提是所有文件都应该已经被追踪到,即不能有新建的文件。

取消暂存

暂存文件时,有时候会手残,把不该暂存的文件添加到了暂存区,此时取消暂存应输入如下代码:

$ git restore --staged file_name

值得注意的是,--之后"staged"不应该有空格,这里file_name可以是多个,把不同文件都取消暂存。
事实上,在我的这个版本里面,输入了查询工作区与暂存区的命令$ git status,人家会给你撤销暂存单的命令提示。

撤销

上面的取消暂存也可以通过撤销操作来实现。

$ git reset HEAD file_name

这是取消对于"file_name"文件的上一次操作。

回滚

想要回到仓库之前的版本,需要回滚,实质仍是撤销命令。

$ git reset --hard HEAD^

此时工作区的文件版本变成了上一次提交的版本。

  • ""表示回退一次,"HEAD"后面接多少个""就回退多少个版本。

  • "HEAD"后面也可以接"~num",这个num是用户需要输入的数字,想回退多少个版本,波浪号后面就写多少。

  • 也可以把"HEAD"换成日志ID,就是查询日志时候每个版本显示的那一大串字符,不需要全部复制,输入前几位不会重复的字母即可。值得注意的是,由于git本来是unix系统,它的拷贝方式不再是"ctrl+c"与"ctrl+v",而是"ctrl+insert"与"shift+insert"。
    这种方式也可以被用来撤销版本回退,其日志ID可以通过查询日志来检索。

文件删除

自然,删除文件本质上也是一种修改,可以暂存并提交来实现仓库里面文件的删除,因此,这种方法不再赘述。
另一种是一步实现功能,命令如下。

$ git rm file_name

此操作将本地仓库连同工作区的文件"file_name"一起删除。

新建分支

新建一个分支并切换至该分支上,默认情况下,新建的分支里面的内容即为本地主干的内容:

$ git checkout -b branch_name

从远程仓库拉取分支至本地,本质也是新建本地分支,只不过是有依据地新建分支:

$ git checkout -b branch_name origin/branch_name

"origin/branch_name"就是需要同步的远程的分支。

顾名思义,"-b"即指分支"branch","checkout"亦为同步之意。

合并分支

合并分支并非分支间随意合并,指的只是分支与主干的合并。在主干未干涉分支修改内容的情况下(即主干在分支修改提交的部分仍保持分支继承时的样子),默认是分支对主干的覆盖。需要注意的是:合并分支一定要在当前已经切换为主干的情况下进行

$ git merge branch_name

分支合并至主干后,分支本身并不会被删除,如果想删除需要手动命令删除。

合并冲突

当主干与分支在同一个地方内容产生冲突(这种情况在拉取远程仓库创建本地分支时极为常见,因为远程仓库的版本很可能与本地仓库的版本不同,合并时不可避免与本地的master冲突),合并分支时,会有冲突提示。

并且此时,工作区的状态既非主干,亦非分支,而是合并中二者的复合物。此复合版本中,在文件里内容冲突发生的地方,git将插入提示,为用户提供仲裁依据。

此时在冲突发生的地方作最终修改,再次提交之后即为最终合并的版本(master),是为冲突解决。

删除分支

$ git branch -d branch_name

对于"branch_name"分支进行删除。但是当分支没有合并就要删除,git就不愿意干,要把-d换成-D来强制删除分支。

顾名思义,"-d"即指"delete"。

重命名分支

$ git branch -m old_name new_name

表示将原来的分支"old_branch"重命名为"new_branch"。

"-m"即表示重命名;如果需要强制重命名则要用"-M"

远程仓库

作为分布式版本管理系统,git自然也需要实现不同计算机之间的合作。

这种合作,由远程仓库来统一,使得不同的本地仓库与远程仓库之间能进行文件交流。

目前最为知名的国际开源远程仓库是github,国内则有码云

以下以github为例,说明如何利用git与github交互,需要先在github注册。有一说一,个人感觉github过于热情,隔几天就发一个邮件教你怎么用github,大家根据邮件学一学可视化的github亦可。

关于远程仓库的git用法,敲入 git remote -h 人家会给你提示的。

远程仓库多在多人协作中被使用,具体步骤有下:

  • 从远程仓库上下载代码(远程仓库有项目而本地没有,即完成本地仓库的穿件)或者新建仓库并绑定(本地仓库有项目而远程仓库没有,即完成远程仓库的创建)或者直接拉取(远程与本地仓库都有相应项目)

  • 修改并推至本地仓库

  • 再次拉取远程仓库的内容,进行协同冲突的解决,避免下一步推送被拒

  • 本地仓库推送至远程仓库

下载代码

$ git clone hrl

此命令将在当前目录下从github下载项目。

这个"hrl"是GitHub中需要下载的项目的仓库地址,就是那个code下载按钮点下去出现的下拉框第一栏显示的地址,选择"HTTPS"的地址,如果用SSH传输就选择"SSH"的地址,将其复制即可。
事实上,这样用命令下载,我感觉还不如直接在code下载按钮下拉框点"download ZIP"来的简单,和用"HTTPS"地址一样,不需要登录。但SSH据说是更高效、更安全的一种下载方式,也是官方推荐的。

下载代码后,这个下载的文件夹下面自动创建了一个本地仓库,其SSH(HTTPS)链接即与其远程仓库关联,因此不需要再进行绑定。

新建远程仓库

如果是创建远程仓库直接在github网站上创建就好了,这个跟着github的邮件走就行,当然也可以直接在这个网站上摸索,人家其实还是挺人性化的。

绑定

github上面新建了仓库后,要将本地仓库与远程仓库绑定,会有一页命令提示你怎么绑定,也就是以下命令:

$ git remote add origin hrl

同样,这个hrl既可以是"HTTPS"的,也可以是"SSH"的。

解绑

解绑命令与绑定很像:

$ git remote rm origin

会意即知,"rm"意为"remove"。

推送

把本地仓库的东西送到自己已连接的远程仓库(主干或分支)中:

$ git push -u origin master

这是建立了远程的主干,并推向主干。如果已经有了,那么后面的-u origin master也就不需要了。直接git push即可。

在远程推送时有可能出现被拒绝的情况,我的就显示"the tip of your current branch is behind",后来输入git push -u origin +master解决了这个问题,之后照常git push

推送本地分支到远程分支,则需要在push后面加上origin branch_name,分支名即为远程的分支名。

拉取

所谓拉取,就是让本地仓库的所有信息与远程仓库同步,并同步工作区。基本上可以理解为获取远程状态同步的合二为一,简单而粗暴:

$ git pull

协同冲突

在多人协作的情况下,有时候会出现不同人依次提交相同部位的代码,这种情况下,后面提交的人将无法提交而被拒绝。

此时需要根据提示再拉取远程仓库的文件,与本地工作区的文件产生冲突而生成合并中的复合版本,相应修改后再提交远程仓库,只要拉取至提交这段时间内,相同部位代码再未被其他人修改并提交,就能提交上最终版本。这种解决方式参考本地的合并冲突

由此可见,冲突的发生并非坏事,这是git为了保护我们的劳动成果,不让前人的代码被后人覆盖而给后来者的一种提醒。

删除远程分支

$ git push origin :branch_name

这里的"branch_name"指的是远程分支的分支名。可以看出,删除远程分支的实质仍然是发起一次推送,只不过推送的内容被":"标记了。

值得注意的是:删除远程分支与推送远程分支只有一个":"的区别,因此要小心使用推送命令。

标签操作

标签是啥?简而言之,就是给版本日志贴一个版本名字(比如v1.0之类的),毕竟有品位的人会觉得版本ID着实难看(dodge)。

打标签

$ git tag tag_name xxxx

标签是针对日志打的,因此,标签名字之后跟的"xxxx"是日志ID。如果什么都没有跟,则默认是当前最近的操作ID。

如果要为标签附加信息,则需要这么打:

$ git tag -a tag_name -m '附加信息' xxxx

同样,"-a"就是起名字,"-m"意指"message","xxxx"就是版本日志ID,不写默认为当前最近版本。

推标签

本地打的标签要推到远程去:

$ git push origin tag_name

就是把"tag_name"标签推到远程仓库去,届时github的项目边上的"release"一栏会有相应的版本名字(标签名字)。

要把所有的标签都推上去,把"tag_name"换成"--tags"即可。

删标签

删除远程标签:

$ git push origin :refs/tags/tag_name

删除远程分支命令异曲同工。

删除本地标签:

$ git tag -d tag_name

删除本地分支命令异曲同工。

通用操作

这些操作在命令框的程序里面几乎都是通用的,大家可以参考cmd。

清屏

和绝大多数命令窗一样,在用户认为窗口的历史命令过多受到影响时,可以使用如下代码清空屏幕:

$ clear

路径跳转

相似的,每个Bash窗口都是在指定的目录下工作的,要使其到其他目录工作,需要先跳转至目标目录下:

$ cd xx/xxx/xx/

路径既可以是相对路径,也可以是绝对路径如D:/profile/profile

退出

$ exit

表示退出程序。


本文章使用limfx的vscode插件快速发布