首页 > 代码库 > git 安装与使用
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‘spassword: 输入服务器上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‘spassword:
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‘spassword:
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‘spassword:
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 访问那台服务器时,就不用输入密码 了。