很多人怕使用git,我个人觉得主要可能是两部分的原因:
Never Be Afraid To Try Something New.
代码对于开发者是劳动成果的结晶,对于公司而言是核心资产,有一些担忧也是正常的。但git也并没有我们想象中的那么复杂,让我们每次使用都心有余悸,其实我们只需要稍微花一点时间尝试多多了解它,在很多时候你会发现,非但git不会让你产生担忧,反而会让自己的交付过程更加高效
谈及git就不得不提到版本控制,我们不妨先开看下版本控制是做什么的,这将有助于后续对git的理解。
当你在工作中面对的是一些经常变化的文档、代码等交付物的时候,考虑如何去追踪和记录这些 changes 就变得非常重要,原因可能是:
对于频繁改动和改进的交付物,非常有必要去记录下每次变更的内容,每次记录的内容汇成了一段修改的历史,有了历史我们才知道我们曾经做了什么。
记录的历史中必须要包含一些重要的信息,这样追溯才变得意义。比如:
Who:是谁执行的变更?
When:什么时候做出的变更?
What:这次变更做了什么事情?
最好可以支持撤销变更,不让某一个提交的严重问题,去污染整个提交历史。
版本控制系统(VCS:Version Control System),正会为你提供这种记录和追溯变更的能力。
大多数的 VCS 支持在多个使用者之间共享变更的提交历史,这从实质上让团队协同变为了可能,简单说来就是:
VCS 历经多年的发展,目前业界中有许多 VCS 工具可供我们选择。在文本中,我们将会针对目前最流行的git来介绍。
刚接触git的时候,git 确实有让人觉得有点像黑魔法一样神秘,但是有那个技术不是这样呢?当我们了解其基本的数据结构之后,会发现git从使用角度来讲其实并不复杂,我们甚至可以进一步的学习git的一些先进的软件设计理论,从中获益。首先,我们先从 commit 说起。
让我们通过实战来帮助理解,第一步我们来初始化一个 repository(git仓库),默契初始化之后仓库是空的,其中即没有保存任何内容也没有附带任何提交:
1 git init hackers
2 cd hackers
3 git status
第二步,让我们来看下执行过后 git 给出的输出内容,它会指引我们进行进一步的了解:
1 → hacker git:(master) git status
2 On branch master
3 No commits yet
4 nothing to commit (create/copy files anduse "git add" to track)
output 1: On branch master
output 2:No commit yet
对于空仓库来说,目前我们还没有进行任意的提交。
nothing to commit (create/copy files anduse "git add" to track)
output 中提示我们需要使用 git add 命令,说到这里就必须要提到暂存或索引(stage),那么如何去理解暂存呢?
一个文件改动到提交到 git 仓库,需要经历三个状态:
-工作区:工作区指的是我们本地工作的目录,比如我们可以在刚才创建的 hackers 目录下新增一个 readme 文件,readme 文件这时只是本地文件系统上的修改,还未存储到git。
-暂存(索引区):暂存实际上是将我们本地文件系统的改动转化为 git 的对象存储的过程。
-仓库:git commit 后将提交对象存储到 git 仓库。
git add 的帮助文档中很详细的解释了暂存这一过程:
DESCRIPTION
-This command updates the index using thecurrent content found in the
working tree, to prepare the content stagedfor the next commit.
( git add 命令将更新暂存区,为接下来的提交做准备)
-It typically adds the current content ofexisting paths as a whole, but
with some options it can also be used toadd content with only part of
the changes made to the working tree filesapplied, or remove paths
that do not exist in the working tree anymore.
-The “index” holds a snapshot ofthe content of the working tree, and it
is this snapshot that is taken as thecontents of the next commit.
(暂存区的 index 保存的是改动的完整文件和目录的快照(非delta))
-Thus after making any changes to theworking tree, and before running the
commit command, you must use the addcommand to add any new or modified
files to the index.
(暂存是我们将改动提交到 git 仓库之前必须经历的状态)
对git暂存有一定了解后,其相关操作的使用其实也是非常简单,简单的说明如下:
1、暂存区操作:
2、暂存区修正
3、暂存区状态
4、Just Commit !
在不知不觉中了解了很多内容,来回顾一下,它们包括了:
附带的,在了解 commit 过程中我们知道了从本地改动到提交到git仓库,经历的几个关键的状态:
下图为上述过程中各个状态的转换过程:
本地改动文件时,此时还仅仅是工作区内的改动;
当执行git add 之后,工作区的改动被索引在暂存区;
当执行git commit 之后,暂存区的内容对象将会存储在 git 仓库中,并执行更新HEAD指向等后续操作,这样就完成了引用与提交、提交与改动快照的一一对应了。
正是因为git本身对于这几个区域(状态)的设计,为git在本地开发过程带来了灵活的管理空间。我们可以根据自己的情况,自由的选择哪些改动暂存、哪些暂存的改动可以commit、commit可以关联到那个引用,从而进一步与他人进行协同。
我们已经有了一个commit,现在我们可以围绕commit做更多有趣的事情:
引用(refs)包含两种分别是branches和tages,我们接下来简单介绍下相关操作:
分支上提交隔离的设计,可以让我们非常轻松的切换我们的修改,非常方便的做各类测试。
tags的名称不会改变,而且它们有自己的描述信息(比如可以作为release note 以及标记发布的版本号等)。
可能很多人的提交历史是长这个样子的:
commit 14: add feature x – maybe even witha commit message about x!
commit 13: forgot to add file
commit 12: fix bug
commit 11: typo
commit 10: typo2
commit 9: actually fix
commit 8: actually actually fix
commit 7: tests pass
commit 6: fix example code
commit 5: typo
commit 4: x
commit 3: x
commit 2: x
commit 1: x
单就git而言,这看上去是没有任何问题而且是合法的,但对于那些对你感兴趣的人(很可能是未来的你!),这样的提交在信息追溯历史时可能并没有多大的帮助。但是如果你的提交已经长成这个样子?我们该怎么办?
没关系,git 有办法可以弥补这一些:
git commit --amend
我们可以将新的改动提交到当前最近的提交上,比如你发现少改了什么,但是又不想多出一个提交时会很有用。
如果我们认为我们的提交信息写的并不好,我要修改修改,这也是一种办法,但是并不是最好的办法。
这个操作会更改先前的提交,并为其提供新的hash值。
git rebase -i HEAD~13
这个命令非常强大,可以说是git提交管理的神器,此命令含义是我们可以针对之前的13次的提交在VI环境中进行重新修改设计:
版本控制的一个常见功能是允许多个人对一组文件进行更改,而不是互相影响。或者更确切的说,为了确保如果他们不会踩到彼此的脚趾,不会在提交代码到服务器时偷偷的覆盖彼此的变化。
在 git 中我们如何保证这一点呢?
git与svn不同,git不存在本地文件lock的情况,这是一种避免出现写作问题的方式,但是并不方便,而git与svn最大的不同在于它是一个分布式VCS,这意味着:
冲突的产生几乎是不可避免的,当冲突产生时你需要将一个分支中的更改与另一个分支中的更改合并,对应git的命令为git merge NAME,一般过程如下:
找到HEAD和NAME的一个共同祖先(common base);
尝试将这些NAME到共同祖先之间的修改合并到HEAD上;
新创建一个merge commit对象,包含所有的这些变更内容;
git将会保证这个过程改动不会丢失,另外一个命令你可能会比较熟悉,那就是git pull命令,git pull命令实际上包含了git merge 的过程,具体过程为:
git fetch REMOTE
git merge REMOTE/BRANCH
和git push一样,有的时候需要先设置 “tracking”(-u),这样可以将本地和远程的分支一一对应。
如果每次merge都如此顺利,那肯定是非常完美的,但有时候你会发现在合并时产生了冲突文件,这时候也不用担心,如何处理冲突的简要介绍如下:
冲突只是因为git不清楚你最终要合并后的文本是什么样子,这是很正常的情况;
产生冲突时,git会中断并操作,并指导你解决好所有的冲突文件;
打开你的冲突文件,找到 <<<<<<< ,这是你需要开始处理冲突的地方,然后找到 ======= ,等号上面的内容是HEAD到共同祖先之间的改动,等号下面是NAME到共同祖先之间的改动。用git mergetool通常是比较好的选择,当然现在大多数IDE都集成了不错的冲突解决工具;
当你把冲突全部解决完毕,请用git add . 来暂存这些改动;
最后进行git commit,如果你想放弃当前修改重新解决库使用git merge --abort,非常方便,
当你完成了以上这些艰巨的任务,最后git push 吧
排除掉远端的git服务存在问题以外,我们push失败的大多数原因都是因为我们在工作的内容其他人也在工作的关系。
Git是这样判断的
当发生push is rejected 后我们的几个处理方法如下:
本文只是选取部分 Git 基本命令进行介绍,目的是抛砖引玉,让大家对 git 有一个基本的认识。当我们深入挖掘 Git 时,你会发现它本身有着如此多优秀的设计理念,值得我们学习和探究。
不要让Git 成为你认知领域的黑魔法,而是让 Git 成为你掌握的魔法。
原文链接 : https://hacker-tools.github.io/version-control/