Monthly Archives: July 2020

Git学习笔记

Git是一个版本控制系统(VCS,全称为Version control System),而源码控制管理(SCM,Source Control Manager)也是VCS的另外一种称呼。

GIt主要的功能在于记录和管理开发人员对软件代码所做的更改,GIT一共有三个区域,分别为工作区,缓存区,仓库,下面有分别对该三个区的解释。

💎术语

📌Commit:用于提交快照,就像游戏保存进度点一样,而该快照将会供你所用,可以随时回顾该快照的中的所有文件内容。

📌Repository/repo:仓库用于来保存快照的地方,同时也可以用于向其他人展示你的代码,或者仅给自己用来回顾历史版本

📌Working Directory:工作目录是指当前操作的目录,比如我在/var下操作一个1.txt文件,那么/var就是工作目录,而你提交Git的那个目录,就是当前工作区。

📌Staging Area / Staging Index / Index:缓存区(暂存区)是用于保存即将提交到仓库的文件,而没有进行commit提交的数据。既使用了add但是没有使用commit命令的那一次版本都处于缓存区中。

add  HEAD  stage  commit  master

📌Checkout:Checkout操作会将上一个版本覆盖当前工作区,即撤销更改,比如”git checkout test.txt”会将上一个版本的test文件覆盖到当前工作区。 checkout有两种方式,如果当前缓存区有数据,就拉去缓存区数据恢复,如果没有即从仓库进行拉去恢复。

📌SHA:SHA全称为”安全散列算法”,其由40个字符组成的字符串,其中包含了(0-9和a-f),GIT每次提交的ID就是由SHA生成的字符串为ID,大致为’e2adf8ae3e2e4ed40add75cc44cf9d0a869afeb6’这样的字符串。

📌Branch:分支即是从主线分出一个新分支,也可以说是从主线发散,这样的开发方式可以在不改变主线的情况下继续,比如一个游戏,一边是你预计的路线,一边是冒险的路线,这个时候你可能决定冒险,然后你先保存点,然后创建一条冒险的分支,进行冒险,这样,当你冒险完了,你还可以回到正常路线中。

💎配置

初次使用Git,需要对Git进行配置才能进行使用,一般配置是设置用户名,邮件,并可以配置一些其他的选项。

除此之外,还可以为Git配置默认的编辑器,比如下面代码展示了设置三种编辑器的配置方式:

Atom编辑器设置
git config –global core.editor “atom –wait”
Sublime Text 设置
git config –global core.editor “‘/Applications/Sublime Text 2.app/Contents/SharedSupport/bin/subl’ -n -w”
VSCode设置
git config –global core.editor “code –wait”

💎命令

🔵 git init:该命令可以在本地创建一个新的仓库

🔵 git clone:该命令可以将一个仓库克隆和复制到本地计算机

🔵 git status:该命令可以来查看仓库的状态

🔵 git log:该命令可以显示有关现有提交的信息

🔵 git log –oneline:可以将历史提交信息输出在一行

🔵 git log –stat:可以显示历史提交中更改的文件,以及添加或删除的行数(stat是统计的缩写)

🔵 git log –patch/-p:该命令可以显示其某个文件被修改的详细内容是什么

🔵 git log -w:该命令将忽略空白处的变化

🔵 git show:该命令可以显示有关给定提交的信息

🔵 git add:该命令可以将文件从工作区提交到缓存区

🔵 git commit:该命令让缓存区的文件提交到仓库,如果是简单的注释信息只需要加上-m参数,然后输出简单的信息就可以绕开编辑器进行提交。

🔵 git diff:该命令可以显示两个文件版本之间的差异,该命令实际上与git log -p命令输出的几乎一致

因为大多数的项目提交是非常多的,所以在提交消息标题的部分需要各位的简单简明,以便于别人在查看提交版本的时候使用–oneline命令的方便性,提交的一些建议:

Do

  • do keep the message short (less than 60-ish characters)
  • do explain what the commit does (not how or why!)

Do not

  • do not explain why the changes are made (more on this below)

  • do not explain how the changes are made (that’s what git log -p is for!)

  • do not use the word “and”

    • if you have to use “and”, your commit message is probably doing too many changes – break the changes into separate commits
    • e.g. “make the background color pink and increase the size of the sidebar”

The best way that I’ve found to come up with a commit message is to finish this phrase, “This commit will…”. However, you finish that phrase, use that as your commit message.

Above all, be consistent in how you write your commit messages!

💎Git Ignore

如果在一个项目当中,希望有部分文件不被提交,那么就可以使用特别命令的文件”.gitignore”,将此文件添加到git当前工作目录中,这个文件的意义就是列出希望Git不跟踪的文件及文件夹名称。

💎标记

🔵 git tag:该命令可以为特定提交添加标签,标签可以特定额外信息,标注一些特定的标签,比如标记这是beta版本、版本号等用途

git tag 将会对当前版本进行打标签,该语法如下:

对当前版本提交标签
git tag -a v1.0
对特定版本进行提交标签
git tag -a v1.0 SHAID
绕过默认编辑器
git tag -a v1.0 -m ‘xxxx’

如果需要删除错误的标签可以使用下面的语法,默认情况下tag标签的字符串是唯一的,所以需要删除哪个版本的标签,直接输入标签的内容就可以删除了:

git tag -d v1.0
或者
git tag –delete v1.0

默认情况下git log 不会显示标签信息,如果要显示标签信息需要用下面的语法:

git log –decorate

💎分支

默认情况下,git提供的主分支默认名为master,而每当我们提交一个版本到仓库的时候,master标签将会自动移动到最近的版本上面,分支可以在不同的隔离环境当中对同一个项目进行操作,并且不影响其他分支。分支最主要的目的是允许进行一些修改而不影响其主分支。

🔵 git branch:该命令可以从主线分出一个分支,用于并行开发项目的不同功能,如果没有参数将列出当前仓库的所有分支

🔵 git checkout:该命令可以让你在不同的分支和标签之间进行切换工作区

在GIT中,由HEAD指针来指定当前活跃的分支,即当前所操作的分支,比如下面的图片中HEAD指针指向的是MASTER主分支。

tri MINGW64  S git log  -one line  N/Desktop/tt/newproject  .gitignore file  (maste r)  c99f15e  7299982  6e2df1f  07b3560  (HEAD -> master) Add  chang  er text  Add header to  Initial commit ” /></p>
<p>如果要切换活跃分支,将会使用checkout命令,比如下面的命令是切换到sidebar分支,并且当前本地工作区的文件将会被替换为切换分区的文件,在切换分支之前请记住提交更改的内容,因为checkout命令将用最近分支版本的文件覆盖当前工作区的文件,所以一定记得保存,不然会造成数据的丢失。</p>
<pre><code class=git checkout sidebar

除此之外,checkout命令还可以从指定版本上的位置创建分支,比如下面代码,创建了一个test分支,并从id为42a69f的版本上进行创建。

 git checkout test 42a69f  

删除分支可以通过branch命令的-d 命令,但是需要注意的是,无法删除当前所在工作区的分支,以及无法删除主分支,但是需要注意的是,可以删除一个空分支,但是无法删除一个有提交的分支,如果确认要删除有提交的分支,需要使用大写的-D标志才能删除掉,下面的代码删除了一个空分支sidebar和一个有提交的分支test

空分支删除
git branch -d sidebar
有提交分支删除
git branch -D test

除此之外,还可以使用checkout快速添加分支,比如下面的代码,如果存在head分支则切换至head分支,如果没有则立马创建head分支。

  git checkout -b head  

如果要显示所有分支的信息,那么可以使用all参数,该参数将显示仓库中的所有分支,为了让打印出来的东西更加清晰,可以添加–graph参数,让打印出来的左侧添加指示的线条。

查看所有分支以及详细情况
git log –oneline –decorate –graph –all

💎合并

将分支组合在一起称为合并,Git可以自动将不同分支上的更改合并在一起,这种分支和合并能力使Git 非常强大,可以对分支

进行小的或广泛的更改,然后只需使用Git将这些更改组合在一起。

分支一般分为两种类型,一种为合并,一种为快速合并,合并的时候其HEAD指针指向哪个分区,就会将其需要合并的分支合并到HEAD指向的分区上,比如下图HEAD指针指向的是MASTER分支,这个时候将SIDEBAR合并到当前工作区(即HEAD指向的工作区),这个时候就产生了一个新的版本ID为8,这也是属于正常的合并操作。

而快速合并指的是当需要合并到一起的分支比另一个分支更靠前的时候,这个时候GIT会做一个所谓的快速合并,即将需要合并到一起的分支的指针移动到靠前的分支上面,这个时候GIT则将指针移动到了更靠前的分支位置,比如下图中的SOCIAL-LINK比MASTER分支更靠前,而如果这个时候需要将SOCIAL-LINK分支合并到MASTER,而这个时候GIT则会移动指针到SOCIAL-LIN分支上,来表示新的合并,如下图的图2.

🔵 git merge:该命令可以将不同分支的更改自动合并到一起

🔵 合并发生时,Git会:

  • 🌱看看它要合并的分支
  • 🌱回顾分支的历史记录,找到两个分支在其提交历史记录中都有的单个提交
  • 🌱将在不同分支上更改的代码行组合在一起
  • 🌱提交记录合并

💡合并冲突

大多数的情况下合并并没有什么问题,但是有些情况下是无法自动完全合并的,合并失败被称为合并冲突,如果确实发生了冲突,那么GIT会尽可能的尝试多种组合,并且会留下特殊的标记(比如<<<和>>>),标明需要手动修复的位置。比如当在单独的分支中更改完全相同的行时,会发生合并冲突。

比如这样的例子,Git跟踪文件中的。当在单独的分支中更改完全相同的行时,将发生合并冲突。例如,如果您在alternate-sidebar-style分支上并将侧边栏的标题更改为“关于我”,然后将其更改为另一个分支,并将侧边栏的标题更改为“关于我的信息”,Git会选择哪个标题?你已经改变了两个分支上的标题,所以Git无法知道你真正想要保留哪一个。肯定不会随便随便挑选你!

在正在合并的不同分支上更改相同的一行或多行时,会发生合并冲突。Git会在合并中暂停,告诉您存在冲突,并会告诉您冲突发生在哪个或哪些文件中,要解决文件中的冲突:

  • 找到并删除包含合并冲突指标的所有行
  • 确定要保留什么
  • 保存文件
  • 暂存文件
  • 提交

💎撤销

撤销主要功能可以撤销在于由于一些误操作导致的提交、合并等导致的问题。

🔵git commit –amend:该命令可以更改最近提交的文件,而不会再次多一个提交记录,比如某个提交忘了包含某个文件或者是打错了一个字,就需要调用该命令,该命令可以让你避免再提交一个版本来修改这些很小的错误。

该命令只能修改最近的提交的版本,其大致的步骤为:

  • 🌱编辑文件
  • 🌱保存文件
  • 🌱暂存文件
  • 🌱并运行 git commit –amend

在最后一步执行后,将会覆盖最后的提交版本,如果你没有进行任何的修改,那么默认将打开编辑器修改提交的消息。

比如下面的代码,首先是对文件没有任何修改的提交,该提交只会覆盖版本修改的标题

git commit –amend 打开默认编辑器修改提交注释
git commit –amend -m ‘test’ 将覆盖默认的版本提交注释

下面的代码将修改已提交的最近版本的内容,下面的代码提交前又对index文件进行了一次小改动。

Git commit -m ‘change head text’ 第一次提交版本
Vim index.html 发现有问题,修改了index
Git add . 再次添加到缓存区
Git commit –amend -m ‘change head text’ 再次提交版本,将并修改到最近提交的版本中,而不是单独再提交一次

🔵git revert:git revert是用于“撤销”某一个文件吗,并回到之前的版本,也可以称之为回滚,可以回滚到某个特定的版本上去,并且使用revert回滚,将重新提交一个版本。

比如:先后做了3次提交 commitA、commitB、commitC,分别改了A文件、B文件、C文件,如果在git中查看,当前是commitC:

commitC
commitB
commitA
想要撤销B文件的更改
git revert commitB
想要撤销C文件的更改
git revert commitC

🔵git reset:该命令可以将HEAD指针指向的活跃分区恢复上一个版本或者上上个版本的状态,该命令是为数不多的删除命令之一,该命令会删除当前工作区以及仓库的内容,所以请谨慎。但是即使删除git还是有一个专门的回收站来保存之前的所有记录,保存记录的时间大概为30天,该回收站可以通过git reflog查看。

📌Git reset 可以使用做“Ancestry References”的特殊字符,用来表示比如上个版本或者上上个版本这样的字符,这些字符是:

^ 表示父提交
~ 表示第一个父提交

通过上面的符号,我们可以用来灵活运用,比如像以下都表示为回滚父提交(即上一个提交):

git reset HEAD^
git reset HEAD~
git reset HEAD~1

下面的代码可以回滚祖父提交(即上上个提交):

git reset HEAD^^
git reset HEAD~2

下面的代码可以回滚曾祖父提交(即上上上个提交):

git reset HEAD^^^
git reset HEAD~3

除此之外,由于合并分支会造成父提交可能有两个祖父提交,比如说下图:

该图中HEAD指针所指向的位置的为93c05ca,父级为db7387a,而796ddb0的父级则有两个,第一个为父级为所在的分支为4c9749e,第二个父级则为合并的分支0c5975a,如果要选择796ddb0的第二个父级,那么从当前HEAD表示该为”HEAD^^^2″。下面的代码展示了针对上图做出的一些代码解释:

HEAD^ 是db7e87a提交
HEAD~1 是db7e87a提交
HEAD^^ 是796ddb0提交
HEAD~2 是796ddb0提交
HEAD^^^ 是0c5975a提交
HEAD~3 是0c5975a提交
HEAD^^^2 是4c9749e提交(这是祖父母的(HEAD^^)第二个父(^2))

除此之外,git reset的擦除方式有三种,分别为:

  1. –mixed

  2. –soft

  3. –hard

这三种方式可以通过下面的视频来大致了解一下其工作原理:

git有四个区,分别为仓库、工作目录、缓存区、回收站,当使用git reset命令恢复到上一个版本的时候,其当前版本的文件有可能会存在工作目录、缓存区、回收站的之中的任何一个区,而具体存在哪个区域则是根据git reset的运行方式。

🌱–mixed参数是reset命令默认的参数,当reset至上一个版本的时候,当前版本所提交的更改将保存至工作目录中,就如下图一样

🌱–soft参数当reset至上一个版本的时候,当前版本所提交的更改将保存至缓存区,就如下图一样

🌱–hard参数当reset至上一个版本的时候,当前版本所提交的更改都将移动到回收站,就如下图一样

💡需要注意的是,git reset会清楚当前分支的修改,如果你需要重置的时候,你可以在当前提交上创建一个可用的备份分支,以达到一个备份的作用,比如像下面这样,在重置前创建一个为backup的分支

git  branch backup 

当然如果你需要恢复备份的话,就可以通过上面创建的分支进行合并,如果你工作区有更改,需要使用checkout –命令,该命令会将工作区文件恢复到最近一次的版本,保持文件属于仓库同步内容,然后确保了没有其他意外的情况下就可以合并分支。比如下面的代码,让Index文件删除更改,然后再合并分支进行恢复。

git checkout — index.html
git merge backup

💎Github

github是git的托管服务网站,任何人都可以注册账户将代码上传至github,相当于云端一样,但github更多的作用是远程协作,比如网上有很多开源的项目,如果你想贡献代码,那么用邮件来发送是一个噩梦,所以你可以通过github来创建你自己的分支,又不会影响主项目。而托管在github上面的仓库叫远程仓库。

管理远程仓库git有专门的命令进行管理,分别为:

🔵Git remote:该命令用于管理远程仓库

将分支发送到远程有两种方法:

  1. 将所有分支合并为一个主分支然后提交
  2. 将所有分支共同发送到远程仓库提交
  3. 单独通过git push 远程仓库名称 本地分支名称

Git remote 命令默认情况下是没有返回内容,除非你配置了远程仓库或者clone了仓库,就会有显示,默认情况下显示的为origin,即原点,这里的原地一词被称为“短名称”。短名称只是一种简单易行的方式来引用远程存储库的位置,短名称是当前

储库的本地名称(如本地存储库),如下图:

tri MINGW64  S git remote  origin  N/Desktop/tt/1ighthouse (master)

如果要查看完整的远程仓库git路径则可以使用参数-v,比如”git remote -v”,结果如下图:

N/Desktop/tt/1ighthouse (master)  -NMA2D9K MINGW64  S git remote  lori gin https ://gi thub . com/Goog1ech rome/l i ghthouse (fetch)  ori gin https ://gi thub . com/Goog1ech rome/l i ghthouse (push)

而添加远程仓库则是使用下面的命令,add后面是远程仓库的本地名称

除此之外还可以重置远程仓库的名称,rename

🔵Git push:该命令将修改推送到远程仓库

使用push命令可以将本地分支提交到远程仓库,比如下面的代码将使用远程仓库的短名称提交master分支

git  push origin master  

跟踪分支指的是远程仓库有一个分支同样指向当前的提交,比如下图中的标识符origin/master就是跟踪标识,该标记是origin/master并且被称为跟踪分支。跟踪分支的名称包括远程存储库的短名称以及分支的名称。因此跟踪分支origin/master告诉我们远程origin有一个master指向提交的分支9b7d28f(并包括之前的所有提交9b7d28f)。这非常有用,因为这意味着我们可以在本地跟踪远程存储库的信息!

🔵Git fetch:该命令通过远程仓库进行获取更新

如果你不想自动将本地分支与跟踪分支进行合并,那么可以使用fetch命令,该命令将会把拉取的更新作为单独的分支origin/master存在,而本地的master也作为单独的分支存在,这样就不会存在相互的影响,如果现在想将远程仓库的更新合并,就使用git merge origin/master。比如下图所示:

⚠️如果本地仓库在未知情的情况下提交了新的版本,但是仓库也提交新的版本,这个时候就可能会存在下面这样的情况,如果存在下面这样的情况 git pull是不会生效的:

处理上面的情况只能依靠于fetch命令,使用过后大概是下图所示:

而在使用过后再使用merge合并就能恢复到正常情况上。

然后处理完合并后记得第一时间提交到远程仓库进行同步

💎fork

在版本控制中fork指的是分裂,即分裂出一个和这个仓库一模一样的副本,fork不是git的功能,而是其他git托管商所提供的功能,比如github等。使用fork,可以让你对一个开源的项目有着完全的控制权限,你可以随意的修改其fork项目。

💎git shortlog

Git shortlog命令可以让我们查看该仓库有哪些贡献者,贡献了多少条以及每一天的注释标题是什么,比如下图:

除此之外,还可以使用-s仅显示提交数量以及-n以数字的方式对他们的名字排序(而不是使用名称排序)

除了上面的参数,还可以使用作者过滤,比如这个代码”git log –author=Surma”过滤只要作者为Surma的提交情况,输出结果如下:

⚠️除此之外,还可以使用grep参数来过滤其内容,比如这个代码”git log –grep=bug”过滤了bug的提交消息。

💎pull request

一个pull request是对一个请求原或源代码库的维护者,以包括在他们的项目,你在你自己的项目叉所做的更改。您要求他们提取您所做的更改。

当我们没有权限修改目标仓库的时候,最好的做法就是fork,然后进行修复bug,修复完成后,可以通过pull request提交给原作者,看原作者是否接受该修复,如果原作者接受,就当提交至原作者的仓库中。

💎git rebase

Git rebase(压缩)命令可以将几个提交合并为一个提交,即将多个commit合并为一个commit,比如最近的几个commit都是一些小的更改,例如拼写错误等问题,这个时候这几个commit就显得有一些臃肿了。

比如下面的代码可以将最近的三个改动合并为一个新改动并提交,下图中的HEAD~3表示之前三个提交:

执行过后将会从上图中的sha为8的提交开始一直到b合并为一个,并保留提交8,然后删除8之后的提交,并生成新版本: