首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >跟着小程一起聊聊GIT那点事

跟着小程一起聊聊GIT那点事

作者头像
小程故事多
发布2018-08-22 10:48:38
4710
发布2018-08-22 10:48:38
举报
文章被收录于专栏:微服务生态微服务生态

一、GIT发展史

同生活中的许多伟大事件一样,Git 诞生于一个极富纷争大举创新的年代。Linux 内核开源项目有着为数众广的参与者。绝大多数的 Linux 内核维护工作都花在了提交补丁和保存归档的繁琐事务上(1991-2002年间)。到 2002 年,整个项目组开始启用分布式版本控制系统 BitKeeper 来管理和维护代码。

到 2005 年的时候,开发 BitKeeper 的商业公司同 Linux 内核开源社区的合作关系结束,他们收回了免费使用 BitKeeper 的权力。这就迫使 Linux 开源社区(特别是 Linux 的缔造者 Linus Torvalds )不得不吸取教训,只有开发一套属于自己的版本控制系统才不至于重蹈覆辙。他们对新的系统订了若干目标:

  • 速度
  • 简单的设计
  • 对非线性开发模式的强力支持(允许上千个并行开发的分支)
  • 完全分布式
  • 有能力高效管理类似 Linux 内核一样的超大规模项目(速度和数据量)

自诞生于 2005 年以来,Git 日臻成熟完善,在高度易用的同时,仍然保留着初期设定的目标。它的速度飞快,极其适合管理大项目,它还有着令人难以置信的非线性分支管理系统,可以应付各种复杂的项目开发需求。

二、如何安装GIT

1、Ubuntu上安装
    $ sudo apt-get install git-core
2、Windows上安装
    有个叫做 msysGit 的项目提供了安装包,参考:
    http://code.google.com/p/msysgit 
3、从源码安装
    Git的工作需要调用curl,zlib,openssl,expat,libiconv等库的代码,所有要先安装这些依赖工具。
    $ sudo apt-get install curl-devel expat-devel gettext-devel openssl-devel zlib-devel
    再从下面的 Git 官方站点下载最新版本源代码 :
    http://git-scm.com/download
    然后编译并安装,例如:
    $ tar -zxf git-1.6.0.5.tar.gz 
    $ cd git-1.6.0.5 
    $ make prefix=/usr/local all 
    $ sudo make prefix=/usr/local install 
    
    现在已经可以用 git 命令了,例如把 Git 项目仓库克隆到本地,以便日后更新: 
    $ git clone git://git.kernel.org/pub/scm/git/git.git 

三、运行GIT前的配置

一般在新的系统上,我们都需要先配置下自己的 Git 工作环境。配置工作只需一次,以后升级时还会沿用现在的配置。当然,如果需要,你随时可以用相同的命令修改已有的配置。

Git 提供了一个叫做 git config 的工具,专门用来配置或读取相应的工作环境变量。而正是由这些环境变量,决定了 Git 在各个环节的具体工作方式和行为。这些变量可以存放在以下三个不同的地方:

  • /etc/gitconfig文件: 系统中对所有用户都普遍适用的配置。若使用 git config 时用 --system 选项,读写的就是这个文件。
  • ~/.gitconfig文件:用户目录下的配置文件只适用于该用户。若使用 git config 时用 --global 选项,读写的就是这个文件。
  • 当前项目的 git 目录中的配置文件(也就是工作目录中的 .git/config 文件):这里的配置仅仅针对当前项目有效。每一个级别的配置都会覆盖上层的相同配置,所以 .git/config 里的配置会覆盖/etc/gitconfig 中的同名变量。

第一个要配置的是你个人的用户名称和电子邮件地址。这两条配置很重要,每次 Git 提交时都会引用这两条信息,说明是谁提交了更新,所以会随更新内容一起被永久纳入历史记录:

$ git config --global user.name "John Doe" 
$ git config --global user.email johndoe@example.com

如果用了 --global 选项,那么更改的配置文件就是位于你用户主目录下的那个,以后你所有的项目都会默认使用这里配置的用户信息。如果要在某个特定的项目中使用其他名字或者电邮,只要去掉 --global 选项重新配置即可,新的设定保存在当前项目的 .git/config 文件里。

接下来要设置的是默认使用的文本编辑器。Git 需要你输入一些额外消息的时候,会自动调用一个外部文本编辑器给你用。默认会使用操作系统指定的默认编辑器,一般可能会是 Vi 或者 Vim。如果你有其他偏好,比如 Emacs 的话,可以重新设置: $ git config --global core.editor emacs

还有一个比较常用的是,在解决合并冲突时使用哪种差异分析工具。比如要改用 vimdiff 的话: $ git config --global merge.tool vimdiff Git可以理解 kdiff3,tkdiff,meld,xxdiff,emerge,vimdiff,gvimdiff,ecmerge,和 opendiff 等合并工具的输出信息。当然,你也可以指定使用自己开发的工具。

查看配置信息 要检查已有的配置信息,可以使用 git config --list 命令:

$ git config --list 
user.name=Scott Chacon 
user.email=schacon@gmail.com 

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

git config user.name 
Scott Chacon 

四、获取GIT帮助

想了解 Git 的各种命令该怎么用,可以阅读它们的使用帮助,方法有三:

$ git help <verb> 
$ git <verb> --help 
$ man git-<verb>

比如,要学习 config 命令可以怎么用,运行: $ git help config

我们随时都可以浏览这些帮助信息而无需连网。不过,要是你觉得还不够,可以到 Frenode IRC 服务器(irc.freenode.net)上的 #git 或 #github 频道寻求他人帮助。这两个频道上总有着上百号人,大多都有着丰富的 git 知识,并且乐于助人。

五、Git中文件的状态和基本工作流程

对于任何一个文件,在 Git 内都只有三种状态:已提交(committed),已修改(modified)和已暂存(staged)。已提交表示该文件已经被安全地保存在本地数据库中了;已修改表示修改了某个文件,但还没有提交保存;已暂存表示把已修改的文件放在下次提交时要保存的清单中。

由此我们看到 Git 管理项目时,文件流转的三个工作区域:Git 的本地数据目录,工作目录以及暂存区域。

Paste_Image.png

每个项目都有一个 git 目录,它是 Git 用来保存元数据和对象数据库的地方。该目录非常重要,每次克隆镜像仓库的时候,实际拷贝的就是这个目录里面的数据。

从项目中取出某个版本的所有文件和目录,用以开始后续工作的叫做工作目录。这些文件实际上都是从 git 目录中的压缩对象数据库中提取出来的,接下来就可以在工作目录中对这些文件进行编辑。

所谓的暂存区域只不过是个简单的文件,一般都放在 git 目录中。有时候人们会把这个文件叫做索引文件,不过标准说法还是叫暂存区域。

基本的 Git 工作流程如下所示:

  • 在工作目录中修改某些文件。
  • 对这些修改了的文件作快照,并保存到暂存区域。
  • 提交更新,将保存在暂存区域的文件快照转储到 git 目录中。

所以,我们可以从文件所处的位置来判断状态:如果是 git 目录中保存着的特定版本文件,就属于已提交状态;如果作了修改并已放入暂存区域,就属于已暂存状态;如果自上次取出后,作了修改但还没有放到暂存区域,就是已修改状态。

六、Git常用命令

git init
git clone
git add <file>
git commit
git diff
git diff --cached
git rm <file>
git rm <file> --cached
git mv <file> <newfile>
git status
git log
git commit --amend
git reset HEAD <file>
git reset --soft HEAD~n
git reset --hard HEAD~n
git checkout -- <file>
git checkout <file>
git remote
git remote add [shortname] [url]
git fetch [remotename]
git push [remotename] [localbranch]:[remotebranch]
git remote show [remotename]
git remote rename [remotename] [new-remotename]
git remote rm [remotename]
git tag
git tag -a [tagname] –m [comments]
git push [remotename] [tagname]
git push [remotename] –tags
git branch [branchname]
git checkout [branchname]
git branch -d [branchname]
git merge [branchname]
git branch
git checkout -b [branchname] [remotename]/[branchname]
git push [remotename] :[remotebranch]
git rebase [branchname]
git pull

七、Git命令使用举例

  • 从当前目录初始化 要对现有的某个项目开始用 Git 管理,只需到此项目所在的目录,执行: git init 初始化后,在当前目录下会出现一个名为 .git 的目录,所有 Git 需要的数据和资源都存放在这个目录中。
  • 从现有仓库克隆,如克隆git的代码库 git clone git://git.kernel.org/pub/scm/git/git.git
  • 跟踪新文件和暂存已修改文件 git add <file>
  • 提交更新 git commit 这种方式会启动文本编辑器以便输入本次提交的说明。也可以使用 -m 参数后跟提交说明的方式,在一行命令中提交更新: git commit -m “Initial commit of test repo”
  • 查看已暂存和未暂存的修改 git diff 此命令比较的是工作目录中当前文件和暂存区域快照之间的差异,也就是修改之后还没有暂存起来的变化内容。若要看已经暂存起来的文件和上次提交时的快照之间的差异,可以用 git diff --cached 命令
  • 移除文件 要从 Git 中移除某个文件,就必须要从已跟踪文件清单中移除(确切地说,是从暂存区域移除),然后提交。 git rm <file> 另外一种情况是,我们想把文件从 Git 仓库中删除(亦即从暂存区域移除),但仍然希望保留在当前工作目录中。 可以用--cached选项 git rm --cached <file>
  • 移动文件 git mv <file> <newfile>
  • 检查当前文件状态 git status
  • 查看提交历史 git log
  • 修改最后一次提交 有时候我们提交完了才发现漏掉了几个文件没有加,或者提交信息写错了。想要撤消刚才的提交操作,可以使用 --amend 选项重新提交: git commit --amend 如果刚才提交完没有作任何改动,直接运行此命令的话,相当于有机会重新编辑提交说明,而所提交的文件快照和之前的一样。如果刚才提交时忘了暂存某些修改,可以先补上暂存操作,然后再运行 --amend 提交。
  • 取消已经暂存的文件 git reset HEAD <file>
  • 取消对文件的修改 git checkout -- <file> git checkout <file> 一般与上面的命令效果相同,但如果有一个分支名与文件名相同,就不一样了。加--来消除歧义。
  • 查看当前的远程库 git remote 也可以加上 -v 选项,显示对应的克隆地址 git remote -v
  • 添加远程仓库 git remote add [shortname] [url]
  • 从远程仓库抓取数据 git fetch [remotename] 此命令会到远程仓库中拉取所有你本地仓库中还没有的数据。运行完成后,你就可以在本地访问该远程仓库中的所有分支,将其中某个分支合并到本地,或者只是取出某个分支,一探究竟。
  • 推送数据到远程仓库 git push [remotename] [localbranch]:[remotebranch]
  • 查看远程仓库信息 git remote show [remotename]
  • 远程仓库的删除和重命名
git remote rename [remotename] [new-remotename]
git remote rm [remotename]
  • 显示已有的标签 git tag
  • 新建标签 git tag -a [tagname] –m [comments] 如果想为以前的某次提交打标签,只要在打标签的时候跟上对应提交对象的校验和(或前几位字符)即可 。
  • 用某个标签新建分支 git checkout –b [branchname] [tagname]
  • 分享标签 默认情况下,git push 并不会把标签传送到远端服务器上,只有通过显式命令才能分享标签到远端仓库。 git push [remotename] [tagname] 如果要一次推送所有(本地新增的)标签上去,可以使用 --tags 选项: git push [remotename] –tags
  • 创建分支 git branch [branchname]
  • 切换分支 git checkout [branchname]
  • 新建并切换到该分支 git checkout -b [branchname]
  • 删除分支 git branch -d [branchname]
  • 合并分支 git merge [branchname] 以上命令将[branchname]分支合并到当前分支
  • 查看分支 git branch
  • 远程分支和创建跟踪分支 远程分支(remote branch)是对远程仓库状态的索引。它们是一些无法移动的本地分支;只有在进行 Git 的网络活动时才会更新。远程分支就像是书签,提醒着你上次连接远程仓库时上面各分支的位置。我们用 (远程仓库名)/(分支名) 这样的形式表示远程分支。从远程分支检出的本地分支成为跟踪分支。 git checkout -b [branchname] [remotename]/[branchname] 或者 git checkout --track [remotename]/[branchname]
  • 删除远程分支 git branch -r -d origin/[branchname]
  • 衍合 git rebase [branchname]
  • 从远程仓库抓取数据并merge git pull

八、Git分支

在 Git 中提交时,会保存一个提交(commit)对象,它包含一个指向暂存内容快照的指针,作者和相关附属信息,以及一定数量(也可能没有)指向该提交对象直接祖先的指针:第一次提交是没有直接祖先的,普通提交有一个祖先,由两个或多个分支合并产生的提交则有多个祖先。

为直观起见,我们假设在工作目录中有三个文件,准备将它们暂存后提交。暂存操作会对每一个文件计算校验和(即SHA-1 哈希字串),然后把当前版本的文件快照保存到 Git 仓库中(Git 使用 blob 类型的对象存储这些快照),并将校验和加入暂存区域。现在,Git 仓库中有五个对象:三个表示文件快照内容的 blob 对象;一个记录着目录树内容及其中各个文件对应 blob 对象索引的 tree 对象;以及一个包含指向 tree 对象(根目录)的索引和其他提交信息元数据的 commit 对象 。

概念上来说,仓库中的各个对象保存的数据和相互关系看起来 如下所示:

Paste_Image.png

多次提交后,仓库历史如下:

Paste_Image.png

Git 中的分支,其实本质上仅仅是个指向 commit 对象的可变指针。

Paste_Image.png

Git 通过个git branch命令创建分支,比如新建一个testing分支: git branch testing 这会在当前commit对象上新建一个分支指针, 同时Git保存着一个名为HEAD的特别指针,来让Git知道当前在哪个分支上工作。如下:

Paste_Image.png

要切换到其他分支,可以执行命令git checkout,如切换到新建的testing分支: git checkout testing 这样HEAD就指向testing分支,如下:

Paste_Image.png

此时在testing分支上工作,如果有新的提交,提交后的结果如下:

Paste_Image.png

此时切换回master分支再提交后的结果如下:

Paste_Image.png

九、Git分支合并与衍合

如将experiment分支合并回master分支执行以下命令:

git checkout master
git merge experiment```

合并前后如下所示:


![Paste_Image.png](http://upload-images.jianshu.io/upload_images/1049928-78e3e7bdccdc4965.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

有时候合并操作并不会如此顺利。如果你修改了两个待合并分支里同一个文件的同一部分,Git 就无法干净地把两者合到一起,这种问题只能由人来解决。如果你想用一个有图形界面的工具来解决这些问题,不妨运行 git mergetool,它会调用一个可视化的合并工具并引导你解决所有冲突。确认所有冲突都解决后,可以用 git commit 来完成这次合并提交。

其实,合并两个分支还有另外一个选择:你可以把在 C3 里产生的变化补丁重新在 C4 的基础上打一遍。在 Git 里,这种操作叫做衍合(rebase)。有了 rebase 命令,就可以把在一个分支里提交的改变在另一个分支里重放一遍。

git checkout experiment git rebase master

衍合前后如下所示:

![Paste_Image.png](http://upload-images.jianshu.io/upload_images/1049928-1d40b0417c9988aa.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

再进行一次快进:

git checkout master git merge experiment

结果如下所示:

![Paste_Image.png](http://upload-images.jianshu.io/upload_images/1049928-f6d5ba058b7464a5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/500)

现在,合并后的 C3(即现在的 C3’)所指的快照,同三方合并例子中的 C5 所指的快照内容一模一样了。最后整合得到的结果没有任何区别,但衍合能产生一个更为整洁的提交历史。如果视察一个衍合过的分支的历史记录,看起来更清楚:仿佛所有修改都是先后进行的,尽管实际上它们原来是同时发生的。 

但衍合也并不是完美无缺的,一句话可以总结这点:
永远不要衍合那些已经推送到公共仓库的更新。
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017.04.11 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档