Git教程

参考

http://www.cnblogs.com/zhangjing230/archive/2012/05/09/2489745.html
http://www.vogella.com/articles/Git/article.html

git

Git是用C语言开发的分布版本控制系统。版本控制系统可以保留一个文件集合的历史记录,并能回滚文件集合到另一个状态(历史记录状态)。另一个状态可以是不同的文件,也可以是不同的文件内容。举个例子,你可以将文件集合转换到两天之前的状态,或者你可以在生产代码和实验性质的代码之间进行切换。文件集合往往被称作是“源代码”。在一个分布版本控制系统中,每个人都有一份完整的源代码(包括源代码所有的历史记录信息),而且可以对这个本地的数据进行操作。分布版本控制系统不需要一个集中式的代码仓库。

当你对本地的源代码进行了修改,你可以标注他们跟下一个版本相关(将他们加到index中),然后提交到仓库中来(commit)。Git保存了所有的版本信息,所以你可以转换你的源代码到任何的历史版本。你可以对本地的仓库进行代码的提交,然后与其他的仓库进行同步。你可以使用Git来进行仓库的克隆(clone)操作,完整的复制一个已有的仓库。仓库的所有者可以通过push操作(推送变更到别处的仓库)或者Pull操作(从别处的仓库拉取变更)来同步变更。

重要术语

术语
定义

仓库(Repository)
一个仓库包括了所有的版本信息、所有的分支和标记信息。在Git中仓库的每份拷贝都是完整的。仓库让你可以从中取得你的工作副本。

分支(Branches)
一个分支意味着一个独立的、拥有自己历史信息的代码线(code line)。你可以从已有的代码中生成一个新的分支,这个分支与剩余的分支完全独立。默认的分支往往是叫master。用户可以选择一个分支,选择一个分支叫做checkout.

标记(Tags)
一个标记指的是某个分支某个特定时间点的状态。通过标记,可以很方便的切换到标记时的状态,例如2009年1月25号在testing分支上的代码状态

提交(Commit)
提交代码后,仓库会创建一个新的版本。这个版本可以在后续被重新获得。每次提交都包括作者和提交者,作者和提交者可以是不同的人

URL
URl用来标识一个仓库的位置

修订(Revision)
用来表示代码的一个版本状态。Git通过用SHA1 hash算法表示的id来标识不同的版本。每一个 SHA1 id都是160位长,16进制标识的字符串.。最新的版本可以通过HEAD来获取。之前的版本可以通过”HEAD~1″来获取,以此类推。

索引

Git 需要将代码的变化显示的与下一次提交进行关联。举个例子,如果你对一个文件继续了修改,然后想将这些修改提交到下一次提交中,你必须将这个文件提交到索引中,通过git add file命令。这样索引可以保存所有变化的快照。

新增的文件总是要显式的添加到索引中来。对于那些之前已经提交过的文件,可以在commit命令中使用-a 选项达到提交到索引的目的。

安装和配置

安装

git客户端下载地址:http://code.google.com/p/msysgit
安装时选择安装git bash和git GUI

配置

你可以在.gitconfig文件中设置git的全局配置。文件位于用户的home目录。 上述已经提到每次提交都会保存作者和提交者的信息,这些信息都可以保存在全局配置中。

运行git Bash,输入下面的命令

忽略某些特定文件

可以配置Git忽略特定的文件或者是文件夹。这些配置都放在.gitignore文件中。这个文件可以存在于不同的文件夹中,可以包含不同的文件匹配模式。为了让Git忽略bin文件夹,在主目录下放置.gitignore文件,其中内容为bin。

追踪空文件夹

Git会忽略空的文件夹。如果你想版本控制包括空文件夹,根据惯例会在空文件夹下放置.gitkeep文件。其实对文件名没有特定的要求。一旦一个空文件夹下有文件后,这个文件夹就会在版本控制范围内。同时Git也提供了全局的配置,core.excludesfile。

开始操作

创建内容

下面创建一些文件,它们会被放到版本控制之中。

创建仓库、添加文件和提交文件

每个Git仓库都是放置在.git文件夹下.这个目录包含了仓库的所有历史记录,.git/config文件包含了仓库的本地配置。

以下将会创建一个Git仓库,添加文件倒仓库的索引中,提交更改。

diff命令与commit更改

通过git diff命令,用户可以查看更改。通过改变一个文件的内容,看看git diff命令输出什么,然后提交这个更改到仓库中

Status, Diff 和 Commit Log

下面会向你展示仓库现有的状态以及过往的提交历史

更正提交的信息 – git amend

通过git amend命令,我们可以修改最后提交的的信息

上述的提交信息中存在错误,下面会修改这个错误

删除文件

如果你删除了一个在版本控制之下的文件,那么使用git add .不会在索引中删除这个文件。需要通过带-a选项的git commit命令或者-A选项的git add命令来完成index的更新,然后git commit

远端仓库remote repositories

设置一个远端的Git仓库

我们将创建一个远端的Git仓库。这个仓库可以存储在本地或者是网络上。

远端Git仓库和标准的Git仓库有如下差别:一个标准的Git仓库包括了源代码和历史信息记录。我们可以直接在这个基础上修改代码,因为它已经包含了一个工作副本。但是远端仓库没有包括工作副本,只包括了历史信息。可以使用–bare选项来创建一个这样的仓库。

为了方便起见,示例中的仓库创建在本地文件系统上

推送更改到其他的仓库

做一些更改,然后将这些更改从你的第一个仓库推送到一个远端仓库

添加远端仓库

除了通过完整的URL来访问Git仓库外,还可以通过git remote add命令为仓库添加一个短名称。当你克隆了一个仓库以后,origin表示所克隆的原始仓库。即使我们从零开始,这个名称也存在。

克隆仓库

通过以下命令在新的目录下创建一个新的仓库

拉取(Pull)更改

通过拉取,可以从其他的仓库中获取最新的更改。在第二个仓库中,做一些更改,然后将更改推送到远端的仓库中。然后第一个仓库拉取这些更改

还原更改

如果在你的工作副本中,你创建了不想被提交的文件,你可以丢弃它。

你可以提取老版本的代码,通过提交的ID。git log命令可以查看提交ID

如果你还未把更改加入到索引中,你也可以直接还原所有的更改

也可以通过revert命令进行还原操作

如果你已经添加一个文件到索引中,但是未提交。可以通过git reset file 命令将这个文件从索引中删除

reset与checkout

git reset

git命令分成两类操作:

一是将数据提交到版本库的操作,这是主要操作;

二是将版本库的数据恢复到工作区,这是逆操作,会改变当前工作区目录下的文件和状态。这类操作主要是两个命令

–soft

(a)将某个commit替换master/HEAD

默认

–mixed

(a)将某个commit替换master/HEAD (b)同时替换暂存区

–hard

(a)将某个commit替换master/HEAD (b)同时替换暂存区 (c)同时替换工作区

git checkout

checkout 是 git 最常用的命令,也是最危险的命令之一,它会改变工作区。

简介

git checkout 4902dc^

checkout 的本质是修改 HEAD 的指向,虽然默认是指向master的,但可以改成指向其他 commit ,比如 git checkout 4902dc^ 会导致提醒:You ar in ‘detached HEAD’ state。如果查看此时的 HEAD 指向:cat .git/HEAD ,结果就是一个具体的 commit 的ID(即一个 40位的ID号)

提交

commit

在 ‘detached HEAD’ 状态下commit,会提醒 ‘commit in detached HEAD mode’,提交之后,HEAD 会指向新的commit的40位ID号。

检出

git checkout master

即将 HEAD 指向 master ,同时会导致工作区和暂存区也全部倒退到master的文件状态。

合并

git merge acc2f69

将 acc2f69 的提交合并到当前 master

从暂存区检出:上面都是从版本库检出(修改HEAD并改写工作区),但如果不填写commit,则默认从暂存区检出,也就是用暂存区的内容改写工作区。它和 reset 不同,reset 有三种参数,默认的mixed是替换暂存区,除非用hard 否则不会改写工作区。而checkout默认是用暂存区替换工作区。如果不省略commit,则除了替换工作区,也替换暂存区。

git checkout branch

更新HEAD指向branch,并用branch指向的树更新暂存区和工作区

git checkout branch — filename

HEAD指向不变,用branch分支的文件覆盖暂存区和工作区的文件

git checkout

汇总显示工作区、暂存区、HEAD的差异

git checkout — filename

用暂存区中的文件覆盖工作区的文件,这个命令很危险,会覆盖本地的修改

–和filename之间有空格

git checkout .

非常危险,将暂存区所有文件替换工作区所有文件

工作目录、索引区、仓库之间互动

git_guide1

上面的四条命令在工作目录、暂存目录(也叫做索引)和仓库之间复制文件。

  • git add files 把当前文件放入暂存区域。
  • git commit 给暂存区域生成快照并提交。
  • git reset — files 用来撤销最后一次git add files,你也可以用git reset 撤销所有暂存区域文件。
  • git checkout — files 把文件从暂存区域复制到工作目录,用来丢弃本地修改。

git_guide2

也可以跳过暂存区域直接从仓库取出文件或者直接提交代码。

  • git commit -a 相当于运行 git add 把所有当前目录下的文件加入暂存区域再运行。git commit.
  • git commit files 进行一次包含最后一次提交加上工作目录中文件快照的提交。并且文件被添加到暂存区域。
  • git checkout HEAD — files 回滚到复制最后一次提交。

标记

Git可以使用对历史记录中的任一版本进行标记。这样在后续的版本中就能轻松的找到。一般来说,被用来标记某个发行的版本

可以通过git tag命令列出所有的标记,通过如下命令来创建一个标记和恢复到一个标记

分支和合并

通过分支,可以创造独立的代码副本。默认的分支叫master。Git消耗很少的资源就能创建分支。Git鼓励开发人员多使用分支

下面的命令列出了所有的本地分支,当前所在的分支前带有*号

推送一个分支到远端仓库

默认的,Git只会推送匹配的分支的远端仓库。这意味在使用git push命令默认推送你的分支之前,需要手工的推送一次这个分支。

解决合并冲突

如果两个不同的开发人员对同一个文件进行了修改,那么合并冲突就会发生。而Git没有智能到自动解决合并两个修改

在这一节中,我们会首先制造一个合并冲突,然后解决它,并应用到Git仓库中

下面会产生一个合并冲突

变基rebase

在同一分支中应用Rebase Commit

通过rebase命令可以合并多个commit为一个。这样用户push更改到远端仓库的时候就可以先修改commit历史

接下来我们将创建多个commit,然后再将它们rebase成一个commit

Rebasing多个分支

你也可以对两个分支进行rebase操作。如下所述,merge命令合并两个分支的更改。rebase命令为一个分支的更改生成一个补丁,然后应用这个补丁到另一分支中

使用merge和rebase,最后的源代码是一样的,但是使用rebase产生的commit历史更加的少,而且历史记录看上去更加的线性

Rebase最佳实践

在push更改到其他的Git仓库之前,我们需要仔细检查本地分支的commit历史

在Git中,你可以使用本地的commit。开发人员可以利用这个功能方便的回滚本地的开发历史。但是在push之前,需要观察你的本地分支历史,是否其中有些commit历史对其他用户来说是无关的

如果所有的commit历史都跟同一个功能有关,很多情况下,你需要rebase这些commit历史为一个commit历史。

交互性的rebase主要就是做重写commit历史的任务。这样做是安全的,因为commit还没有被push到其它的仓库。这意味着commit历史只有在被push之前被修改

如果你修改然后push了一个已经在目标仓库中存在的commit历史,这看起来就像是你实现了一些别人已经实现的功能

Cherry Pick

cherry-pick命令”复制”一个提交节点并在当前复制做一次完全一样的新提交。

git merge vs rebase vs cherry-pick

git merge是用来合并两个分支的。

git cherry-pick可以选择某一个分支中的一个或几个commit(s)来进行操作。例如,假设我们有个稳定版本的分支,叫v2.0,另外还有个开发版本的分支v3.0,我们不能直接把两个分支合并,这样会导致稳定版本混乱,但是又想增加一个v3.0中的功能到v2.0中,这里就可以使用cherry-pick了。

git rebase有点类似git merge,但是两者又有不同,打个比方,你有两个抽屉A和B,里面都装了衣服,现在想把B中的衣服放到A中,git merge是那种横冲直撞型的,拿起B就倒入A里面,如果满了(冲突)再一并整理;而git rebase就很持家了,它会一件一件的从B往A中加,会根据一开始放入的时间顺序的来加,如果满了你可以处理这一件,你可以继续加,或者跳过这一件,又或者不加了,把A还原。所以merge适合那种比较琐碎的,简单的合并,系统级的合并还是用rebase吧。

创建和应用补丁

一个补丁指的是一个包含对源代码进行修改的文本文件。你可以将这个文件发送给某人,然后他就可以应用这个补丁到他的本地仓库

下面会创建一个分支,对这个分支所一些修改,然后创建一个补丁,并应用这个补丁到master分支

放弃跟踪文件

有时候,你不希望某些文件或者文件夹被包含在Git仓库中。但是如果你把它们加到.gitignore文件中以后,Git会停止跟踪这个文件。但是它不会将这个文件从仓库中删除。这导致了文件或者文件夹的最后一个版本还是存在于仓库中。为了取消跟踪这些文件或者文件夹,你可以使用如下的命令

这样做不会将这些文件从commit历史中去掉。如果你想将这些文件从commit历史中去掉,可以参考git filter-branch命令

发表评论

电子邮件地址不会被公开。 必填项已用*标注