Git和Github知识概括

Git和Github知识概括

  • 版本控制简介
  • Git 简介
  • Git 命令行操作
  • git命令详解
  • Git 基本原理
  • GitHub
  • Eclipse,Idea 操作
  • Git 工作流
  • Gitlab 服务器搭建过程
  • 总结

版本控制简介

版本控制工具应该具备的功能:

  • 协同修改
    ①多人并行不悖的修改服务器端的同一个文件。
  • 数据备份
    ① 不仅保存目录和文件的当前状态,还能够保存每一个提交过的历史状态。
  • 版本管理
    ① 在保存每一个版本的文件信息的时候要做到不保存重复数据,以节约存储空 间,提高运行效率。这方面SVN 采用的是增量式管理的方式,而 Git 采取了文 件系统快照的方式。
  • 权限控制
    ① 对团队中参与开发的人员进行权限控制。
    ②对团队外开发者贡献的代码进行审核——Git 独有。
  • 历史记录
    ①查看修改人、修改时间、修改内容、日志信息。
    ②将本地文件恢复到某一个历史状态。
  • 分支管理
    ①允许开发 团队在工作过程中多条生产线同时推进任务,进一步提高效率。

版本控制简介:

  • 版本控制:工程设计领域中使用版本控制管理工程蓝图的设计过程。在 IT 开发过程中也可以 使用版本控制思想管理代码的版本迭代。
  • 思想:版本控制
  • 实现:版本控制工具
  • 集中式版本控制工具: CVS、SVN、VSS……
    Git和Github知识概括_第1张图片
  • 分布式版本控制工具: Git、Mercurial、Bazaar、Darcs……
    Git和Github知识概括_第2张图片

Git 简介

Git 简史:Git和Github知识概括_第3张图片
Git 的优势:

  • 大部分操作在本地完成,不需要联网
  • 完整性保证
  • 尽可能添加数据而不是删除或修改数据
  • 分支操作非常快捷流畅
  • 与 Linux 命令全面兼容

Git 安装:

  • 第一步安装到一个非中文没有空格的目录下
  • 第二步建议使用VIM编辑器(Use Vim)
  • 第三步完全不修改PATH环境变量,仅在Git Bash中使用Git(Use Git from Git Bash only)
  • 第四步使用默认值(Use the OpenSSL library)
  • 第五步行末换行符转换方式,使用默认值(Checkout Windows-style,commit…)
  • 第六步执行Git命令的默认终端,使用默认值(Use MinTTY)
  • 第七步直接点击安装(install)

Git 结构:
Git和Github知识概括_第4张图片

Git 和代码托管中心:

  • 代码托管中心的任务:维护远程库
  • 局域网环境下:GitLab 服务器
  • 外网环境下:GitHub , 码云Gitee

本地库和远程库:

  • 团队内部协作:Git和Github知识概括_第5张图片
  • 跨团队协作:Git和Github知识概括_第6张图片

Git 工作区、暂存区和版本库:

  • 工作区:就是你在电脑里能看到的目录。
  • 暂存区:英文叫 stage 或 index。一般存放在 .git 目录下的 index文件(.git/index)中,所以我们把暂存区有时也叫作索引(index)。
  • 版本库:工作区有一个隐藏目录 .git,这个不算工作区,而是 Git 的版本库。
  • 下面这个图展示了工作区、版本库中的暂存区和版本库之间的关系:
    ①图中左侧为工作区,右侧为版本库。在版本库中标记为 “index” 的区域是暂存区(stage/index),标记为 “master” 的是 master 分支所代表的目录树。
    ②图中我们可以看出此时 “HEAD” 实际是指向 master 分支的一个"游标"。所以图示的命令中出现 HEAD 的地方可以用 master 来替换。
    ③图中的 objects 标识的区域为 Git 的对象库,实际位于 “.git/objects” 目录下,里面包含了创建的各种对象及内容。
    ④当对工作区修改(或新增)的文件执行 git add 命令时,暂存区的目录树被更新,同时工作区修改(或新增)的文件内容被写入到对象库中的一个新的对象中,而该对象的ID被记录在暂存区的文件索引中。
    ⑤当执行提交操作(git commit)时,暂存区的目录树写到版本库(对象库)中,master 分支会做相应的更新。即 master 指向的目录树就是提交时暂存区的目录树。
    ⑥当执行 git reset HEAD 命令时,暂存区的目录树会被重写,被 master 分支指向的目录树所替换,但是工作区不受影响。
    ⑦当执行 git rm --cached 命令时,会直接从暂存区删除文件,工作区则不做出改变。
    ⑧当执行 git checkout . 或者 git checkout – 命令时,会用暂存区全部或指定的文件替换工作区的文件。这个操作很危险,会清除工作区中未添加到暂存区的改动。
    ⑨当执行 git checkout HEAD . 或者 git checkout HEAD 命令时,会用 HEAD 指向的 master 分支中的全部或者部分文件替换暂存区和以及工作区中的文件。这个命令也是极具危险性的,因为不但会清除工作区中未提交的改动,也会清除暂存区中未提交的改动。
    Git和Github知识概括_第7张图片

Git 命令行操作

简述:

  • 下图中:
    ①git bash here在此处使用git终端命令行
    ②git GUI here在此处使用git图形化界面
    Git和Github知识概括_第8张图片
  • Window用户家目录:
    Git和Github知识概括_第9张图片
  • 注意:
    ①当在工作目录新建一个文件,运行 git status ,会显示这个文件是untracked(为跟踪)状态。
    ②这时候需要使用 git add 将这个文件加入暂存区,也就是告诉Git需要去跟踪这个文件。
    ③第一次提交为根提交
    .开头的文件表示隐藏文件.git 目录中存放的是本地库相关的子目录和文件,不要删除,也不要胡乱修改。
    ⑤git:
    <1>红色: 未提交到暂存区
    <2>绿色: 未提交到本地库

Git 创建仓库:

  • git init:
    ①Git 使用 git init 命令来初始化一个 Git 仓库,Git 的很多命令都需要在 Git 的仓库中运行,所以 git init 是使用 Git 的第一个命令。
    ②在执行完成 git init 命令后,Git 仓库会生成一个 .git 目录,该目录包含了资源的所有元数据,其他的项目目录保持不变。
    ③使用方法:使用当前目录作为Git仓库,我们只需使它初始化。
  • git clone:
    ①我们使用 git clone 从现有 Git 仓库中拷贝项目(类似 svn checkout)。
    ②克隆仓库的命令格式为:git clone
    ③如果我们需要克隆到指定的目录,可以使用以下命令格式:git clone

Git配置:

  • git 的设置使用git config 命令,显示当前的 git 配置信息:
$ git config --list
credential.helper=osxkeychain
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
core.ignorecase=true
core.precomposeunicode=true
  • 如果是第一次提交,需要配置提交者信息,推荐和gitee/github/gitlab的账号邮箱一致,这是非常重要的,因为每次Git提交都会使用该信息。它被永远的嵌入到了你的提交中。
  • 编辑 git 配置文件:
$ git config -e    # 针对当前仓库 
或者:
$ git config -e --global   # 针对系统上所有仓库
  • 设置提交代码时的用户信息(签名):
    ①作用:区分不同开发人员的身份
    注意:
    <1>这里设置的签名(名字和邮箱)和登录远程库(代码托管中心)的账号、密码没有任何关系。
    <2>这里设置的签名(名字和邮箱)仅仅用来区分身份,不涉及登录操作。
    ③级别优先级 :
    <1>就近原则:项目级别优先于系统用户级别,二者都有时采用项目级别的签名
    <2>如果只有系统用户级别的签名,就以系统用户级别的签名为准
    <3>二者都没有不允许
$ git config --global user.name "runoob"
$ git config --global user.email [email protected]
如果去掉 --global 参数只对当前仓库有效。
  • Git设置默认的push分支:
    ①Git缺省情况下并没有什么默认的推送的分支,如果你执行git push就会告诉你给一个警告!
    ②所以如果你即使要推送当前对应分支,你还是要告诉git,例如当前是myBranch,要推送的话, git push origin myBranch
    ③为了简化这个命令,也就是当我们输入git push,让git直接推送到本branch就好。
    ④要做到这一点,就需要告诉默认的推送目的branch,这个需要是动态的,不然当我们checkout到别的branch,就会有问题。git为我们提供了这个功能,就是直接设置默认的推送branch为current。
    再用下面的命令查看我们设置的值git config –global push.default

Git 基本操作:

  • 链接:Git 基本操作
  • Git 的工作就是创建和保存你项目的快照及与之后的快照进行对比。
  • Git 常用的是以下 6 个命令:git clone、git push、git add 、git commit、git checkout、git pull。
  • 说明:
    ①workspace:工作区
    ②staging area:暂存区/缓存区
    ③local repository:版本库或本地仓库
    ④remote repository:远程仓库
    Git和Github知识概括_第10张图片
  • 提交与修改:
命令 说明
git add 添加文件到仓库
git status 查看仓库当前的状态,显示有变更的文件。
git diff 比较文件的不同,即暂存区和工作区的差异。
git commit 提交暂存区到本地仓库。
git reset 回退版本。
git rm 删除工作区文件。
git mv 移动或重命名工作区文件。
  • 提交日志:
命令 说明
git log 查看历史提交记录
git blame 以列表形式查看指定文件的历史修改记录
  • 远程操作:
命令 说明
git remote 远程仓库操作
git fetch 是从远程获取最新版本到本地,不会自动merge
git pull 是从远程获取最新版本到本地,并自动merge
git push 是将本地库中的最新信息发送给远程库
git merge 是用于从指定的commit(s)合并到当前分支,用来合并两个分支

分支简介

  • 在版本控制过程中,使用多条线同时推进多个任务。Git和Github知识概括_第11张图片
  • 分支的好处:
    ①同时并行推进多个功能开发,提高开发效率
    ②各个分支在开发过程中,如果某一个分支开发失败,不会对其他分支有任 何影响。失败的分支删除重新开始即可。

分支操作:

  • 创建分支 git branch [分支名]
  • 查看分支 git branch -v
  • 切换分支 git checkout [分支名]
  • 合并分支:
    切换到接受修改的分支(被合并,增加新内容)上 git checkout [被合并分支名]
    执行 merge 命令 git merge [有新内容分支名]
  • 每次合并分支的时候,会同时默认操作一次commit.
  • 冲突简介:
    ①冲突的产生:同时修改了一个文件。
    提交时要先更新:如果你不更新直接提交,这段时间有可能别人更新后已经提交了,你没有更新还是老得版本,直接提交后会把别人更新的覆盖掉,所以你在提交的时候最好先更新,更新到最新版本的核对之后再提交。
    ③冲突的表现:Git和Github知识概括_第12张图片
    ④IDEA冲突颜色:
    <1>蓝色:修改
    <2>绿色:新增
    <3>灰色:删除
    <4>红色:冲突
    ④冲突的解决:
    <1>编辑文件,删除特殊符号
    <2>把文件修改到满意的程度,保存退出
    <3>git add [文件名]
    <4>git commit -m “日志信息”
    <5>注意:此时 commit 一定不能带具体文件名

Git 标签:

  • 如果你达到一个重要的阶段,并希望永远记住那个特别的提交快照,你可以使用 git tag 给它打上标签。
  • 比如说,我们想为我们的 runoob 项目发布一个"1.0"版本。 我们可以用 git tag -a v1.0命令给最新一次提交打上(HEAD)"v1.0"的标签。
  • -a 选项意为"创建一个带注解的标签"。 不用 -a 选项也可以执行的,但它不会记录这标签是啥时候打的,谁打的,也不会让你添加个标签的注解。 我推荐一直创建带注解的标签。

git命令详解

~ 与 ^ 的关系:

  • 我们知道,~ 获取第一个祖先提交,^ 可以获取第一个父提交。
  • 其实第一个祖先提交就是第一个父提交,反之亦然。
  • ~ 用来表示一个提交的第 n 个祖先提交,如果不指定 n,那么默认为 1。另外,HEAD~~~ 和 HEAD~3 是等价的。
  • ^ 用来表示一个提交的第 n 个父提交,如果不指定 n,那么默认为 1。和 ~ 不同的是,HEAD^^^ 并不等价于 HEAD^3,而是等价与 HEAD^1^1^1。

Git回退(reset)与反做(revert):

  • git reset [--soft | --mixed | --hard] [HEAD]
    ①工作流中先是本地修改,然后git add,然后gitcommit。以本地修改为最高量级,以自己为中心。该参数用于你在本地改了文件一部分commit了,一部分刚好git add了,这时候你要恢复到你的工作副本状态,要求再次审查代码。
    <1>soft: 重置git commit
    <2>mixed: 重置git commit 和 git add
    <3>hard: 重置git commit 和 git add 和工作副本的修改。
    git reset完一定要提交远程,不然本地会混乱。
    Git和Github知识概括_第13张图片
  • git revert -n 目标版本号
    ①git revert是用于“反做”某一个版本,以达到撤销该版本的修改的目的。比如,我们commit了三个版本(版本一、版本二、 版本三),突然发现版本二不行(如:有bug),想要撤销版本二,但又不想影响撤销版本三的提交,就可以用 git revert 命令来反做版本二,生成新的版本四,这个版本四里会保留版本三的东西,但撤销了版本二的东西。
  • git revert和git reset的区别是什么?
    ①git中,每一次提交都会生成一个commit
    <1>git revert会生成一个新的commit,将之前的某个commit的修改恢复过来
    <2>git reset会将HEAD移动到某个commit上,换种说法就是将某个commit变成最后一个commit
    ②譬如现在有A,B,C三个commit
    <1>执行git revert C的话,会生成commit D,当前code的内容会变成和B一样
    <2>执行git reset B --hard的话,会在当前的工作目录中将C丢弃掉,内容变成和B一样
    从内容上来看,这两种做法是一样的;但从commit的历史来看,是不同的
  • 链接:git远程仓库回退操作详解

Git commit和Git stash的区别:

  • git在一个分支上修改了代码必须要commit到本地git库,才可以切换一个分支去修改代码。
  • 在一个分支上修改了代码但是不想commit到本地git库,需要切换一个分支去修改代码,这个时候也可以使用git stash
    stash命令可用于临时保存和回复修改,可跨分支。
    注:在未add之前才能执行stash!!!!
  • 修该完后可再使用Unstash,选中你刚刚的stash,选中Pop stash。点击pop stash即可。
  • 工作区和缓存区内容是公共的,不从属于任何一个分支,因此git add没用。
  • 链接:git切换分支时,会将未add或未commit的内容切换过去

git diff 和git log的区别:

  • git diff 命令比较文件的不同,即比较文件在暂存区和工作区的差异。git diff 命令显示已写入暂存区和已经被修改但尚未写入暂存区文件对区别。git diff 有两个主要的应用场景。
    ①尚未缓存的改动:git diff(工作区与暂存区)
    ②查看已缓存的改动: git diff --cached(暂存区与版本库)
    ③查看已缓存的与未缓存的所有改动:git diff HEAD(工作区与版本库)
    git diff <分支名1> <分支名2> :比较两个分支上最后 commit 的内容的差别
    ⑤显示摘要而非整个 diff:git diff --stat
    ⑥链接:git diff的最全最详细的4大主流用法

  • git log 在使用 Git 提交了若干更新之后,又或者克隆了某个项目,想回顾下提交历史,我们可以使用 git log 命令查看。命令格式:git log [] [] [[--] ...]
    ①git log 查看提交历史记录
    ②git log --oneline 或者 git log --pretty=oneline 以精简模式显示
    ③git log --graph 以图形模式显示
    ④git log --stat 显示文件更改列表
    ⑤git log $分支名/tag名/远程分支名
    ⑥链接:git log 查看提交记录

Git分支图谱与git log:

  • 仓库是指一个历史可追溯(tracked)的文件集合,可以把该文件集合的任意一个历史状态变更看成是一个单位,图中的一个个小圆点即为该仓库的某个历史状态变更。
  • 通过commit,每一次commit就会生成一个commit对象,产生一次历史状态变更。因此这一个个小圆点也可以看成是一个个commit对象。
  • 什么是分支?分支和历史状态变更的关系,分支和仓库的关系:
    分支是一个指向叶子节点的指针,每个节点都是一个历史状态变更。叶子节点可以理解为最新的历史状态变更。
    一个分支包括多个历史状态变更(节点),可以在本分支的各个历史状态变更(节点)中穿梭。
    ③一个仓库通常有各种分支错综复杂,IDEA 可视化log中可以可以查看各个分支之间的关系。单个分支,select几个分支和所有分支。
    Git和Github知识概括_第14张图片
  • 分支总结:
    ①当查看单个分支时,查看的都是从该分支切出去或者该分支的信息。
    ②当查看所有分支时,查看的都是所有分支的信息了。
  • 远程分支和本地分支对应:
    ①push成功的条件就是远程分支是我本地分支的父亲,意思就是远程做过的修改(历史状态变更/节点)我本地都做过了,所以我可以push成功,否则远程分支有另外的修改(有分叉)但我本地却没有,因此push会产生冲突。通过合并(merge)\解决冲突(solve conflict)后再合并(merge)。
    ②同理,pull(fetch+merge)成功的条件是本地分支是远程分支的父亲。
    ③链接:远程分支和本地分支的解释
  • Idea中的git log:
    ①git log不只看自己的分支也可以看所有分支
    ②idea的git log是所有模块的git log(IDEA上方的git的选项为整个project)
    ③选择某个模块再点击show git history是单个模块的git log(选择某个模块的git为某个模块)
  • Git图谱:
    ①链接:
    <1>带你一步一步看懂Git图谱
    <2>怎么才能看懂 git log的线?
    在只有一种分支的情况下,有多少个本地仓库,就有可能衍生出多少条支线。
    每条颜色的支线不会固定代表某个分支,不同颜色的线可能代表同一个分支。
    项目最早的一次提交与最近的一次提交连成的最长的直线就是主线,也是唯一的一条直线,它的走向也就是时间轴的走向。主线上衍生支线,支线上又会衍生出新的支线。
    <1>新的分支commit的差异,产生了新的支线
    <2>同一分支,不同仓库commit的差异,产生了新的支线
    <3>同一分支,不同仓库的merge,合并了支线
    <4>不同分支的merge合并了支线
    在最早提交和最近提交这条线中的每一个comit点分叉出去的都会产生支线。
    <1>新建分支时会hash一下,commit时也会hash一下,因此新建分支和新建版本都是新建版本。
    <2>首次提交产生的提交对象没有父对象,普通提交操作产生的提交对象有一个父对象,而由多个分支合并产生的提交对象有多个父对象。
    <3>且新建分支时会新建一个Tree对象索引。
    git图谱中分支名称若包括origin则是提交到了远程库,若无则单纯提交。此外若无分支名称,则沿用上个提交节点的分支。
    Git和Github知识概括_第15张图片

Git状态跟踪与移除:

  • 链接:Git状态跟踪
  • 对于任何一个文件,在 Git 内都只有三种状态:已提交(committed),已修改(modified)和已暂存(staged):
    ①已提交:表示该文件已经被安全地保存在版本库中了。
    ②已修改:表示修改了某个文件,但还没有提交到暂存区。
    ③已暂存:表示把已修改的文件已经放到暂存区了,下次提交时一并被保存到版本库中。
  • 跟踪详解:
    使用命令 git add 开始跟踪文件README,则该文件会纳入索引文件。
    当文件修改时会与索引文件对比,若不同则会显示为未提交。
  • 移除文件:
    ①要从 Git 中移除某个文件,就必须要从已跟踪文件清单中注册删除(确切地说,是在暂存区域注册删除),然后提交。可以用 git rm 命令完成此项工作,并连带从工作目录中删除指定的文件,这样以后就不会出现在未跟踪文件清单中了。

git rebase命令:

  • git merge操作合并分支会让两个分支的每一次提交都按照提交时间(并不是push时间)排序,并且会将两个分支的最新一次commit点进行合并成一个新的commit,最终的分支树呈现非整条线性直线的形式
  • git rebase操作实际上是将当前执行rebase分支的所有基于原分支提交点之后的commit打散成一个一个的patch,并重新生成一个新的commit hash值,再次基于原分支目前最新的commit点上进行提交,并不根据两个分支上实际的每次提交的时间点排序,rebase完成后,切到基分支进行合并另一个分支时也不会生成一个新的commit点,可以保持整个分支树的完美线性
  • 另外值得一提的是,当我们开发一个功能时,可能会在本地有无数次commit,而你实际上在你的master分支上只想显示每一个功能测试完成后的一次完整提交记录就好了,其他的提交记录并不想将来全部保留在你的master分支上,那么rebase将会是一个好的选择,他可以在rebase时将本地多次的commit合并成一个commit,还可以修改commit的描述等
  • 在项目中使用rebase的原则:不要修改已经提交到公共仓库中的commit。
  • 举例:
    ①如果提交之前提交记录是这样的:
    Git和Github知识概括_第16张图片
    ②然后在feature分支rebase master分支之后,feature分支上的提交记录会改变:
    Git和Github知识概括_第17张图片
  • 链接:
    ①你真的懂git rebase吗?
    ②git rebase 还是 merge的使用场景最通俗的解释

git cherry-pick:

  • git cherry-pick命令的作用,就是将指定的提交(commit)应用于其他分支。命令:git cherry-pick
  • git cherry-pick命令的参数,不一定是提交的哈希值,分支名也是可以的,表示转移该分支的最新提交。
  • Cherry pick 支持一次转移多个提交。但会形成多个提交。
    a - b - c - d   Master
         \
           e - f - g Feature

# 切换到 master 分支
$ git checkout master

# Cherry pick 操作
$ git cherry-pick f


    a - b - c - d - f   Master
         \
           e - f - g Feature
  • 链接:git cherry-pick 教程

git pull 和git fetch区别:

  • git fetch 命令:
    ①git fetch <远程主机名> //这个命令将某个远程主机的更新全部取回本地仓库
  • git pull 的过程可以理解为:
    git fetch //从远程主机的选定的分支拉取最新内容
    git merge FETCH_HEAD //将拉取下来的最新内容合并到当前所在的分支中
    这样使用一次后idea会自动建立选中分支的远程跟踪分支,以后可直接点击Update Project,不需要再选分支,除非要拉取另一分支。
    ③链接:idea使用git更新代码 : update project(git merge、git rebase)

git push详解:

  • 如果本地版本与远程版本有差异,但又要强制推送可以使用 --force 参数:
    ①git push --force origin master
  • 删除主机但分支可以使用 --delete 参数,以下命令表示删除 origin 主机的 master 分支:
    ①git push origin --delete master
  • 如果当前分支与多个主机存在追踪关系,则可以使用-u选项指定一个默认主机,这样后面就可以不加任何参数使用git push:
    ①git push -u origin master

git merge详解:

  • git merge的冲突判定机制如下:先寻找两个commit的公共祖先,比较同一个文件分别在ours和theirs下对于公共祖先的差异,然后合并这两组差异。如果双方同时修改了一处地方且修改内容不同,就判定为合并冲突,依次输出双方修改的内容。
    因此分支合并,不管谁合并谁都是共同向前进的。

  • 怎样撤销git的merge?
    那我就尝试提交代码(commit)--Git--Commit Directory--Commit Changes
    Revert Changes

  • –no-commit使用:
    ①–no-commit执行合并但假装合并失败并且不自动提交,以使用户有机会在提交前检查并进一步调整合并结果。

  • git merge #没有参数:
    ①即默认启用fast-forward方式进行合并,不会显示 feature,只保留单条分支记录。git直接把HEAD指针指向合并分支的头,完成合并。属于“快进方式”,不过这种情况如果删除分支,则会丢失分支信息。因为在这个过程中没有创建commit。

  • git merge --squash:
    ①用来把一些不必要commit进行压缩,比如说,你的feature在开发的时候写的commit很乱,那么我们合并的时候不希望把这些历史commit带过来,于是使用–squash进行合并,此时文件已经同合并后一样了,但不移动HEAD,不提交。需要进行一次额外的commit来“总结”一下,然后完成最终的合并。

  • git merge --no-ff:
    ①强行关闭fast-forward方式。可以保存你之前的分支历史。能够更好的查看 merge历史,以及branch 状态。
    Git和Github知识概括_第18张图片

git rm 和 rm详解:

  • rm的作用: 删除工作区的文件。
  • git rm 的作用: 删除工作区文件,并且将这次删除放入暂存区。
  • git rm -f的作用: 删除工作区和暂存区文件,并且将这次删除放入暂存区。
  • git rm --cached的作用: 删除暂存区文件,但保留工作区的文件,并且将这次删除放入暂存区。

工作树(working tree), 树对象(index file):

  • 树对象(tree object),它能解决文件名保存的问题,也允许我们将多个文件 组织到一起。Git 以一种类似于 UNIX文件系统的方式存储内容。所有内容均以 树对象和数据对象(git 对象)的形式存储,其中树对象对应了 UNIX 中的目录项,数据对象(git 对象)则大致上对应文件内容。一个树对象包含了一条或多条记录(每条记录含有一个指向 git 对象或者子树对象的 SHA-1 指针,以及相应的模式、类型、文件名信息)。一个树对象也可以包含另一个树对象。
  • Git 根据某一时刻暂存区(即 index 区域)所表示的状态创建并记录一个对应的树对象,如此重复便可依次记录(某个时间段内)一系列的树对象。其实树对象是对暂存区内操作的抽象,这颗树对象相对于就是快照。当我们的工作区有任何更改同步到暂存区时。便会调用 write-tree 命令通过 write-tree 命令向暂存区内容写入一个树对象。它会根据当前暂存区状态自动创建一个新的树对象。即每一次同步都产生一颗树对象。且该命令会返回一个 hash 指向树对象。在 Git 中每一个文件(数据)都对应一个 hash(类型 blob)每一个树对象都对应一个 hash(类型 tree)
  • 我们可以认为树对象就是我们项目的快照
  • 总结:
    working tree:就是你所工作在的目录,每当你在代码中进行了修改,working tree的状态就改变了。
    index file:是索引文件它是连接working tree和commit的桥梁,每当我们使用git-add命令来登记后,index file的内容就改变了,此时index file就和working tree同步了。
    ③commit:是最后的阶段,只有commit了,我们的代码才真正进入了git仓库。我们使用git-commit就是将index file里的内容提交到commit中。

Git tag详解:

  • Git tag顾名思义打标签 像其他版本控制系统(VCS)一样,Git 可以给仓库历史中的某一个提交打上标签,以示重要。比较有代表性的是人们会使用这个功能来标记发布结点( v1.0 、 v2.0 等等)。
    ①列出标签:在 Git 中列出已有的标签非常简单,只需要输入 git tag,加上-l命令可以使用通配符来过滤tag。
    ②新建tag:使用git tag命令跟上tag名字,直接创建一个tag。还可以加上-a参数来创建一个带备注的tag,备注信息由-m指定。如果你未传入-m则创建过程系统会自动为你打开编辑器让你填写备注信息。
    ③查看tag详细信息:git show命令可以查看tag的详细信息,包括commit号等。
  • tag最重要的是有git commit号,后期我们可以根据这个commit号来回溯代码。
  • 给指定的某个commit号加tag,打tag不必要在head之上,也可在之前的版本上打,这需要你知道某个提交对象的校验和(通过git log获取,取校验和的前几位数字即可)。
    ①示例:git tag -a v1.2 9fceb02 -m "my tag"
  • 将tag同步到远程服务器:同提交代码后,使用git push来推送到远程服务器一样,tag也需要进行推送才能到远端服务器。
    ①示例:使用git push origin [tagName]推送单个分支。
    ②示例:使用git push origin --tags 推送本地所有。
  • 切换到某个tag:跟分支一样,可以直接切换到某个tag去。这个时候不位于任何分支,处于游离状态,可以考虑基于这个tag创建一个分支。
  • 删除某个tag:
    ①本地删除:git tag -d
    ②远端删除:git push origin :refs/tags/
  • 链接:git打tag

git update-index详解:

  • 提交代码时,忽略某一个文件不提交,即某个文件不被版本控制
    ①git update-index --assume-unchanged [文件路径名称]
  • 恢复被忽略的文件重新被版本控制
    ①git update-index --no-assume-unchanged [文件路径名称]

总结:

  • Git知识总览(五) Git中的merge、rebase、cherry-pick以及交互式rebase

Git 基本原理

哈希:

  • 哈希:明文→加密算法→密文
  • 哈希是一个系列的加密算法,各个不同的哈希算法虽然加密强度不同,但是有以下几个共同点:
    ①不管输入数据的数据量有多大,输入同一个哈希算法,得到的加密结果长度固定。
    ②哈希算法确定,输入数据确定,输出数据能够保证不变
    ③哈希算法确定,输入数据有变化,输出数据一定有变化,而且通常变化很大
    ④哈希算法不可逆, Git 底层采用的是 SHA-1 算法。
    ⑤哈希算法可以被用来验证文件。
  • 原理如下图所示:Git和Github知识概括_第19张图片
  • Git 就是靠这种机制(哈希)来从根本上保证数据完整性的。

Git 保存版本的机制:

  • 其它大部分系统都使用集中式版本控制工具的文件管理机制,这种机制以文件变更列表的方式存储信息。这类系统将它们保存的信息看作是一组基本文件和每个文件随时间逐步累积的差异。Git和Github知识概括_第20张图片

  • Git 的文件管理机制:
    ①Git 把数据看作是小型文件系统的一组快照。
    每次提交更新时 Git 都会对当前 的全部文件制作一个快照并保存这个快照的索引。
    ③为了高效,如果文件没有修改, Git 不再重新存储该文件,而是只保留一个链接指向之前存储的文件。所以 Git 的工作方式可以称之为快照流。Git和Github知识概括_第21张图片

.git目录:

  • 链接:Git内部原理剖析
  • 当我们在某个目录下执行 git init 命令时,该目录就会成为 Git 的一个工作目录(Working
    Directory),而该目录下面的 .git 目录则是 工作目录的全部历史在 Git 内的表示 。
  • 在开始Git内部原理的探索之旅前,我们有必要认识一下 .git 目录,我们在命令行或者 GUI 界面的各种操作,本质都是操作 .git目录下的文件。现在我们通过 git init 创建一个仓库,并通过 tree 命令查看 .git 目录的结构:
$ tree .git
.git
├── HEAD
├── branches
├── config
├── description
├── hooks
│ ├── applypatch-msg.sample
│ ├── commit-msg.sample
│ ├── fsmonitor-watchman.sample
│ ├── post-update.sample
│ ├── pre-applypatch.sample
│ ├── pre-commit.sample
│ ├── pre-push.sample
│ ├── pre-rebase.sample
│ ├── pre-receive.sample
│ ├── prepare-commit-msg.sample
│ └── update.sample
├── info
│ └── exclude
├── objects
│ ├── info
│ └── pack
└── refs
    ├── heads
    └── tags
9 directories, 15 files
  • 各个目录/文件的作用如下:
    ①文件:
    <1>HEAD : 当前分支
    <2>config : 仓库级的配置信息
    <3>description : 只会被Git的网络程序(如Github)使用,无需关注
    <4>index : 暂存区(staging area)
    ②目录:
    <1>hooks : Git Hook 的示例脚本
    <2>info/exclude : 保存了一些你不想在 .gitignore 中配置的忽略文件的信息
    <3>objects : 所有工作目录的内容(content)会以 Git 对象(objects)的形式存放在这个目录
    <4>refs : 存放分支、tag的信息
    其中 objects refs 将是本文剖析的重点,也是Git的核心。

GitHub

Github简介:

  • 账号信息:
    ①GitHub 首页就是注册页面:https://github.com/
    ②Email 地址:[email protected]
    ③GitHub 账号:XXXXX
  • 创建远程库:
    ①在github个人主页上点击New repository
    ②输入仓库名(Repository name),设置仓库的属性:Public/Private,最后点击Create Repository

Github网页基本概念:

  • 仓库(Repository):仓库的意思,即你的项目,你想在Github上面开源一个项目,那就必须的创建一个Repostitory,如果你开源的项目多了,就拥有了多个Repostitory
  • 收藏(star):仓库主页的star按钮,意思为收藏该项目的人数
  • 复制克隆项目(Fork):意思就是将别人的开源项目复制一份到自己的仓库中(本质是在原有项目基础上打了一个分支),可以将复制后的仓库随心所欲的进行修改,并且丝毫不会影响原有的项目代码.
  • 发起请求(Pull Request):发起请求,这个是基于Fork的,相当于在在Fork了别人的项目之后,自己做了一些修改,想要分享给更多的人,这个时候可以把代码提交(Pull Request)给原有的项目,若原有项目经过测试或者review代码确认后,原有项目就可拥有这些新的代码了.
  • 关注(Watch):如果你关注了某个项目,那么这个项目有了变化的时候,你就会收到通知.
  • 事物卡片(issue):发现代码bug,但是没有成型代码,需要讨论时用,类似于留言板
  • 项目(projects):GitHub 上的项目板帮助您组织工作和排列工作的优先级。 您可以为特定功能工作、全面的路线图甚至发布检查列表创建项目板。 通过项目板可以灵活地创建适合需求的自定义工作流程。项目板包括议题、拉取请求和注释,在选择的列中分类为卡片。 您可以拖放或使用键盘快捷键对列中的卡片重新排序,在不同列之间移动卡片,以及更改列的顺序。
  • 持续集成(Actions) :
    ①相比较持续集成这个大概念,GitHub推出的 Actions就显得非常轻量和巧妙了。Actions就相当于持续集成中的某个特定功能的脚本,通过多个actions的自由组合,便可实现自己特定功能的持续集成服务。
    有了 GitHub Action 以后, GitHub 除了上面这些功能以外,能做的事情就更多了,比如我在 master 分支上提交了一段代码, GitHub Action 可以自动的帮我部署到我自己的服务器上去,或者它还可以帮我把代码打成镜像,将镜像自动提交到镜像仓库里。
    ③链接:你知道什么是 GitHub Action 么?
  • Github主页:帐号创建成功或者点击点击导航栏图标可进入主页,该页面主要展示用户的动态以及关注的仓库的动态,右侧展示所有的git仓库.
  • 仓库主页:仓库主页主要显示项目的信息,如:项目代码,版本,收藏/关注/fork等等各种情况.
  • 个人主页:个人信息,头像,关注我的人,我关注的人,我关注的仓库,我的开源仓库.

GitHub的几个主要功能:

  • 提供Git仓库,也就是开源代码放的地方。
  • Origanization账户,小团体开发软件很方便。
  • Issue功能,将一个任务或问题分配给一个Issue进行追踪和管理,就要修改什么,怎么修改的过程,什么时间修改的,就一目了然。
  • Wiki功能,任何人可以通过这个功能对文章进行修改保存。
    全球最大的wiki,应该就是维基百科吧,其实百度百科,csdn写博客等等也是wiki,不久前自己接触了Github wiki的编写,因此做个记录吧。
    模式一般选择Markdown,因为这个模式的功能是最多的。
  • Pull Request:开发者向 GitHub 的仓库推送更改或功能添加后,可以通过 Pull Request
    功能向别人的仓库提出申请,请求对方合并。Pull Request 送出后,目标仓库的管理者等人将能够查看 Pull Request的内容及其中包含的代码更改。
  • 链接:github详解

跨团队协作Fork:

  • 在别的仓库主页点击Fork,随后会跳出Forking XXXX,等待其复制完成即可
  • 在自己仓库详情中会显示forked fromXXX,说明for的来源。
  • Pull Request:拉取到自己远程仓库后再把它克隆下到本地,在本地修改完成后再上传到自己的远程仓库再点击New pull rquest,填写相关信息即可。
  • 被fork方的仓库的Pull request则会显示记录,被fork方审核代码通过后即可合并代码。

团队成员邀请:

  • 在仓库主页上的setting中选择Manage Access再点击Invite a collaborator。
  • 填写合作的账号,再点击add XX to this repository。随后可以Pending Invite发送链接。
  • 被邀请的人登录自己的github账号就能看到邀请消息,也可以在浏览器中访问别人复制给你的邀请链接添加。

远程库操作:

  • 创建远程库地址别名:
    ①git remote -v 查看当前所有远程地址别名
    ②git remote add [别名] [远程地址]
  • 推送:
    ①git push [别名] [分支名]
  • 克隆:
    ①git clone [远程地址]
  • 拉取:
    pull=fetch+merge
    ②git fetch [远程库地址别名] [远程分支名]
    ③git merge [远程库地址别名/远程分支名]
    ④git pull [远程库地址别名] [远程分支名]

解决冲突:

  • 要点:
    如果不是基于GitHub远程库的最新版所做的修改,不能推送,必须先拉取。因为要保证当前版本为最新,不然提交会将其他人提交的给覆盖了。
    拉取下来后如果进入冲突状态,则按照“分支冲突解决”操作解决即可。
  • 操作:
    ①解决冲突时要对import进行两者的对比。
    ②解决冲突时要对代码进行对比。
    解决代码的冲突时要注意代码符号的缺失等等细节。
    解决完冲突要去IDEA查看是否能够成功编译。
  • 类比:
    ①债权人:老王
    ②债务人:小刘
    ③老王说:10 天后归还。小刘接受,双方达成一致。
    ④老王媳妇说:5 天后归还。小刘不能接受。老王媳妇需要找老王确认后再执行

https 和 SSH 的区别:

  • 链接:Git远程仓库(Github)
  • https :
    ①可以随意克隆github上的项目,而不管是谁的。
    ②https url 在push的时候是需要验证用户名和密码的。
  • SSH:
    ①SSH则是你必须是你要克隆的项目的拥有者或管理员,且需要先添加 SSH key,否则无法克隆。
    ②SSH 在push的时候,是不需要输入用户名的,如果配置SSHkey的时候设置了密码,则需要输入密码的,否则直接是不需要输入密码的。
    SSH:需要git生成密钥对,将钥匙对配置到github或者gitee上,才能使用ssh继续操作
    ④生成密钥命令:
    <1>-t = The type of the key to generate密钥的类型
    <2>-C = comment to identify the key用于识别这个密钥的注释,所以这个注释你可以输入任何内容,很多网站和软件用这个注释作为密钥的名字,邮箱仅仅是识别用的key
一、输入命令:ssh-keygen -t rsa -C "[email protected]"
二、后面的 [email protected] 改为你在 Github 上注册的邮箱,
之后会要求确认路径和输入密码,我们这使用默认的一路回车就行。
三、成功的话会在 ~/ 下生成 .ssh 文件夹,进去,打开 id_rsa.pub,复制里面的 key。
四、回到 github 上,进入 Account => Settings(账户配置)。
五、左边选择 SSH and GPG keys,然后点击 New SSH key 按钮,title 设置标题,
可以随便填,粘贴在你电脑上生成的 key。
六、为了验证是否成功,输入以下命令:
$ ssh -T [email protected]

Github 本身提供了多种认证方式,所有开发人员可以各取所需:

  • SSH,这是最原始的方式,如果使用git bash只要按照官方文档一步一步配置就好了
    ①小心坑:SSH有可能需要配置代理,否则无法解析服务器域名。错误如下:
    ②ssh: Could not resolve hostname github.com: no address associated with name
    ③解决办法:给SSH以及git 客户端配置代理。
  • HTTPS,这也是比较方便的方式,但是每一次都需要输入用户名和密码。
    ①小心坑:本机的SSL证书不是正规机构颁发的,验证失败。错误如下:
    ②fatal: unable to access ‘https://github.com/owner/repo.git/’: SSL certificate problem: unable to get local issuer certificate
    ③解决办法:将Git的SSL验证关闭,命令如下: git config --global http.sslVerify false
    ④链接:SSH 秘钥Key的简介以及生成和使用
  • Access Token,我个人认为最为便捷的方式之一,不失安全性。
    ①链接:生成token教程
    ②使用方法:
    <1>从Settings页面生成唯一的Token
    <2> 手动拼接出远程仓库的地址,比如:https://[email protected]/owner/repo.git
    <3>从以上地址克隆或使用git remote add 的方式关联本地仓库,之后都不需要输入用户名和密码信息。

github总结:

  • github的一个仓库对应一个IDEA中的Project。
  • github仓库中的各个文件夹和文件对应IDEA中的Project中的module和配置文件。
  • github仓库中的文件有多个分支。

Eclipse,Idea 操作

Eclipse操作:

  • Eclipse工程初始化为本地库:工程→右键→Team→Share Project→Git
  • 克隆工程操作:
    ①Import…导入工程
    ②到远程库复制工程地址
    ③指定工程的保存位置
    ④指定工程导入方式,这里只能用:Import as general project
    ⑤转换工程类型

Eclipse 中忽略文件:

  • 概念:Eclipse 特定文件
  • 这些都是 Eclipse 为了管理我们创建的工程而维护的文件,和开发的代码没有 直接关系。最好不要在 Git中进行追踪,也就是把它们忽略。
    ① .classpath 文件
    ② .project 文件
    ③ .settings 目录下所有文件
  • 为什么要忽略 Eclipse 特定文件呢?
    同一个团队中很难保证大家使用相同的 IDE 工具,而 IDE 工具不同时,相关工 程特定文件就有可能不同。如果这些文件加入版本控制,那么开发时很可能需要为 了这些文件解决冲突。
  • 编辑本地忽略配置文件,文件名任意,在~/.gitconfig 文件中引入上述文件

idea中.ignore的配置:

  • 编写.gitignore文件,并直接复制到idea项目目录下即可,不需要安装插件。满足几乎全部git提交过滤需求
# 以'#'开始的行,被视为注释.                                                                                                                          

# 忽略掉所有文件名是 foo.txt的文件.

foo.txt

# 忽略所有生成的 html文件,

*.html

# foo.html是手工维护的,所以例外.

!foo.html

# 忽略所有.o和 .a文件.

*.[oa]
配置语法:
以斜杠“/”开头表示目录;
以星号“*”通配多个字符;
以问号“?”通配单个字符
以方括号“[]”包含单个字符的匹配列表;
以叹号“!”表示不忽略(跟踪)匹配到的文件或目录;

idea中.ignore插件:

  • 在Plguins中安装插件名为.ignore的插件
  • 步骤:
    ①在项目上右键->New ->.ignore file ->.gitignore file(Git)
    ②先选择Example user template好了,以后有什么想过滤的可以自行添加,最后点击Generate生成
    ③然后就会发现被忽略的文件名变成了灰色。
    ④也可以右键文件将其加入忽略的名单中。
  • 注意:
    .gitignore只能忽略那些原来没有被track(没被加入索引,没被跟踪)的文件,如果某些文件已经被纳入了版本管理中,则修改.gitignore是无效的。那么解决方法就是先把本地缓存删除(改变成未track状态),然后再提交。
    git rm file_path --cached :表示只删除暂存区和远程分支上(要push)的文件,但本地的保留,此时ignore生效,这些本地文件就会git忽略了。

idea分支操作:

  • 右键根项目点击git,再点击branches。
  • 再点击对应的分支,最后点击checkout即可切换。
  • 注意:
    一般来说一个项目down到本地只需一套代码,切换分支时再点击切换。而不是多个分支对应多个代码。
    因为每个分支之间差异不大,若是每个分支对应一套,这样是不行的。
    github多个分支复制出来属于同一个地址。
    ④Idea右下角有对应得分支操作:
    Git和Github知识概括_第22张图片

Idea中的smart Checkout跟force checkout的区别:

  • 这是因为在某个分支修改了代码,但是没有commit,所以在切换到其他分支的时候回弹出这个窗口。
    Git和Github知识概括_第23张图片

  • smart checkout就会把冲突的这部分内容带到目的分支(如果你没有点进窗口的那些文件处理冲突的话)

  • force checkout就不会把冲突的这部分内容带到目的分支,但是你在当前分支修改的所有内容就会被删除,就算你再切回来也找不到了,所以需要慎重哦

  • don`t checkout 当然是不切分支,继续留在当前分支了

Idea的upadte project:

  • Update Type选项:
    ①Merge(合并)(对应远程master分支):
    <1>采用合并的方式来更新代码,此时会产生一个commit,这也是一般常用的默认的操作,这个的好处是能够在log中看到所有的操作记录,但是对于代码洁癖来说,可能会无法接受。
    <2>结果等同于执行git pull(git fetch + git merge)
    ②Rebase(重定)(对应远程master分支):
    <1>就是所有的本地commit都是默认放到远程的commit记录的顶部,log也只会有一条记录线,简洁,但是有时候排查问题会不方便。
    <2>结果等同于执行git pull --rebase(git fetch + git rebase)
    ③Brance Default(对应本地设置的默认远程分支):
    <1>每个分支都可以设置自己的update方式,可以在config中设置,这个是选择分支默认的方式。
    <2>此选项用于选择应用分支的默认命令,default branch在.git/config配置文件中指定
  • Clean working tree before update(更新前清洁工作树)
    ①Using Stash 默认这个即可(使用储备)
    ②Using Shelve:使用搁置

idea 的git merge详情:

  • git merge时主要分为两部分:
    ①代码部分
    ②依赖部分
  • 这两部分都要仔细对比左右两边,不能随意修改。
    ①代码部分固然不用说,涉及功能。
    ②依赖部分则涉及编译问题。

idea中安装git以后的颜色::

  • 代码文件出现了不同的颜色分别表示的含义:
    绿色,已经加入控制暂未提交
    红色,未加入版本控制
    ③蓝色,加入,已提交,有改动
    ④白色,加入,已提交,无改动
    灰色:版本控制已忽略文件。

Git 工作流

Git 工作流简介:

  • 概念:在项目开发过程中使用 Git 的方式
  • 分类:
    集中式工作流:像 SVN 一样,集中式工作流以中央仓库作为项目所有修改的单点实体。所有修改都提交到Master 这个分支上。 这种方式与 SVN 的主要区别就是开发人员有本地库。Git 很多特性并没有用到。Git和Github知识概括_第24张图片
    GitFlow 工作流:Gitflow 工作流通过为功能开发、发布准备和维护设立了独立的分支,让发布 迭代过程更流畅。严格的分支模型也为大型项目提供了一些非常必要的结构。Git和Github知识概括_第25张图片
    Forking工作流:Forking 工作流是在 GitFlow 基础上,充分利用了 Git 的 Fork 和 pull request 的 功能以达到代码审核的目的。更适合安全可靠地管理大团队的开发者,而且能接受不信任贡献者的提交。Git和Github知识概括_第26张图片

GitFlow 工作流详解:

  • 分支种类:
    主干分支 master:主要负责管理正在运行的生产环境代码。永远保持与正在运行的生产环境完全一致。
    开发分支 develop:主要负责管理正在开发过程中的代码。一般情况下应该是最新的代码。
    bug 修理分支 hotfix :主要负责管理生产环境下出现的紧急修复的代码。 从主干分支分出,修 理完毕并测试上线后,并回主干分支。并回后,视情况可以删除该分支。
    准生产分支(预发布分支) release:较大的版本上线前,会从开发分支中分出准生产分支,进行最后阶段的集 成测试。该版本上线后,会合并到主干分支。生产环境运行一段阶段较稳定后 可以视情况删除。
    功能分支 feature:为了不影响较短周期的开发工作,一般把中长期开发模块,会从开发分支 中独立出来。 开发完成后会合并到开发分支。
  • GitFlow 工作流举例:
    Git和Github知识概括_第27张图片
  • 分支实战:
    Git和Github知识概括_第28张图片

Gitlab 服务器搭建过程

官网地址:

  • 首页:https://about.gitlab.com/
  • 安装说明:https://about.gitlab.com/installation/

安装命令摘录:

sudo yum install -y curl policycoreutils-python openssh-server cronie
sudo lokkit -s http -s ssh 
sudo yum install postfix 
sudo service postfix start 
sudo chkconfig postfix on 
curl https://packages.gitlab.com/install/repositories/gitlab/gitlab-ee/script.rpm.sh | sudo bash 
sudo EXTERNAL_URL="http://gitlab.example.com" yum -y install gitlab-ee
  • 实际问题:yum 安装 gitlab-ee(或 ce)时,需要联网下载几百 M 的安装文件,非常耗 时,所以应提前把所需 RPM包下载并安装好。
  • 下载地址为:
    https://packages.gitlab.com/gitlab/gitlab-ce/packages/el/7/gitlab-ce-10.8.2-ce.0.el7.x86_64.rpm

调整后的安装过程:

sudo rpm -ivh /opt/gitlab-ce-10.8.2-ce.0.el7.x86_64.rpm 
sudo yum install -y curl policycoreutils-python openssh-server cronie 
sudo lokkit -s http -s ssh 
sudo yum install postfix 
sudo service postfix start 
sudo chkconfig postfix on 
curl https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.rpm.sh | sudo bash 
sudo EXTERNAL_URL="http://gitlab.example.com" yum -y install gitlab-ce
  • 当前步骤完成后重启。

gitlab 服务操作:

  • 初始化配置
    gitlab gitlab-ctl reconfigure
  • 启动 gitlab 服务
    gitlab-ctl start
  • 停止 gitlab 服务
    gitlab-ctl stop

浏览器访问 :

  • 访问 Linux 服务器 IP 地址即可,如果想访问 EXTERNAL_URL 指定的域名还需要配置 域名服务器或本地 hosts 文件。

  • 初次登录时需要为 gitlab 的 root 用户设置密码。

总结

总结:

  • github两大操作:
    ①fork与pull request
    ②Invite a collaborator
  • Git 常用命令大全:

注意:

  • 若该仓库团队中没有邀请你,你clone下来后提交会报错显示你没有权限。
  • 关于Git暂存区的理解:
    ①所谓的暂存区只是一个简单的索引文件而已。
    ②暂存区这个索引文件里面包含的是文件的目录树,像一个虚拟的工作区,在这个虚拟工作区的目录树中,记录了文件名、文件的时间戳、文件长度、文件类型以及最重要的SHA-1值,文件的内容并没有存储在其中,所以说 它像一个虚拟的工作区。
    索引指向的是.Git/objects下的文件。
    暂存区的作用:除非是绕过暂存区直接提交,否则Git想把修改提交上去,就必须将修改存入暂存区最后才能commit。每次提交的是暂存区所对应的文件快照。
  • SVN的提交是原子性的,但在SVN命令行下面选择要提交的修改是挺麻烦的一个事情,但在GIT中我们只需要在commit前面,发明一个暂存区的概念就好了,这个暂存区是可以随意的将各种文件的修改放进去的,这样我们就可以用多个指令精确的挑选出我们需要提交的所有修改,然后再一次性的(原子性的)提交到版本库,问题就完美的解决了。
  • 这个先 commit 再 pull 最后再push 的情况就是为了应对多人合并开发的情况:
    commit 是为了告诉 git 我这次提交改了哪些东西,不然你只是改了但是 git 不知道你改了,也就无从判断比较;
    pull是为了本地 commit 和远程commit 的对比记录,git 是按照文件的行数操作进行对比的,如果同时操作了某文件的同一行那么就会产生冲突,git 也会把这个冲突给标记出来,这个时候就需要先把和你冲突的那个人拉过来问问保留谁的代码,然后在 git add && git commit && git pull 这三连,再次 pull 一次是为了防止再你们协商的时候另一个人给又提交了一版东西,如果真发生了那流程重复一遍,通常没有冲突的时候就直接给你合并了,不会把你的代码给覆盖掉
    ③出现代码覆盖或者丢失的情况:比如A B两人的代码pull 时候的版本都是1,A在本地提交了2,3并且推送到远程了,B 进行修改的时候没有commit 操作,他先自己写了东西,然后 git pull 这个时候 B 本地版本已经到3了,B 在本地版本3的时候改了 A 写过的代码,再进行了git commit && git push 那么在远程版本中就是4,而且 A 的代码被覆盖了,所以说所有人都要先 commit 再 pull,不然真的会覆盖代码的
  • 与svn的差异:
    git clone更像是一个类似于svn checkout而不是 git checkout。git checkout只是检查你的本地存储库中的分支或提交,git clone生成远程存储库的新副本。
  • 远程分支与本地分支:
    ①远程分支其实就是远程代码仓库当中的分支,比如我们的repo如果是存在github的,那么这个远程仓库就是github,如果是存在gitlab的,那么这个仓库就是gitlab,如果是其他的仓库也是一样的道理。
    当我们在使用git clone的时候,git会自动地将这个远程的repo命名为origin,拉取它所有的数据之后,创建一个指向它master的指针,命名为origin/master,之后会在本地创建一个指向同样位置的指针,命名为master,和远程的master作为区分。
    也就是说,origin的含义指的是远程的仓库。它只是一个标记,就和默认分支叫做master一样,本身并没有特别的含义。如果我们愿意也可以起其他的名字,但是一般没有人这么干。比如我们在clone的时候可以添加一个参数-o给远程的repo起一个别名:git clone -o chengzhi
    ④这样一来,远程的这个repo就会被命名为chengzhi,代替原本的origin。但是这样除了装逼和增加成本之外,没有任何用处,不推荐这么干。
    HEAD :当前活跃分支的游标,可以用 checkout 命令改变 HEAD 指向的位置。形象的记忆就是:你现在在哪儿,HEAD 就指向哪儿,所以 Git 才知道你在那儿!
  • 关于本地库与远程库:工作区<—git init—> 本地库 <—git remote—>远程库
  • git初始化与克隆(git init 与 git clone):
    在现存的目录下,通过导入所有文件来创建新的 Git 仓库,此为 git 初始化,需要 git init 命令。并使用 git remote 创建和同步远端仓库。
    从已有的 Git 仓库克隆出一个新的镜像仓库来,此为 git 克隆,需要 git clone 命令。也就是从原本已经存在的远端仓库中,下载和创建为本地仓库。
    ③链接:git初始化与克隆(git init 与 git clone)
    此外若直接从github下载项目的压缩文件,它的git文件中是已经配置好信息的了。
  • 使用git将本地仓库上传到远程仓库:
    ①创建一个工程目录
    ②执行git init
    ③把文件添加到版本库中,使用命令 git add .添加到暂存区里面去,不要忘记后面的小数点“.”,意为添加文件夹下的所有文件
    ④git commit告诉Git,把文件提交到仓库。引号内为提交说明,git commit -m ‘这是第一次提交’
    ⑤关联到远程库:git remote add origin 你的远程库地址
    ⑥获取远程库与本地同步合并(如果远程库不为空必须做这一步,否则后面的提交会失败):git pull --rebase origin master
    ⑦把本地库的内容推送到远程,使用 git push命令,实际上是把当前分支master推送到远程。执行此命令后会要求输入用户名、密码,验证通过后即开始上传。
  • git本地分支和远程分支如何关联:
    ①其实在从远程分支分出来的分支都是跟踪分支(track),当对该分支进行push和pull时,如果该分支和远程分支同名git会知道推送到远程哪个分支,从哪个远程分支同步到本地分支。其实每次克隆一个仓库时,本地新建一个master分支来track远程origin/master。如果不同名,我们需要人为指定git push origin branch_name
    ②如果本地新建了一个分支branch_name,但是在远程没有,这时候push和pull指令就无法确定该跟踪谁,一般来说我们都会使其跟踪远程同名分支,所以可以利用git push --set-upstream origin branch_name这样就可以自动在远程创建一个branch_name分支,然后本地分支会track该分支。后面再对该分支使用push和pull就自动同步。无需再指定分支。
    ③跟踪远程分支
    1)如果远程新建了一个分支,本地没有该分支,可以用git checkout --track origin/branch_name,这时候本地会新建一个分支名叫branch_name,会自动跟踪远程的同名分支branch_name。
    2)用上面中方法,得到的分支名永远和远程的分支名一样,如果想新建一个本地分支不同名字,同时跟踪一个远程分支可以利用。
    git checkout -b new_branch_name branch_name,这条指令本来是根据一个branch_name分支分出一个本地分支new_branch_name,但是如果所根据的分支branch_name是一个远程分支名,那么本地的分支会自动的track远程分支。建议跟踪分支和被跟踪远程分支同名。
    ④总结:一般我们就用git push --set-upstream origin branch_name来在远程创建一个与本地branch_name同名的分支并跟踪;利用git checkout --track origin/branch_name来在本地创建一个与branch_name同名分支跟踪远程分支。
  • git clone 和git branch详解:
    ①git clone默认会把远程仓库整个给clone下来,但只会在本地默认创建一个master分支,如果远程还有其他的分支,此时用git branch -a查看所有分支。可以使用checkout命令来把远程分支取到本地,并自动建立tracking。
    ②查看分支 git branch [-r | -a]:
    1.git branch查看本地所有分支
    2.git branch -r查看远程所有分支
    3.git branch -a查看本地和远程所有分支
  • 新建远程分支:
    ①新建一个本地分支:git checkout -b XXX
    ②查看一下现在的分支状态:git branch
    创建远程分支并关联:git branch --set-upstream-to=origin/XXX
    把新建的本地分支push到远程服务器,远程分支与本地分支同名(当然可以随意起名):git push origin XXX:XXX

总结:

  • 链接:工作中Git使用实践和常用命令流程合集

你可能感兴趣的:(构建与版本控制工具,git)