深入浅出Git(偏向理论)

一.理论概述

还记得之前不太熟悉Git时候,看到很多人都用这个,去百度了下,想知道这到底是个什么程序.大部分文章都在说是如何如何厉害的一个版本控制系统,说法未免太过于笼统

1. 什么是Git

程序员开发一个项目时,本地只有几十行代码或几百行代码,自己还可以有精力维护,但是代码数量太多或者多人同时开发一个项目,很容易出现代码的混乱,冲突,项目出问题也无法确认责任人.维护项目成本也变大.所以,就需要用到一个专业的版本控制系统,这样或许会容易理解好多.

版本控制是一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统。是的,我们就是可以这么理解,它就是这么的简单.

版本控制系统分类

版本控制系统 优点 缺点 特点
本地版本控制 简单,便捷 人为手动操作,出错性高 *
集中化的版本控制系统 集中管理代码 数据整体冗余性较差 代码集中存储在一台服务器上
分布式版本控制系统 几乎不用担心因为服务器故障而造成代码丢失 ? 每一个客户端都会把代码仓库完整地进项克隆下来,然后在进行修改

而Git就是一个开源的分布式版本控制系统,用来高效处理各种项目的版本管理.

一个原始的Git版本仓库,可以让其他主机克隆这个原始版本仓库,从而使得一个Git版本仓库可以同时分不到不同主机上,并且版本库一致

所以在Git中并不存在主库这样的概念,每份复制出去的库都可以独立使用,任何两个库之间的不一致之处都可以进行合并

2. GitLab和GitHub是什么

这两孪生兄弟到底是什么,又有什么区别呢?

先说一下相同点,二者都是基于web的Git仓库,在很大程度上GitLab是仿照GitHub来做的,它们都提供了分享开源项目的平台,为开发团队提供了存储、分享、发布和合作开发项目的中心化云存储的场所。

区别是:

在GitHub上的代码对于外界都是公开的,要想使用私有仓库是需要付费的.

​ 但是被微软给收购后提供了私有仓库,当然:条件就是,免费私有仓库最多只能添加三个协同操作者,这也就意味着适合小团队的项目协同管理。不过这已经很好了,毕竟这在以前可是为付费的用户和企业提供创建私有不公开的仓库,进行代码管理的。普通用户只能免费创建公开仓库,以致于一些私有代码无法通过 GitHub 来进行管理。

GitLab让开发团队对他们的代码仓库拥有更多的控制,相比于GitHub,它有不少的特色:允许免费设置仓库权限;允许用户选择分享一个project的部分代码;允许用户设置project的获取权限,进一步的提升安全性;可以设置获取到团队整体的改进进度;通过innersourcing让不在权限范围内的人访问不到该资源。

从代码私有性方面来看,有时公司并不希望员工获取到全部的代码,这个时候GitLab无疑是更好的选择。但对于开源项目而言,GitHub依然是代码托管的首选。

3.Git功能

  1. 从服务器上克隆数据库到本机;
  2. 在本机上自己创建的分支上提交代码
  3. 在本机上合并分支
  4. 新建一个分支,把服务器上最新版的代码fetch下来,跟自己的主分支合并
  5. 代码冲突解决,开发者之间使用pull命令解决冲突,解决完之后再向主开发者提交补丁

接下来根据配置命令以便于更好的理解它是如何工作的

二.结合具体命令了解其工作

像这三个仓库,使用几乎没什么差别,本案例主要以Git为例,辅助其它两种,对这三种进行相对透彻的理解

1.环境

主机名 ip 角色
gitremo 192.168.111.3 Git远程仓库
git 192.168.111.4 Git本地仓库

2.部署

Git仓库的使用

centos7系列默认自带Git,但版本比较老,这里我们配置epel源,使用yum安装

[root@git ~]# yum -y install git
[root@git ~]# git version
git version 1.8.3.1

配置个人的用户名称和电子邮件地址:

[root@git ~]# git config --global user.name "joinbest"
[root@git ~]# git config --global user.email "joinbestbest@163.com"
[root@git ~]# git config --global color.ui true
#语法高亮
[root@git ~]# cat .gitconfig 
[user]
	name = joinbest
	email = joinbestbest@163.com
[color]
	ui = true

在另一台机器创建git的仓库

[root@gitremo ~]# mkdir /git_data
[root@gitremo ~]# useradd git
[root@gitremo ~]# echo "123456" | passwd --stdin git
更改用户 git 的密码 。
passwd:所有的身份验证令牌已经成功更新。
[root@gitremo ~]# chown -Rf git:git /git_data/

初始化一个git仓库

[root@gitremo ~]# cd /git_data/
[root@gitremo git_data]# ls
[root@gitremo git_data]# git --bare init
初始化空的 Git 版本库于 /git_data/
[root@gitremo git_data]# ls
branches  config  description  HEAD  hooks  info  objects  refs

将111.4机器上的公钥上传到111.3,因为111.4机器会clone111.3上的git仓库

[root@git ~]# ssh-keygen 

[root@git ~]# ssh-copy-id 192.168.111.3

克隆在111.3上刚刚创建的git仓库

[root@git ~]# git clone root@192.168.111.3:/git_data
正克隆到 'git_data'...
warning: 您似乎克隆了一个空版本库。

git库所在的文件夹中的文件大致有4种状态

Untracked: 未跟踪, 此文件在文件夹中, 但并没有加入到git库, 不参与版本控制. 通过git add 状态变为Staged.

Unmodify: 文件已经入库, 未修改, 即版本库中的文件快照内容与文件夹中完全一致. 这种类型的文件有两种去处, 如果它被修改, 而变为Modified. 如果使用git rm移出版本库, 则成为Untracked文件

Modified: 文件已修改, 仅仅是修改, 并没有进行其他的操作. 这个文件也有两个去处, 通过git add可进入暂存staged状态, 使用git checkout 则丢弃修改过, 返回到unmodify状态, 这个git checkout即从库中取出文件, 覆盖当前修改

Staged: 暂存状态. 执行git commit则将修改同步到库中, 这时库中的文件和本地文件又变为一致, 文件为Unmodify状态. 执行git reset HEAD filename取消暂存, 文件状态为Modified

更详细的可以参考官方文档

Git仓库工作流程

pull流程:客户端从远程仓库将指定的代码仓库克隆到本机

push流程:客户端必须先将需要上传到远程仓库的代码文件使用git add添加到本地的暂存区staged;然后执行git commit将暂存区的所有文件同步到本地的代码仓库里;随后使用git push将本地仓库的代码文件同步到远程仓库上.

简单命令解释

[root@git git_data]# touch README
[root@git git_data]# git status
# 位于分支 master
#
# 初始提交
#
# 未跟踪的文件:
#   (使用 "git add <file>..." 以包含要提交的内容)
#
#	README
提交为空,但是存在尚未跟踪的文件(使用 "git add" 建立跟踪)

如上命令,在本地Git仓库所在的文件夹新建一个文件,这是它处于untracked状态

[root@git git_data]# git add README
[root@git git_data]# git status
# 位于分支 master
#
# 初始提交
#
# 要提交的变更:
#   (使用 "git rm --cached <file>..." 撤出暂存区)
#
#	新文件:    README

如上命令,将该文件添加到缓存区

[root@git git_data]# git commit -m 'joinbestRDME'
[master(根提交) 1f73750] joinbestRDME
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 README
[root@git git_data]# git status
# 位于分支 master
无文件要提交,干净的工作区

如上命令将缓存区所有的提交到了本地的Git仓库

[root@git git_data]# git push root@192.168.111.3:/git_data
fatal: 您正推送至远程 'root@192.168.111.3:/git_data'(其并非当前分支 'master' 的上游),
而没有告诉我要推送什么、更新哪个远程分支。

报错:原因这里也没有深深专研,但是只是用git push后面不加任何参数,是可以同步到远程仓库的,后来试了一下源码包安装的2.*的版本,该问题得到了解决


删除暂存区数据

rm -rf FileName
#删除为添加到暂存区的文件

git rm --cached FileName
#将该文件从暂存区追踪列表删除

git rm -f FileName
#将该文件从暂存区追踪列表和实际的工作目录下删除

重命名暂存区数据

[root@git git_data]# ls
1123
无文件要提交,干净的工作区
[root@git git_data]# git mv 1123 11
[root@git git_data]# git status
# 位于分支 master
# 要提交的变更:
#   (使用 "git reset HEAD <file>..." 撤出暂存区)
#
#	重命名:    1123 -> 11
#
[root@git git_data]# ls
11

还原历史数据

Git有一个叫做HEAD的版本指针,用户执行响应命令申请还原数据时,其实就是将HEAD指针指向到某个特定的提交版本,默认会指向到最近一次提交版本记录,上一个提交版本就叫HEAD^,上两个版本叫HEAD^^,一般会用HEAD~5往上数第五个提交版本.

[root@git git_data]# touch 111
[root@git git_data]# echo 111 > 111
[root@git git_data]# git add 111
[root@git git_data]# git commit -m '2019年7月5日22:23:24'
[master 8dc13a6] 2019年7月5日22:23:24
 2 files changed, 1 insertion(+)
 rename 1123 => 11 (100%)
 create mode 100644 111
[root@git git_data]# git log
commit 8dc13a616d3fe894f4d20805f546525fff990192
Author: joinbest <joinbestbest@163.com>
Date:   Sat Apr 27 18:21:50 2019 +0800
    2019年7月5日22:23:24
commit ac2497fe01337cff9e538c22f05867e64cd154dc
Author: joinbest <joinbestbest@163.com>
Date:   Sat Apr 27 17:04:56 2019 +0800
[root@git git_data]# ls
11  111
[root@git git_data]# git reset --hard  ac2497fe
HEAD 现在位于 ac2497f 2019年7月5日20:05:43
#后面的值为历史还原点的SHA-1的值,不用写全
[root@git git_data]# ls
1123

还原未来数据

接着上面例子,我还原了,但是又后悔了,想回到还原前的文件状态,git log已经不显示了呢.

[root@git git_data]# git reflog 
#查看未来历史更新点
ac2497f HEAD@{0}: reset: moving to ac2497fe
8dc13a6 HEAD@{1}: commit: 2019年7月5日22:23:24
ac2497f HEAD@{2}: commit: 2019年7月5日20:05:43
478dfea HEAD@{3}: clone: from root@192.168.111.3:/git_data.git
[root@git git_data]# git reset --hard 8dc13a6
HEAD 现在位于 8dc13a6 2019年7月5日22:23:24
[root@git git_data]# ls
11  111

标签使用

像其他版本控制系统(VCS)一样,Git 可以给历史中的某一个提交打上标签,以示重要。 比较有代表性的是开发人员会使用这个功能来标记发布结点(v1.0 等等)。

在 Git 中列出已有的标签是非常简单直观的。 只需要输入 git tag

$ git tag
v0.1
v1.3
[root@git git_data]# git tag v1
#针对于当前数据提交情况创建一个标签

[root@git git_data]# git tag
v1
[root@git git_data]# git tag -d v1 
已删除 tag 'v1'(曾为 8dc13a6)
#-d删除标签
[root@git git_data]# git tag
[root@git git_data]# git tag v1 -m "2019年7月5日22:38:37"
#-m说明文字
[root@git git_data]# git tag
v1
[root@git git_data]# git show v1 
tag v1
Tagger: joinbest <joinbestbest@163.com>
Date:   Sat Apr 27 18:38:20 2019 +0800
2019年7月5日22:38:37
...
#查看改标签的详细信息

[root@git git_data]# ls
11  111
[root@git git_data]# rm -rf *
[root@git git_data]# ls
[root@git git_data]# git reset --hard v1
HEAD 现在位于 8dc13a6 2019年7月5日22:23:24
#针对于标签进行数据还原
[root@git git_data]# ls
11  111

Git中的分支理解及配置

Git的"master"分支并不是一个特殊分支.它跟其他我们自定义创建的分支完全没有区别,之所以几乎每一个仓库都有master分支,是因为git init命令默认创建它,并且大多数人都懒得去改动它

分支的作用

分支这块笔者整理的并不是很好,只是便于理解,如果需要深入理解参考这篇文章

假如开发人员开发一个新功能,但是需要一周能完成,第一天完成了20%,如果立刻提交,由于代码还没有完成,代码库不完整导致别人没法正常工作.如果等代码全部完成再一次性提交,会存在丢失每天进度的风险

Git分支比其它版本控制系统优势很明显,创建,切换和删除分支,速度非常快

在工作中,一般保持master分支稳定,仅用于发布新版本,平时开发工作都在dev分支上,每个人员从dev分支创建自己个人分支,开发完合并到dev分支,最后dev分支合并到master分支

[root@git git_data]# git branch joinbest
#基于当前所在分支提交情况创建新分支
[root@git git_data]# git branch 
  joinbest
* master
#*表示当前所处于的分支
[root@git git_data]# git checkout joinbest 
切换到分支 'joinbest'
#切换到该分支
[root@git git_data]# git branch
* joinbest
  master
[root@git git_data]# git merge joinbest
#合并分支,将joinbest分支合并到master

分支合并失败解决

模仿冲突

[root@git git_data]# git branch
  linux
* master

[root@git git_data]# cat notice 
hello,git
hello,gitlab
hello,joinbest
[root@git git_data]# echo "hi,joinbest" >> notice 
[root@git git_data]# git commit -a -m "2019年7月6日10:33:23"
[master f3338c2] 2019年7月6日10:33:23
 1 file changed, 2 insertions(+), 1 deletion(-)

切到Linux分支

[root@git git_data]# git checkout linux
切换到分支 'linux'

[root@git git_data]# cat notice 
hello,git
hello,gitlab
hello,joinbest

[root@git git_data]# echo "hi,joinbesterror" >> notice 
[root@git git_data]# git commit -a -m "2019年7月6日10:36:03"
[linux a64f014] 2019年7月6日10:36:03
 1 file changed, 2 insertions(+), 1 deletion(-)

现在的合并冲突是代码文件同一行出现了不同代码

回到master分区,合并分支

[root@git git_data]# git checkout master
切换到分支 'master'
[root@git git_data]# git merge linux
自动合并 notice
冲突(内容):合并冲突于 notice
自动合并失败,修正冲突然后提交修正的结果。
[root@git git_data]# vim notice 

hello,git
hello,gitlab
hello,joinbest
<<<<<<< HEAD
hi,joinbest
=======
hi,joinbesterror
>>>>>>> linux

解决冲突看我们想保留哪个分支的代码,就把另一个冲突分支删除掉即可,这里是手动解决冲突,此外也是有很多小工具解决冲突

#手动解决就是把不想保留的删除即可
[root@git git_data]# git commit -a -m "2019年7月6日10:42:02"
[master dd33a51] 2019年7月6日10:42:02
#这种一条命令可以提交的情况,主要是用于文件已跟踪,后来修改过的代码文件,如果是新建的文件还是需要两条命令才可以提交到本地的仓库
#git branch -d joinbest
#表示删除一个分支

3.Windows下Git的安装与使用参考文章

三.总结

  • Git和GitLab以及GitHub的关系,我想还是再次总结下.
    • Git是一个版本控制系统,可以有本地仓库,也可以从别的仓库里克隆到本地
    • GitLab本质上讲跟Git没什么两样,但是更方便使用,比如提供web界面等等,它是基于Git做了些扩展
    • GitLab多用于企业自己的私有代码仓库管理,都是自己进行搭建的GitLab.而GitHub是在互联网上存在的一个代码仓库
原文地址:https://www.cnblogs.com/jojoword/p/11143470.html