面经每日一总结 (九,git)


highlight: agate
theme: qklhk-chocolate

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第5天,点击查看活动详情

分布式和集中式版本控制工具的区别

集中式

svn, cvs

将代码集中到一台服务器管理控制。多人开发只需要连接到这台服务器,取出最新的文件或者提交更新。

但是如果这个服务器出现问题,就不能进行下载和更新了。

分布式

git

客户端并不只提取最新版本的文件快照, 而是把代码仓库完整的镜像下 来,包括完整的历史记录

如果任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜像出来的本地仓库恢复。

每一个用户的克隆都是对代码仓库的完整备份。 即每台克隆的电脑都有一个仓库存储着该项目所有的内容。

如何初始化一个仓库

  • git init
  • git clone

git管理下的两种状态

  • 未跟踪:默认情况下,Git仓库下的文件也没有添加到Git仓库管理中,我们需要通过add命令来操作。
  • 已跟踪:添加到Git仓库管理的文件处于已跟踪状态,Git可以对其进行各种跟踪管理。

已跟踪的文件又可以进行细分状态划分:

  • staged:暂缓区中的文件状态。执行git add 后的状态。
  • Unmodified:commit命令,可以将staged中文件提交到Git仓库。
  • Modified:修改了某个文件后,会处于Modified状态。

这三种状态是一个闭环。文件修改后执行git add,状态将从Modified变为staged

image.png

注意git commit -a -m ""命令只能提交那些已经跟踪过一次的文件,新创建的文件不能被提交成功。

git校验和

Git 中所有的数据在存储前都计算校验和,然后以 校验和 来引用。

  • Git 用以计算校验和的机制叫做 SHA-1 散列(hash,哈希)。
  • 这是一个由 40 个十六进制字符组成的字符串,基于 Git 中文件的内容或目录结构计算出来。

git log 查看提交的历史

// 打印详细历史记录。空格查看下一个
git log 
// 只包含校验和和描述信息的记录
git log --pretty=oneline 
// 通过图来展示。(多分支)
git log --pretty=oneline --graph

git reset 版本回退

Git通过HEAD指针记录当前版本。

HEAD 是当前分支引用的指针,它总是指向该分支上的最后一次提交。就是将它看做 该分支上的最后一次提交 的快照。

我们可以通过HEAD来改变Git目前的版本指向:

  • 上一个版本就是HEAD^,上上一个版本就是HEAD^^。
  • 如果是上1000个版本,我们可以使用HEAD~1000。
  • 我们可以可以指定某一个commit id(校验和)。
git reset --hard HEAD^ 

git reset --hard HEAD~1000 

git reset --hard 2d44982

由于我们撤回了历史记录。那么git log将不会保存该记录之前的历史提交记录。如果还想找回以前的提交记录,我们可以这样

git reflog

// 然后通过 
git reset --hard commit id

远程仓库

查看远程地址:比如我们之前从GitHub上clone下来的代码,它就是有自己的远程仓库的:

    git remote 
    git remote –v  //-v是—verbose的缩写(冗长的)

添加远程地址:我们也可以继续添加远程服务器(让本地的仓库和远程服务器仓库建立连接):

    // git remote add <shortname> <url>
    git remote add origin(一般起名origin) 仓库地址

重命名远程地址:

    // git remote rename 原仓库名称 现在仓库名称
    git remote rename origin changeOrigin

移除远程地址:

  // git remote remove 仓库名称
  git remote remove origin

远程仓库的交互

从远程仓库clone代码:将存储库克隆到新创建的目录中。

    git clone url

将代码push到远程仓库:将本地仓库的代码推送到远程仓库中

  • 默认情况下是将当前分支push到origin远程仓库的。
    git push 
    git push origin master

从远程仓库fetch代码:从远程仓库获取最新的代码

  • 默认情况下是从origin中获取代码。
  • 获取到代码后默认并没有合并到本地仓库,我们需要通过merge来合并。
    git fetch 
    git fetch origin master
    
    git merge

从远程仓库pull代码:上面的两次操作有点繁琐,我们可以通过一个命令来操作

    git pull 
    git fetch + git merge(rebase)

本地分支的上游分支(跟踪分支)

在我们直接通过git pull拉取并合并远程仓库代码时,如果没有跟踪两个分支,将会报错。

image.png
在没有跟踪的情况下,我们直接执行pull操作的时候必须指定从哪一个远程仓库中的哪一个分支中获取内容。

    git pull origin master

image.png
如果我们想要直接执行git fetch是有一个前提的:必须给当前分支设置一个跟踪分支。可以通过上面那种方式解决,也可以通过下面这种方式解决git fetch报错。

image.png
设置完上游分支后,它将可以把代码获取到本地内存中(git fetch),但是不能进行合并(git merge),会出现refusing to merge unrelated histories

拒绝合并不相干的历史

过去git merge允许将两个没有共同基础的分支进行合并,这导致了一个后果:新创建的项目可能被一个毫不 怀疑的维护者合并了很多没有必要的历史,到一个已经存在的项目中,目前这个命令已经被纠正,但是我们依然可以通过– allow-unrelated-histories选项来逃逸这个限制,来合并两个独立的项目。

我们在合并两个不相干的分支(即没有共同祖先的分支)时,可以在后面跟上-- allow-unrelated-histories来强制合并。
image.png
如果设置了上游分支,git merge不加任何分支,他表示和当前分支的上游分支进行合并。

上面这些问题只会在git init初始化仓库提交的时候会遇到,通过git clone克隆项目并提交时不会遇到。所以一般都是在远程仓库中常见一个新仓库,然后克隆下来进行开发。

git push完整写法

git push origin head:远程分支

修改git push的默认行为

git push报错就是因为git push的默认行为。

如果我们想要直接使用git push推送代码到远程仓库,我们需要修改git push的默认行为,因为git push的默认行为是simple

  • simple表示推到远程仓库和本地分支同名的分支上去,如果远程仓库没有的话,那么将会推送不成功。报错。
  • nothing : 无默认操作,需要显示地指定远程分支。
  • current表示提交到远程仓库中同名分支,如果没有则重新创建一个分支进行提交。
  • upstream表示提交到设置的远程仓库上游分支中。
    git branch --set-upstream-to=origin/master
  • matching表示push所有本地和远程两端都存在的同名分支

在Git的2.0之前,push.default属性默认被设为’matching’,2.0之后被改成为’simple’。

修改git push默认行为

    git config push.default <simple | current | upstream | nothing | matching>

如果我们没有设置当前分支的上游分支,则可以在首次push的时候,加上-u(或者是 –set-upstream)参数来push当前分支到远程仓库。

    git push -u origin master

Git标签(一般不会使用)

对于重大的版本我们常常会打上一个标签,以表示它的重要性:

  • Git 可以给仓库历史中的某一个提交打上标签。
  • 比较有代表性的是人们会使用这个功能来标记发布结点( v1.0 、 v2.0 等等)。

创建标签

Git 支持两种标签。轻量标签(lightweight)与附注标签(annotated)

附注标签:通过-a选项,并且通过-m添加额外信息。

    git tag v1.0.0
    
    git tag -a v1.1.1 -m "标签描述"

默认情况下,git push 命令并不会传送标签到远程仓库服务器上。 在创建完标签后你必须显式地推送标签到共享服务器上,当其他人从仓库中克隆或拉取,他们也能得到你的那些标签。

    git push origin v1.1.1 // 推送指定标签
    
    git push origin --tags // 推送本地全部标签

删除和检出tag

删除本地tag

    git tag -d <tagname>

删除远程tag

    git push <remote> –d <tagname>
    
    // git push origin -d v1.1.1

检出tag

  • 如果你想查看某个标签所指向的文件版本。
    git checkout <tagname>
    git checkout v.1.1.1
  • 通常我们在检出tag的时候还会创建一个对应的分支。就是切换到该tag版本下,依据这个版本代码创建一个分支进行开发。
    image.png

git 提交对象

当我们执行完git add 后,存储的文件对象。

以下命令默认会去.git/objects文件夹下查找

    // 查看存储文件对象的类型
    git cat-file -t commtid(校验和)
    
    // 查看存储文件的内容
    git cat-file -p commtid(校验和)

image.png

image.png
当执行git commit -m ""命令后,.git/objects文件夹下又多出了一些文件。

  • 多出的文件是记录git add后校验和和具体文件的映射关系。
    image.png
  • 多出的文件是记录当前提交的用户信息和commit描述。
    image.png

下面总结一下

在进行提交操作时,Git 会保存一个提交对象(commit object):

  • 该提交对象会包含一个指向暂存内容快照的指针。
  • 该提交对象还包含了作者的姓名和邮箱、提交时输入的信息以及指向它的父对象的指针。
    • 首次提交产生的提交对象没有父对象,普通提交操作产生的提交对象有一个父对象。
    • 而由多个分支合并产生的提交对象有多个父对象。
      image.png

image.png
当前分支就是指向最后一个的commit对象。即保存用户信息的文件。然后head指向当前分支。

git 分支

切换分支就是将head指向当前分支而已。

创建分支表示从当前分支包含的代码,克隆一个副本进行开发。

image.png

image.png

分支相关操作

查看本地和远程仓库的所有分支

git branch -a

查看远程所有分支

git branch -r

如果想要拉取其他分支,可以这样。

如果想要将远程分支与本地分支联系起来,则执行(以feature分支为例)

git checkout -b feature origin/feature

或者使用-t参数,它默认 在本地建立一个和远程分支名字一样的分支,并拉取该分支的所有代码。

git checkout -t origin/feature 

// 或者
git checkout feature

查看所有合并到当前分支的分支

    git branch --merged

查看所有没有合并到当前分支的分支

    git branch --no-merged

删除当前分支,注意删除分支并不是删除提交历史记录,只是将该分支名称删除。

    git branch –d 分支名称

强制删除某一个分支

    git branch –D 分支名称

删除远程分支

 git push origin -d 远程分支名称

git 工作流

image.png

常见仓库的两种情况分析

image.png

git rebase 和 git merge

git rebase, 就是重新设置当前分支的base。使用 rebase 命令将提交到某一分支上的所有修改都移至另一分支上, 让其提交记录成为线性结构,而非图结构。

image.png

事实上,rebase和merge是对Git历史的不同处理方法:

  • merge用于记录git的所有历史,那么分支的历史错综复杂,也全部记录下来。
  • rebase用于简化历史记录,将两个分支的历史简化,整个历史更加简洁。

注意:rebase有一条黄金法则:永远不要在主分支上使用rebase。

如果在main上面使用rebase,会造成大量的提交历史在main分支中不同(因为会在main中写大量的代码)。而多人开发时,其他人依然在原来的main中,对于提交历史来说会有很大的变化。

© 版权声明
THE END
喜欢就支持一下吧
点赞6 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容