专栏首页微服务生态跟着小程一起聊聊GIT那点事

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

一、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 所指的快照内容一模一样了。最后整合得到的结果没有任何区别,但衍合能产生一个更为整洁的提交历史。如果视察一个衍合过的分支的历史记录,看起来更清楚:仿佛所有修改都是先后进行的,尽管实际上它们原来是同时发生的。 

但衍合也并不是完美无缺的,一句话可以总结这点:
永远不要衍合那些已经推送到公共仓库的更新。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Git常用命令速查手册

    小程故事多
  • 由参加领域驱动大会与自己所想的

    2017首届领域驱动技术大会一直是我非常期望的,要非常感谢右军赠送的门票能够让我领略大会风采。

    小程故事多
  • 深入理解并发之CompareAndSet(CAS)

    java.util.concurrent包中借助CAS实现了区别于synchronouse同步锁的一种乐观锁,使用这些类在多核CPU的机器上会有比较好的性能.

    小程故事多
  • Git 不同情况下的回滚操作

    在未进行git push前的所有操作,都是在“本地仓库”中执行的。我们暂且将“本地仓库”的代码还原操作叫做“撤销”

    JS菌
  • GIT 远程仓库搭建与使用

    这一步生成了 idrsa 和 idrsa.pub 两个文件 (windows 在用户文件夹找),将 idrsa.pub 上传到 git 用户的 .ssh 目录下...

    Gaussic
  • 使用码云新建、推拉第一个项目文件

    本地电脑安装git。可通过 git --version 查看版本,确保本机已有git。

    子乾建建-Jeff
  • 10分钟带你入门git到github

    开局先来一个故事吧,故事看完如果不想看枯燥无味的指令,没关系我已经把这篇文章的内容录制成了一个视频,点击文末阅读原文就可以观看。或者说你已经熟练掌握git的使用...

    java金融
  • Git详细操作

    1.参考帮助文档:https://gitee.com/help/ 仓库管理 =公钥管理 =生成/添加SSH公钥

    小小咸鱼YwY
  • Git常用命令总结

    ​ 在本地新建一个repo,进入一个项目目录,执行git init,会初始化一个repo,并在当前文件夹下创建一个.git文件夹.

    小小咸鱼YwY
  • 教妹子用 git(一)

    最近和一个研一妹纸合作弄自己的网站,然后发现妹纸不太懂 git。于是就写下这篇文章。看看能不能言简意赅的教会一个新手如何使用 git。

    程序员小浩

扫码关注云+社区

领取腾讯云代金券