版本控制工具应该具备的功能:
版本控制简介:
集中式版本控制工具: CVS、SVN、VSS……
分布式版本控制工具: Git、Mercurial、Bazaar、Darcs……
Git 安装:
第一步安装到一个非中文没有空格的目录下
第二步建议使用VIM编辑器(Use Vim)
第三步完全不修改PATH环境变量,仅在Git Bash中使用Git(Use Git from Git Bash only)
Git 和代码托管中心:
本地库和远程库:
Git 工作区、暂存区和版本库:
一般存放在 .git 目录下的 index文件(.git/index)中,所以我们把暂存区有时也叫作索引(index)。
工作区有一个隐藏目录 .git,这个不算工作区,而是 Git 的版本库。
简述:
.开头的文件表示隐藏文件
,.git 目录中存放的是本地库相关的子目录和文件,不要删除,也不要胡乱修改。
Git 创建仓库:
git init:
git clone:
git clone
git clone
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 config -e # 针对当前仓库
或者:
$ git config -e --global # 针对系统上所有仓库
注意:
<1>这里设置的签名(名字和邮箱)和登录远程库(代码托管中心)的账号、密码没有任何关系。
不涉及登录操作。
$ git config --global user.name "runoob"
$ git config --global user.email [email protected]
如果去掉 --global 参数只对当前仓库有效。
Git设置默认的push分支:
git为我们提供了这个功能,就是直接设置默认的推送branch为current。
再用下面的命令查看我们设置的值git config –global push.default
Git 基本操作:
命令 | 说明 |
---|---|
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 标签:
~ 与 ^ 的关系:
~ 用来表示一个提交的第 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 reset完一定要提交远程,不然本地会混乱。
git revert -n 目标版本号
git revert和git reset的区别是什么?
从内容上来看,这两种做法是一样的;但从commit的历史来看,是不同的
Git commit和Git stash的区别:
git在一个分支上修改了代码必须要commit到本地git库,才可以切换一个分支去修改代码。
git stash
。stash命令可用于临时保存和回复修改,可跨分支。
注:在未add之前才能执行stash!!!!
修该完后可再使用Unstash,选中你刚刚的stash,选中Pop stash。点击pop stash即可。
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:
图中的一个个小圆点即为该仓库的某个历史状态变更。
分支是一个指向叶子节点的指针,每个节点都是一个历史状态变更。叶子节点可以理解为最新的历史状态变更。
一个分支包括多个历史状态变更(节点),可以在本分支的各个历史状态变更(节点)中穿梭。
在只有一种分支的情况下,有多少个本地仓库,就有可能衍生出多少条支线。
每条颜色的支线不会固定代表某个分支,不同颜色的线可能代表同一个分支。
在最早提交和最近提交这条线中的每一个comit点分叉出去的都会产生支线。
git图谱中分支名称若包括origin则是提交到了远程库,若无则单纯提交。此外若无分支名称,则沿用上个提交节点的分支。
Git状态跟踪与移除:
使用命令 git add 开始跟踪文件README,则该文件会纳入索引文件。
当文件修改时会与索引文件对比,若不同则会显示为未提交。
可以用 git rm 命令完成此项工作
,并连带从工作目录中删除指定的文件,这样以后就不会出现在未跟踪文件清单中了。git rebase命令:
在项目中使用rebase的原则:不要修改已经提交到公共仓库中的commit。
feature分支
rebase master分支
之后,feature分支上的提交记录会改变:git cherry-pick:
命令:git 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 pull 和git fetch区别:
这个命令将某个远程主机的更新全部取回本地仓库
git fetch //从远程主机的选定的分支拉取最新内容
git merge FETCH_HEAD //将拉取下来的最新内容合并到当前所在的分支中
这样使用一次后idea会自动建立选中分支的远程跟踪分支,以后可直接点击Update Project,不需要再选分支,除非要拉取另一分支。
git push详解:
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 rm 和 rm详解:
工作树(working tree), 树对象(index file):
其实树对象是对暂存区内操作的抽象,这颗树对象相对于就是快照。当我们的工作区有任何更改同步到暂存区时。
便会调用 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同步了。Git tag详解:
Git tag顾名思义打标签 像其他版本控制系统(VCS)一样,Git 可以给仓库历史中的某一个提交打上标签,以示重要。比较有代表性的是人们会使用这个功能来标记发布结点( v1.0 、 v2.0 等等)。
tag最重要的是有git commit号,后期我们可以根据这个commit号来回溯代码。
git tag -a v1.2 9fceb02 -m "my tag"
git update-index详解:
总结:
哈希:
Git 就是靠这种机制(哈希)来从根本上保证数据完整性的。
Git 保存版本的机制:
其它大部分系统都使用集中式版本控制工具的文件管理机制
,这种机制以文件变更列表的方式存储信息。这类系统将它们保存的信息看作是一组基本文件和每个文件随时间逐步累积的差异。
Git 的文件管理机制:
①Git 把数据看作是小型文件系统的一组快照。
②每次提交更新时 Git 都会对当前 的全部文件制作一个快照并保存这个快照的索引。
③为了高效,如果文件没有修改, Git 不再重新存储该文件,而是只保留一个链接指向之前存储的文件。所以 Git 的工作方式可以称之为快照流。
.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
其中 objects refs 将是本文剖析的重点,也是Git的核心。
Github简介:
账号信息:
创建远程库:
Github网页基本概念:
发起请求(Pull Request):发起请求,这个是基于Fork的,相当于在在Fork了别人的项目之后,自己做了一些修改,想要分享给更多的人,这个时候可以把代码提交(Pull Request)给原有的项目,若原有项目经过测试或者review代码确认后,原有项目就可拥有这些新的代码了.
事物卡片(issue):发现代码bug,但是没有成型代码,需要讨论时用,类似于留言板
有了 GitHub Action 以后, GitHub 除了上面这些功能以外,能做的事情就更多了,比如我在 master 分支上提交了一段代码, GitHub Action 可以自动的帮我部署到我自己的服务器上去,或者它还可以帮我把代码打成镜像,将镜像自动提交到镜像仓库里。
GitHub的几个主要功能:
全球最大的wiki,应该就是维基百科吧,其实百度百科,csdn写博客等等也是wiki,不久前自己接触了Github wiki的编写,因此做个记录吧。
模式一般选择Markdown,因为这个模式的功能是最多的。
跨团队协作Fork:
Pull Request:拉取到自己远程仓库后再把它克隆下到本地,在本地修改完成后再上传到自己的远程仓库再点击New pull rquest,填写相关信息即可。
被fork方的仓库的Pull request则会显示记录,被fork方审核代码通过后即可合并代码。
团队成员邀请:
远程库操作:
pull=fetch+merge
解决冲突:
如果不是基于GitHub远程库的最新版所做的修改,不能推送,必须先拉取。
(因为要保证当前版本为最新,不然提交会将其他人提交的给覆盖了。)拉取下来后如果进入冲突状态,则按照“分支冲突解决”操作解决即可。
解决代码的冲突时要注意代码符号的缺失等等细节。
解决完冲突要去IDEA查看是否能够成功编译。
https 和 SSH 的区别:
SSH:需要git生成密钥对,将钥匙对配置到github或者gitee上,才能使用ssh继续操作
一、输入命令: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只要按照官方文档一步一步配置就好了HTTPS
,这也是比较方便的方式,但是每一次都需要输入用户名和密码。Access Token
,我个人认为最为便捷的方式之一,不失安全性。github总结:
github的一个仓库对应一个IDEA中的Project。
github仓库中的各个文件夹和文件对应IDEA中的Project中的module和配置文件。
github仓库中的文件有多个分支。
Eclipse操作:
Eclipse 中忽略文件:
idea中.ignore的配置:
编写.gitignore文件,并直接复制到idea项目目录下即可,不需要安装插件。满足几乎全部git提交过滤需求
# 以'#'开始的行,被视为注释.
# 忽略掉所有文件名是 foo.txt的文件.
foo.txt
# 忽略所有生成的 html文件,
*.html
# foo.html是手工维护的,所以例外.
!foo.html
# 忽略所有.o和 .a文件.
*.[oa]
配置语法:
以斜杠“/”开头表示目录;
以星号“*”通配多个字符;
以问号“?”通配单个字符
以方括号“[]”包含单个字符的匹配列表;
以叹号“!”表示不忽略(跟踪)匹配到的文件或目录;
idea中.ignore插件:
.gitignore只能忽略那些原来没有被track(没被加入索引,没被跟踪)的文件,如果某些文件已经被纳入了版本管理中,则修改.gitignore是无效的。那么解决方法就是先把本地缓存删除(改变成未track状态),然后再提交。
git rm file_path --cached :表示只删除暂存区和远程分支上(要push)的文件,但本地的保留,此时ignore生效,这些本地文件就会git忽略了。
idea分支操作:
一般来说一个项目down到本地只需一套代码,切换分支时再点击切换。而不是多个分支对应多个代码。
因为每个分支之间差异不大,若是每个分支对应一套,这样是不行的。
github多个分支复制出来属于同一个地址。
Idea中的smart Checkout跟force checkout的区别:
smart checkout就会把冲突的这部分内容带到目的分支(如果你没有点进窗口的那些文件处理冲突的话)
force checkout就不会把冲突的这部分内容带到目的分支,但是你在当前分支修改的所有内容就会被删除,就算你再切回来也找不到了,所以需要慎重哦
don`t checkout 当然是不切分支,继续留在当前分支了
Idea的upadte project:
对应远程master分支
):对应远程master分支
):对应本地设置的默认远程分支
):idea 的git merge详情:
idea中安装git以后的颜色::
绿色,已经加入控制暂未提交
红色,未加入版本控制
灰色:版本控制已忽略文件。
Git 工作流简介:
集中式工作流:
像 SVN 一样,集中式工作流以中央仓库作为项目所有修改的单点实体。所有修改都提交到Master 这个分支上。 这种方式与 SVN 的主要区别就是开发人员有本地库。Git 很多特性并没有用到。GitFlow 工作流:
Gitflow 工作流通过为功能开发、发布准备和维护设立了独立的分支,让发布 迭代过程更流畅。严格的分支模型也为大型项目提供了一些非常必要的结构。Forking工作流:
Forking 工作流是在 GitFlow 基础上,充分利用了 Git 的 Fork 和 pull request 的 功能以达到代码审核的目的。更适合安全可靠地管理大团队的开发者,而且能接受不信任贡献者的提交。GitFlow 工作流详解:
主干分支 master:
主要负责管理正在运行的生产环境代码。永远保持与正在运行的生产环境完全一致。开发分支 develop:
主要负责管理正在开发过程中的代码。一般情况下应该是最新的代码。bug 修理分支 hotfix :
主要负责管理生产环境下出现的紧急修复的代码。 从主干分支分出,修 理完毕并测试上线后,并回主干分支。并回后,视情况可以删除该分支。准生产分支(预发布分支) release:
较大的版本上线前,会从开发分支中分出准生产分支,进行最后阶段的集 成测试。该版本上线后,会合并到主干分支。生产环境运行一段阶段较稳定后 可以视情况删除。功能分支 feature:
为了不影响较短周期的开发工作,一般把中长期开发模块,会从开发分支 中独立出来。 开发完成后会合并到开发分支。官网地址:
安装命令摘录:
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
调整后的安装过程:
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 服务操作:
浏览器访问 :
访问 Linux 服务器 IP 地址即可,如果想访问 EXTERNAL_URL 指定的域名还需要配置 域名服务器或本地 hosts 文件。
初次登录时需要为 gitlab 的 root 用户设置密码。
总结:
注意:
若该仓库团队中没有邀请你,你clone下来后提交会报错显示你没有权限。
文件的内容并没有存储在其中,所以说 它像一个虚拟的工作区。
索引指向的是.Git/objects下的文件。
暂存区的作用:除非是绕过暂存区直接提交,否则Git想把修改提交上去,就必须将修改存入暂存区最后才能commit。每次提交的是暂存区所对应的文件快照。
commit 是为了告诉 git 我这次提交改了哪些东西,不然你只是改了但是 git 不知道你改了,也就无从判断比较;
pull是为了本地 commit 和远程commit 的对比记录,git 是按照文件的行数操作进行对比的
,如果同时操作了某文件的同一行那么就会产生冲突,git 也会把这个冲突给标记出来,这个时候就需要先把和你冲突的那个人拉过来问问保留谁的代码,然后在 git add && git commit && git pull 这三连,再次 pull 一次是为了防止再你们协商的时候另一个人给又提交了一版东西,如果真发生了那流程重复一遍,通常没有冲突的时候就直接给你合并了,不会把你的代码给覆盖掉git clone更像是一个类似于svn checkout而不是 git checkout。git checkout只是检查你的本地存储库中的分支或提交,git clone生成远程存储库的新副本。
当我们在使用git clone的时候,git会自动地将这个远程的repo命名为origin,拉取它所有的数据之后,创建一个指向它master的指针,命名为origin/master,之后会在本地创建一个指向同样位置的指针,命名为master,和远程的master作为区分。
也就是说,origin的含义指的是远程的仓库。它只是一个标记
,就和默认分支叫做master一样,本身并没有特别的含义。如果我们愿意也可以起其他的名字,但是一般没有人这么干。比如我们在clone的时候可以添加一个参数-o给远程的repo起一个别名:git clone -o chengzhiHEAD :当前活跃分支的游标,可以用 checkout 命令改变 HEAD 指向的位置。形象的记忆就是:你现在在哪儿,HEAD 就指向哪儿,所以 Git 才知道你在那儿!
工作区<—git init—> 本地库 <—git remote—>远程库
在现存的目录下,通过导入所有文件来创建新的 Git 仓库,此为 git 初始化,需要 git init 命令。并使用 git remote 创建和同步远端仓库。
从已有的 Git 仓库克隆出一个新的镜像仓库来,此为 git 克隆,需要 git clone 命令。也就是从原本已经存在的远端仓库中,下载和创建为本地仓库。
此外若直接从github下载项目的压缩文件,它的git文件中是已经配置好信息的了。
git init
git add .
添加到暂存区里面去,不要忘记后面的小数点“.”,意为添加文件夹下的所有文件git commit -m ‘这是第一次提交’
git remote add origin 你的远程库地址
git pull --rebase origin master
git push
命令,实际上是把当前分支master推送到远程。执行此命令后会要求输入用户名、密码,验证通过后即开始上传。git push --set-upstream origin branch_name
,这样就可以自动在远程创建一个branch_name分支,然后本地分支会track该分支。后面再对该分支使用push和pull就自动同步。无需再指定分支。
如果远程新建了一个分支,本地没有该分支
,可以用git checkout --track origin/branch_name
,这时候本地会新建一个分支名叫branch_name,会自动跟踪远程的同名分支branch_name。一般我们就用git push --set-upstream origin branch_name来在远程创建一个与本地branch_name同名的分支并跟踪;利用git checkout --track origin/branch_name来在本地创建一个与branch_name同名分支跟踪远程分支。
可以使用checkout命令来把远程分支取到本地,并自动建立tracking。
git branch查看本地所有分支
git branch -r查看远程所有分支
git branch -a查看本地和远程所有分支
创建远程分支并关联:git branch --set-upstream-to=origin/XXX
把新建的本地分支push到远程服务器,远程分支与本地分支同名(当然可以随意起名):git push origin XXX:XXX
总结: