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

集中式

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

注意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 reset三参数的解释

  • --mixed 为默认,可以不用带该参数,用于重置暂存区的文件与上一次的提交(commit)保持一致,工作区文件内容保持不变。就是将暂存区的文件拿出来。不会将暂存区的文件丢失。

  • --soft 参数用于回退到某个版本。将修改的内容放置在暂缓区。

  • --hard 参数撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交。慎用。

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

git reset 是回退到指定提交记录,而不是之前还是之后。例如:git reset --hard HEAD~3回退到最近第三次提交记录。git reset --hard commid 回退到制定commitId记录。

他只是本地提交记录被回退,远程的并没有被回退。还需要执行下面指令回退。

git push -f 回滚远程仓库版本

远程仓库

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

    git remote 
    git remote –v  

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

    
    git remote add origin(一般起名origin) 仓库地址

重命名远程地址:

    
    git remote rename origin changeOrigin

移除远程地址:

  
  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拉取并合并远程仓库代码时,如果没有跟踪两个分支,将会报错。

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

    git pull origin master

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

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

拒绝合并不相干的历史

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

我们在合并两个不相干的分支(即没有共同祖先的分支)时,可以在后面跟上-- allow-unrelated-histories来强制合并。

如果设置了上游分支,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-cherry-pick

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>
    
    

检出tag

  • 如果你想查看某个标签所指向的文件版本。

    git checkout <tagname>
    git checkout v.1.1.1

  • 通常我们在检出tag的时候还会创建一个对应的分支。就是切换到该tag版本下,依据这个版本代码创建一个分支进行开发。

git 提交对象

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

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

    
    git cat-file -t commtid(校验和)
    
    
    git cat-file -p commtid(校验和)

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

下面总结一下

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

  • 该提交对象会包含一个指向暂存内容快照的指针。

  • 该提交对象还包含了作者的姓名和邮箱、提交时输入的信息以及指向它的父对象的指针。
    • 首次提交产生的提交对象没有父对象,普通提交操作产生的提交对象有一个父对象。

    • 而由多个分支合并产生的提交对象有多个父对象。

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

git 分支

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

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

分支相关操作

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

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 --delete 远程分支名称

git 工作流

常见仓库的两种情况分析

git rebase 和 git merge

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

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

  • merge用于记录git的所有历史,那么分支的历史错综复杂,也全部记录下来。

  • rebase用于简化历史记录,将两个分支的历史简化,整个历史更加简洁。

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

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

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐