git 安装与使用

 

说明:下面文章中黑体字是命令行的输入,斜体是命令行的输出,汉字为正文或注释。

Git 是用于Linux 内核开发的版本控制工具。与常用的CVS, Subversion 等不同,它采用了分布式版本库的方式,不必服务器端软件支持,使源代码的发布和交流极其方便。 Ubuntu上可以在“system -> 系统管理 -> 新立得软件包管理器中搜索到git-core, 这个下载下来即可很方便的开始使用git了。下面从用户角度分两部分讲述,首先是单个用户独立使用git,其次是多个用户一起使用git进行团队开发。

一:单个用户

  Git安装与使用

    先在自己的 /home/chenchi/ 目录下开始操作

$ mkdir gittest

$ cd gittest

$ git init

然后会自动输出类似的语句 :

Initialized empty Git repository in /home/chenchi/testgit/.git/

这时候我们输入下面的命令

$ ls -a

可以看到当前目录下创建了一个隐藏的 .git 目录,它就是所谓的Git 仓库,不过现在仓库还是空的。另外当前目录也不再是普通的文档目录了,今后我们将其称为工作树。有兴趣的话,可以先到.git 目录下看看都有哪些文件。

 

一个叫 HEAD 的文件,我们现在来查看一下它的内容:

$ cat .git/HEAD

现在 HEAD 的内容应该是这样:

ref: refs/heads/master

我们可以看到,HEAD 文件中的内容其实只是包含了一个索引信息,并且,这个索引将总是指向你的项目中的当前开发分支。

 

一个叫 objects 的子目录,它包含了你的项目中的所有对象,我们不必直接地了解到这些对象内容,我们应该关心是存放在这些对象中的项目的数据。

 

一个叫 refs 的子目录,它用来保存指向对象的索引。

 

具体地说,子目录 refs 包含着两个子目录叫 heads 和 tags,就像他们的名字所表达的意味一样:他们存放了不同的开发分支的头的索引, 或者是你用来标定版本的标签的索引。

 

请注意:master 是默认的分支,这也是为什么 .git/HEAD 创建的时候就指向 master 的原因,尽管目前它其实并不存在。 git 将假设你会在 master 上开始并展开你以后的工作,除非你自己创建你自己的分支。

 

另外,这只是一个约定俗成的习惯而已,实际上你可以将你的工作分支叫任何名字,而不必在版本库中一定要有一个叫 master 的分支,尽管很多 git 工具都认为 master 分支是存在的。

 

现在已经创建好了一个 git 版本库,但是它是空的,还不能做任何事情,下一步就是怎么向版本库植入数据了。

 

为了简明起见,我们创建两个文件作为练习:

$ echo "Hello world" > hello

$ echo "Silly example" > example

 

这样在当前的testgit目录下就生成了两个文件hello和example,如果我们想将它们加入到库中,该怎么做呢? 首先利用 git add 命令将这两个文件加入到版本库文件索引(一个临时的存储区域,Git 称该区域为索引,如果不理解,先跳过去)当中:

$ git add hello example

现在让我们看看版本库的状态:

$ git status

 

# On branch master

#

# Initial commit

#

# Changes to be committed:

#   (use "git rm --cached <file>..." to unstage)

#

#     new file: example

#     new file: hello

#

我们能看到 git 的状态提示。提示信息告诉我们版本库中加入了两个新的文件,并且 git 提示我们提交这些文件,我们可以通过 git-commit 命令来提交,这里我们有两种输入方式,

 

(1)带参数m

$ git commit -m "Initial commit of gittest reposistory"

//引号中的内容就是类似于SVN中每次提交代码前,都要填写的message信息,以便于以后自己或者别人能明白你这次更改的原因,及相关改动的信息。

 

(2)不带参数m

$ git commit

//系统会自动调用一个叫GNU nano的编辑器,来让你输入与上面类似的信息,在编辑器的下面会出现^G ^X ^O ^J等等,^表示ctrl键,所以他们分别是“ctrl键+G”(获取帮助),“ctrl键+X”(Exit 退出),“ctrl键+O”(WriteOut 写保存),“ctrl键+J”(Justify),具体就不详述了。


Created initial commit 7ffe128: Initial commit of gittest reposistory

2 files changed, 2 insertions(+), 0 deletions(-)

create mode 100644 example

create mode 100644 hello

 

来看看自己的劳动成果吧:

 

$ git log

 

commit 7ffe1285bda6febfa8d24f8d366ad97c97f3b550

Author: chenchi <chen.chi@kortide.com.cn>

Date: Tue Feb 24 17:54:46 2009 +0800

  Initial commit of gittest reposistory

这里我们已经知道如何创建版本库,并向库中添加数据。

 

再往下走:

$ vim hello

添加如下语句:

today is Tuesday, 20090224, rain.

Are you happy?

 

利用git diff 查看改了什么:

 

$ git diff    //注意:该命令只比较已经在index索引中存在的文件,也即如果是一个新加的文件。git diff是不会产生比较的。

diff --git a/hello b/hello

index 802992c..e042b07 100644

--- a/hello

+++ b/hello

@@ -1 +1,4 @@

Hello world

+

+today is Tuesday, 20090224, rain.

+Are you happy?

 

现在让我们看看版本库的状态:

$ git status

 

# On branch master   //表示master分支

# (use "git add <file>..." to update what will be committed)

#

#   modified: hello

# no changes added to commit (use "git add" and/or "git commit -a")

它表示hello文件已经被更改了,但没有更新(update)。

 

$ git add hello

$ git diff   //此时已经没有不同的内容了

$ git status   //再看看版本库状态,有什么区别呢?

 

# On branch master   //表示master分支

# Changes to be committed:

# (use "git reset HEAD <file>..." to unstage)

#

#   modified: hello

#

它表示hello文件已经被更改了,但没有提交(committed)到本地的仓库中

 

$ git commit -m "1---add date to hello file"

这里我们其实已经完成了又一次的更改和提交了。

 

二:多个用户,团队开发

 

实际开发中,我们通常是直接用别人的仓库来进行进一步的开发,那么下面的流程就是必须要看的了:

因为是团队合作,所以每个人在使用git时,要先进行类似的配置。

$ git config --global user.name "chenchi"

$ git config --global user.email "chen.chi@kortide.com.cn"

这样的配置文件也可以在/home/chenchi/.gitconfig中看到。

 

回到自己的 /home/chenchi/ 目录下

$ mkdir project

$ cd project

 

首先从服务器上克隆(clone出完整的工作树到本地):

$ git clonechenchi@192.168.2.171:/home/chenchi/git1 (内网用户)

$ git clone ssh://chenchi@210.22.155.236:9092/home/chenchi/git1 (外网用户)


Initialized empty Git repository in /home/chenchi/project/git1/.git/

chenchi@192.168.2.171's password:    输入服务器上chenchi用户的密码(123456),然后输出下面的内容

remote: Counting objects: 94, done.

remote: Compressing objects: 100% (67/67), done.

remote: Total 94 (delta 12), reused 0 (delta 0)

Receiving objects: 100% (94/94), 7.91 KiB, done.

Resolving deltas: 100% (12/12), done.

 

注意:

 

1:git clone 命令是将别的仓库克隆(clone)过来,后面是别人仓库的源地址,你可以直接用上面的地址试试。这时如果一切顺利,系统会自动在你的当前目录下建立一个git1的目录;如果你想弄一个linux的源代码来玩玩,可以试试这个:

$ git-clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git linux-2.6

2:因为git clone在默认时用的是ssh协议,所以用git clone前应该确保我们当前机器机器上已经安装了openssh,详见wiki中:开发环境 ------> Openssh服务 。

这样在当前目录中就生产了一个git1的工作树,它的内容和服务器中是一样的。你可以在自己的机器上进行各种更改了,具体用法和前面单机时类似(add -> commit ->OK )。只是当你想将自己的工作放到服务器中时(也就是SVN中的提交代码),建议按如下步骤:

 

$ git pull           

//先更新本地代码,使其是服务器中最新的代码,防止提交时有冲突,如果没有,继续下一步;如果有冲突,则先在编辑器中修改掉冲突部分,再继续下面的步骤

$ git push 

//将本地的更改最后push到服务器上,使服务器上也同步保留了自己的更改

这里一次代码更改并最后提交就完成了。

这个时候在服务器端可以用 git log 来看看是否有更新,同时可以通过在服务器端输入 git checkout 将Git仓库中更新的内容导到当前工作目录中,显现出来。

当服务器上有新的代码(其他人git push 上去的),而某个开发者在本地忘记了git pull直接git push 时,会出现类似下面的错误:

 

zhenguo@zhenguo-desktop:~/chenchi/git1/drv-pxa310$ git push

zhenguo@210.22.155.236's password:

To ssh://210.22.155.236:9092/home/chenchi/git1

![rejected]   master -> master (non-fast forward)

error: failed to push some refs to 'ssh://210.22.155.236:9092/home/chenchi/git1'

这时需要git pull 更新本地代码,系统会在这个过程中自动的进行merger操作,如果本地更改和服务器上最新代码没有冲突,则merger操作自动完成,如果有冲突,则出现类似下面的输出:

zhenguo@zhenguo-desktop:~/chenchi/git1/drv-pxa310$ git pull

zhenguo@210.22.155.236's password:

remote: Counting objects: 15, done. r

emote: Compressing objects: 100% (12/12), done.

remote: Total 12 (delta 5), reused 0 (delta 0)

Unpacking objects: 100% (12/12), done.

From ssh://210.22.155.236:9092/home/chenchi/git1

  a3803c8..9ceb8ee master   ->   origin/master

Auto-merged drv-pxa310/t3

CONFLICT (content): Merge conflict in drv-pxa310/t3

Automatic merge failed; fix conflicts and then commit the result.

这时需要我们自己手动更改文件,再提交到本地仓库,最后 git push 到服务器上去。

 

如果在push过程中有类似下面的错误:

zhenguo@zhenguo-desktop:~/chenchi/git1/drv-pxa310$ git push

zhenguo@210.22.155.236's password:

Counting objects: 14, done.

Compressing objects: 100% (8/8), done.

Writing objects: 100% (8/8), 755 bytes, done.

Total 8 (delta 4), reused 0 (delta 0)

error: unable to create temporary sha1 filename ./objects/ca: File exists

 

fatal: failed to write object

error: unpack failed: unpacker exited with error code

To ssh://210.22.155.236:9092/home/chenchi/git1

! [remote rejected] master -> master (n/a (unpacker error))

error: failed to push some refs to 'ssh://210.22.155.236:9092/home/chenchi/git1'

 

三:库的逆转与恢复 -- git-reset -- git-checkout

 

库的逆转与恢复除了用来进行一些废弃的研发代码的重置外,还有一个重要的作用。比如我们从远程clone了一个代码库,在本地开发后,准备提交回远程。但是本地代码库在开发时,有功能性的commit,也有出于备份目的的commit等等。总之,commit的日志中有大量无用log,我们并不想把这些log在提交回远程时也提交到库中。因此,就要用到git-reset。

Git-reset的概念比较复杂。它的命令形式:git-reset [--mixed | --soft | --hard] [<commit-ish>]

命令的选项:

--mixed   这个是默认的选项。 如

$  git  reset  --mixed  dev1^   //dev1^ 其实就是某个具体的commit ID,也就是那一串数字,如 a3803c862eb73b3a7a61b356e3fb5c7e95a17bfd

 

它的作用仅是重置分支状态到dev1^, 但是却不改变任何工作文件的内容。即,从dev1^到dev1的所有文件变化都保留了,但是dev1^到dev1之间的所有commit日志都被清除了,而且,发生变化的文件内容也没有通过git-add标识,如果您要重新commit,还需要对变化的文件做一次git-add。简单点说就是:将前面几次log信息清除,而将相应的更改一次性进行 add --> commit。 这样,add --> commit后,就会得到了一份非常干净的提交记录。

 

$ git reset --mixed 7fde43204              //相当于做了git-reset –mixed,后,又对变化的文件做了git-add。如果用了该选项, 就可以直接commit了。

 

$ git reset --hard 7fde43204               //这个命令就会导致所有信息的回退, 包括文件内容。 一般只有在重置废弃代码时,才用它。 执行后,文件内容也无法恢复回来了。慎用。

 

当我们改了大量的文件以后,既没有 git add 也没有git commit,这时我们想将其中部分文件的更改撤销掉,即想做SVN中的revert类似操作,这时可以:

 

$  git   checkout   HEAD   -- filename1   filename2   filename3   dir1/filename4   dir1/filename4

 

四 .Git pull push 操作无需输密码的方法

 

在本地使用git与服务器进行pull、push操作时,每次都要输入密码,比较麻烦,我们可以用ssh密钥来进行验证。这样git使用过程中ssh就会自动登录而无需输入密码。方法如下:

首先用自己账号登录到server上,输入ssh-keygen -t rsa

 

chenchi@Ubuntu-8:~$ ssh-keygen -t rsa

Generating public/private rsa key pair.

Enter file in which to save the key (/home/chenchi/.ssh/id_rsa):

Enter passphrase (empty for no passphrase):

Enter same passphrase again:

Your identification has been saved in /home/chenchi/.ssh/id_rsa.

Your public key has been saved in /home/chenchi/.ssh/id_rsa.pub.

The key fingerprint is:

79:8a:78:8f:c6:12:12:3c:fd:40:84:7b:e3:fc:60:dfchenchi@Ubuntu-8

The key's randomart image is:

.........

输入ssh-keygen -t rsa 后,出现各个提示,不用管,一直按回车。这样密钥对就生成完了。其中公共密钥保存在 ~/.ssh/id_rsa.pub ( ~ 表示自己账号的home目录,像我的就是/home/chenchi目录);

私有密钥保存在 ~/.ssh/id_rsa 文件中。

chenchi@Ubuntu-8:~$ cd .ssh/

chenchi@Ubuntu-8:~/.ssh$ ls

config id_rsa id_rsa.pub known_hosts

chenchi@Ubuntu-8:~/.ssh$ cat id_rsa.pub   > >  authorized_keys

chenchi@Ubuntu-8:~/.ssh$ chmod 600 authorized_keys

将公共密钥id_rsa.pub内容放到authorized_keys文件中,并修改authorized_keys的权限。

退出server,然后登录到本地的机器上执行:

$ scp chenchi@192.168.2.171:/home/chenchi/.ssh/id_rsa  /home/chenchi/.ssh/ (内网)

$ scp -P 9092 yourname@210.22.155.236:/home/yupeng/.ssh/id_rsa  ~/.ssh/id_rsa (外网)

$ cd /home/chenchi/.ssh/

$ chmod 600 id_rsa

将服务器上密钥对中的私有密钥(id_rsa)用scp命令复制到你自己本地.ssh目录下,修改一下本地的id_rsa 文件权限,这样就好了。之后你用ssh 访问那台服务器时,就不用输入密码 了。

 

 

 

posted @ 2014-05-22 19:41  LAXlerbo  阅读(253)  评论(0编辑  收藏  举报