git使用介绍

Git简单介绍

参考网址:

git使用简介

这个教程推荐使用:git教程


git和svn的差异

git和svn的最大差异在于git是分布式的管理方式而svn是集中式的管理方式。如果不习惯用代码管理工具,可能比较难理解分布式管理和集中式管理的概念。下面介绍两种工具的工作流程(团队开发),通过阅读下面的工作流程,你将会很好的理解以上两种概念。

集中式管理

集中式管理的工作流程如下图:

集中式管理的核心是服务器,所有的开发者在开始的新一天的工作之前必须要从服务器获取代码,然后开发,最后解决冲突,提交。所有的版本信息都放在服务器上面。如果脱离了服务器,开发者基本上就不可以工作了。一次开发者需要老是对代码进行更新,老是会有冲突需要解决。

svn有下面的优缺点:

优点:

  1. 管理方便,逻辑明确,符合我们的思维逻辑
  2. 易于管理,集中式服务器更能保证安全性
  3. 代码一致性高
  4. 适合开发人数不多的项目开发

缺点

  1. 服务器压力太大
  2. 如果我们连接不到服务器上,基本上就是不可以工作了。因为我们不可以从服务器上进行操作了,不可以下载和提交。
  3. 不适合人数多的人开发
分布式管理

分布式管理的工作流程如下图:

分布式和集中式的最大区别就在于开发者可以在本地提交。每一个开发者机器上都有一个服务器的数据库。

根据上面的分布式管理的图片,对分布式管理进行简单介绍:
一般开发者的角度:

  1. 从服务器上克隆数据库(包括代码和版本信息)到单机上
  2. 在自己的机器上创建分支,修改代码
  3. 在单机上自己创建的分支上提交的代码
  4. 在单机上合并分支
  5. 建立一个分支,把服务器上最新版的代码fetch下来,然后跟自己的主分支合并
  6. 生成补丁,把补丁发送给主开发者
  7. 看主开发者的反馈,如果主开发者发现两个开发者之间有冲突,要求他们进行协调,然后一个人提交。
  8. 一般开发者之间解决冲突的方法,开发者之间可以使用pull命令解决冲突,解决完冲突之后再向主开发者提交补丁

主开发者的角度

  1. 查看邮件或者通过其他方式查看一般开发者的提交状态
  2. 打上补丁,解决冲突
  3. 向公共服务器提交结果,然后通知所有开发者人员

优点

  1. 适合分布式开发,强调个体
  2. 公共服务器压力和数据量都不会太大
  3. 速度快,灵活
  4. 任意两个开发者之间都可以解决冲突

Git存储空间

git中有两个空间,工作区,版本库

工作区

工作区(working directory)就是你在电脑里能看到的目录,比如我创建了一个learnGit的目录,然后在这个目录里面git init创建了git库,那么这个文件夹就是工作区。

版本库

版本库(repository)就是工作区中的一个隐藏目录.git,这个不算工作区,而是git的版本库。git里面有许多东西,其中最重要的就是称为stage的暂存区,还有git为我们自动创建的第一个分支master,以及指向master的一个指针head

添加过程

我们把文件往Git版本库里添加的时候,是分两步执行的:

第一步是用git add把文件添加进去,实际上就是把文件修改添加到暂存区;

第二步是用git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支。

因为我们创建Git版本库时,Git自动为我们创建了唯一一个master分支,所以,现在,git commit就是往master分支上提交更改。

你可以简单理解为,需要提交的文件修改通通放到暂存区,然后,一次性提交暂存区的所有修改。
git_WorkingAndRepository_img)


Git分支工作状态

在每次提交的时候,git都把他们串成一条时间线,这条时间线就是一个分支。下面是一个例子,这里例子中是有一条主分支master分支,HEAD严格来说不是指向提交的,而是指向mastermaster才是指向提交的,所以,HEAD指向的就是当前分支.

一开始的时候,master分支是一条线,git用master指向最新的提交,在用HEAD指向master,就能确定当前分支以及分支的提交点:
git_creatBranch01

每次提交,master分支都会向前移动一步,这样,随着你不断提交,master分支的线也越来越长.

当我们创建新的分支,例如dev时,Git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev上:
git_creatBranch01

你看,Git创建一个分支很快,因为除了增加一个dev指针,改改HEAD的指向,工作区的文件都没有任何变化!

不过,从现在开始,对工作区的修改和提交就是针对dev分支了,比如新提交一次后,dev指针往前移动一步,而master指针不变:
git_creatBranch01

假如我们在dev上的工作完成了,就可以把dev合并到master上。Git怎么合并呢?最简单的方法,就是直接把master指向dev的当前提交,就完成了合并:
git_creatBranch01
所以Git合并分支也很快!就改改指针,工作区内容也不变!

合并完分支后,甚至可以删除dev分支。删除dev分支就是把dev指针给删掉,删掉后,我们就剩下了一条master分支:
git_creatBranch01


Git远程仓库的创建

github网站为我们提供了一个免费的git仓库托管服务,我们可以在这个网站上建立远程代码仓库。

由于你的本地的Git仓库和github仓库之间的传输是通过ssh加密的,所以需要一点的设置:

  1. 创建SSH Key。在用户主目录下,看看有没有.ssh,注意.ssh是一个隐藏文件,我们需要命令行ls -ah来查看,如果有,看进入到这个目录下有没有id_rsaid_rsa.pub这两个文件,如果已经有了,就直接跳过下一步。如果没有,那么在终端中创建一个SSH Key

    $ ssh-keygen -t rsa -C "youremail@example.com"
    

    你需要把邮件地址换成你自己的邮件地址,然后一路回车,使用默认值即可,由于这 个Key也不是用于军事目的,所以也无需设置密码。

    如果一切顺利的话,可以在用户主目录里找到.ssh目录,里面有id_rsa和 id_rsa.pub两个文件,这两个就是SSH Key的秘钥对,id_rsa是私钥,不能泄露 出去,id_rsa.pub是公钥,可以放心地告诉任何人。

  2. 登陆GitHub,打开“Account settings”,“SSH Keys”页面:

    然后,点“Add SSH Key”,填上任意Title,在Key文本框里粘贴id_rsa.pub文件的内容
    git_romoteRepository_SSHKey)
    为什么GitHub需要SSH Key呢?因为GitHub需要识别出你推送的提交确实是你推送的,而不是别人冒充的,而Git支持SSH协议,所以,GitHub只要知道了你的公钥,就可以确认只有你自己才能推送。

    当然,GitHub允许你添加多个Key。假定你有若干电脑,你一会儿在公司提交,一会儿在家里提交,只要把每台电脑的Key都添加到GitHub,就可以在每台电脑上往GitHub推送了。

你也许还注意到,GitHub给出的地址不止一个,还可以用https://github.com/michaelliao/gitskills.git这样的地址。实际上,Git支持多种协议,默认的git://使用ssh,但也可以使用https等其他协议。

使用https除了速度慢以外,还有个最大的麻烦是每次推送都必须输入口令,但是在某些只开放http端口的公司内部就无法使用ssh协议而只能用https。


Git命令行

git仓库创建

$ mkdir learngit//创建一个目录
$ cd learngit//进入目录
$ pwd//查看所处文件位置
/Users/michael/learngit
$git init//将目录改为git仓库
$ls -ah//显示隐藏文件,里面有一个.git文件,就代表了创建git成功

向git仓库里面添加文件,并提交

$ git add readme.txt
$ git commit -m "wrote a readme file"//-m后面添加commit的时候的解释。便于合作开发的理解。
[master (root-commit) cb926e7] wrote a readme file
1 file changed, 2 insertions(+)
create mode 100644 readme.txt

git中查看工作区的状态

$ git status
$ git diff readme.txt //查看这个readme.txt文件的改变

git版本回退

Git必须知道当前版本是哪个版本,在Git中,用HEAD表示当前版本,也就是最新的提交3628164…882e1e0(注意我的提交ID和你的肯定不一样),上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100。

下面是版本回退的编码

$ git reset --hard HEAD^//回退到上一个版本
$ git reset --hard 3628164//回退到id号为3628164的版本,这个版本号(3628164)不需要写全,系统会搜索
$ git log//可以查看当前版
$ git reflog//查看所有版本

穿梭前,用git log可以查看提交历史,以便确定要回退到哪个版本。
要重返未来,用git reflog查看命令历史,以便确定要回到未来的哪个版本。

git撤销修改

$ git checkout -- readme.txt

当修改还没有add到暂存区里面的时候,可以使用上面的命令行来撤销对readme.txt文件的修改

$ git reset HEAD readme.txt

git reset命令既可以回退版本,也可以把暂存区的修改回退到工作区。当我们用HEAD时,表示最新的版本。这句话要在我们已经将修改传到了暂存区里面的时候,我们就使用命令行来将暂存区中的修改退回,然后在使用一开始的命令行来撤销readme.txt的修改

git添加远程代码仓库

  1. 首先在github里面创建一个远程代码仓库,然后将本地库与远程库进行关联在本地创建的learngit仓库中运行下面命令:

    $ git remote add origin git@github.com:michaelliao/learngit.git
    

    请千万注意,把上面的michaelliao替换成你自己的GitHub账户名,否则,你在本地关联的就是我的远程库,关联没有问题,但是你以后推送是推不上去的,因为你的SSH Key公钥不在我的账户列表中。

    添加后,远程库的名字就是origin,这是Git默认的叫法,也可以改成别的,但是origin这个名字一看就知道是远程库。

  2. 下一步,将本地库中的内容添加到到远程库中:3.

    $ git push -u origin master
    

    把本地库的内容推送到远程,用git push命令,实际上是把当前分支master推送到远程。

    由于远程库是空的,我们第一次推送master分支时,加上了-u参数,Git不但 会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。

  3. 之后,我们要做本地提交,执行下面命令即可:

    $ git push origin master
    

git克隆远程代码库

$ git clone git@github.com:michaelliao/gitskills.git

在本地仓库中运行命令行来克隆远程代码库

创建与合并分支

可能我总结的不是很好,下面是原版大神教程:git教程——创建与合并分支

创建一个new分支,然后查看分支

$ git checkout -b dev
$ git branch

然后更改工作区中的文件

$git add readme.txt
$git commit -m"branch test"

然后切换到master分支中去

$ git checkout master

我们发现刚刚添加的更改不见了,因为我们切换到了另一个分支,这个分支的指针还是指向原来状态的文件的。因此没有看到改变。

最关键的工作来了,就是合并两个分支:现在,我们把dev分支的工作成果合并到master分支上

$ git merge dev
Updating d17efd8..fec145a
Fast-forward
readme.txt |    1 +
1 file changed, 1 insertion(+)

git merge命令用于合并指定分支到当前分支。合并后,再查看readme.txt的内容,就可以看到,和dev分支的最新提交是完全一样的。

删除分支命令行:

$ git branch -d dev

git推送分支

重点:我总结的不是很好,下面是原版大神教程:git教程——推送分支

推送分支就是把该分支上的所有本地提交到远程库。推送时,要指定本地分支,这样,git就会把该分支推送到远程库对应的远程分支上:

$git push origin master

如果要推送其他分支,只要将master改为dev,就ok了

但是,并不是一定要把本地分支往远程推送,那么,哪些分支需要推送,哪些不需要呢?

master分支是主分支,因此要时刻与远程同步;

dev分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步;

bug分支只用于在本地修复bug,就没必要推到远程了,除非老板要看看你每周到底修复了几个bug;

feature分支是否推到远程,取决于你是否和你的小伙伴合作在上面开发。

git抓取分支

重点:我总结的不是很好,下面是原版大神教程:git教程——抓取分支

多人协作时,大家都会往master和dev分支上推送各自的修改。

现在,模拟一个你的小伙伴,可以在另一台电脑(注意要把SSH Key添加到GitHub)或者同一台电脑的另一个目录下克隆:

$ git clone git@github.com:michaelliao/learngit.git
Cloning into 'learngit'...
remote: Counting objects: 46, done.
remote: Compressing objects: 100% (26/26), done.
remote: Total 46 (delta 16), reused 45 (delta 15)
Receiving objects: 100% (46/46), 15.69 KiB | 6 KiB/s, done.
Resolving deltas: 100% (16/16), done.

当你的小伙伴从远程库clone时,默认情况下,你的小伙伴只能看到本地的master分支。不信可以用git branch命令看看:

$ git branch
* master

现在,你的小伙伴要在dev分支上开发,就必须创建远程origin的dev分支到本地,于是他用这个命令创建本地dev分支:

$ git checkout -b dev origin/dev

现在,他就可以在dev上继续修改,然后,时不时地把dev分支push到远程:

$ git commit -m "add /usr/bin/env"
[dev 291bea8] add /usr/bin/env
 1 file changed, 1 insertion(+)

$ git push origin dev
Counting objects: 5, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 349 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@github.com:michaelliao/learngit.git
fc38031..291bea8  dev -> dev

你的小伙伴已经向origin/dev分支推送了他的提交,而碰巧你也对同样的文件作了修改,并试图推送:

$ git add hello.py 
$ git commit -m "add coding: utf-8"
[dev bd6ae48] add coding: utf-8
 1 file changed, 1 insertion(+)

$ git push origin dev
To git@github.com:michaelliao/learngit.git
 ! [rejected]        dev -> dev (non-fast-forward)
error: failed to push some refs to 'git@github.com:michaelliao/learngit.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Merge the remote changes (e.g. 'git pull')
hint: before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

推送失败,因为你的小伙伴的最新提交和你试图推送的提交有冲突,解决办法也很简单,Git已经提示我们,先用git pull把最新的提交从origin/dev抓下来,然后,在本地合并,解决冲突,再推送:

$ git pull
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 3 (delta 0)
Unpacking objects: 100% (3/3), done.
From github.com:michaelliao/learngit
   fc38031..291bea8  dev        -> origin/dev
There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details

git pull <remote> <branch>

If you wish to set tracking information for this branch you can do so with:

git branch --set-upstream dev origin/<branch>

git pull也失败了,原因是没有指定本地dev分支与远程origin/dev分支的链接,根据提示,设置dev和origin/dev的链接:

$ git branch --set-upstream dev origin/dev
Branch dev set up to track remote branch dev from origin.

再pull:

$ git pull
Auto-merging hello.py
CONFLICT (content): Merge conflict in hello.py
Automatic merge failed; fix conflicts and then commit the result.

这回git pull成功,但是合并有冲突,需要手动解决,解决的方法和分支管理中的解决冲突完全一样。解决后,提交,再push:

$ git commit -m "merge & fix hello.py"
[dev adca45d] merge & fix hello.py
$ git push origin dev
Counting objects: 10, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (6/6), 747 bytes, done.
Total 6 (delta 0), reused 0 (delta 0)
To git@github.com:michaelliao/learngit.git
   291bea8..adca45d  dev -> dev

因此,多人协作的工作模式通常是这样:

  1. 首先,可以试图用git push origin branch-name推送自己的修改;
  2. 如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并;
  3. 如果合并有冲突,则解决冲突,并在本地提交;
  4. 没有冲突或者解决掉冲突后,再用git push origin branch-name推送就能成功!
  5. 如果git pull提示“no tracking information”,则说明本地分支和远程分支的链接关系没有创建,用命令git branch –set-upstream branch-name origin/branch-name。

这就是多人协作的工作模式,一旦熟悉了,就非常简单。

posted @ 2015-04-10 21:41  AbeDay  阅读(237)  评论(0编辑  收藏  举报