git知识分享

Git&GitHub知识分享

  1. 前言

1.1什么是版本控制

版本控制(Revision control)是一种在开发的过程中用于管理我们对文件、目录或工程等内容的修改历史,方便查看更改历史记录,备份以便恢复以前的版本的软件工程技术。优点:

协同修改

多人并行不悖的修改服务器端的同一个文件。

数据备份

不仅保存目录和文件的当前状态,还能够保存每一个提交过的历史状态。

版本管理

在保存每一个版本的文件信息的时候要做到不保存重复数据,以节约存储空间,提高运行效率。这方面 SVN 采用的是增量式管理的方式,而 Git 采取了文件系统快照的方式

权限控制

对团队中参与开发的人员进行权限控制。

对团队外开发者贡献的代码进行审核——Git 独有。

历史记录

查看修改人、修改时间、修改内容、日志信息。

将本地文件恢复到某一个历史状态。

分支管理

允许开发团队在工作过程中多条生产线同时推进任务,进一步提高效率。

简单说就是用于管理多人协同开发项目的技术。没有进行版本控制或者版本控制本身缺乏正确的流程管理,在软件开发过程中将会引入很多问题,如软件代码的一致性、软件内容的冗余、软件过程的事物性、软件开发过程中的并发性、软件源代码的安全性,以及软件的整合等问题。无论是工作还是学习,或者是自己做笔记,都经历过这样一个阶段!我们就迫切需要一个版本控制工具!git知识分享_第1张图片

多人开发就必须要使用版本控制!

1.2常见的版本控制工具

主流的版本控制器有如下这些:

Git

SVN(Subversion)

CVS(Concurrent Versions System)

VSS(Micorosoft Visual SourceSafe)

TFS(Team Foundation Server)

Visual Studio Online

版本控制产品非常的多(Perforce、Rational ClearCase、RCS(GNU Revision Control System)、Serena Dimention、SVK、BitKeeper、Monotone、Bazaar、Mercurial、SourceGear Vault),现在影响力最大且使用最广泛的是Git与SVN

1.3版本控制分类

1、本地版本控制

记录文件每次的更新,可以对每个版本做一个快照,或是记录补丁文件,适合个人用,如RCS。

2、集中版本控制  SVN

所有的版本数据都保存在服务器上,协同开发者从服务器上同步更新或上传自己的修改

所有的版本数据都存在服务器上,用户的本地只有自己以前所同步的版本,如果不连网的话,用户就看不到历史版本,也无法切换版本验证问题,或在不同分支工作。而且,所有数据都保存在单一的服务器上,有很大的风险如果这个服务器损坏就会丢失所有的数据,当然可以定期备份。代表产品:SVN、CVS、VSS

3、分布式版本控制 Git

    所有版本信息仓库全部同步到本地的每个用户,这样就可以在本地查看所有版本历史,可以离线在本地提交,只需在连网时push到相应的服务器或其他用户那里。由于每个用户那里保存的都是所有的版本数据,只要有一个用户的设备没有问题就可以恢复所有的数据,但这增加了本地存储空间的占用。不会因为服务器损坏或者网络问题,造成不能工作的情况!

git知识分享_第2张图片

Git与SVN的主要区别

SVN是集中式版本控制系统,版本库是集中放在中央服务器的,而工作的时候,用的都是自己的电脑,所以首先要从中央服务器得到最新的版本,然后工作,完成工作后,需要把自己做完的活推送到中央服务器。集中式版本控制系统是必须联网才能工作,对网络带宽要求较高。

Git是分布式版本控制系统,没有中央服务器,每个人的电脑就是一个完整的版本库,工作的时候不需要联网了,因为版本都在自己电脑上。协同方法是这样的:比如说自己在电脑上改了文件A,其他人也在电脑上改了文件A,这时,你们两之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。Git可以直接看到更新了哪些代码和文件!

Git是目前世界上最先进的分布式版本控制系统。

2、Git 简介 

2.1 Git 简史 

   git知识分享_第3张图片

2.2 Git 官网和 Logo

官网地址:Git

Logo

git知识分享_第4张图片

2.3 Git 的优势 

大部分操作在本地完成,不需要联网

完整性保证(提交每条数据进行hash运算)

尽可能添加数据而不是删除或修改数据

分支操作非常快捷流畅(1因为用快照,2每个分支只是创建一个指针)

与 Linux 命令全面兼容

2.4 Git 安装

最早Git是在Linux上开发的,很⻓⼀段时间内,Git也只能在Linux和Unix系统上跑。不过, 慢慢地有⼈把它移植到了Windows上。现在,Git可以在Linux、Unix、Mac和Windows这⼏⼤平台上正常运⾏了

2.4.1  Linux安装  

⾸先,你可以试着输⼊git,看看系统有没有安装Git:

$ git

The program 'git' is currently not installed. You can install it

by typing:

$ sudo apt-get install git

像上⾯的命令,有很多Linux会友好地告诉你Git没有安装,还会告诉你如何安装Git。

2.4.2  windows安装  

打开 [git官网] https://git-scm.com/,下载git对应操作系统的版本。所有东西下载慢的话就可以去找镜像!官网下载太慢,我们可以使用淘宝镜像下载http://npm.taobao.org/mirrors/git-for-windows/

git知识分享_第5张图片

 

2下面默认设置就行:下图(下一步) 3这个的下一步也使用默认 直接下一步

 git知识分享_第6张图片

4 选择默认的文本编辑器

git知识分享_第7张图片

5 然后修改环境变量(选第一完全不修改),下面选项第二个(是被认为安全的)

git知识分享_第8张图片

6 选择客服端本地库和远程库连接方式(1通用连接2使用Windows连接方式)

git知识分享_第9张图片

7 选择换行符的方式(1检查文件时LF 转为 CRLF 提交相反)

git知识分享_第10张图片

8  选择终端(1Git默认终端(是liunx命令)2选择Windows终端(wind命令))

git知识分享_第11张图片

9 使用默认(选择第二个需要安装.NET framework c4.5.1以上版本)

NET framework安装失败解决方案:

https://jingyan.baidu.com/article/fb48e8bee50ebf6e632e1464.html 

git知识分享_第12张图片

10 

git知识分享_第13张图片

11 (1加载他的git Bash终端2查看更新的文档)

git知识分享_第14张图片

2.4.3启动Git

安装成功后在开始菜单中会有Git项,菜单下有3个程序:任意文件夹下右键也可以看到对应的程序!

git知识分享_第15张图片

Git Bash:Unix与Linux风格的命令行,使用最多,推荐最多

Git CMD:Windows风格的命令行

Git GUI:图形界面的Git,不建议初学者使用,尽量先熟悉常用命令

2.4.4 Git配置

所有的配置文件,其实都保存在本地!

查看配置 git config -l

正在上传…重新上传取消

查看不同级别的配置文件:

#查看系统config

git config --system --list

#查看当前用户(global)配置

git config --global  --list

正在上传…重新上传取消

2.4.4.1 Git相关的配置文件:

1)、Git\etc\gitconfig  :Git 安装目录下的 gitconfig  --system 系统级

2)、C:\Users\Administrator\ .gitconfig    只适用于当前登录用户的配置  --global 全局

正在上传…重新上传取消

这里可以直接编辑配置文件,通过命令设置后会响应到这里。

2.4.4.2设置用户名与邮箱(用户标识,必要)

当你安装Git后首先要做的事情是设置你的用户名称和e-mail地址。这是非常重要的,因为每次Git提交都会使用该信息。它被永远的嵌入到了你的提交中:

git config --global user.name "chilynn"  #名称

git config --global user.email chilinman@qq.com   #邮箱

只需要做一次这个设置,如果你传递了--global 选项,因为Git将总是会使用该信息来处理你在系统中所做的一切操作。如果你希望在一个特定的项目中使用不同的名称或e-mail地址,你可以在该项目中运行该命令而不要--global选项。总之--global为全局配置,不加为某个项目的特定配置表⽰你这台机器上所有的Git仓库都会有。

2.4.4.3 windows删除或者修改本地git保存的账号密码

当保存了密码后又想修改密码或删除密码怎么办?由于在Windows上git的密码是交给window进行管理的所以需要进入“控制面板”--“用户账户” --“凭证管理,管理windows凭据”点开后找到有git:xxx的凭据,删除还是修改看自己意愿修改即可

正在上传…重新上传取消

补充常用的Linux命令

平时一定要多使用多积累这些基础的命令!

1)、cd : 改变目录。

2)、cd . . 回退到上一个目录,直接cd进入默认目录

3)、pwd : 显示当前所在的目录路径。

4)、ls(ll):  都是列出当前目录中的所有文件,只不过ll(两个ll)列出的内容更为详细。

5)、touch : 新建一个文件 如 touch index.js 就会在当前目录下新建一个index.js文件。

6)、rm:  删除一个文件, rm index.js 就会把index.js文件删除。

7)、mkdir:  新建一个目录,就是新建一个文件夹。

8)、rm -r :  删除一个文件夹, rm -r src 删除src目录

rm -rf / 切勿在Linux中尝试!删除电脑中全部文件!

9)、mv 移动文件, mv index.html src index.html 是我们要移动的文件, src 是目标文件夹,当然, 这样写,必须保证文件和目标文件夹在同一目录下。

10)、reset 重新初始化终端/清屏。

11)、clear 清屏。

12)、history 查看命令历史。

13)、help 帮助。

14)、exit 退出。

15)、#表示注释

3、Git基本理论

3.1三个区域

Git本地有三个工作区域:工作目录(Working Directory)、暂存区(Stage/Index)、资源库(Repository或Git Directory)。如果在加上远程的git仓库(Remote Directory)就可以分为四个工作区域。文件在这四个区域之间的转换关系如下:

正在上传…重新上传取消

正在上传…重新上传取消

Directory:使用Git管理的一个目录,也就是一个仓库,包含我们的工作空间和Git的管理空间。

WorkSpace:工作区,就是你平时存放项目代码的地方需要通过Git进行版本控制的目录和文件,这些目录和文件组成了工作空间。

Index/Stage:暂存区,或者叫待提交更新区,在提交进入repo之前,我们可以把所有的更新放在暂存区。事实上它只是一个文件,保存即将提交文件列表信息

Repository:仓库区(或本地仓库),就是安全存放数据的位置,这里面有你提交到所有版本的数据。其中HEAD指向最新放入仓库的版本⼯作区有⼀个隐藏录“.git”,存放Git管理信息的目录,初始化仓库的时候自动创建。这个不算⼯作区,⽽是Git的版本库

Local Repo:本地仓库,一个存放在本地的版本库;HEAD会只是当前的开发分支(branch)。

Remote:远程仓库,托管代码的服务器,可以简单的认为是你项目组中的一台电脑用于远程数据交换

Stash:隐藏,是一个工作状态保存栈,用于保存/恢复WorkSpace中的临时状态。

3.2工作流程

git的工作流程一般是这样的:

1、在工作目录中添加、修改文件;

2、将需要进行版本管理的文件放入暂存区域;

3、将暂存区域的文件提交到git仓库。

因此,git管理的文件有三种状态:未跟踪(untracked),已修改(modified),已暂存(staged),已提交(committed)

正在上传…重新上传取消

文件的四种状态

版本控制就是对文件的版本控制,要对文件进行修改、提交等操作,首先要知道文件当前在什么状态,不然可能会提交了现在还不想提交的文件,或者要提交的文件没提交上。

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

4、Git项目搭建

4.1 创建工作目录与常用指令

工作目录(WorkSpace)一般就是你希望Git帮助你管理的文件夹,可以是你项目的目录,也可以是一个空目录,建议不要有中文。日常使用只要记住下图6个命令:

正在上传…重新上传取消

4.2 本地仓库搭建

创建本地仓库的方法有两种:一种是创建全新的仓库,另一种是克隆远程仓库。

1、创建全新的仓库,需要用GIT管理的项目的根目录执行:

#在当前目录新建一个Git代码库

$ git init

执行后可以看到,仅仅在项目目录多出了一个.git目录,关于版本等的所有信息都在这个目录里面。

2、另一种方式是克隆远程目录,由于是将远程服务器上的仓库完全镜像一份至本地!

#克隆一个项目和它的整个代码历史(版本信息)

$ git clone [url]  # https://gitee.com/kuangstudy/openclass.git

举例说明:在本地搭建仓库

  1. 创建版本库

版本库可以简单理解成⼀个目录,这个目录⾥⾯的所有⽂件都可以被Git管理起来,每个⽂件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。 

正在上传…重新上传取消

通过git init命令把这个录变成Git可以管理的仓库:

正在上传…重新上传取消

 编写⼀个readme.txt⽂件,内容如下:

正在上传…重新上传取消

把⼀个⽂件放到Git仓库只需要两步

第⼀步,⽤命令git add告诉Git,把⽂件添加到仓库

第⼆步,⽤命令git commit告诉Git,把⽂件提交到仓库。(因为commit可以⼀次提交很多⽂件, 所以你可以多次add不同的⽂件  

正在上传…重新上传取消

-m 加入本次提交信息

  1. 时空穿梭机

正在上传…重新上传取消

git status命令可以让我们时刻掌握仓库当前的状态,上⾯的命令告诉我们,readme.txt被修改过了,但还没有准备提交修改。 git diff可以给出具体修改什么内容。

正在上传…重新上传取消

⼩结

1、要随时掌握⼯作区的状态,使⽤git status命令。

2、如果git status告诉你有⽂件被修改过,⽤git diff

  1. 版本回退

现在修改readme.txt文件如下:

正在上传…重新上传取消

现在,我们回顾⼀下readme.txt⽂件⼀共有⼏个版本被提交到Git仓库⾥了:

版本1:wrote a readme file

Git is a version control system.

Git is free software.

版本2:add distributed

Git is a distributed version control system.

Git is free software.

版本3:append GPL

Git is a distributed version control system.

Git is free software distributed under the GPL.

版本控制系统肯定有某个命令可以告诉我们历史记录,在Git 中,我们⽤git log命令查看:

正在上传…重新上传取消

git log命令显⽰从最近到最远的提交⽇志,我们可以看到3次提交,最近的⼀次 是“append GPL”,上⼀次是“add distributed”,最早的⼀次是“wrote a readme file”。 如果嫌输出信息太多,看得眼花缭乱的,可以试试加上--pretty=oneline参数

正在上传…重新上传取消

准备把readme.txt回退到上⼀个版本,也就是“add distributed”的那个版本,怎么做呢?

⾸先,Git必须知道当前版本是哪个版本,在Git中,⽤HEAD表⽰当前版本,也就是最新的,上⼀个版本就是 HEAD^,上上⼀个版本就是HEAD^^,当然往上100 个版本写100个^⽐较容易数不过来, 所以写成HEAD~100。

现在,我们要把当前版本“append GPL”回退到上⼀个版本“add distributed”,就可以使⽤git reset

正在上传…重新上传取消

最新的那个版本“append GPL”已经看不到了!好⽐你从21世纪坐时光穿梭机来到了19 世纪,想再回去已经回不去了,办法其实还是有的,再想恢复到“append GPL”,就必须找到“append GPL”的 commit id。Git提供了⼀个命令git reflog⽤来记录你的每⼀次命令:

正在上传…重新上传取消

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

改为指向“add distributed”: 然后顺便把⼯作区的⽂件更新了。所以你让HEAD指向哪个版本号,你就把当前版本定位在哪。

正在上传…重新上传取消

⼩结

HEAD指向的版本就是当前版本,因此,Git允许我们在版本的历史之间穿梭,使⽤命令git reset --hard commit_id。 穿梭前,⽤git log可以查看提交历史,以便确定要回退到哪个版本。 要重返未来,⽤git reflog

(2)⼯作区和暂存区

正在上传…重新上传取消

前⾯讲了我们把⽂件往Git版本库⾥添加的时候,是分两步执⾏的:

第⼀步是⽤“git add”把⽂件添加进去,实际上就是把⽂件修改添加到暂存区;

第⼆步是⽤“git commit”提交更改,实际上就是把暂存区的所有内容提交到当前分⽀。

因为我们创建Git版本库时,Git⾃动为我们创建了唯⼀⼀个master分⽀,所以,现commit就是往master分⽀上提交更改。

你可以简单理解为,需要提交的⽂件修改通通放到暂存区,然后,⼀次性提交暂存区的所有 

先对readme.txt做个修改,⽐如加上⼀⾏内容

正在上传…重新上传取消

所以,git add命令实际上就是把要提交的所有修改放到暂存区(Stage),然后,执⾏git  commit就可以⼀次性把暂存区的所有修改提交到分⽀。

正在上传…重新上传取消

(3)管理修改

Git是如何跟踪修改的,每次修改,如果不add到暂存区,那就不会加⼊

到commit中。Git管理的是修改,⽽不是⽂件。

正在上传…重新上传取消

怎么第⼆次的修改没有被提交? 我们回顾⼀下操作过程:

第⼀次修改 -> git add -> 第⼆次修改 -> git commit 

因为Git管理的是修改,当你⽤“git add”命令后,在⼯作区的第⼀次修改被放⼊暂存区,准备提交,但是,在⼯作区的第⼆次修改并没有放⼊暂存区,所以,“git commit”只负责把暂存区的修改提交了,也就是第⼀次的修改被提交了,第⼆次 的修改不会被提交。

提交后,⽤“git diff HEAD -- readme.txt”命令可以查看⼯作区和版本库⾥⾯最新版本的区别:

正在上传…重新上传取消

  1. 撤销修改

命令git checkout -- readme.txt意思就是,把readme.txt⽂件在⼯作区的修改全部撤销,这⾥有两种情况:

⼀种是readme.txt⾃修改后还没有被放到暂存区,现在,撤销修改就回到和版本库⼀模⼀ 样的状态;

⼀种是readme.txt已经添加到暂存区后,⼜作了修改,现在,撤销修改就回到添加到暂存区后的状态。

总之,就是让这个⽂件回到最近⼀次git commitgit add

正在上传…重新上传取消

Git同样告诉我们,⽤命令git reset HEAD file可以把暂存区的修改撤销掉(unstage),重新放回⼯作区:

正在上传…重新上传取消

正在上传…重新上传取消

⼩结

场景1:当你改乱了⼯作区某个⽂件的内容,想直接丢弃⼯作区的修改时,⽤命令git checkout -- file

场景2:当你不但改乱了⼯作区某个⽂件的内容,还添加到了暂存区时,想丢弃修改,分两步,第⼀步⽤命令git reset HEAD file,就回到了场景1,第⼆步按场景1操作。

场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,参考版本回退⼀节,不过前提是没有推送到远程库。

  1. 删除⽂件

在Git中,删除也是⼀个修改操作,我们实战⼀下先添加⼀个新⽂件test.txt到Git并且提交:

正在上传…重新上传取消

⼀般情况下,你通常直接在⽂件管理器中把没⽤的⽂件删了,或者⽤rm命令删了: $ rm test.txt

这个时候,Git知道你删除了⽂件,因此,⼯作区和版本库就不⼀致了,git status命令会⽴刻告诉你哪些⽂件被删除了:

正在上传…重新上传取消

现在你有两个选择,⼀是确实要从版本库中删除该⽂件,那就⽤命令git rm删掉,并且 commit: 现在⽂件就从版本库中被删除了。

另⼀种情况是删错了,因为版本库⾥还有呢,所以可以很轻松地把误删的⽂件恢复到最新版本:

正在上传…重新上传取消

git checkout其实是⽤版本库⾥的版本替换⼯作区的版本,⽆论⼯作区是修改还是删除,都可以“⼀键还原”。 

小结

命令git rm ⽤于删除⼀个⽂件。如果⼀个⽂件已经被提交到版本库,那么你永远不⽤担⼼误删,但是要⼩⼼,你只能恢复⽂件到最新版本,你会丢失最近⼀次提交后你修改的内容。

  1. 分支管理机制

(1)创建和合并分支

在版本回退⾥你已经知道每次提交,Git都把它们串成⼀条时间线,这条时间线就是⼀个分⽀。截⽌到前,只有⼀条时间线,在Git⾥,这个分⽀叫主分⽀,即 master分⽀。

正在上传…重新上传取消 

HEAD严格来说不是指向提交,⽽是指向master,master才是指向提交的,所以HEAD指向的就是当前分⽀。 ⼀开始的时候,master分⽀是⼀条线,Git⽤master指向最新的提交,再⽤HEAD指向每次提交,master分⽀都会向前移动⼀步,这样,随着你不断提交,master分⽀的线也越来越⻓。 

当我们创建新的分⽀,例如dev时,Git新建了⼀个指针叫dev,指向master相同的提交,

正在上传…重新上传取消

你看,Git创建⼀个分⽀很快,因为除了增加⼀个dev指针,改改HEAD的指向,⼯作区的⽂件都没有任何变化!

不过,从现在开始,对⼯作区的修改和提交就是针对dev分⽀了,⽐如新提交⼀次后,dev :

正在上传…重新上传取消

假如我们在dev上的⼯作完成了,就可以把dev合并到master上。Git怎么合并呢?最简单的⽅法,就是直接把master指向dev的当前提交,就完成了合并: 

正在上传…重新上传取消

所以Git合并分⽀也很快!就改改指针,⼯作区内容也不变! 合并完分⽀后,甚⾄可以删除dev分⽀。删除dev分⽀就是把dev指针给删掉,删掉后,剩下了⼀条master分⽀:

正在上传…重新上传取消

正在上传…重新上传取消

切换回master分⽀后,再查看⼀个readme.txt⽂件,刚才添加的内容不⻅了!因为那个提交没有改变。

正在上传…重新上传取消

正在上传…重新上传取消

因为创建、合并和删除分⽀⾮常快,所以Git⿎励你使⽤分⽀完成某个任务,合并后再删掉分⽀,这和直接在master分⽀上⼯作效果是⼀样的,但过程更安全。

 

⼩结

Git⿎励⼤量使⽤分⽀:

查看分⽀:git branch

创建分⽀:git branch name

切换分⽀:git checkout name

创建+切换分⽀:git checkout -b name

合并某分⽀到当前分⽀:git merge name

删除分⽀:git branch -d name如果要丢弃⼀个没有被合并过的分⽀,可以通过git branch -D name强⾏删除

(2)解决冲突

准备新的feature1分⽀,继续我们的新分⽀开发,修改readme.txt最后⼀⾏,改为: Creating a new branch is quick AND simple. 在feature1分⽀上提交:

正在上传…重新上传取消

切换master分支修改文档

正在上传…重新上传取消

合并分支:

正在上传…重新上传取消

现在,master分⽀和feature1分⽀各⾃都分别有新的提交,变成了这样:

正在上传…重新上传取消

这种情况下,Git⽆法执⾏“快速合并”,只能试图把各⾃的修改合并起来,但这种合并就 可能会有冲突!Git告诉我们,readme.txt⽂件存在冲突,必须⼿动解决冲突后再提交。git status也可以告诉我们冲突的⽂件查看文件:

正在上传…重新上传取消

Git⽤<<<<<<<,=======,>>>>>>>标记出不同分⽀的内容,我们修改如下后保存

Creating a new branch is quick and simple.

再提交:$ git add readme.txt

$ git commit -m "conflict fixed"

现在,master分⽀和feature1分⽀变成了下图所⽰:

正在上传…重新上传取消

⽤带参数的git log也可以看到分⽀的合并情况:

正在上传…重新上传取消

现在,删除feature1分⽀,⼯作完成。

正在上传…重新上传取消

⼩结

当Git⽆法⾃动合并分⽀时,就必须⾸先解决冲突。解决冲突后,再提交,合并完成。⽤git log --graph可以查看分支合并情况。

(3)分⽀管理策略

通常,合并分⽀时,如果可能,Git会⽤“Fast forward”模式,但这种模式下,删除分⽀后,会丢掉分⽀信息。如果要强制禁⽤“Fast forward”模式,Git就会在merge时⽣成⼀个新的commit,这样,从分⽀历史上就可以看出分⽀信息。

下⾯我们实战⼀下--no-ff ⽅式的merge 修改readme.txt⽂件,并提交⼀个新的commit:

正在上传…重新上传取消

新建dev分⽀:

正在上传…重新上传取消

现在,我们切换回master,准备合并dev分⽀,请注意--no-ff参数,表⽰禁⽤“Fast forward”:

正在上传…重新上传取消

因为本次合并要创建⼀个新的commit,所以加上-m参数,把commit描述写进去。合并后,我们⽤git log看看分⽀历史:

正在上传…重新上传取消

可以看到,不使⽤“Fast forward”模式,merge后就像这样:

正在上传…重新上传取消

分⽀策略

在实际开发中,我们应该按照⼏个基本原则进⾏分⽀管理:

⾸先,master分⽀应该是⾮常稳定的,也就是仅⽤来发布新版本,平时不能在上⾯干活;

那在哪干活呢?干活都在dev分⽀上,也就是说,dev分⽀是不稳定的,到某个时候,⽐如 1.0版本发布时,再把dev分⽀合并到master上,在master分⽀发布1.0版本;

你和你的⼩伙伴们每个⼈都在dev分⽀上干活,每个⼈都有⾃⼰的分⽀,时不时地往dev分 ⽀上合并就可以了。

所以,团队合作的分⽀看起来就像这样:

正在上传…重新上传取消

⼩结

Git分⽀⼗分强⼤,在团队开发中应该充分应⽤。

合并分⽀时,加上--no-ff参数就可以⽤普通模式合并,合并后的历史有分⽀,能看出来曾经做过合并。

(4)bug分支

软件开发中,bug就像家常便饭⼀样。有了bug就需要修复,在Git中,由于分⽀是如此的强⼤,所以,每个bug都可以通过⼀个新的临时分⽀来修复,修复后,合并分⽀,然后将临时分⽀删除。

当你接到⼀个修复⼀个代号101的bug的任务时,很⾃然地,你想创建⼀个分⽀issue -101来修复它,

正在上传…重新上传取消

但是,等等,当前正在dev上进⾏的⼯作还没有提交: 

正在上传…重新上传取消

正在上传…重新上传取消并不是你不想提交,⽽是⼯作只进⾏到⼀半,还没法提交,预计完成还需1天时间。但是必须在两个⼩时内修复该bug,怎么办?

幸好,Git还提供了⼀个stash功能,可以把当前⼯作现场“储藏”起来,等以后恢复现场后继续⼯作:

正在上传…重新上传取消

现在,⽤git status查看⼯作区,就是干净的(除⾮有没有被Git管理的⽂件),因此可以放⼼地创建分⽀来修复bug。⾸先确定要在哪个分⽀上修复bug,假定需要在master分⽀上修复,就从master创建临时分⽀:

正在上传…重新上传取消

现在修复bug,需要把“chilinan llllllll”改为“chilinman”,然后提交修复完成后,切换到master分⽀,并完成合并,最后删除issue-101分⽀: 

正在上传…重新上传取消 

现在,是时候接着回到dev分⽀干活了! ⼯作区是干净的,刚才的⼯作现场存到哪去了?⽤git stash list命令看看: 

正在上传…重新上传取消

⼯作现场还在,Git把stash内容存在某个地⽅了,但是需要恢复⼀下,有两个办法:

⼀是⽤git stash apply恢复,但是恢复后,stash内容并不删除,你需要⽤git stash drop来删除;

另⼀种⽅式是⽤git stash pop,恢复的同时把stash内容也删了:

再⽤git stash list查看,就看不到任何stash内容了:

正在上传…重新上传取消

你可以多次stash,恢复的时候,先⽤git stash list查看,然后恢复指定的stash,⽤命令:

$ git stash apply stash@{0}

⼩结

修复bug时,我们会通过创建新的bug分⽀进⾏修复,然后合并,最后删除;

当⼿头⼯作没有完成时,先把⼯作现场git stash⼀下,然后去修复bug,修复后,再git stash pop

  1. 标签管理

发布⼀个版本时,我们通常先在版本库中打⼀个标签,这样,就唯⼀确定了打标签时刻的版本。将来⽆论什么时候,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来。 所以,标签也是版本库的⼀个快照。 Git的标签虽然是版本库的快照,但其实它就是指向某个commit的指针(跟分⽀很像对不

对?但是分⽀可以移动,标签不能移动),所以,创建和删除标签都是瞬间完成的。

  1. 创建标签

在Git中打标签⾮常简单,⾸先,切换到需要打标签的分⽀上:

正在上传…重新上传取消

然后,敲命令git tag name就可以打⼀个新标签,可以⽤命令git tag查看所有标签:

正在上传…重新上传取消

默认标签是打在最新提交的commit上的。有时候,如果忘了打标签,⽐如,现在已经是周五了,但应该在周⼀打的标签没有打,怎么办? ⽅法是找到历史提交的commit id,然后打上就可以了:

正在上传…重新上传取消

⽐⽅说要对“add merge”这次提交打标签,找到对应的commit id,敲⼊

命令: 

正在上传…重新上传取消

注意,标签不是按时间顺序列出,⽽是按字⺟排序的。可以⽤git show tagname查看标签信息:

正在上传…重新上传取消

可以看到,“v0.9”确实打在“add merge”这次提交上。

还可以创建带有说明的标签,⽤-a指定标签名,-m指定说明⽂字:

正在上传…重新上传取消

⼩结

命令git tag name⽤于新建⼀个标签,默认为HEAD,也可以指定⼀个commit id;

-a tagname -m "blablabla..."可以指定标签信息;

-s tagname -m "blablabla..."可以⽤PGP签名标签;

命令git tag可以列出所有标签。

  1. 操作标签

如果标签打错了,也可以删除:

正在上传…重新上传取消

因为创建的标签都只存储在本地,不会⾃动推送到远程。所以,打错的标签可以在本地安全删除。 如果要推送某个标签到远程,使⽤命令git push origin tagname

$ git push origin v1.0

Total 0 (delta 0), reused 0 (delta 0)

To [email protected]:michaelliao/learngit.git

* [new tag] v1.0 -> v1.0

或者,⼀次性推送全部尚未推送到远程的本地标签:

$ git push origin --tags

Counting objects: 1, done.

Writing objects: 100% (1/1), 554 bytes, done.

Total 1 (delta 0), reused 0 (delta 0)

To [email protected]:michaelliao/learngit.git

* [new tag] v0.2 -> v0.2

* [new tag] v0.9 -> v0.9

如果标签已经推送到远程,要删除远程标签就⿇烦⼀点,先从本地删除:

$ git tag -d v0.9

Deleted tag 'v0.9' (was 6224937)

然后,从远程删除。删除命令也是push,但是格式如下:

$ git push origin :refs/tags/v0.9

To [email protected]:michaelliao/learngit.git

- [deleted] v0.9

要看看是否真的从远程库删除了标签,可以登陆GitHub查看。

⼩结

命令git push origin tagname可以推送⼀个本地标签;

命令git push origin --tags可以推送全部未推送过的本地标签;

命令git tag -d tagname可以删除⼀个本地标签;

命令git push origin :refs/tags/tagname

  1. 其他改写提交git命令与区别

  1. git fetch\clone\pull

基本用法

  1. git clone 

git clone顾名思义就是将其他仓库克隆到本地,包括被clone仓库的版本变化。举个例子,你当前目录比方说是在e:/course/中,此时若想下载远程仓库,本地无需git init,直接git clone url(url是你远程仓库的地址,直接复制就可以了)。执行git clone等待clone结束,e:/course/目录下自动会有一个.git的隐藏文件夹(如果看不见,请尝试设置隐藏文件夹可见),因为是clone来的,所以.git文件夹里存放着与远程仓库一模一样的版本库记录。clone操作是一个从无到有的克隆操作,再次强调不需要git init初始化。 

基本用法:

$ git clone <版本库的url>

例如克隆TensorFlow:

$ git clone https://github.com/tensorflow/tensorflow.git

或者使用SSH协议:

$ git clone git@github.com:tensorflow/tensorflow.git

这样就会在本地生成一个目录,该目录与远程仓库同名。
如果本地目录不想与远程仓库同名怎么办??也有办法,将目录名作为git clone命令的第二个参数:

$ git clone <版本库的网址> <本地目录名>

  1. git pull

git pull是拉取远程分支更新到本地仓库的操作。比如远程仓库里的学习资料有了新内容,需要把新内容下载下来的时候,就可以使用git pull命令。事实上,git pull是相当于从远程仓库获取最新版本,然后再与本地分支merge(合并)。即:git pull = git fetch + git merge

注:git fetch不会进行合并,执行后需要手动执行git merge合并,而git pull拉取远程分支后直接与本地分支进行合并。更准确地说,git pull是使用给定的参数运行git fetch,并调用git merge将检索到的分支头合并到当前分支中。

基本用法:

$ git pull <远程主机名> <远程分支名>:<本地分支名>

举例:将远程主机origin的master分支拉取过来,与本地的branch test分支合并。

$ git pull origin master:branchtest

如果将冒号和后面的branchtest去掉,则表示将远程origin仓库的master分支拉取下来与本地当前分支合并。
   以上的git pull操作如果用git fetch来表示:

$ git fetch origin master: brantest

$ git merge brantest

相比起来,git fetch更安全也更符合实际要求,因为可以在merge前,我们可以查看更新情况,根据实际情况再决定是否合并。

  1. git fetch

理解 fetch 的关键, 是理解FETCH_HEAD,FETCH_HEAD指的是:某个branch在服务器上的最新状态。这个列表保存在 .Git/FETCH_HEAD 文件中, 其中每一行对应于远程服务器的一个分支。当前分支指向的FETCH_HEAD, 就是这个文件第一行对应的那个分支一般来说, 存在两种情况:

  1. 如果没有显式的指定远程分支, 则远程分支的master将作为默认的FETCH_HEAD
  2. 如果指定了远程分支, 就将这个远程分支作为FETCH_HEAD

git fetch更新本地仓库的两种用法:

# 方法一

$ git fetch origin master  #从远程的origin仓库的master分支下载代码到本地的origin maste

$ git log -p master.. origin/master #比较本地的仓库和远程仓库的区别

$ git merge origin/master   #把远程下载下来的代码合并到本地仓库,远程的和本地的合并

# 方法二

$ git fetch origin master:temp   #从远程的origin仓库的master分支下载到本地并新建一个分支temp

$ git diff temp         #比较master分支和temp分支的不同

$ git merge temp        #合并temp分支到master分支

$ git branch -d temp    #删除temp

区别

  1.  是否需要本地初始化仓库

git clone 不需要,git pull 和 git fetch 需要。

  1.  是否可以指定分支推送到远程

git clone下来的项目可以直接推送到远程,git pull 和 git fetch 需要先执行 git remote add 添加远程仓库后才能 push。

(2)git commit --amend

有时你提交过代码之后,发现一个地方改错了,你下次提交时不想保留上一次的记录;或者你上一次的commit message的描述有误,这时候你可以使用接下来的这个命令:git commit --amend。

git功能十分强大,接下来我将讲解一下git commit --amend命令的用法git log之后,可以看到你之前提交过的git历史:

正在上传…重新上传取消接下来,执行:

$ git commit --amend

这时bash里会出现以下内容:

正在上传…重新上传取消

其中,second commit 是你上次提交的描述,下面是一下说明信息,有告诉你上次提交的文件信息等等,可忽略。接下来你要是想修改描述信息的话。直接键入:i,此时进入了输入模式,变成上图的样子可用键盘上下键转到描述所在的那一行,然后进行修改修改完成后,按下 Esc键退出编辑模式,在键入 :wq 回车退出并保存修改,完成提交。这是你再git log看一下提交日志:

正在上传…重新上传取消

已经修改了提交描述信息,且原来的git版本没有了但是有个地方要注意,就是该操作会改变你原来的commit id。

(3)版本回退

在利用github实现多人合作程序开发的过程中,我们有时会出现错误提交的情况,此时我们希望能撤销提交操作,让程序回到提交前的样子,本文总结了两种解决方法:回退(reset)、反做(revert)。

方法一:git reset

原理:git reset的作用是修改HEAD的位置,即将HEAD指向的位置改变为之前存在的某个版本,如下图所示,假设我们要回退到版本一:
 

正在上传…重新上传取消
适用场景:如果想恢复到之前某个提交的版本,且那个版本之后提交的版本我们都不要了,就可以用这种方法。

具体操作:

  1. 查看版本号:
    可以使用命令“git log”查看:

    正在上传…重新上传取消
    2. 使用“git reset --hard 目标版本号”命令将版本回退:

正在上传…重新上传取消
再用“git log”查看版本信息,此时本地的HEAD已经指向之前的版本:

3. 使用“git push -f”提交更改:
此时如果用“git push”会报错,因为我们本地库HEAD指向的版本比远程库的要旧:

所以我们要用“git push -f”强制推上去,就可以了:

方法二:git revert

原理:git revert是用于“反做”某一个版本,以达到撤销该版本的修改的目的。比如,我们但又commit了三个版本(版本一、版本二、 版本三),突然发现版本二不行(如:有bug),想要撤销版本二,不想影响撤销版本三的提交,就可以用 git revert 命令来反做版本二,生成新的版本四,这个版本四里会保留版本三的东西,但撤销了版本二的东西。如下图所示:
 

正在上传…重新上传取消
适用场景:如果我们想撤销之前的某一版本,但是又想保留该目标版本后面的版本,记录下这整个版本变动流程,就可以用这种方法。

具体操作:

个例子,现在库里面有三个文件:READ.md、text.txt、text2.txt。
 

正在上传…重新上传取消
1. 查看版本号:
可以通过命令行查看(输入git log):
如图,最近的两个版本分别叫:“add text.txt”(即新增了文件text.txt)、“add text2.txt”(新增了文件text2.txt)。这个时候我们不需要text.txt这个文件了,那就是说不想要“add text.txt”那个版本的操作,那可以通过反做“add text.txt”这个版本来实现。


2.使用“git revert -n 版本号”反做,并使用“git commit -m 版本名”提交:
(1)反做,使用“git revert -n 版本号”命令。如下命令,我们反做版本号为8b89621的版本:

git revert -n 8b89621019c9adc6fc4d242cd41daeb13aeb9861

注意:这里可能会出现冲突,那么需要手动修改冲突的文件。而且要git add 文件名。

(2)提交,使用“git commit -m 版本名”,如:

git commit -m "revert add text.txt"

此时可以用“git log”查看本地的版本信息,可见多生成了一个新的版本,该版本反做了“add text.txt”版本,但是保留了“add text2.txt”版本:
 

正在上传…重新上传取消
3.使用“git push”推上远程库:


此时查看仓库的文件,剩下两个:READ.md、text2.txt

正在上传…重新上传取消

(4)Rebase

在Git中整合来自不同分支的修改主要有两种方法:merge以及rebase“变基”在本节中我们将学习什么是“变基”,怎样使用“变基”,以及“变基”的风险

基的基本操作

回顾之前在分支的合并中的一个例子,你会看到开发任务分叉到两个不同支,又各自提交了更新。

正在上传…重新上传取消

分叉的提交历史

之前介绍过,整合分支最容易的方法是merge命令。它会把两个分支的最新快照(C3C4)以及二者最近的共同祖先(C2)进行三方合并,合并的结果是生成一个新的快照(并提交)。

正在上传…重新上传取消

通过合并操作来整合分叉的历史

其实,还有一种方法:你可以提取在C4中引入的补丁和修改,然C3的基础上应用一次。Git中,这种操作就叫做变基(rebase)。你可以使用rebase命令将提交到某一分支上的所有修改都移至另一分支上,就好像“重新播放”一样。在这个例子中,你可以检出experiment分支,然后将它变基到master分支上:

$ git checkout experiment

$ git rebase master

First, rewinding head to replay your work on top of it...

Applying: added staged command

的原理是首先找到这两个分支(即当前分支experiment、变基操作的目标基底分支master)的最近共同祖先C2,然后对比当前分支相对于该祖先的历次提交,提取相应的修改并存为临时文件,然后将当前分支指向目标基底C3, 最后以此将之前另存为临时文件的修改依序应用。

正在上传…重新上传取消

C4中的修改变基到C3

现在回到master分支,进行一次快进合并。

$ git checkout master

$ git merge experiment

正在上传…重新上传取消

master分支的快进合并

此时,C4'指向的快照就和the merge exampleC5指向的快照一模一样了。 这两种整合方法的最终结果没有任何区别,但是变基使得提交历史更加整洁。你在查看一个经过变基的分支的历史记录时会发现,尽管实际的开发工作是并行的, 但它们看上去就像是串行的一样,提交历史是一条直线没有分叉。

一般我们这样做的目的是为了确保在向远程分支推送时能保持提交历史的整洁——例如向某个其他人维护的项目贡献代码时。在这种情况下,你首先在自己的分支里进行开发,当开发完成时你需要先将你的代码变基到origin/master上,然后再向主项目提交修改。这样的话,该项目的维护者就不再需要进行整合工作,只需要快进合并便可。

请注意,无论是通过变基,还是通过三方合并,整合的最终结果所指向的快照始终是一样的,只不过提交历史不同罢了。变基是将一系列提交按照原有次序依次应用到另一分支上,而合并是把最终结果合在一起。

更有趣的变基例子

在对两个分支进行变基时,所生成的“重放”并不一定要在目标分支上应用,你也可以指定另外的一个分支进行应用。你创建了一个主题分支server,为服务端添加了一些功能,提交了C3C4。然后从C3上创建了主题分支client,为客户端添加了一些功能,提交了C8C9 最后,你回到server分支,又提交了C10

正在上传…重新上传取消

从一个主题分支里再分出一个主题分支的提交历史

假设你希望将client中的修改合并到主分支并发布,但暂时并不想合并server中的修改, 因为它们还需要经过更全面的测试。这时,你就可以使用git rebase命令的--onto选项, 选中在client分支里但不在server分支里的修改(即C8C9),将它们在master分支上重放:

$ git rebase --onto master server client

以上命令的意思是:“取出client分支,找出它从server分支分歧之后的补丁, 然后把这些补丁在master分支上重放一遍,让client看起来像直接基于master修改一样”。这理解起来有一点复杂,不过效果非常酷。

正在上传…重新上传取消

截取主题分支上的另一个主题分支,然后变基到其他分支

现在可以快进合并master分支了。(如快进合并master分支,使之包含来自client分支的修改):

$ git checkout master

$ git merge client

正在上传…重新上传取消

快进合并master分支,使之包含来自client分支的修改

接下来你决定将server分支中的修改也整合进来。使用git rebase 命令可以直接将主题分支(即本例中的server)变基到目标分支(即master)上。这样做能省去你先切换到server分支,再对其执行变基命令的多个步骤。

$ git rebase master server

将server中的修改变基到master上所示,server中的代码被“续”到了master后面。

正在上传…重新上传取消

server中的修改变基到master

然后就可以快进合并主分支master了:

$ git checkout master

$ git merge server

至此,clientserver分支中的修改都已经整合到主分支里了,你可以删除这两个分支,最终提交历史会变成图中的样子:

$ git branch -d client

$ git branch -d server

正在上传…重新上传取消

最终的提交历史

变基的风险

奇妙的变基也并非完美无缺,要用它得遵守一条准则:如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。

变基操作的实质是丢弃一些现有的提交,然后相应地新建一些内容一样但实际上不同的提交。如果你已经将提交推送至某个仓库,而其他人也已经从该仓库拉取提交并进行了后续工作,此时,如果你用git rebase命令重新整理了提交并再次推送,你的同伴因此将不得不再次将他们手头的工作与你的提交进行合,如果接下来你还要拉取并整合他们修改过的提交,事情就会变得一团糟。让我们来看一个在公开的仓库上执行变基操作所带来的问题。假设你从一个中央服务器克隆然后在它的基础上进行了一些开发你的提交历史如图所示:

正在上传…重新上传取消

克隆一个仓库,然后在它的基础上进行了一些开发

然后,某人又向中央服务器提交了一些修改,其中还包括一次合并。你抓取了这些在远程分支上的修改,并将其合并到你本地的开发分支,然后你的提交历史就会变成这样:

正在上传…重新上传取消

抓取别人的提交,合并到自己的开发分支

接下来这个人又决定把合并操作回滚,改用变基;继而又用git push --force命令覆盖了服务器上的提交历史。之后你从服务器抓取更新,会发现多出来一些新的提交。

正在上传…重新上传取消

有人推送了经过变基的提交,并丢弃了你的本地开发所基于的一些提交

结果就是你们两人的处境都十分尴尬。 如果你执行git pull命令,你将合并来自两条提交历史的内容,生成一个新的合并提交,最终仓库会如图所示:

正在上传…重新上传取消

你将相同的内容又合并了一次,生成了一个新的提交

此时如果你执行git log命令,你会发现有两个提交的作者、日期、日志居然是一样的,这会令人感到混乱。此外,如果你将这一堆又推送到服务器上,你实际上是将那些已经被变基抛弃的提交又找了回来,这会令人感到更加混乱。很明显对方并不想在提交历史中看到C4C6,因为之前就是他把这两个提交通过变基丢弃的。

用变基解决变基

如果真的遭遇了类似的处境,Git 还有一些高级魔法可以帮到你。如果团队中的某人强制推送并覆盖了一些你所基于的提交,你需要做的就是检查你做了哪些修改,以及他们覆盖了哪些修改。如果你拉取被覆盖过的更新并将你手头的工作基于此进行变基的话,一般情况下Git都能成功分辨出哪些是你的修改,并把它们应用到新分支上。

举个例子,如果遇到前面提到的有人推送了经过变基的提交,并丢弃了你的本地开发所基于的一些提交那种情境,如果我们不是执行合并,而是执行git rebase teamone/master, Git将会:

1检查哪些提交是我们的分支上独有的(C2,C3,C4,C6,C7)

2检查其中哪些提交不是合并操作的结果(C2,C3,C4)

3检查哪些提交在对方覆盖更新时并没有被纳入目标分支(只有 C2 和 C3,因为 C4 其实就是 C4')

4把查到的这些提交应用在teamone/master上面

从而我们将得到与你将相同的内容又合并了一次,生成了一个新的提交中不同的结果,如在一个被变基然后强制推送的分支上再次执行变基所示。

正在上传…重新上传取消

在一个被变基然后强制推送的分支上再次执行变基

要想上述方案有效,还需要对方在变基时确保C4'C4是几乎一样的。否则变基操作将无法识别,并新建另一个类似C4的补丁(而这个补丁很可能无法整洁的整合入历史,因为补丁中的修改已经存在于某个地方了)。

在本例中另一种简单的方法是使用git pull --rebase命令而不是直接git pull。又或者你可以自己手动完成这个过程,先git fetch,再git rebase teamone/master

如果你习惯使用git pull,同时又希望默认使用选项--rebase,你可以执行这条语句git config --global pull.rebase true来更改pull.rebase的默认配置。

如果你只对不会离开你电脑的提交执行变基,那就不会有事。如果你对已经推送过的提交执行变基,但别人没有基于它的提交,那么也不会有事。如果你对已经推送至共用仓库的提交上执行变基命令,并因此丢失了一些别人的开发所基于的提交,那你就有大麻烦了,你的同事也会因此鄙视你。

如果你或你的同事在某些情形下决意要这么做,请一定要通知每个人执行git pull --rebase命令。

变基 vs. 合并

至此,你已在实战中学习了变基和合并的用法,你一定会想问,到底哪种方式更好。在回答这个问题之前,让我们退后一步,想讨论一下提交历史到底意味着什么。

有一种观点认为,仓库的提交历史即是记录实际发生过什么。它是针对历史的文档,本身就有价值,不能乱改。如果由合并产生的提交历史是一团糟怎么办? 既然事实就是如此,那么这些痕迹就应该被保留下来,让后人能够查阅。

另一种观点则正好相反,他们认为提交历史是项目过程中发生的事。没人会出版一本书的第一版草稿,软件维护手册也是需要反复修订才能方便使用。持这一观点的人会使用rebasefilter-branch等工具来编写,怎么方便后来的读者就怎么写。

现在,让我们回到之前的问题上来,到底合并还是变基好?希望你能明白,这并没有一个简单的答案。Git 是一个非常强大的工具,它允许你对提交历史做许多事情,但每个团队、每个项目对此的需求并不相同。既然你已经分别学习了两者的用法,相信你能够根据实际情况作出明智的选择。

总的原则是,只对尚未推送或分享给别人的本地修改执行变基操作清理历史,从不对已推送至别处的提交执行变基操作,这样你才能享受到两种方式带来的便利。

5、GItHub

5.1 远程仓库

Git是分布式版本控制系统,同⼀个Git仓库,可以分布到不同的机器上。实际情况往往是这样,找⼀台电脑充当服务器的⾓⾊,每天24⼩时开机,其他每个⼈都从这个“服务器”仓库克隆⼀份到⾃⼰的电脑上,并且各⾃把各⾃的提交推送到服务器仓库⾥,也从服务器仓库中拉取别⼈的提交。

完全可以⾃⼰搭建⼀台运⾏Git的服务器,不过现阶段,为了学Git先搭个服务器绝对是⼩题⼤作。好在这个世界上有个叫GitHub的神奇的站,从名字就可以看出,这个网站就是提供Git仓库托管服务的,所以,只要注册⼀个GitHub账号,就可以免费获得Git远程仓库。

  1. 配置

由于你的本地Git仓库和GitHub仓库之间的传输是通过SSH加密的,所以,需要⼀点设置:

第1步:创建SSH Key。在⽤户主目录下,看看有没有.ssh目录,如果有,再看看这个目录下有没有id_rsa和id_rsa.pub这两个⽂件,如果已经有了,可直接跳到下⼀步。

正在上传…重新上传取消

如果没有,打开Shell(Windows下打开Git Bash),创建SSH Key:

$ ssh-keygen -t rsa -C "xxx[email protected]"

你需要把邮件地址换成你⾃⼰的邮件地址,然后⼀路回⻋,使⽤默认值即可,由于这个Key 也不是⽤于军事目的,所以也⽆需设置密码。 如果⼀切顺利的话,可以在⽤户主目录⾥找到.ssh目录,⾥⾯有id_rsa和id_rsa.pub两个⽂件,这两个就是SSH Key的秘钥对,id_rsa是私钥,不能泄露出去,id_rsa.pub是公钥,可以放⼼地告诉任何⼈。

第2步:登陆GitHub,打开“Account settings”,“SSH Keys”⻚⾯: 

正在上传…重新上传取消

然后,点“Add SSH Key”,填上任意Title,在Key⽂本框⾥粘贴id_rsa.pub⽂件的内容:

正在上传…重新上传取消

点“Add Key”,你就应该看到已经添加的Key。

为什么GitHub需要SSH Key呢?因为GitHub需要识别出你推送的提交确实是你推送的,⽽不是别⼈冒充的,⽽Git⽀持SSH协议,所以,GitHub只要知道了你的公钥,就可以确认只有你⾃⼰才能推送。

当然,GitHub允许你添加多个Key。假定你有若干电脑,你⼀会⼉在公司提交,⼀会⼉在家⾥提交,只要把每台电脑的Key都添加到GitHub,就可以在每台电脑上往GitHub推送了。

最后友情提⽰,在GitHub上免费托管的Git仓库,任何⼈都可以看到(但只有你⾃⼰才能改)。所以,不要把敏感信息放进去。如果你不想让别⼈看到Git库,有两个办法,⼀个是交点保护费,让GitHub把公开的仓库变成私有的,这样别⼈就看不⻅了(不可读更不可写)。另⼀个办法是⾃⼰动⼿,搭⼀个Git 服务器,因为是你⾃⼰的Git服务器,所以别⼈也是看不⻅的。这个⽅法我们后⾯会讲到的,相当简单公司内部开发必备。

(2)添加远程库

现在的情景是,你已经在本地创建了⼀个Git仓库后,⼜想在GitHub创建⼀个Git仓库,并且让这两个仓库进⾏远程同步,这样,GitHub上的仓库既可以作为备份,⼜可以让其他⼈通过该仓库来协作,真是⼀举多得。

⾸先,登陆GitHub,然后,在右上⾓找到“Create a new repo”按钮,创建⼀个新的仓库:

正在上传…重新上传取消

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

正在上传…重新上传取消

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

现在,我们根据GitHub的提⽰,在本地的learngit仓库下运⾏命令:

正在上传…重新上传取消

(如果报错的话:1、先输入$ git remote rm origin 2、再输入$ git remote add origin [email protected]: xxxxxx/gitdemo.git 就不会报错了!

添加后,远程库的名字就是origin,这是Git默认的叫法,也可以改成别的,但是origin这个名字⼀看就知道是远程库。

下⼀步,就可以把本地库的所有内容推送到远程库上:

正在上传…重新上传取消

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

由于远程库是空的,我们第⼀次推送master分⽀时,加上了-u参数,Git不但会把本地的master分⽀内容推送的远程新的master分⽀,还会把本地的master分⽀和远程的master分⽀关联起来,在以后的推送或者拉取时就可以简化命令。

推送成功后,可以⽴刻在GitHub⻚⾯中看到远程库的内容已经和本地⼀模⼀样:

正在上传…重新上传取消

从现在起,只要本地作了提交,就可以通过命令:

$ git push origin master

把本地master分⽀的最新修改推送⾄GitHub,现在,你就拥有了真正的分布式版本库!

⼩结

要关联⼀个远程库,使⽤命令git remote add origin git@server-name:path/repo-name.git;关联后,使⽤命令git push -u origin master第⼀次推送master分⽀的所有内容;

此后,每次本地提交后,只要有必要,就可以使⽤命令git push origin master推送最新修改;分布式版本系统的最⼤好处之⼀是在本地⼯作完全不需要考虑远程库的存在,也就是有没有联网都可以正常⼯作

(3)从远程库克隆

上次我们讲了先有本地库,后有远程库的时候,如何关联远程库。现在,假设我们从零开发,那么最好的⽅式是先创建远程库,然后,从远程库克隆。⾸先,登陆GitHub,创建⼀个新的仓库,名字叫gitskills,我们勾选Initialize this repository with a README,这样GitHub会⾃动为我们创建⼀个README.md⽂件。创建完毕后,可以看到README.md⽂件:

正在上传…重新上传取消

现在,远程库已经准备好了,下⼀步是⽤命令git clone克隆⼀个本地库:

正在上传…重新上传取消

如果有多个⼈协作开发,那么每个⼈各⾃从远程克隆⼀份就可以了。你也许还注意到,GitHub给出的地址不⽌⼀个,还可以⽤https://github.com/

xxxxxxx/gitskills.git这样的地址。实际上,Git⽀持多种协议,默认的git://使⽤ssh,但也可以使⽤https等其他协议。使⽤https除了速度慢以外,还有个最⼤的⿇烦是每次推送都必须输⼊⼝令,但是在某些只开放http端⼝的公司内部就⽆法使⽤ssh协议⽽只能⽤https。

⼩结

要克隆⼀个仓库,⾸先必须知道仓库的地址,然后使⽤git clone命令克隆。

Git⽀持多种协议,包括https,但通过ssh⽀持的原⽣git协议速度最快。

5.2 邀请团队成员

正在上传…重新上传取消

举例说明:

实验账号: itkuke 为主人, 邀请183用户来参与

项目 test2018 (public)


  如果itkuke用户没有邀请183用户,183用户是可以直接克隆下来test2018, 可以本地修改, 但是没有权限推送到itkuke的仓库上面如图:
 

正在上传…重新上传取消
接下来邀请183用户参与test2018的开发, 183用户再来推送


对方收到邀请邮件, 确认就可以了!


  
同意后, 就能够一起开发了

itkuke用户, 查看刚才183用户的提交:

5.3 多⼈协作

当你从远程仓库克隆时,实际上Git⾃动把本地的master分⽀和远程的master分⽀对应起来了,并且,远程仓库的默认名称是origin。

要查看远程库的信息,⽤git remote或者⽤git remote -v显⽰更详细的信息:

正在上传…重新上传取消

(1)推送分支

推送分⽀,就是把该分⽀上的所有本地提交推送到远程库。推送时,要指定本地分⽀,这样,Git就会把该分⽀推送到远程库对应的远程分⽀上:

$ git push origin master 

如果要推送其他分⽀,⽐如dev,就改成:

$ git push origin dev

但是,并不是⼀定要把本地分⽀往远程推送,那么,哪些分⽀需要推送,哪些不需要呢?

• master分⽀是主分⽀,因此要时刻与远程同步;

• dev分⽀是开发分⽀,团队所有成员都需要在上⾯⼯作,所以也需要与远程同步;

• bug分⽀只⽤于在本地修复bug,就没必要推到远程了,除⾮⽼板要看看你每周到底修复了⼏个bug;

• feature分⽀是否推到远程,取决于你是否和你的⼩伙伴合作在上⾯开发。 

总之,就是在Git中,分⽀完全可以在本地⾃⼰藏着玩,是否推送,视你的⼼情⽽定!

  1. 抓取分支

多⼈协作时,⼤家都会往master和dev分⽀上推送各⾃的修改。现在,模拟⼀个你的⼩伙伴,可以在另⼀台电脑(注意要把SSH Key添加到GitHub)或者同⼀台电脑的另⼀个目录下克隆:

正在上传…重新上传取消

当你的⼩伙伴从远程库clone时,默认情况下,你的⼩伙伴只能看到本地的master分⽀。不信可以⽤git branch命令看看:

正在上传…重新上传取消

现在,你的⼩伙伴要在dev分⽀上开发,就必须创建远程origin的dev分⽀到本地,于是他⽤这个命令创建本地dev分⽀:

$ git checkout -b dev origin/dev

正在上传…重新上传取消

现在,他就可以在dev上继续修改,然后,时不时地把dev分⽀push到远程:

正在上传…重新上传取消

你的⼩伙伴已经向origin/dev分⽀推送了他的提交,⽽碰巧你也对同样的⽂件作了修改,并试图推送:

正在上传…重新上传取消

推送失败,因为你的⼩伙伴的最新提交和你试图推送的提交有冲突,解决办法也很简单,Git已经提⽰我们,先⽤git pull把最新的提交从origin/dev抓下来,然后,在本地合并,解决冲突,再推送:

正在上传…重新上传取消

git pull也失败了,查看文件解决冲突后push:

正在上传…重新上传取消

因此,多⼈协作的⼯作模式通常是这样: 

1. ⾸先,可以试图⽤git push origin branch-name推送⾃⼰的修改;

2. 如果推送失败,则因为远程分⽀⽐你的本地更新,需要先⽤git pull试图合并;

3. 如果合并有冲突,则解决冲突,并在本地提交;

4. 没有冲突或者解决掉冲突后,再⽤git push origin branch-name推送就能成功!

如果git pull提⽰“no tracking information”,则说明本地分⽀和远程分⽀的链接关系没有创建,⽤命令git branch --set-upstream branch-name origin/branch-name

这就是多⼈协作的⼯作模式,⼀旦熟悉了,就⾮常简单。

⼩结

• 查看远程库信息,使⽤git remote -v

• 本地新建的分⽀如果不推送到远程,对其他⼈就是不可⻅的;

• 从本地推送分⽀,使⽤git push origin branch-name,如果推送失败,先⽤git pull抓取远程的新提交;

• 在本地创建和远程分⽀对应的分⽀,使⽤git checkout -b branch-name origin/branchname,本地和远程分⽀的名称最好⼀致;

• 建⽴本地分⽀和远程分⽀的关联,使⽤git branch --set-upstream branch-name origin/branch-name

• 从远程抓取分⽀,使⽤git pull,如果有冲突,要先处理冲突。

要点

如果不是基于 GitHub 远程库的最新版所做的修改,不能推送,必须先拉取。拉取下来后如果进入冲突状态,则按照“分支冲突解决”操作解决即可。

  1. pycharm操作

6.1 pycharm上登录github账户

File->settings->Vesion Control中的GitHub可以查看添加账户:

正在上传…重新上传取消

输入github邮箱账户、密码
点击Test测试连接

 

正在上传…重新上传取消

勾选ssh
点击Apply即可

6.2 创建github仓库

点击VSC——Import into Version Control——Share Project on Github

正在上传…重新上传取消

然后会弹出框让你输入一个仓库名(不能为中文)然后点击share
然后会弹出让你选择哪些文件需要被同步,选好后,在下面的commit Message可以输入自己的信息,然后点OK,你的代码就提交到网上了

 

正在上传…重新上传取消

然后就可以在github上看到新建的repositories

6.3 修改后的文件提交

对修改后的文件或文件夹右击:Git->Add
然后点击Add上的commit file

正在上传…重新上传取消

填好commit message 然后在commit按钮的下拉中选择commit and Push,就可以直接提交到网上

6.4 使用pycharm克隆github仓库

VSC->Checkout from Vesion Control就可以克隆github上的工程

正在上传…重新上传取消

6.5 在pycharm内进行git的相关操作

具体的push,add,status等git常用操作都在VCS菜单里的git下可以找得到。

正在上传…重新上传取消

6.6 新建github分支

默认工程有一个master分支,我们开发时可以建一个dev分支。在pycharm有git的分支信息,可以点击里面的New Brash创建。

正在上传…重新上传取消

(补充:罗红梅分享的

正在上传…重新上传取消

  1. git工作流

解决 Git合并冲突是每个开发人员都讨厌的事情之一,尤其是当你准备进行生产环境部署时!正确的设置 Git 工作流可以改善你的开发流程。当然,拥有正确的 Git 工作流并不能解决你的所有问题。但这是朝正确方向迈出的一步。毕竟,由于每个团队都是远程工作的,在不破坏代码库的情况下共同开发产品功能是非常重要的。

7.1 基本的 Git 工作流

最基本的 Git工作流是只有一个分支-master分支的模式。开发人员直接提交 master 分支并使用它来部署到预发布和生产环境。

正在上传…重新上传取消

上图为基本的 Git 工作流,所有提交都直接添加到 master 分支。通常不建议使用此工作流,除非你正在开发一个side项目并且希望快速开始。由于只有一个分支,因此这里实际上没有任何流程。这样一来,你就可以轻松开始使用 Git。但是,使用此工作流时需要记住它的一些缺点

1、在代码上进行协作将导致多种冲突。

2、生产环境出现 bug的概率会大增。

3、维护干净的代码将更加困难。

7.2 Git功能分支工作流

当你有多个开发人员在同一个代码库上工作时,Git功能分支工作流将成为必选项。假设你有一个正在开发一项新功能的开发人员。另一个开发人员正在开发第二个功能。现在,如果两个开发人员都向同一个分支提交代码,这将使代码库陷入混乱,并产生大量冲突。

正在上传…重新上传取消

上图为具有功能分支的 Git 工作流模型。

为避免这种情况,两个开发人员可以分别从 master 分支创建两个单独的分支,并分别开发其负责的功能。完成功能后他们可以将各自的分支合并到 master分支,然后进行部署,而不必等待对方的功能开发完成。

使用此工作流的优点是Git功能分支工作流使你可以在代码上进行协作,而不必担心代码冲突。

7.3带有Develop分支的Git功能分支工作流

此工作流是开发团队中比较流行的工作流之一。它与 Git 功能分支工作流相似,但它的 develop 分支与 master 分支并行存在。在此工作流中,master 分支始终代表生产环境的状态。每当团队想要部署代码到生产环境时,他们都会部署 master 分支。

Develop 分支代表针对下一版本的最新交付的代码。开发人员从 develop 分支创建新分支,并开发新功能。功能开发完毕后,将对其进行测试,与 develop 分支合并,在合并了其他功能分支的情况下使用 develop 分支的代码进行测试,然后与 master 分支合并。

正在上传…重新上传取消

上图为具有 develop 分支的 Git 功能分支工作流模型。

此工作流的优点是,它使团队能够一致地合并所有新功能,在预发布阶段对其进行测试并部署到生产环境中。尽管这种工作流让代码维护变得更加容易,但是对于某些团队来说,这样做可能会感到有些疲倦,因为频繁的 Git 操作可能会让你感到乏味。

7.4 Gitflow 工作流

Gitflow 工作流与我们之前讨论的工作流非常相似,我们将它们与其他两个分支( release 分支和 hot-fix 分支)结合使用。

7.4.1 Hot-Fix 分支

Hot-fix 分支是唯一一个从master分支创建的分支,并且直接合并到 master分支而不是develop分支。仅在必须快速修复生产环境问题时使用。该分支的一个优点是,它使你可以快速修复并部署生产环境的问题,而无需中断其他人的工作流,也不必等待下一个发布周期。

将修复合并到 master 分支并进行部署后,应将其合并到 develop 和当前的 release 分支中。这样做是为了确保任何从 develop 分支创建新功能分支的人都具有最新代码。

7.4.2 Release 分支

在将所有准备发布的功能的代码成功合并到 develop 分支之后,就可以从 develop 分支创建 release 分支了。

Release 分支不包含新功能相关的代码。仅将与发布相关的代码添加到 release 分支。例如,与此版本相关的文档,错误修复和其他关联任务才能添加到此分支。

一旦将此分支与 master 分支合并并部署到生产环境后,它也将被合并回 develop 分支中,以便之后从 develop 分支创建新功能分支时,新的分支能够具有最新代码。

正在上传…重新上传取消

上图为具有 hot-fix 和 release 分支的 Gitflow 工作流模型

此工作流已被具有预定发布周期的组织广泛使用。由于 git-flow 是对 Git 的包装,因此你可以为当前代码库安装 git-flow。git-flow 非常简单,除了为你创建分支外,它不会更改代码库中的任何内容。

要在 Mac 机器上安装 ,请在终端中执行 brew install git-flow

要在 Windows 机器上安装,你需要下载并安装 git-flow。安装完成后,运行git flow init命令,就可以在项目中使用它了。

7.5 Git Fork 工作流

Fork工作流在使用开源软件的团队中很流行。Forking 工作流是在 GitFlow 基础上,充分利用了 Git 的 Fork 和 pull request 的功能以达到代码审核的目的。更适合安全可靠地管理大团队的开发者,而且能接受不信任贡献者的提交。该流程通常如下所示:

1、开发人员 fork 开源软件的官方代码库在他们的帐户中创建此代码库的副本。

2、然后,开发人员将代码库从其帐户克隆到本地系统。

3、官方代码库的远端源已添加到克隆到本地系统的代码库中。

4、开发人员创建一个新的功能分支,该分支将在其本地系统中创建,进行更改并提交。

5、这些更改以及分支将被推送到其帐户上开发人员的代码库副本。

6、从该新功能分支创建一个 pull request,提交到官方代码库。

7、官方代码库的维护者检查 pull request 中的修改并批准将这些修改合并到官方代码库中。

7.6 版本控制工具的使用基本原则

1、精准的提交

每次提交都是一个小完整的功能或者一个BUG的修复。不应该出现多个功能点一块提交或者多个BUG一起修复的情况。如果一旦发现提交的代码有问题,可以方便的滚到改动之前的正确状态,不会影响到其他协作者开发进程。

2、频繁的提交

尽可能频繁的提交你的改动到远程仓库,这样,可以避免将来合并代码的时候产生大量的冲突以至于难以解决。同时,也可以让其他同事比较快的共享你的改动。

3、不要提交不完整的功能

如果你正在开发的新功能比较庞大,那么可以讲这个功能尽可能拆分为几个逻辑模块,并且要保证分次提交的逻辑模块不会影响到整个系统的正确性。如果你只是因为临时的一些事情需要切到别的分支或者是临时需要中断开发(比如说下班),那么应该使用Stash储藏功能来保存你的更改。

4、提交前进行测试

不要想当然的认为自己的代码是正确的,提交之前应该经过充分的测试才能提交,即使是提交到本地仓库,也应该进行测试,因为这些代码在未来会被推送到远程共享给你的同事。

5、高质量的提交注释

每次提交都应该包含完整的注释。团队成员应当遵循统一的提交规则,一般应当明确的体现出提交的类型以及具体的事情,例如 feat: add message list;

6、遵循统一的流程规范

Git可以支持很多不同的工作流程:长期分支、功能分支、合并以及 rebase、git-flow 等等。选择什么样的开发流程要取决如下一些因素:项目开发的类型,部署模式和(可能是最重要的)开发团队成员的个人习惯。不管怎样,选择什么样的流程都需要得到所有开发成员的一致认可,并且一直遵循它。

  1. 自定义git

在安装Git⼀节中,我们已经配置了user.name和user.email,实际上,Git还有很多可配置项。 ⽐如,让Git显⽰颜⾊,会让命令输出看起来更醒目:

$ git config --global color.ui true

正在上传…重新上传取消

⽂件名就会标上颜⾊。我们在后⾯还会介绍如何更好地配置Git,以便让你的⼯作更⾼效。

8.1忽略特殊⽂件

1、原因

当你使用git add .的时候有没有遇到把你不想提交的文件也添加到了缓存中去?比如项目的本地配置信息,如果你上传到Git中去其他人pull下来的时候就会和他本地的配置有冲突,所以这样的个性化配置文件我们一般不把它推送到git服务器中,但是又为了偷懒每次添加缓存的时候都想用git add .而不是手动一个一个文件添加,该怎么办呢?很简单,git为我们提供了个.gitignore文件只要在这个文件中申明那些文件你不希望添加到git中去,这样当你使用git add .的时候这些文件就会被自动忽略掉。 

在Git⼯作区的根录下创建⼀个特殊的.gitignore⽂件,然后把要忽略的⽂件名填进去,Git就会⾃动忽略这些⽂件。

2、忽略⽂件的原则是 

(1)忽略操作系统⾃动⽣成的⽂件,⽐如缩略图等;

(2)忽略编译⽣成的中间⽂件、可执⾏⽂件等,也就是如果⼀个⽂件是通过另⼀个⽂件⾃动⽣成的,那⾃动⽣成的⽂件就没必要放进版本库,⽐如Java编译产⽣的.class⽂件;

(3)忽略你⾃⼰的带有敏感信息的配置⽂件,⽐如存放⼝令的配置⽂件。

3、使用方法

首先,在你的工作区新建一个名称为.gitignore的文件。然后,把要忽略的文件名填进去,Git就会自动忽略这些文件。不需要从头写.gitignore文件,GitHub已经为我们准备了各种配置文件,只需要组合一下就可以使用了。所有配置文件可以直接在线浏览:https://github.com/github/gitignore

4、举例说明

假设你在Windows下进⾏Python开发,Windows会⾃动在有图⽚的目录下⽣成隐藏的缩略图⽂件,如果有⾃定义目录,目录下就会有Desktop.ini⽂件,因此你需要忽略Windows⾃动⽣成的垃圾⽂件:

正在上传…重新上传取消

然后,继续忽略Python编译产⽣的.pyc、.pyo、dist等⽂件或目录:

正在上传…重新上传取消

加上你⾃⼰定义的⽂件,最终得到⼀个完整的.gitignore⽂件,内容如下:

正在上传…重新上传取消 

最后⼀步就是把.gitignore也提交到Git,就完成了!当然检验.gitignore的标准是git status 命令是不是说“working directory clean”。 (使⽤Windows的时候需要注意,如果你在资源管理器⾥新建⼀个.gitignore⽂件,它会⾮常弱智地提⽰你必须输⼊⽂件名,但是在⽂本编辑器⾥“保存”或者“另存为”就可以把⽂件保存为.gitignore了。)

  1. 查看gitignore规则

如果你发下.gitignore写得有问题,需要找出来到底哪个规则写错了,可以用git check-ignore命令检查:

$ git check-ignore -v HelloWorld.class

.gitignore:1:*.class    HelloWorld.class

可以看到HelloWorld.class匹配到了我们的第一条*.class的忽略规则所以文件被忽略了。

6.忽略规则文件语法

a.忽略指定文件/目录

# 忽略指定文件

HelloWrold.class

# 忽略指定文件夹

bin/

bin/gen/

b.通配符忽略规则

通配符规则如下:

# 忽略.class的所有文件*.class

# 忽略名称中末尾为ignore的文件夹*ignore/

# 忽略名称中间包含ignore的文件夹*ignore*/

⼩结

1. 忽略某些⽂件时,需要编写.gitignore。

2. .gitignore⽂件本⾝要放到版本库⾥,并且可以对.gitignore做版本管理!

8.2 配置别名

有没有经常敲错命令?⽐如git status?status这个单词真⼼不好记。如果敲git st就表⽰git status那就简单多了。我们只需要敲⼀⾏命令,告诉Git,以后st就表⽰status:

$ git config --global alias.st status

好了,现在敲git st看看效果。

正在上传…重新上传取消

当然还有别的命令可以简写,很多⼈都⽤co表⽰checkout,ci表⽰commit,br表⽰ branch:

$ git config --global alias.co checkout

$ git config --global alias.ci commit

$ git config --global alias.br branch

以后提交就可以简写成:

$ git ci -m "bala bala bala..."

--global参数是全局参数,也就是这些命令在这台电脑的所有Git仓库下都有⽤。

在撤销修改⼀节中,我们知道,命令git reset HEAD file可以把暂存区的修改撤销掉(unstage),重新放回⼯作区。既然是⼀个unstage操作,就可以配置⼀个unstage别名:

$ git config --global alias.unstage 'reset HEAD'

当你敲⼊命令:

$ git unstage test.py

实际上Git执⾏的是:

$ git reset HEAD test.py

配置⼀个git last,让其显⽰最后⼀次提交信息:

$ git config --global alias.last 'log -1'

这样,⽤git last就能显⽰最近⼀次的提交:

正在上传…重新上传取消

更优雅的使用git log:

正在上传…重新上传取消

$ git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --"

来看看git lg

正在上传…重新上传取消

如果你想看看git log –pretty=format的参数,你可以看看这篇文章

8.3 搭建Git服务器

在远程仓库⼀节中,我们讲了远程仓库实际上和本地仓库没啥不同,纯粹为了7x24⼩时开机并交换⼤家的修改。 GitHub就是⼀个免费托管开源代码的远程仓库。但是对于某些视源代码如⽣命的商业公司来说,既不想公开源代码,⼜舍不得给GitHub交保护费,那就只能⾃⼰搭建⼀台Git服务器作为私有仓库使⽤。

1、搭建git服务器

    搭建Git服务器需要准备⼀台运⾏Linux的机器,这样通过⼏条简单的apt命令就可以完成安装。假设你已经有sudo权限的⽤户账号,下⾯正式开始安装。

第⼀步,安装git:

$ sudo apt-get install git

第⼆步,创建⼀个git⽤户,⽤来运⾏git服务:

$ sudo adduser git

第三步,创建证书登录:

收集所有需要登录的⽤户的公钥,就是他们⾃⼰的id_rsa.pub⽂件,把所有公钥导⼊到/ home/git/.ssh/authorized_keys⽂件⾥,⼀⾏⼀个。

 

第四步,初始化Git仓库: 

先选定⼀个录作为Git仓库,假定是/srv/sample.git,在/srv录下输⼊命令:

$ sudo git init --bare sample.git

Git就会创建⼀个裸仓库,裸仓库没有⼯作区,因为服务器上的Git仓库纯粹是为了共享,所以不让⽤户直接登录到服务器上去改⼯作区,并且服务器上的Git仓库通常都以.git结尾。然后,把owner改为git:

$ sudo 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.

剩下的推送就简单了。

2、管理公钥

如果团队很⼩,把每个⼈的公钥收集起来放到服务器的/home/git/.ssh/authorized_keys⽂件⾥就是可⾏的。如果团队有⼏百号⼈,就没法这么玩了,这时,可以⽤Gitosis来管理公钥。

3、管理权限

有很多公司会在版本控制系统⾥设置⼀套完善的权限控制,每个⼈是否有读写权限会精确到每个分⽀甚⾄每个录下。因为Git是为Linux 源代码托管⽽开发的,所以Git也继承了开源社区的精神,不⽀持权限控制。不过,因为Git ⽀持钩⼦(hook),所以可以在服务器端编写⼀系列脚本来控制提交等操作,达到权限控制的Gitolite就是这个⼯具。

 

⼩结

搭建Git服务器⾮常简单,通常10分钟即可完成;

要⽅便管理公钥,⽤Gitosis;

要像SVN那样控制权限,⽤Gitolite。

(补充)9 Gitlab 服务器搭建过程

9.1官网地址

首页:https://about.gitlab.com/

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

9.2安装命令摘录

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

9.3调整后的安装过程 ee是企业版本 ce是社区版本

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 

当前步骤完成后重启。

9.4 gitlab 服务操作 

初始化配置 gitlab

gitlab-ctl reconfigure

启动 gitlab 服务

gitlab-ctl start

停止 gitlab 服务

gitlab-ctl stop

9.5浏览器访问 

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

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

正在上传…重新上传取消

root/atguigu2018good

※应该会需要停止防火墙服务: service firewalld stop

你可能感兴趣的:(其他配置,git)