“版本控制之道”——Git使用解析

该系列文章系个人读书笔记及总结性内容,任何组织和个人不得转载进行商业活动!

 

Git是一个开源的分布式版本控制系统——源码版本控制软件;

由于采用了分布式版本库的方式,不必服务器端软件的支持;

 

Git把内容按元数据方式存储,代码内容完整性较优;《Git完整命令手册地址

 

Git

Git安装

本博客内容关注Git的使用,对于Git的安装大家自行查阅

bogon:~ huaqiang$ git --version

git version 2.15.1 (Apple Git-101)

 

Git配置

Git提供了一个git config的工具,专门用来配置或读取相应的工作环境变量;

这些环境变量,决定了各个环节的具体工作方式和行为;

这些变量存放在以下三个地方:

/etc/gitconfig文件:

系统中对所有用户都普遍适用的配置;若使用git config时用—system选项,读写的就是这个文件;

~/.gitconfig文件:

用户目录下的配置文件只适用于该用户;若使用git config时用—global选项,读写的就是这个文件;

当前项目的Git目录中的配置文件(也就是工作目录汇中的.git/config文件):

这里的配置仅仅针对当前项目有效;

 

每一个级别的配置都会覆盖上层的相同配置,如 .git/config里的配置会覆盖/etc/gitconfig中的同名变量;

 

用户信息

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

$git config —global user.name “flower”

$git config —global user.email flower@163.com

 

使用了—global选项,更改的配置文件就是位于你目录下的那个,以后所有的项目都会默认使用这里配置的用户信息;

如果要在某个特定的项目中使用其他名字或者电邮,只要去掉--global选项重新配置即可,新的设定保存在当前项目的.git/config文件里;

 

文本编辑器

设置Git默认使用的文本编辑器,一般会是Vi或者Vim;如果你有其他偏好,比如Emacs;

$git config —global core.editor emacs

 

差异分析工具

修改在解决合并冲突时 使用的差异分析工具;

$git config —global merge.tool vimdiff

git可以理解多种合并工具的输出信息,如opendiff等;

 

查看配置信息

$git config —list

 

有时候可能会看见重复的变量名,那是来自不同配置文件的,不过最终Git实际采用最后一个;

这些配置也可以在~/.config或/etc/gitconfig看到;

$vim ~/.gitconfig

 

要查阅某个环境变量的设定,只要把特定的名字跟在后面即可:

$git config user.name

 


 

Git工作流程

 

一般的工作流程:

1.克隆Git资源作为工作目录;

2.在克隆的资源上添加或修改文件;

3.如果其他人修改了,你可以更新资源;

    你也可以在修改前查看修改;

4.提交修改

 


 

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

 

基本概念

工作区:

就是你的电脑能看见的目录;

 

暂存区:

stage或index;一般存在“.git目录”下的index文件中(.git/index);

所以我们把暂存区也叫索引(index);

 

版本库:

工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库;

 

工作区、版本库中的暂存区和版本库之间的关系:

 

上图的左侧为工作区,右侧为版本库;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<file>

会直接从暂存区删除文件,工作区并不会做出改变;

$git checkout 或者 $git checkout —<file>

会用暂存区全部或指定的文件替换工作区的文件;

这个操作很危险,会清除工作区中尚未添加到暂存区的改动;

$git checkout HEAD 或者 $git checkout HEAD <file>

会用HEAD指向的master分支中的全部或者部分文件替换暂存区以及工作区中的文件;

这个命令极具危险性,因为不但会清除工作区中未提交的改动,也会清除暂存区中未提交的修改;

 


 

Git创建仓库

 

git init

Git使用git init来创建一个仓库;Git很多命令都是在仓库中运行;

$git init 

是使用Git的第一个命令;

bogon:my_project huaqiang$ git init

Initialized empty Git repository in /Users/huaqiang/my_project/.git/

该命令执行完之后会在当前目录生成一个.git目录;

 

我们也可以指定一个目录作为Git仓库:

bogon:my_project huaqiang$ git init newrepo

Initialized empty Git repository in /Users/huaqiang/my_project/newrepo/.git/

初始化之后,会在newrepo目录下出现一个名为.git的目录;

所有Git需要的资源都存放在这个目录中;

 

由于不需要我们可以移除这个目录:

bogon:my_project huaqiang$ rm -r newrepo/

rm用来删除文件,使用-r则会删除目录;

 

可以使用 $git status 命令查看当前版本控制状态:

bogon:my_project huaqiang$ git status

On branch master

No commits yet

nothing to commit (create/copy files and use "git add" to track)

 

我们可以添加一个测试目录和文件README:

bogon:my_project huaqiang$ mkdir TestPath

bogon:my_project huaqiang$ touch README

 

此时的Git:

bogon:my_project huaqiang$ git status

On branch master

No commits yet

Untracked files:

  (use "git add <file>..." to include in what will be committed)

README

nothing added to commit but untracked files present (use "git add" to track)

 

如果当前目录下有几个文件想要纳入版本控制,需要先用git add命令告诉Git开始对这些文件进行跟踪,然后提交:

bogon:my_project huaqiang$ git add README

bogon:my_project huaqiang$ git commit -m '初始化项目 增加项目说明文件'

[master (root-commit) 84f4540] 初始化项目 增加项目说明文件

 1 file changed, 0 insertions(+), 0 deletions(-)

 create mode 100644 README

 

这样,我们就将README文件提交到了仓库中,注意空文件夹不会被提示追踪;

 

git clone

我们使用$git clone从现有的Git仓库中拷贝项目;

$git clone <repo>

$git clone <repo> <directory>

repo:Git仓库;

directory:本地目录;

 

现在,我们重新构建一下仓库目录,在初始目录下GitRepo中新建文件夹:

    然后新建repolocal目录,并使用这个文件夹目录初始化仓库;

    新建文件README,之后add、commit;

 

[master (root-commit) 09a24ac] 本地仓库初始化

[master 9ae9841] 修改了 README中的内容 增加文本readme1

 

我们在码云上新建了一个测试代码库:https://gitee.com/flower_hua/TestGit.git

这个仓库中初始的是一个OC项目,只有一个README.md文件;

我们使用clone命令,将其克隆到本地目录:reporemotetest1

bogon:GitRepo huaqiang$ git clone https://gitee.com/flower_hua/TestGit.gitreporemotetest1

 

需求:

 

Cloning into 'reporemotetest1'...

remote: Counting objects: 3, done.

remote: Compressing objects: 100% (2/2), done.

remote: Total 3 (delta 0), reused 0 (delta 0)

Unpacking objects: 100% (3/3), done.

 

 


 

Git基本操作

 

Git的工作就是创建和保存你的项目,将项目快照与之后的项目快照尽心对比;

上一节中我们已经熟悉了Git的几个操作命令,这一节,让我能更加详细的介绍Git的有关创建和提交项目快照的基本操作命令;

 

获取与创建项目命令

git init

在目录中创建新的Git仓库;任何目录中都可以这样做,完全本地化;我们也可以查看.git这个子目录;

bogon:GitRepo huaqiang$ cd repoloacal/

bogon:repoloacal huaqiang$ ls -a

. .. .git README

这就是我们的Git仓库了,所有有关你的此项目的快照数据都存放在这里;

 

git clone

使用git clone 拷贝一个Git地址到本地,这样就可以查看或修改;

默认,Git会按照你提供的URL所指示的项目名称创建你的本地目录;通常就是URL最后一个/之后的项目名称;

如果想要一个不一样的名称,你可以在该命令后加上你想要的名称;

 

基本快照

git add

git add命令可将该文件添加到缓存;

 

$git add .

加一个.表示添加当前项目的所有文件;

 

git status

git status 命令用于查看项目的当前状态;查看在你上次提交之后是否有修改;

 

$git status -s 

则是以精简的方式显示文件状态;获得简单的输出结果;

 

绿色的M标示在所有的修改已经添加到缓存;

红色的M标示在它添加到缓存之后又有了新的改动;

绿色的A标示成功添加到缓存;

红色的??标示新增的文件

 

git diff

执行git diff 查看执行git status的结果的详细信息;该命令会显示写入缓存与已修改但尚未写入缓存的改动的区别;

 

git diff的两个主要应用场景:

1)git diff:尚未缓存的改动;

2)git diff —cached:已缓存的所有改动;

3)git diff HEAD:已缓存 与 为缓存的所有改动;

4)显示摘要(注意不是整个diff):git diff —stat

 

 

git status:显示的是你上次提交更新后的更改或者写入缓存的改动;

git diff:则是一行一行的显示git status显示的改动具体是啥;

 

git commit

使用git add命令将想要快照的内容写入缓存,而执行git commit将缓存区内容添加到仓库中;

Git为你的每一个提交都记录名字和邮箱,所以需要先配置用户名和email地址;

 

如果是自己新建的仓库,默认使用已经配置的用户名和邮箱;

如果是clone别人的项目,使用默认的配置需要获得许可;

 

$git config —global user.name ‘flower’

$git config —global user.email test@163.com

 

接下来就是写入缓存,然后提交修改;这个我们之前已经了解过;

bogon:repoloacal huaqiang$ git status -s

M  README

bogon:repoloacal huaqiang$ git commit -m 'start1-修改1'

[master 708b20c] start1-修改1

 1 file changed, 2 insertions(+), 1 deletion(-)

bogon:repoloacal huaqiang$ git status

On branch master

nothing to commit, working tree clean

 

上边的输出说明在最近一次提交之后,没有任何改动,是一个’干净的工作目录’;

如果没有使用-m选项,git会尝试打开编辑器供填写信息用;

 

如果觉得git add之后在提交的过程太过繁琐,Git也允许你用-a选项跳过这一步; 

 

git reset HEAD

该命令用于消除已缓存的内容;

 

我们将修改之后helloworld.c add到暂存区;之后使用git reset HEAD <file>;

现在该文件的缓冲区内容将会被清除;

此时,执行git commit,只会讲其余的改动提交,如果没有其他修改,会提示没有需要提交的修改;

此时执行 $git status -s

会显示本地修改了helloworld.c M是红色的,表示该修改尚未提交到缓存区;

 

测试的最后,我们将修改提交$git commit -am ‘modify’

 

简而言之,执行git reset HEAD以取消之前git add添加,但不希望包含在下已提交快照中的缓存;

 

git rm

如果只是简单地从工作目录中删除文件,运行git status时就会在’Changes not staged for commit’中提示;

而要从Git中移除某个文件,就必须要从已跟踪文件清单中移除,然后提交;

 

可以用以下命令完成删除文件:

$git rm <file>   ->删文件

 

如果删除之前修改过并且已经放到暂存区的话,就必须要用强制删除选项 -f

$git rm -f <file>    ->删文件和暂存区

 

如果把文件从暂存区域删除,但仍然希望保留在当前工作目录中,换句话说,仅从跟踪清单中删除,使用--cached选项即可:

$git rm —cached <file>    ->删暂存区

 

递归删除:即跟的是一个目录作为参数,则会递归删除整个目录中的所有子目录和文件

$git rm -r <path>

 

进入某个目录执行$git rm -r * 则会删除该目录下所有的文件和子目录;

 

git mv

git mv命令用于移动或重命名一个文件、目录、软连接;

首先将helloworld.c重新add到暂存区;

然后对其进行重命名;

$ git mv helloworld.c helloworld.m

 


 

Git分支管理

 

使用分支意味着你可以从开发主线上分离开来,然后在不影响主线的同时继续开发;

 

创建分支命令:

$git branch <branchname>

 

切换分支命令:

$git checkout <branchname>

当你切换分支的时候,Git会用该分支的最后提交的快照替换你的工作目录的内容,所以多个分支不需要多个目录;

 

合并分支命令:

$git merge

你可以多次合并到统一分支,也可以选择在合并之后直接删除被并入的分支;

 

下面来看下具体的使用;

 

Git分支管理

列出分支

列出分支的基本命令:

$git branch

 

没有参数的时候,git branch会列出你本地的分支:

即,我们有一个叫做master的分支,并且该分支是当前分支;(执行 git init 缺省的情况下,Git会为你创建master分支)

 

当你在上次提交更新之后创建了一个新分支,如果后来又有更新提交,然后又切换到这个新分支上,Git将还原你的工作目录到你创建分支时候的样子;

 

切换分支

使用$git checkout <branch> 切换到我们要修改的分支;

 

上边我们修改了helloworld.c为.m后缀名,接下来我们提交这个修改;

 

接下来我们查看分支,并使用$git checkout <branch>来切换分支:

 

我们注意到,切换了分支之后,我们的工作目录中的helloworld.c是未经后缀名修改的;(在创建分支时,这一修改还未提交master)

 

再切换为master分支,我们的修改又出现了:

 

我们也可以使用$git checkout -b <branchname>

来创建新的分支并立即切换到该分支下,从而在该分支中操作;

 

我们创建分支,在分支上操作,然后切换回分支,相应的改动没有了;

使用分支将工作切分开来,从而让我们能够在不同上下文中做事,并来回切换;

 

删除分支

删除分支命令:

$git branch -d <branchname>

 

 

合并分支

一旦某分支有了独立内容,最终希望合并到主分支上;你可以使用以下命令将任何分支合并到当前分支中去:

$git merge

 

我们新建一个newtest分支,然后修改helloworld.c中的注释文字,并提交;

之后,切换到主分支,执行merge ,将相应的newtest分支的修改内容,合并到主分支上;

相应的主分支上的helloworld.c也发生了变化,对应合并之前在newtest分支上的修改;

 

合并冲突

在Git合并修改的过程中,常常需要面临的问题;

 

我们将当前的修改commit到master上;

然后切换到testconflict分支上,对helloworld.c进行修改;commit;

再切换回master分支上,继续对helloworld.c进行修改;commit;

最后执行merge操作;

冲突出现了:

接下来我们需要手动修改它;

在Git中,我们可以用git add来告诉Git冲突已经解决;

 

最后已经不用的分支可以删除掉;

 


 

Git查看提交历史

 

回顾Git的提交历史,可以使用$git log命令查看;

或者使用$git log —oneline 选项查看历史记录的简介版本;

 

还可以使用—graph选项,查看历史中何时出现分支、合并;开启拓扑图选项;

 

也可以使用—reverse参数来逆向显示所有日志;

$ git log --reverse —oneline

 

如果只想查找指定用户的提交日志:$git log —author

 

如果要指定日期,可以执行几个选项:—since和—before,也可以使用—until和—after;

—no-merges选项 可以隐藏合并提交;

 


 

Git标签

 

添加标签

如果你打到了一个重要的阶段,并希望永远记住那个特别的提交快照,你可以使用git tag给它打上标签;

$git tag -a <tagname> -m "omething"   会给最新一次提交打上标签

-a选项:创建一个带注解的标签;

 

追加标签

 

查看标签

 

删除标签

$git tag -d v1.0

 

查看标签详细信息及版本修改的内容

 

Git的标签也是版本库的一个快照,其实就是指向某个commit的指针;

虽然和分支很像,但是分支可以移动,标签不能移动;

创建和删除标签都是瞬间完成的;

 

Git使用的标签有两种类型:轻量级 和 含附注的(使用-a选项);

含附注标签,实际上是存储在仓库中的一个独立对象,他有自身的校验和信息,包含着标签的名字,电子邮件地址和日期,以及标签说明(-m添加的);

标签本身也允许使用GNU Private Guard(GPG)来签署或验证;

 

轻量级标签是指向特定提交对象的引用;

 


 

Git远程仓库

 

目前我们使用的Git命令都是在本地执行的,如果你想要通过Git分享你的代码或与其他开发人员合作;你就需要将数据放到一台其他人能连接的服务器上;

 

有关git添加远程仓库以及将本地库链接到远程仓库(如Github)的相关内容,可参考:http://www.runoob.com/git/git-remote-repo.html

 

我们之前使用码云新建了一个远程仓库,我们直接clone到本地,对应的文件夹是热破remotetest1文件夹;

 

查看当前远程库

 

加上-v参数,可以看到每个别名的实际链接地址;

 

提取远程仓库

Git有两个命令用来提取远程仓库的更新:

1.从远程仓库下载新分支与数据

$git fetch <alias>    告诉Git获取远程仓库有 但是本地没有的数据

该命令执行完需要执行git merge 远程分支 到你所在的分支

 

2.从远端仓库提取数据并尝试合并到当前分支

$git merge <alias>/<branch>    将服务器上的更新合并到当前分支

 

我们在码云上修改README.md:

 

然后在本地更新修改:

 

提取到了更新之后,我们需要使用一下命令将更新同步到本地:

 

查看文件内容:

 

 

推送到远程仓库

推送你的新分支与数据到某个远端仓库(链接账户会启用钥匙串中的信息)

$git push <alias> <branch>    将你的branch分支推送到alias远程仓库上的branch 分支

 

我们修改README文件,增加local modify文本;

然后,推送到远程仓库:

 

再看码云上的文件,可以看到相应的修改已经提交上来了:

 

 

删除远程仓库

我们先添加:

然后删除

 


 

至此,Git的使用我们就学习完了,远程仓库实际使用过程中,更多的使用add commit pull push等命令,其中pull可以看作是fetch和merge的合并操作;

 

 

Git服务器搭建请参考:http://www.runoob.com/git/git-server.html 这里暂不介绍。

 

 

Thanks!!!

 

补充:

git拉取远程分支到本地

git获取远程服务器的指定分支

bogon:Tongqianguan huaqiang$ git branch
* dev
  master

//远程新建分支‘201809’

bogon:Tongqianguan huaqiang$ git pull origin 201809:201809
Username for 'http://192.168.10.10': xxxxxx
Password for 'http://huaqiang@192.168.10.10': 
From http://192.168.10.10/tqgnew/ios
 * [new branch]      201809     -> 201809
 * [new branch]      201809     -> origin/201809
Already up to date.

bogon:Tongqianguan huaqiang$ git branch
  201809
* dev
  master

bogon:Tongqianguan huaqiang$ git checkout 201809
Switched to branch '201809'

bogon:Tongqianguan huaqiang$ git branch
* 201809
  dev
  master
bogon:Tongqianguan huaqiang$ 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值