git的运用

一,版本控制系统的介绍

版本控制系统
版本控制是一种记录若干文件内容变化,以便将来查阅特定版本修订情况的系统。大部分时候我们使用最频繁的还是对源代码文件的版本控制,其实任何文件都可以纳入版本控制系统。


1).更好备份:相比于将不同版本的文件以时间等命名存储备份,使用版本控制系统能节约更多的磁盘空间,因为版本控制系统不是文件的复制备份,而是差异备份,文件快照备份等等。

2).更好的回溯:可以将某个文件回溯到之前的任何一个提交状态,甚至将整个项目回退到过去的某个时间点。

3).更好的团队协作:这是最重要的,团队共同开发一款软件,如果没有版本控制,那是不可想象的,简单点的可以使用文件传输到某一位核心开发者库上进行合并,但如果团队的成员是分散在全国各地的,甚至是世界各地的,比如linux内核的开发,那完全是没办法进行的。使用版本控制后,可以比较文件的变化系统,可以查询是谁提交了新的更新,并且可以由项目负责人管理提交,进行更新的管理。

相比于svn, git有什么优势?
从不同的角度和不同的需求可能都会有不同的观点,这里也只能说明两者的适用情景。

svn属于集中化的版本控制系统:
有一个单一的集中管理的服务器,保存所有文件的修订版本,而协同工作的成员通过客户端连接到这台服务器,进行文件上传和更新。

优点:
a.使用简单,比较符合我们的常规思维(我当年从SVN转向Git也花费了不少时间)。
b.同步代码比较简单,只要一步操作即可。

缺点:
a.丢失数据的风险:最显而易见的,由于集中化的特点,如果版本库的服务器磁盘发生故障等,你不
能保证所有的数据已经有人提取出来了,最坏的情况是彻底的丢失整个项目的所有历史更改记录。
b.网络中断的情况下,协作就无法进行了,因为无法连接服务器进行上传和更新。

git属于分布式版本控制系统:
客户端并不只提取最新版本的文件快照,而是把原始的代码仓库完整地镜像下来。

优点:
a.由于任何人每次提取操作,实际上都是一次对代码仓库的完整备份,因此近乎所有的操作都可以在
本地执行,速度就是相当的快,并且可以在网络断开的时候操作仍然不受影响,可以频繁的进行提交
更新,等到有网络的时候再上传到远程的镜像仓库就可以了。
b.文档很详细,并且命令行的提示也很到位,用起来比较得新应手,而且很多的设置与操作跟linux操
作很相近(不亏是linux之父创造的)。
c.git的分支模型,相当的轻量级,被称为“必杀技”。
 
缺点:
a.每个开发人员都拥有所有的代码,不利于核心代码的保密(如果有重要代码需要保密,则不建议使
用git)

git的历史
Linus在1991年创建了开源的Linux,从此,Linux系统不断发展,已经成为最大的服务器系统软件了。
Linus虽然创建了Linux,但Linux的壮大是靠全世界热心的志愿者参与的,这么多人在世界各地为Linux编写代码,那Linux的代码是如何管理的呢?
事实是,在2002年以前,世界各地的志愿者把源代码文件通过diff的方式发给Linus,然后由Linus本人通过手工方式合并代码!
你也许会想,为什么Linus不把Linux代码放到版本控制系统里呢?不是有CVS、SVN这些免费的版本控制系统吗?因为Linus坚定地反对CVS和SVN,这些集中式的版本控制系统不但速度慢,而且必须联网才能使用。有一些商用的版本控制系统,虽然比CVS、SVN好用,但那是付费的,和Linux的开源精神不符。
不过,到了2002年,Linux系统已经发展了十年了,代码库之大让Linus很难继续通过手工方式管理了,社区的弟兄们也对这种方式表达了强烈不满,于是Linus选择了一个商业的版本控制系统BitKeeper,BitKeeper的东家BitMover公司出于人道主义精神,授权Linux社区免费使用这个版本控制系统。
安定团结的大好局面在2005年就被打破了,原因是Linux社区牛人聚集,不免沾染了一些梁山好汉的江湖习气。开发Samba的Andrew试图破解BitKeeper的协议(这么干的其实也不只他一个),被BitMover公司发现了(监控工作做得不错!),于是BitMover公司怒了,要收回Linux社区的免费使用权。
Linus可以向BitMover公司道个歉,保证以后严格管教弟兄们,嗯,这是不可能的。实际情况是这样的:
Linus花了两周时间自己用C写了一个分布式版本控制系统,这就是Git!一个月之内,Linux系统的源码已经由Git管理了!牛是怎么定义的呢?大家可以体会一下。
Git迅速成为最流行的分布式版本控制系统,尤其是2008年,GitHub网站上线了,它为开源项目免费提供Git存储,无数开源项目开始迁移至GitHub,包括jQuery,PHP,Ruby等等。
历史就是这么偶然,如果不是当年BitMover公司威胁Linux社区,可能现在我们就没有免费而超级好用的Git了。

集中式VS分布式

Linus一直痛恨的CVS及SVN都是集中式的版本控制系统,而Git是分布式版本控制系统,集中式和分布式版本控制系统有什么区别呢?

先说集中式版本控制系统,版本库是集中存放在中央服务器的,而干活的时候,用的都是自己的电脑,所以要先从中央服务器取得最新的版本,然后开始干活,干完活了,再把自己的活推送给中央服务器。中央服务器就好比是一个图书馆,你要改一本书,必须先从图书馆借出来,然后回到家自己改,改完了,再放回图书馆。

集中式版本控制系统最大的毛病就是必须联网才能工作,如果在局域网内还好,带宽够大,速度够快,可如果在互联网上,遇到网速慢的话,可能提交一个10M的文件就需要5分钟,这还不得把人给憋死啊。
那分布式版本控制系统与集中式版本控制系统有何不同呢?首先,分布式版本控制系统根本没有“中央服务器”,每个人的电脑上都是一个完整的版本库,这样,你工作的时候,就不需要联网了,因为版本库就在你自己的电脑上。既然每个人电脑上都有一个完整的版本库,那多个人如何协作呢?比方说你在自己电脑上改了文件A,你的同事也在他的电脑上改了文件A,这时,你们俩之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。
和集中式版本控制系统相比,分布式版本控制系统的安全性要高很多,因为每个人电脑里都有完整的版本库,某一个人的电脑坏掉了不要紧,随便从其他人那里复制一个就可以了。而集中式版本控制系统的中央服务器要是出了问题,所有人都没法干活了。
在实际使用分布式版本控制系统的时候,其实很少在两人之间的电脑上推送版本库的修改,因为可能你们俩不在一个局域网内,两台电脑互相访问不了,也可能今天你的同事病了,他的电脑压根没有开机。因此,分布式版本控制系统通常也有一台充当“中央服务器”的电脑,但这个服务器的作用仅仅是用来方便“交换”大家的修改,没有它大家也一样干活,只是交换修改不方便而已。

当然,Git的优势不单是不必联网这么简单,后面我们还会看到Git极其强大的分支管理,把SVN等远远抛在了后面。
CVS作为最早的开源而且免费的集中式版本控制系统,直到现在还有不少人在用。由于CVS自身设计的问题,会造成提交文件不完整,版本库莫名其妙损坏的情况。同样是开源而且免费的SVN修正了CVS的一些稳定性问题,是目前用得最多的集中式版本库控制系统。
除了免费的外,还有收费的集中式版本控制系统,比如IBM的ClearCase(以前是Rational公司的,被IBM收购了),特点是安装比Windows还大,运行比蜗牛还慢,能用ClearCase的一般是世界500强,他们有个共同的特点是财大气粗,或者人傻钱多。
微软自己也有一个集中式版本控制系统叫VSS,集成在Visual Studio中。由于其反人类的设计,连微软自己都不好意思用了。
分布式版本控制系统除了Git以及促使Git诞生的BitKeeper外,还有类似Git的Mercurial和Bazaar等。这些分布式版本控制系统各有特点,但最快、最简单也最流行的依然是Git!

二,git相关概念


工作区
版本库
暂存区
HEAD
版本号
版本日志
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
工作区(Working Directory):
存放git版本仓库的目录就是工作区

版本库(Repository):
工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库。

暂存区:
Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD。

HEAD:
你的本地仓库由 git 维护的三棵“树”组成。
第一个是你的 工作目录,它持有实际文件;
第二个是 缓存区(Index),它像个缓存区域,临时保存你的改动;
第三个HEAD,指向你最近一次提交后的结果。



添加修改到暂存区:
创建两个文件add到stage:
#git add 文件名
或者
#git add *


从stage提交到当前master分支的HEAD:
#git commit -m “版本描述信息” //提交暂存区里的修改到版本库的分支



Git跟踪并管理的是修改,而非文件
什么是修改?比如你新增了一行,这就是一个修改,删除了一行,也是一个修改,更改了某些字符,也是一个修改,删了一些又加了一些,也是一个修改,甚至创建一个新文件,也算一个修改。

第一次修改 -> git add -> 第二次修改 -> git add -> git commit
每次修改,如果不add到暂存区,那就不会加入到commit中。

实验(本实验要学过基本操作后再做):
1.现有源文件:
[root@vm20 gittest]# cat a.txt
friday
monday

2.第一次修改:添加一行tuesday
[root@vm20 gittest]# cat a.txt
friday
monday
tuesday

3.执行add:
[root@vm20 gittest]# git add a.txt

4.第二次修改:添加一行wednesday
[root@vm20 gittest]# cat a.txt
friday
monday
tuesday
wednesday

5.不做add,直接提交:
[root@vm20 gittest]# git commit -m "看看第二次修改有没有被commit"
[master 0e14810] 看看第二次修改有没有被commit
1 file changed, 1 insertion(+)
[root@vm20 gittest]# git status
# 位于分支 master
# 尚未暂存以备提交的变更:
# (使用 "git add <file>..." 更新要提交的内容)
# (使用 "git checkout -- <file>..." 丢弃工作区的改动)
#
# 修改: a.txt
#
修改尚未加入提交(使用 "git add" 和/或 "git commit -a")

注意:如果第二修改也被add了不会出现上面的提示

6.查看当前版本和a.txt文件内容的区别(有输出内容,说明现在版本库和文件a.txt内容有区别,也就是第二次修改并没有被提交):
[root@vm20 gittest]# git diff HEAD -- a.txt
diff --git a/a.txt b/a.txt
index 1091166..adfd1e9 100644
--- a/a.txt
+++ b/a.txt
@@ -1,3 +1,4 @@
friday
monday
tuesday
+wednesday

7.再次add后,发现工作区干净了,而且当前版本库HEAD和a.txt没有任何区别了:
[root@vm20 gittest]# git add a.txt
[root@vm20 gittest]# git commit -m "再看第二次修改有没有被commit"
[master fe18903] 再看第二次修改有没有被commit
1 file changed, 1 insertion(+)

[root@vm20 gittest]# git status
# 位于分支 master
无文件要提交,干净的工作区

[root@vm20 gittest]# git diff HEAD -- a.txt
[root@vm20 gittest]#
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
版本号:
也就是commit id,和SVN不一样,Git的commit id不是1,2,3……递增的数字,而是一个SHA1计算出来的一个非常大的数字,用十六进制表示。为什么commit id需要用这么一大串数字表示呢?因为Git是分布式的版本控制系统,如果多人在同一个版本库里工作,如果大家都用1,2,3……作为版本号,那肯定就冲突了。

查看版本号:
版本号可以通过版本日志查看

版本日志:
commit完成的功能类似快照,可以使用git log查看每次的commit记录

[root@vm20 gittest]# git log
commit fbecfa3d04ae5038aa11bf55942e46c840077ace
Author: tom@up.com <tom>
Date: Fri Sep 29 02:20:51 2017 -0400

add haha

commit 7e99d947e4878029edb3bf7f32e5dcc4c785e765
Author: tom@up.com <tom>
Date: Fri Sep 29 00:01:50 2017 -0400

添加hello一行

commit addd750a13477d215cc75f4634aae0a686133e90
Author: tom@up.com <tom>
Date: Thu Sep 28 23:15:25 2017 -0400

test

显示分支:
[root@vm20 gittest]# git log --graph

单行方式显示:
[root@vm20 gittest]# git log --pretty=oneline
fbecfa3d04ae5038aa11bf55942e46c840077ace add haha
7e99d947e4878029edb3bf7f32e5dcc4c785e765 添加hello一行
addd750a13477d215cc75f4634aae0a686133e90 test

[root@vm20 gittest]# git log --graph

三,git部署

环境:
centos7u4
vm20 192.168.245.139 充当中央服务器
vm21 192.168.245.249

安装:所有机器都安装
# yum install git -y
# git --version
git version 1.8.3.1

准备:
因为Git是分布式版本控制系统,所以,每个机器都必须自报家门:你的名字和Email地址。你也许会担心,如果有人故意冒充别人怎么办?这个不必担心,首先我们相信大家都是善良无知的群众,其次,真的有冒充的也是有办法可查的。
注意git config命令的--global参数,用了这个参数,表示你这台机器上所有的Git仓库都会使用这个配置,当然也可以对某个仓库指定不同的用户名和Email地址。
# git config --global user.email "wing@qianfeng.com"
# git config --global user.name "wing"

四,版本库的管理

1.创建版本库

版本库:
又名仓库,英文名repository,可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”.

1.创建一个空目录在vm20上创建
[root@vm20 /]# mkdir gittest
[root@vm20 /]# cd gittest/

2.通过git init命令把这个目录变成Git可以管理的仓库:
方式1.创建本地库
这样创建的库其他机器可以clone,但是没办法push
[root@vm20 gittest]# git init
初始化空的 Git 版本库于 /gittest/.git/

创建完成后查看库目录:
[root@vm20 gittest]# ls -a
. .. .git

方式2.创建裸库: 适用与作为远程中心仓库使用
创建裸库才可以从别处push代码过来,使用--bare参数
[root@vm20 gittest2]# git init --bare
初始化空的 Git 版本库于 /gittest2/

默认会把当前所在目录做成库目录,可以在命令后面跟目录指定子目录为版本库
# git init --bare 库名字

裸库创建完成后查看库目录:
[root@vm20 gittest2]# ls
branches config description HEAD hooks info objects refs

注:不一定必须在空目录下创建Git仓库,选择一个已经有东西的目录也是可以的

添加文件到版本库
所有版本控制系统,其实只能跟踪文本文件的改动,比如TXT文件,网页,所有的程序代码等等,Git也不例外。版本控制系统可以告诉你每次的改动,比如在第5行加了一个单词“Linux”,在第8行删了一个单词“Windows”。而图片、视频这些二进制文件,虽然也能由版本控制系统管理,但没法跟踪文件的变化,只能把二进制文件每次改动串起来,也就是只知道图片从100KB改成了120KB,但到底改了啥,版本控制系统不知道,也没法知道。

Microsoft的Word格式是二进制格式,因此,版本控制系统是没法跟踪Word文件的改动的,如果要真正使用版本控制系统,就要以纯文本方式编写文件。

强烈建议使用标准的UTF-8编码,所有语言使用同一种编码,既没有冲突,又被所有平台所支持。

3.在gittest目录下创建一个测试文件readme.txt
[root@vm20 gittest]# cat readme.txt
Git is a version control system.
Git is free software.

4.把文件添加到暂存区:使用 "git add" 建立跟踪
[root@vm20 gittest]# git add readme.txt

使用#git status可以查看状态
使用#git rm --cached readme.txt可以删除文件跟踪,但是不可以回退文件内容的修改,建议使用下一节讲到的撤销修改

5.提交文件到仓库分支:
[root@vm20 gittest]# git commit -m "test"
[master(根提交) addd750] test
1 file changed, 2 insertions(+)
create mode 100644 readme.txt

-m 本次提交的说明

6.查看git状态:
[root@vm20 gittest]# git status
# 位于分支 master
无文件要提交,干净的工作区

修改文件后再此查看状态
[root@vm20 gittest]# echo hello >> readme.txt

[root@vm20 gittest]# git status
# 位于分支 master
# 尚未暂存以备提交的变更:
# (使用 "git add <file>..." 更新要提交的内容)
# (使用 "git checkout -- <file>..." 丢弃工作区的改动)
#
# 修改: readme.txt
#
修改尚未加入提交(使用 "git add" 和/或 "git commit -a")

查看修改了什么内容:
[root@vm20 gittest]# git diff
diff --git a/readme.txt b/readme.txt
index 795d143..57083df 100644
--- a/readme.txt
+++ b/readme.txt
@@ -1,2 +1,3 @@
Git is a version control system.
Git is free software.
+hello

再次提交可以先add再commit,也可以使用-a和commit一起:
[root@vm20 gittest]# git commit -a -m "添加hello一行"
[master 7e99d94] 添加hello一行
1 file changed, 1 insertion(+)

[root@vm20 gittest]# git status
# 位于分支 master
无文件要提交,干净的工作区

本地库和裸库的区别

在使用Git初始化版本库的时候,使用”git init”命令和使用”git init --bare”命令有什么区别呢?
用”git init”初始化的版本库(暂且称之为working repository)将会生成2类文件:“.git“版本库目录(记录版本历史)和实际项目文件的拷贝。你可以把这类版本库叫做“工作目录”。工作目录是一个包含有版本历史目录“.git”和源文件的目录。你可以在工作目录修改你的源文件并使用”git add”和”git commit”命令进行版本管理。
用“git init –bare”初始化的版本库(暂且称之为bare repository)仅包含”.git”目录(记录版本历史),不含项目源文件拷贝。如果你进入版本目录,你会发现仅有”.git”目录,没有其他文件。版本库仅包含记录着版本历史的文件。
什么情况下使用“git init”和”git init --bare”呢?
working repository适合于实际编辑生产过程中,在工作目录下,你将会进行实际的编码、文件管理操作和保存项目在本地工作。如果你开始创建一个项目将包含有源代码和和版本跟踪记录的时候你可以使用”git init”.或者,如果你克隆”git clone”一个已经存在的版本库的时候,你也可以得到一个working repository,它也将包含”.git”目录和源文件的拷贝。
bare repository主要是用作分享版本库。开发者使用bare repository可以向其他人分享存储在本地的版本库,以便于实时分享代码更新和团队协作 。通过使用”git push”命令,你可以将你的本地更新提交至“中心版本库”(其他开发者可访问的中心库)。其他开发者可以使用“git pull”命令者接受你提交的版本更新。如果你正在一个多人协作的项目团队或者同一个项目需要在不同电脑上面完成的时候,bare repository可以满足你的分布式开发需求。
总结:“工作目录”是通过使用“git init“或“git clone”创建的本地项目拷贝。我们可以在工作目录下面修改和测试代码。通过测试后我们可以使用“git add“和”git commit“命令本地提交修改,然后使用“git push”命令向远程 bare repository库提交更新,通常bare repository指定其他服务器,其他开发者将可以及时看到你的更新。当我们想去更新本地工作目录的时候,我们可以使用“git pull”命令去接受其他开发者提交的更新。

2.撤销修改

撤销修改
场景1:当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令git checkout -- file。
场景2:当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令git reset HEAD file,
就回到了场景1,第二步按场景1操作。
场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,使用版本回退,不过前提是没有推送到远程库。(见下节)

场景1: 源文件添加了一行thursday,还没有add到stage(前提:之前提交过此文件)
[root@vm20 gittest]# cat a.txt
wednesday
thursday

撤销刚才的修改:
[root@vm20 gittest]# git checkout -- a.txt
[root@vm20 gittest]# cat a.txt
wednesday

场景2:源文件添加了一行thursday,并且add到了stage(前提:之前提交过此文件)
[root@vm20 gittest]# cat a.txt
wednesday
thursday
[root@vm20 gittest]# git add a.txt
[root@vm20 gittest]# git status
# 位于分支 master
# 要提交的变更:
# (使用 "git reset HEAD <file>..." 撤出暂存区)
#
# 修改: a.txt
#

[root@vm20 gittest]# git reset HEAD a.txt
重置后撤出暂存区的变更: add后后悔了要想撤回
M a.txt
[root@vm20 gittest]# cat a.txt
wednesday
thursday

[root@vm20 gittest]# git checkout -- a.txt
撤出工作区的变更,就是刚在a.txt中做的修改
[root@vm20 gittest]# cat a.txt
wednesday


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

3.版本回收

场景3:已经提交到版本库
查看现在的版本:
[root@ansible gittest]# git log
commit 898a61cb50da77daeda51453bef38c98fecd46a0
Author: wing <wing@wing.com>
Date: Sun Feb 25 18:04:27 2018 +0800
test1
commit d75411fb17e661cefc1900a09c8a784e8aa0d79a
Author: wing <wing@wing.com>
Date: Sun Feb 25 17:56:45 2018 +0800
test1

版本回退(切换):
在Git中,上一个版本就HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100

回到上一个版本:
[root@vm20 gittest]# git reset --hard HEAD^
HEAD 现在位于 83f6e8d Signed-off-by: tom@up.com <tom>

回到指定的版本(根据版本号):
[root@vm20 gittest]#git reset --hard 6fe5b9a2

消失的ID号:
回到早期的版本后再查看git log会发现最近的版本消失,可以使用reflog查看消失的版本ID,用于回退到消失的版本
[root@vm20 gittest]# git reflog
32c31f5 HEAD@{0}: reset: moving to 32c31f54c1
6fe5b9a HEAD@{1}: reset: moving to 6fe5b9a2
928ab9e HEAD@{2}: reset: moving to HEAD^^
83f6e8d HEAD@{3}: reset: moving to HEAD^
6fe5b9a HEAD@{5}: commit: 这个能写中文
83f6e8d HEAD@{6}: commit: Signed-off-by: tom@up.com <tom>
32c31f5 HEAD@{7}: commit: add a line monday
928ab9e HEAD@{8}: commit (amend): this is a new file test
bee2ba0 HEAD@{9}: commit: this is a new file test
c8e6b87 HEAD@{10}: commit: 添了两个
fbecfa3 HEAD@{11}: commit: add haha
7e99d94 HEAD@{12}: commit: 添加hello一行
addd750 HEAD@{13}: commit (initial): test

Git的版本回退速度非常快,因为Git在内部有个指向当前版本的HEAD指针,当你回退版本的时候,Git仅仅是把HEAD从指向
append GPL:

git-head

改为指向add distributed:

git-head-move

然后顺便把工作区的文件更新了。所以你让HEAD指向哪个版本号,你就把当前版本定位在哪。

4.删除文件

删除文件
从工作区删除a.txt,并且从版本库一起删除
[root@vm20 gittest]# rm -rf a.txt
[root@vm20 gittest]# git status
# 位于分支 master
# 尚未暂存以备提交的变更:
# (使用 "git add/rm <file>..." 更新要提交的内容)
# (使用 "git checkout -- <file>..." 丢弃工作区的改动)
#
# 删除: a.txt
#
修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
[root@vm20 gittest]# git rm a.txt
rm 'a.txt'

[root@vm20 gittest]# git commit -m "删除文件a.txt"
[master 4bb90a4] 删除文件a.txt
1 file changed, 4 deletions(-)
delete mode 100644 a.txt

[root@vm20 gittest]# git status
# 位于分支 master
无文件要提交,干净的工作区

删除了文件readme.txt之后又后悔了,恢复回来
[root@vm20 gittest]# ls
readme.txt
[root@vm20 gittest]# rm -rf readme.txt
[root@vm20 gittest]# git checkout -- readme.txt
[root@vm20 gittest]# ls
readme.txt

五,远程仓库

1.概念

远程仓库
Git是分布式版本控制系统,同一个Git仓库,可以分布到不同的机器上。怎么分布呢?最早,肯定只有一台机器有一个原始版本库,此后,别的机器可以“克隆”这个原始版本库,而且每台机器的版本库其实都是一样的,并没有主次之分。

一台电脑上也是可以克隆多个版本库,只要不在同一个目录下。不过,一台电脑上搞几个远程库完全没有意义,而且硬盘挂了会导致所有库都挂掉。

实际情况是,找一台电脑充当服务器的角色,每天24小时开机,其他每个人都从这个“服务器”仓库克隆一份到自己的电脑上,并且各自把各自的提交推送到服务器仓库里,也从服务器仓库中拉取别人的提交。

完全可以自己搭建一台运行Git的服务器,不过现阶段,为了学Git先搭个服务器绝对是小题大作。好在这个世界上有个叫GitHub的神奇的网站,这个网站就是提供Git仓库托管服务的,所以,只要注册一个GitHub账号,就可以免费获得Git远程仓库。

自行注册GitHub账号:


第2步:登陆GitHub,打开“Account settings”,“SSH Keys”页面:
然后,点“Add SSH Key”,填上任意Title,在Key文本框里粘贴id_rsa.pub文件的内容:



GitHub允许添加多个Key用于可以在多台电脑上往GitHub推送。

在GitHub上免费托管的Git仓库,任何人都可以看到(但只有你自己才能改)
如果你不想让别人看到Git库,有两个办法:
一个是交保护费,让GitHub把公开的仓库变成私有的
一个是自己动手,搭一个Git服务器

检出仓库:
执行如下命令以创建一个本地仓库的克隆版本:
# git clone /path/to/repository

如果是远端服务器上的仓库,命令如下:
# git clone username@host:/path/to/repository
# git clone https://github.com/yanqiang20172017/test1.git

推送改动
你的改动现在已经在本地仓库的 HEAD 中了。执行如下命令以将这些改动提交到远端仓库:
#git push origin master
可以把 master 换成你想要推送的任何分支。

如果你还没有克隆现有仓库,并欲将你的仓库连接到某个远程服务器,你可以使用如下命令添加:
git remote add origin <server>
如此你就能够将你的改动推送到所添加的服务器上去了。

2.添加远程仓库

现在的情景是,你已经在本地创建了一个Git仓库后,又想在GitHub创建一个Git仓库,并且让这两个仓库进行远程同步,这样,GitHub上的仓库既可以作为备份,又可以让其他人通过该仓库来协作,真是一举多得。
首先,登陆GitHub,然后,在右上角找到“Create a new repo”按钮,创建一个新的仓库:

在Repository name填入learngit,其他保持默认设置,点击“Create repository”按钮,就成功地创建了一个新的Git仓库:

目前,在GitHub上的这个learngit仓库还是空的,GitHub告诉我们,可以从这个仓库克隆出新的仓库,也可以把一个已有的本地仓库与之关联,然后,把本地仓库的内容推送到GitHub仓库。

现在,在本地的gittest仓库下运行命令:换掉用户名
[root@ansible gittest]# git remote add origin https://github.com/yanqiang20172017/test1.git
origin 远程库的名字,是Git默认的叫法,也可以改成别的

下一步,就可以把本地库的所有内容推送到远程库上:
[root@ansible gittest]# git push -u origin master
Username for 'https://github.com': yanqiang20172017
Password for 'https://yanqiang20172017@github.com':
Counting objects: 3, done.
Writing objects: 100% (3/3), 202 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To https://github.com/yanqiang20172017/test1.git
* [new branch] master -> master
分支 master 设置为跟踪来自 origin 的远程分支 master。

把本地库的内容推送到远程,用git push命令,实际上是把当前分支master推送到远程。

-u 我们第一次推送master分支时,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。

查看远程add的库:
[root@ansible gittest]# git remote -v
删除远程add:
[root@ansible gittest]# git remote remove haha

推送成功后,可以立刻在GitHub页面中看到远程库的内容已经和本地一模一样:

从现在起,只要本地作了提交,就可以通过命令:
# git push origin master
把本地master分支的最新修改推送至GitHub

3.部署远程仓库

远程仓库实际上和本地仓库没啥不同,纯粹为了7x24小时开机并交换大家的修改。
GitHub就是一个免费托管开源代码的远程仓库。但是对于某些视源代码如生命的商业公司来说,既不想公开源代码,又舍不得给GitHub交保护费,那就只能自己搭建一台Git服务器作为私有仓库使用。

搭建Git服务器需要准备一台运行Linux的机器
第一步,安装git:
#yum install git

第二步,创建一个git用户,用来运行git服务:
#adduser git

第三步,创建证书登录:
收集所有需要登录的用户的公钥,就是他们自己的id_rsa.pub文件,把所有公钥导入到/home/git/.ssh/authorized_keys文件里,一行一个。
开发者:做密钥对(私钥)传公钥给主库上的账户 ssh-copy-id -i user@server
主库:/home/git/.ssh/authorized_keys

第四步,初始化Git仓库:
选定一个目录作为Git仓库,假定是/srv/sample.git,在/srv目录下输入命令:
# git init --bare sample.git
Git就会创建一个裸仓库,裸仓库没有工作区,因为服务器上的Git仓库纯粹是为了共享,所以不让用户直接登录到服务器上去改工作区,并且服务器上的Git仓库通常都以.git结尾。然后,把owner改为git:
# chown -R git:git sample.git

第五步,禁用shell登录:
出于安全考虑,第二步创建的git用户不允许登录shell,这可以通过编辑/etc/passwd文件完成。找到类似下面的一行:
git:x:1001:1001:,,,:/home/git:/bin/bash
改为:
git:x:1001:1001:,,,:/home/git:/usr/bin/git-shell
这样,git用户可以正常通过ssh使用git,但无法登录shell,因为我们为git用户指定的git-shell每次一登录就自动退出。

第六步,克隆远程仓库:
现在,可以通过git clone命令克隆远程仓库了,在各自的电脑上运行:
# git clone git@server:/srv/sample.git
Cloning into 'sample'...
warning: You appear to have cloned an empty repository.
剩下的推送就简单了。

[root@tomcat gittest4]# git push -u origin master
tesla@192.168.245.3's password:
Counting objects: 3, done.
Writing objects: 100% (3/3), 213 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To tesla@192.168.245.3:/gittest3/teslaProject.git
* [new branch] master -> master
分支 master 设置为跟踪来自 origin 的远程分支 master。

六,分支

分支
分支是用来将特性开发绝缘开来的。在你创建仓库的时候,master 是“默认的”。在其他分支上进行开发,完成后再将它们合并到主分支上。


创建一个叫做“feature_x”的分支,并切换过去:
#git checkout -b feature_x

查看分支:
[root@ansible gittest]# git branch -a
* feature_x //带*号的代表你当前工作目录所处的分支

master
remotes/origin/master

切换回主分支:
# git checkout master

再把新建的分支删掉:
# git branch -d feature_x

除非你将分支推送到远端仓库,不然该分支就是 不为他人所见的
# git push origin <branch>

更新与合并


要更新你的本地仓库至最新改动,执行:
#git pull
以在你的工作目录中 获取(fetch)合并(merge) 远端的改动。

要合并其他分支到你的当前分支(例如 master),执行:
git merge <branch>

两种情况下,git 都会尝试去自动合并改动。不幸的是,自动合并并非次次都能成功,并可能导致 冲突(conflicts)。 这时候就需要你修改这些文件来人肉合并这些 冲突(conflicts) 了。改完之后,你需要执行如下命令以将它们标记为合并成功:
git add <filename>

在合并改动之前,也可以使用如下命令查看:
git diff <source_branch> <target_branch>

标签


在软件发布时创建标签,是被推荐的。这是个旧有概念,在 SVN 中也有。

创建一个叫做 1.0.0 的标签:
# git tag 1.0.0 1b2e1d63ff
1b2e1d63ff 是你想要标记的提交 ID 的前 10 位字符。使用如下命令获取提交 ID:
# git log

显示的标签按字母顺序排列,所以标签的先后并不表示重要程度的轻重。
可以用特定的搜索模式列出符合条件的标签。在 Git 自身项目仓库中,有着超过 240 个标签,如果你只对 1.4.2 系列的版本感兴趣,可以运行下面的命令:
# git tag -l 'v1.4.2.*'
v1.4.2.1
v1.4.2.2
v1.4.2.3
v1.4.2.4


含附注的标签
创建一个含附注类型的标签非常简单,用 -a (译注:取 annotated 的首字母)指定标签名字即可:
-m 选项则指定了对应的标签说明,Git 会将此说明一同保存在标签对象中。如果没有给出该选项,Git 会启动文本编辑软件供你输入标签说明。
# git tag -a v1.4 -m 'my version 1.4'
# git tag
v0.1
v1.3
v1.4
[root@ansible gittest]# git show 1.0.0
commit 5b83380e818f44c850dc4fe96a29148744903ff2
Author: wing <wing@wing.com>
Date: Sun Feb 25 23:09:09 2018 +0800

my version 1.4

diff --git a/a.txt b/a.txt
new file mode 100644
index 0000000..ce01362
--- /dev/null
+++ b/a.txt
@@ -0,0 +1 @@
+hello

分享标签
默认情况下,git push 并不会把标签传送到远端服务器上,只有通过显式命令才能分享标签到远端仓库。其命令格式如同推送分支,运行 git push origin [tagname] 即可:
# git push origin v1.5
Counting objects: 50, done.
Compressing objects: 100% (38/38), done.
Writing objects: 100% (44/44), 4.56 KiB, done.
Total 44 (delta 18), reused 8 (delta 1)
To git@github.com:schacon/simplegit.git
* [new tag] v1.5 -> v1.5

如果要一次推送所有本地新增的标签上去,可以使用 --tags 选项:
# git push origin --tags
Counting objects: 50, done.
Compressing objects: 100% (38/38), done.
Writing objects: 100% (44/44), 4.56 KiB, done.
Total 44 (delta 18), reused 8 (delta 1)
To git@github.com:schacon/simplegit.git
* [new tag] v0.1 -> v0.1
* [new tag] v1.2 -> v1.2
* [new tag] v1.4 -> v1.4
* [new tag] v1.4-lw -> v1.4-lw
* [new tag] v1.5 -> v1.5
现在,其他人克隆共享仓库或拉取数据同步后,也会看到这些标签。

七,替换本地改动

假如你做错事,可以使用如下命令替换掉本地改动:
git checkout -- <filename>
此命令会使用 HEAD 中的最新内容替换掉你的工作目录中的文件。已添加到缓存区的改动,以及新文件,都不受影响。 也就是之前的本地撤销修改

假如你想要丢弃你所有的本地改动与提交,可以到服务器上获取最新的版本并将你本地主分支指向到它:
[root@ansible gittest]# vim a.txt 这一步操作后上传后通过下面两步来获得主仓库的更新后的程序
[root@ansible gittest]# git fetch origin 从远程库抓取
[root@ansible gittest]# git reset --hard origin/master
HEAD 现在位于 5b83380 hello

八,git-gui

1.gitk

gitk 是一个历史记录的图形化查看器,你可以把它当作是基于 git log 和 git grep 命令的一个强大的图形操作界面,当你需要查找过去发生的某次记录,或是可视化查看项目历史的时候,你将会用到这个工具。

安装:
#yum install gitk -y

使用:
cd到仓库目录,执行下面命令
root@vm20 gittest]# gitk --all



2.git gui

git-gui 主要是一个用来制作提交的工具。
安装:
#yum install git-gui -y

使用工具:
1.修改需要改动的文件
2.打开git-gui工具
#git gui
3.点击提交菜单-->重新扫描-->缓存为提交-->选择要提交的文件-->添加描述信息-->提交


3.gitg

功能跟git-gui类似,可以修改缓存、提交
# yum install gitg -y
























  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值