版本管理软件-git

  • git是版本管理软件,服务器和客户机都有版本库,而且版本库中都可以有所有的版本。客户机和服务器通过push、clone、fetch、pull等交互操作命令来进行文件的提交下载来达到版本的同步。

  • 创建服务器共享版本库:在某个要存放代码的文件夹中执行git init --bare (前提是安装了git软件),会生成相应的代码管理文件,该文件夹就是服务器端版本库,一般不会在服务器版本库中直接编写代码,而是由各个客户端编写完成后不断向服务器提交代码文件。(注意,远端仓库有两个概念,一个是指服务器端的共享库,一个是客户端从服务器端共享下来的远端库:其实多人开发模式,客户端版本库中有两个版本库,一个是从服务器端拉取下来的远端库,一个是自己的本地版本库,这也是为什么git既是集中式又是分布式版本管理软件的基础)

  • 创建客户端本地版本库:在某个要存放代码的文件夹中,单人开发模式执行git init,多人协同开发模式通过git clone命令从服务器克隆,初始化版本库,二者都会生成一个隐藏的.git文件夹,该.git文件夹就是本地版本库(包含暂存区和对象区)。多人协同开发,以后通过git pull从服务器拉取最新版本文件,通过git push向服务器推送最新版本文件。

  • 我们选择的存放代码的文件夹(含有隐藏文件夹.git)就是工作区,放在这里面的文件才会被git软件管理,当然我们可以通过.gitignore文件来配置哪些文件可以被忽略管理。

  • 当然,在工作区的文件只有被管理的可能性,但还没有真正的被管理,这里所谓的真正的被管理,是指git会监督文件的修改,比如文件内容的增删,甚至文件的删除(工作区的文件怎么修改都不会被监管),但可以检测到该文件的存在。如果需要正式管理该文件,需要通过git add命令将文件添加进版本库中的暂存区,文件一旦进入暂存区以后,其内容的变化就会受到git软件的监管,我们称之为“文件被追踪”。

  • 进入暂存区的文件的修改也只是被检测到,但不会永久记录每次修改。所以并不能通过所谓的"版本"来回到某个“历史版本”。而要形成真正的版本,则是文件通过git commit命令被从暂存区添加进对象区,也就是每进行一次commit操作,就形成一个新版本(注,版本并不是针对文件而言的,是针对分支而言,一个版本包含该分支内的所有文件),相当于对所有已经commit过的文件进行一次镜像备份,这样就可以通过历史“版本”回退到某个历史时候的特定版本,这就是所谓的版本管理,具有记录版本更进和备份的功能。所谓版本,就是某时刻文件集合的镜像。

  • 文件通过commit命令进入的是本地版本库,如果是单人开发的话,可以到此为此;如果是多人协同开发,我们还需要通过git push 命令将我们本地的"版本"推送到服务器版本库。以供其他人clone或者pull(客户端从服务器初始化版本库用clone,从服务器更新最新版本库用pull)

  • 所以一个文件被管理的流程是: 工作区中创建--> add进暂存区(被追踪)--> commit进入对象区(形成版本) --> push进入服务器版本库更新服务器版本

  • git log命令可以查看commit记录,也就是提交形成新版本的记录,git reset命令可以回滚到指定版本(创建一个和指定版本镜像一样的新版本,即形成一个新的commit记录)

  • 分支branch,版本管理以分支为主线,每个分支有自己的版本历史,即commit记录(在工作区创建的每个文件属于第一个把它们add进暂存区并commit对象区的分支以及以后依据该分支创建的新分支),分支在文件上可以理解为不同的文件夹,每个分支代表一个文件夹,每个文件夹都有自己的版本历史记录。

  • 子分支从父分支创建,子分支拥有被创建时刻之前的父分支所有的版本历史记录,并在此基础上开始自己的版本历史之旅。从文件上来讲,创建分支就相当于复制了一份相同的文件夹。

  • 根据协同开发阶段的不同,我们需要创建不同的分支,分支可以合并merge(一般是在父分支合并子分支,将子分支合并到父分支中来),合并他人分支,会将他人分支中的代码文件添加进来,有冲突的需要解决冲突(所谓冲突,就是同一个文件的同一行被不同的人写了不同的代码),被合并的分支并不会因此消失和改变。从文件上讲,合并一个分支就是文件夹中的文件复制到另一个文件夹。

  • gitflow是根据实践总结的一种分支管理模式

    image.png

  • 撤销、修改,命令git checkout --要撤销的文件(.代表全部文件),这样就会拉取文件在原暂存区的状态至工作区,即改变的是工作区的该文件(此时,工作区和暂存区文件内容一致);git reset HEAD 要撤销的文件(.代表全部文件),将该文件从最近一次commit版本中的状态拉取至暂存区,即改变的是暂存区中的该文件(此时,该文件暂存区和对象区中是一致的),reset命令是有选项的,默认是--mixed,后面我们将详细解释一下reset命令。注意,这里说的拉取是相当于从中copy一份到暂存区,并不会对原commit版本中文件造成什么改变或者损害;另外这里的HEAD是指针,代表当前版本编号,默认是指向版本链条中最后一个commit版本,当然,可以恢复到任何指定的版本,所以这里的HEAD,可以用任何具体的版本号直接替换。
    对于已经commit的文件,可以通过git commit --amend命令来用暂存区文件来对上一次的commit版本进行覆盖commit操作。

  • git reset HEAD(或者具体版本号)。该命令有三个选项:--soft,--mixed(默认),--hard。
    版本号像一个链条一样,从头至尾,HEAD就是指针(或代表当前指向的版本),指向当前版本,默认是最后一个版本。
    reset命令可以改变指针HEAD指向指定的版本,不管哪个选项,这个作用是一定的。reset是版本回撤的作用,将指针指向某个历史版本作为当前版本,之后再新提交commit,就在该“当前版本”往后延伸版本链,就像树枝发了新叉一样。
       --soft 只改变指针指向指定版本,不进行任何其他操作(但因为当前版本变了,所以工作区、暂存区通常都和对象区文件不一致)。
       --mixed 默认模式,除了改变指针指向指定版本,还会从指定版本拉取文件内容覆盖暂存区文件内容(这样暂存区和对象区文件内容是一致的,但通常和工作区文件内容不一致)
       --hard 除了改变指针指向指定版本,还会从指定版本拉取文件内容至暂存区和工作区(这样,三个区域的文件内容都是一致的)参考文章
    当再次进行commit时,版本链条还是会从最后一个版本接着往后延续,新版本编号跟着最后一个版本后面。

  • 通过commit可以提交版本,reset可以回退到指定版本。通过git log [-n] 可以查看(当前版本之前的n次)提交记录(该命令后面可以跟很多选项参数,可以自行百度)。如果有回退到某个版本,那么用该命令时看不到当前版本之后的版本的,要想看所有版本,则用git reflog 命令。

  • git中文件的4种状态(注,文件的状态都是指文件最后修改过的状态。并且:凡是我们通过编辑器编写修改的代码,都是修改的工作区的文件内容)。①untracked:工作区中新建的文件(未被追踪);②modified:文件被add进暂存区后又被修改后的状态; ③staged:文件被add进暂存区后没有被再次修改过时的状态;④commited:文件被commit进版本库中对象区后没被再次修改时的状态。

  • git status 可以检测同一个文件当前时刻在工作区、暂存区、对象区内容是否一致,如果一个文件从工作区被add进暂存区后被修改(非git命令直接修改文件,都是修改的工作区中的文件内容),那么此时该文件在工作区和暂存区的内容就不是一致的,所以为modified状态(提示需要被add进暂存区或者git restore 文件名来用暂存区文件内容同步至工作区文件中),git restore命令是新版本中用来分担替代git checkout命令的文件恢复功能(不加参数默认是从暂存区恢复数据到工作区),具体参考文章;同样的,当一个文件被commit后再被修改也是如此,文件修改后并再次被add进暂存区后,该文件此时在工作区、暂存区内容一致,但和当前对象区内容不一致,所以文件当前状态是staged(提示需要commit,或者通过git restore --staged来取消暂存,即从对象区当前版本恢复数据到暂存区)。对于同一个文件而言,其内容的状态,在工作区、暂存区都只有一份,而对象区,因为每次commit都形成了不同的版本(相当于创建了不同时期的镜像),所以会有很多份。另外需要明确的一点是,我们在文件中进行的编辑修改甚至删除(非git rm命令删除),都是修改或者删除(注:删除可以理解为某种意义上的修改)的工作区中的该文件。(git rm 文件删除命令:对于工作区和暂存区该文件内容为最后态时(即没有被修改过,二者内容一致),该命令可将文件从这两个区中同时删除;当修改导致两个区文件内容不一致时,会进行错误提示,并可通过git rm --cached只从暂存区中删除该文件,git rm -f 同时从两个区删除该文件)

  • git分支和分支指针:
       所谓指针,是指保存了版本地址的变量。
       默认情况下,分支指针都是保存了各自分支的最新版本的地址(编号),当然如果有版本回退,该指针保存的地址就会改变为之前的某个版本的地址,所以所谓的版本回滚并不是文件的混滚覆盖,只是指针指向了需要回滚的历史版本的地址而已。这是分支指针的作用(而且每个版本还保存了其上一个版本—parent的地址,以方便追踪)。每个分支都有自己的指针HEAD,指向当前版本。

  • 分支的创建,其实是指针的创建。这就不难理解,为什么子分支可以拥有父分支在创建其时刻之前的全部版本记录;所有的分支都是从一个master分支发展而来的(每个分支都有一个版本链条,每个版本都保存了其父版本的parent的地址信息)。分支就像树一样,无论哪个树枝,沿着往前摸,最后都能摸到树干直至树根。

  • 分支的创建和合并: 比如在某个时刻,从父分支A同时创建出a1、a2两个子分支,a1、a2在诞生之时起,就拥有其父分支A所有的版本记录(记住所谓版本是不同时刻文件集合的镜像,而且每个版本的id都是通过sha1值来记录的,说明不同版本的id值是不可能相同的不可能重复的)。其后a1、a2在各自的道路上不断往前发展,版本链条不断延伸,在这个过程中,不断创建新文件也有可能删除旧文件。当a1发展到第m个版本时,a2发展到第n个版本时,开发完成,A需要对a1、a2两个分支进行合并merge,当A准备合并a1分支时,git根据版本id和创建时间发现A当前版本id是a1分支某个历史时间点中的一个版本的id,说明A处于a1分支历史的某个阶段,那么直接将A分支的指针HEAD指向a1分支的当前版本即可;当A准备再次合并a2分支时,根本版本id和创建时间,发现A分支当前版本并不是a2分支的某个历史时刻的版本,所以A和a2分支当前版本中,都有可能拥有对方不拥有的文件。那么git会将二者当前版本中的文件进行融合形成一个新的版本放在当前版本的后面,并且将其设置为A分支的当前版本。这样A分支的最新版本中就能保证拥有最全的文件信息和版本记录(该版本会同时保存融合前两个分支中父版本的信息)。

  • 当进行分支切换时,如果文件在工作区和暂存区的内容同当前版本不一致时(比如修改了文件),则是会报错的,可以通过stash命令将当前修改后的内容暂存到stash数组变量中,这样文件内容就会退回修改之前的内容的样子,这样就可以进行分支切换了,当再次切回该分支时,还可以通过stash的相关命令方法(apply、pop、remove等),从其数组变量中取回之前存放的修改后的内容样子。

  • 对于多人开发模式(会在服务器建立共享版本库),通常每个人在各自电脑上采用不同分支分别开发的方式(每天开发前先用git pull或git fetch命令从服务器更新最新代码),各自开发完成后,由项目经理在自己电脑上用一个Develop分支对各个分支进行merge;这样的好处就是减少冲突,试想如果两个人用同一个分支在两个电脑同时开发,每个人开发完一个小功能分别不停交替的向服务器提交新版本,每当其中一个人向服务器提交新版本后,另一个人再次向服务器提交时,发现本地存储的远端版本库版本信息(本地版本库除了保存自己的版本库信息,同时还会保存远端服务器相应分支的版本信息,每次向服务器提交新版本的时候,会将服务器最新版本信息和本地保存的服务器版本信息进行比对)已经不一样了,这样每次都要先更新本地保存的远端服务器版本,而且当两人同时编辑了同一份文件的话,还会产生冲突,更新的时候还要解决冲突。从服务器更新代码的命令有git pull 和git fetch,具体区别参考文档

    image.png

    image.png

  • git 用户、邮箱的配置 —— 共有三种级别的配置
       git config --local(默认是该级别,选项可以省略) user.name 用户名
       git config --local (默认是该级别,选项可以省略) user.email 邮箱名
       三种级别分别是:①--local 仓库级别,优先级最高,配置在当前仓库下.git/config 文件中;②--global用户级别,优先级次之,配置文件为当前用户宿主目录下的~/.gitconfig文件;③--system 系统级别,配置文件为git安装目录下的/etc/gitconfig文件;
       删除用户、邮箱配置用git config --global --unset user.name 用户名
       修改用git config --system --replace user.email 新邮箱名;
       查看用git config --global -l
       注:修改指定级别的分别改为对应的--local、--global、--system

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,064评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,606评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,011评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,550评论 1 269
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,465评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,919评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,428评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,075评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,208评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,185评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,191评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,914评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,482评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,585评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,825评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,194评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,703评论 2 339

推荐阅读更多精彩内容

  • 以下笔记主要参考gitgot,大致了解git使用和原理。 第一部分我们从个人的视角去研究如何用好Git,并且揭示G...
    carolwhite阅读 2,347评论 0 1
  • Git 是目前最流行的分布式版本控制系统之一。 版本控制指的是,记录每次版本变更的内容和时间等细节,保留各版本之间...
    神齐阅读 1,384评论 0 7
  • 一、基本概念: 注:对于git的分布式概念及其优点,不重复说明,自己百度或谷歌。本文中涉及到指令前面有$的,在cm...
    大厂offer阅读 1,396评论 0 3
  • Git教程 一、Git简介 1.1. Git的诞生1.2.集中式的vs分布式 二、安装Git 三、创建版本库 四、...
    曹渊说创业阅读 929评论 0 2
  • Add & Commit git init 初始化一个 Git 仓库(repository),即把当前所在目录变成...
    冬絮阅读 4,758评论 0 8