• Git 使用教程(2)


    我用git最开始是在github,每次提交代码以后,右上角的部分就会显示这些信息,类似于下面的:
    引用
    commit  fa6f27b7de063c2f301b0e7148b5bd5e813faa98
    tree       5e7a19c158b89fbc52a078771a833ee839727404
    parent   76f31606376180ca88efa12be341dbb14fb06fdf


    咋一看,这40位的乱码挺吓人的,但是你了解它的作用就不会被吓到了。 这是object name,是作为你每次提交的信息标识。这是用SHA1加密hash函数根据你的对象的内容算出来的。Git的一些优点:

    Git通过简单比较object name就可以快速的确定这两个对象是否相等。
    因为object name在每个repository里都是以相同的方法来计算的,所以在不同的两个repository的同一个内容都会被存储在相同的object name下。
    Git可以在读取对象的时候检查错误,检查该对象的名称是否还是它的内容的SHA1 hash。

    The Objects

    每个对象都由三个东东组成:type,size,content。size当然是content的size了,而content却是依赖于这个对象是个什么type了。而type又有四类:“blob”,”tree”, “commit”, “tag”。
    Ruby代码  收藏代码
    1. blob # 通常被用来存储文件数据,一般是个文件。  
    2. tree  # 基本上像个目录结构,比如x / yyy  
    3. commit # 它指向一个单独的tree,它标记了一个时刻的项目的面貌,就像给这个project照了个艳照一样。它包含那个时刻的元信息,例如时间戳,改变本次提交的作者,前一个提交的指向标等等。  
    4. tag # 专门用来指定某些特殊行为的commits。  


    和svn的不同是?
    传统的SCM系统,比如svn,CVS, perforce, Mercuial等,它们存储的都是本次和下次提交的differents。而Git不同,这是关键的一点。Git就像一个狗仔队的记者一样,把你项目的所有文件以及每次提交时候的tree 结构都拍了个照,把这个照片存储下来而已。这点对于理解Git来说,相当重要!

    Blob Object

    刚才说了,这是指文件数据。
    git show 命令可以帮助你看type,具体用法可以参照(http://www.kernel.org/pub/software/scm/git/docs/git-show.html)例如:


    Ruby代码  收藏代码
    1. git show  
    2. commit cf70117f3cc497fba42890171d29ae404061d25f  
    3. Author: Alex <blackanger.z@gmail.com>  
    4. Date:   Sun Dec 7 05:55:46 2008 +0800  
    5.   
    6. modify .gitignore  
    7.    
    8. diff --git a/.gitignore b/.gitignore  
    9. index deb5b7c..77573ab 100644  
    10. --- a/.gitignore  
    11. +++ b/.gitignore  
    12. @@ -1,2 +1,2 @@  
    13. -log/  
    14. +/log  
    15. .DS_Store  


    因为blob是由它的数据决定的实体,如果在目录tree里有两个内容相同的blob,那么它们就会共享同一个blob对象。该对象是完全独立于它在目录tree里的位置的,并且你重命名文件的话也不会改变与这个文件相关联的那个blob对象。

    Tree Object

    这是个简单的对象,它就是指向一堆blob对象和其他的tree目录。它一般表现的是目录和子目录的内容。你用git ls-tree命令可以把tree 对象看的更详细。例如:
    引用
    git ls-tree cf701
    100644 blob 77573ab40c4f010c0e050f1bbff2ad3ab78f1428       .gitignore
    100644 blob f8cd794a2d06e6c409737d5bcd39a20abb62db26    README
    100644 blob 3bb0e8592a41ae3185ee32266c860714980dbed7    Rakefile
    040000 tree ee99c7a2e9842acbab05fcd02ec510ea917218b2    app
    040000 tree 0aff84690f37df01a7cac96529657222cbeeebf6               config
    040000 tree 92aaeee021e9c7da661bac141ab55c17a3ae79ee    db
    040000 tree 0269300738b048a5cc34769d1436d9f228499018    doc
    040000 tree 1e384157d8bc3cd7aab5b0b5605e9a78d0612426    features
    040000 tree 9f87e761776449b7d43ea112573f8ae27faaf826    lib
    040000 tree 4875662d9a7e07a7b95b68958e518fdd65235124    public
    040000 tree 11741373949f86364c10af17db764d1af3bc048f               script
    040000 tree 20433690c23ae3a299b5a02147f68fdf94820370    spec
    040000 tree 646d8b1458d23ba0ec396ef5748205977b023f3f    stories
    040000 tree cc48cdef8eba2b5333c6a01d5795bb6efb43182f    test
    040000 tree e85767f4716fd20a53d7d6455972c6ec6571c833    vendor


    cf701.。。是上一个tree对象,是整个app的tree对象,熟悉Rails的人就可以看得出来这个tree目录。

    请注意这些文件到mode为644或755,以保证git执行时候有足够到权限。

    Commit Object
    你可以用git show或git  log加–pretty=raw参数来检查你的提交,例如:



    Ruby代码  收藏代码
    1. git show -s --pretty=raw cf701  
    2. commit cf70117f3cc497fba42890171d29ae404061d25f  
    3. tree 6ccb7edcdb14205861feb263a7607b8921c75fa3  
    4. parent 3e794f3e4dcb8d362bfb11464c849070bd04a35f  
    5. author Alex <blackanger.z@gmail.com> 1228600546 +0800  
    6. committer Alex <blackanger.z@gmail.com> 1228600546 +0800  
    7.    
    8. modify .gitignore  


    看见没有?
    有个parent, 这基本上是每个commit都有的,但是当一个commit没有parent的时候,那么就叫root commit,这是初始化工程第一次提交才有的。每个project必然会有一个root commit,有的有多个root commit,不过很少见(project 套project ?)。

    author是这次提交的人。
    committer实际创建这次提交的人,它和author有可能不同,例如,我写的代码发email给你,你帮我commit的,但实际author并不是你,对不?
    comment是对这次提交的描述。这里没有我不知道为什么 。。。

    Tag Object

    到这里可以看到如何创建和验证一个object对象。
    http://www.kernel.org/pub/software/scm/git/docs/git-tag.html


    Git Directory and Working Directory

    1. The Git Directory

    git directory是存储你工程所有Git历史和元信息的目录。包括所有的对象,所有到不同分支的指向。
    每个project仅有一个git directory。这个目录就是你工程根目录下的那个.git。例如:



    Ruby代码  收藏代码
    1. cd .git  
    2. ~/work/mars/.git&gt;ls  
    3. COMMIT_EDITMSG    branches    description    index        logs        refs  
    4. HEAD        config        hooks        info        objects  


    2.The Working Directory
    工作目录自然就是你当前检出文件的目录了,大白话就是项目的目录,你要在这里面工作的。。。

    The Git Index

    如果把你当前修改过的这些文件比作是你从你的部队你精选出来的突击队的话,把commit比作深入敌后的话,那么这个git index就是你这支突击队在深入敌后之前的排练场,你需要在这里点兵,看看有没有怕死的逃兵漏掉。因为你要提交的只是你修改的文件,而不是全部文件,所有你只需要有一个修改文件集合就可以了。
    用这个命令来看:



    Ruby代码  收藏代码
    1. git status  
    2. # On branch master  
    3. nothing to commit (working directory clean)  


    我距离上次提交没有改动过任何文件,自然不会出现什么文件列表了。我无耻的抄个例子:

    Ruby代码  收藏代码
    1. $git status  
    2. # On branch master  
    3. # Your branch is behind 'origin/master' by 11 commits, and can be fast-forwarded.  
    4. #  
    5. # Changes to be committed:  
    6. #   (use "git reset HEAD &lt;file&gt;..." to unstage)  
    7. #  
    8. #   modified:   daemon.c  
    9. #  
    10. # Changed but not updated:  
    11. #   (use "git add &lt;file&gt;..." to update what will be committed)  
    12. #  
    13. #   modified:   grep.c  
    14. #   modified:   grep.h  
    15. #  
    16. # Untracked files:  
    17. #   (use "git add &lt;file&gt;..." to include in what will be committed)  
    18. #  
    19.    blametree  
    20.    blametree-init  
    21.    git-gui/git-citool  


    用过svn的人也很容易懂把。

    Setup and Initialization

    安装就不说了,用mac或linux的人都会安装,用windows的人我只能无耻的抄一句别人的话来骂你:
    who fucking need to run a separate software just for using git。

    Git Config


    Ruby代码  收藏代码
    1. $ git config --global user.name "Alex Zhang"  
    2. $ git config --global user.email “blackanger.z@gmail.com"  

    然后你
    vi ~/.gitconfig
    就会看到:
    [user]
    name = Alex Zhang
    email = blackanger.z@gmail.com

    如果你想为指定的项目用别的git 配置,那么你可以使用git config命令来修改你的信息,不需要加--global参数。

    Getting a Git Repository
    那么现在我需要一个Git仓库了。怎么办?

    两个办法:
    克隆一个已经存在的。
    初始化一个新的。

    如果你要clone的话,你需要知道一个project的git url。git操作跨越多个协议,例如:
    Ruby代码  收藏代码
    1. git url  :  git clone git://git.kernel.org/pub/scm/git/git.git  
    2. #或者  
    3. http     :  git clone http://www.kernel.org/pub/scm/git/git.git  


    请记住git:// 协议是更快的。但是当你有防火墙或其他原因的时候,还得用http。

    Initializing a New Repository
    假如你有个工程叫project,那么:

    Ruby代码  收藏代码
    1. cd project  
    2. git init  
    3. #则会输出:  
    4. Initialized empty Git repository in .git/  


    你可以去这里看git的视频:
    http://www.gitcasts.com/

    Normal Workflow

    一般的工作流程就是:
    1.增加一些新的文件
    $ git add file1 file2 file3   把新文件加到git index里。
    2.  git diff –cached
    你可能需要显示你刚add到git index里的那些改变。如果没有--cached,那么就不会显示刚add到index的改变。 你也可以用git status来看。
    Ruby代码  收藏代码
    1. git commit  #你可能需要提交了。  
    2. git commit -a #把新近的改变加到index里顺便提交。  

    为每次commit写message是最佳实践。
    svn或其他的版本控制工具也有add方法,它们只是把新加的文件加到index里来跟踪。但是git的add更加强大, git add,不仅仅是增加新文件到index里,还包括最新的修改。

    Basic Branching and Merging
    一个单一的git仓库就可以提供多个分支给开发者。创建一个新的分支:



    Ruby代码  收藏代码
    1. git  branch experimental  
    2. <pre lang="bash" line="1">  
    3. #如果你现在运行:  
    4. <pre lang="bash" line="1">  
    5. git branch  


    你就会得到一个所有分支的列表。
    Ruby代码  收藏代码
    1. experimental  
    2. * master  


    experimenta是刚刚创建的那个,那个master是默认的分支。星号标识的是你当前所处的分支。


    Ruby代码  收藏代码
    1. git checkout experimental  


    来选择那个experimental的分支内容。如果修改了一个文件,commit这个改变,并且选择回到master 分支:
    (edit file)


    Ruby代码  收藏代码
    1. $ git commit -a  
    2. git branch  
    3.   
    4. #输出  
    5.   
    6.   
    7. * experimental  
    8. master  
    9.   
    10. $ git checkout master  
    11. git branch  
    12.   
    13. #输出:  
    14.   
    15.       
    16.   
    17. experimental  
    18. master  

    然后你这master分支里做了一个不同的改变,然后提交。 那么现在master和experimental这两分支里都有了不同的修改,那么我们来合并这些不同:
    git merge experimental
    注意,你现在是这master里,把其他分支的不同合并到master里来。
    如果没有冲突还好,那么有冲突怎么办?
    git diff 呀

    查看不同,然后解决冲突,再提交一次。

    命令行里输入:
    gitk
    会出来一个x-windows工具,很挫的,截图给大家看,太难看,github上有个好看的工具介绍,我忘了名字了。

    来看看如何解决冲突:



    Ruby代码  收藏代码
    1. $ git merge next  
    2. 100% (4/4) done  
    3. Auto-merged file.txt  
    4. CONFLICT (content): Merge conflict in file.txt  
    5. Automatic merge failed; fix conflicts and then commit the result.  


    merge的时候有冲突,会有警告信息,这可真墨迹。

    git status来看冲突的地方:
    <<<<<<< HEAD:file.txt
    Hello world
    =======
    Goodbye
    >>>>>>> 77976da35a11db4580b80ae27e8d65caf5208086:file.txt
    那么你需要编辑文件来解决冲突,然后:


    Ruby代码  收藏代码
    1. $ git add file.txt  
    2. $ git commit  


    具体可以看gitcasts的视频六:GitCast #6: Branching and Merging

    查看历史:
    Ruby代码  收藏代码
    1. git log #版本号  


    加各种参数可以让log格式化输入便于阅读。

    以上都是简单的情况。 大体命令都去查文档吧。

    Distributed Workflows
    麻烦的情况怎么处理呢?
    Alice有个新的工程,存储这一个git仓库:/home/alice/project, 但是Bob,在同一台机器上也有一个home目录。

    Bob:


    Ruby代码  收藏代码
    1. $ git clone /home/alice/project myrepo  


    创建了一个新的project,叫myrepo。
    Bob修改了一些文件,然后提交它们:
    (edit files)





    Ruby代码  收藏代码
    1. $ git commit -a  
    2. (repeat as necessary)  


    当他准备好以后,他告诉Alice去更新这些改变从他的项目里:/home/bob/myrepo

    那么Alice她是这么做的:



    Ruby代码  收藏代码
    1. $ cd /home/alice/project  
    2. $ git pull /home/bob/myrepo master #(此命令,master参数不是必须的)  


    这个操作把bob的master分支合并到了Alice的当前的master分支里。但是如果此时Alice有自己的改变,有可能会出现冲突。因此pull命令是两个操作:
    从远程分支取一些改变。
    merge到本地当前分支。

    为了避免这种麻烦,我们可以这么做:


    Ruby代码  收藏代码
    1. $ git remote add bob /home/bob/myrepo  


    然后先取回来bob的修改,但是并不去merge

    Ruby代码  收藏代码
    1. $ git fetch bob  


    然后看看日志:
    Ruby代码  收藏代码
    1. $ git log -p master..bob/master  


    然后就会显示bob的所有改变,再检查完这些改变以后,Alice就可以合并这些改变到她的分支里了:

    Ruby代码  收藏代码
    1. $ git merge bob/master  


    这一步也可以这么做:


    Ruby代码  收藏代码
    1. $ git pull . remotes/bob/master  


    之后, Bob更新Alice最新的改变就可以用:


    Ruby代码  收藏代码
    1. $ git pull  


    没有alice的路径是因为,是bob clone的alice的代码。你可以用这个命令查看:

    Ruby代码  收藏代码
    1. $ git config --get remote.origin.url  
    2. /home/alice/project  


    Git也可以做一份Alice master分支的原始拷贝在“origin/master”下:
    Ruby代码  收藏代码
    1. $ git branch -r  
    2.   
    3. #输出  
    4. origin/master  

    Public git repositories
    使用一个公共的仓库,这是通用的做法,这样可以把一些私有的工作过程清晰的和版本库清晰的分离出来。你只需要在你私人的仓库里完成你的工作,然后把你做的改变提交到你的那个公共仓库里,别的开发者可以从你的公共仓库里更新代码。同样,别的开发者push他的改变到他的公共仓库,你从他的公共仓库获取更新。

    引用
    you push
    your personal repo ——————> your public repo
    ^                                     |
    |                                     |
    | you pull                            | they pull
    |                                     |
    |                                     |
    |               they push      V
    their public repo <——————- their repo


    Pushing changes to a public repository



    Ruby代码  收藏代码
    1. $ git push ssh://yourserver.com/~you/proj.git master:master  
    2. #或者是  
    3. $ git push ssh://yourserver.com/~you/proj.git master  


    当然你可以设置.git/config:
    Ruby代码  收藏代码
    1. $ cat >>.git/config <<EOF  
    2. [remote "public-repo"]  
    3. url = ssh://yourserver.com/~you/proj.git  
    4. EOF  


    这样你就可以使用命令:




    Ruby代码  收藏代码
    1. $ git push public-repo master  
    2. </pr>  
    3.    
    4. #以GitHub为例子, 保存在github上的一个项目, 我查看它的config:  
    5. [remote "origin"]  
    6. url = git@github.com:blackanger/mars.git  
    7. fetch = +refs/heads/*:refs/remotes/origin/*  
    8.    
    9. #这样,我每次往github push代码就是用命令:  
    10. git push origin master  
    11.    
    12. #详细的可以去看 www.gitcasts.com  
    13.    
    14. <em><strong>Git Tag</strong></em>  
    15.    
    16. 1.Lightweight Tags  
    17. ~/work/mars&gt;git tag stable-1 cf701  
    18. ~/work/mars&gt;git show stable-1  
    19. commit cf70117f3cc497fba42890171d29ae404061d25f  
    20. Author: Alex &lt;blackanger.z@gmail.com&gt;  
    21. Date:   Sun Dec 7 05:55:46 2008 +0800  
    22.    
    23. modify .gitignore  
    24. 。。。  

    使用tag和一个object关联起来。这是创建一个轻量级的tag。

    Tag Objects
    如果加上-a,-s或-u &lt;key-id&gt;参数,则是创建一个tag对象。
    <pre lang="bash" line="1">
    Ruby代码  收藏代码
    1. $ git tag -a stable-1 1b2e1d63ff  


  • 相关阅读:
    知识管理系统
    小强地狱(Bug Hell)——优先级和缺陷修改的平衡
    搜索引擎中用到的一些拆词方式解析
    TPLINK TLWR841N 路由变无线交换机设置
    .iso与.mdx(mds)格式的区别
    关于“小米盒子”等的被喷
    刚开通了博客园,以后就在这里安家吧
    温故而知新,算法在我心
    silverlight应用图片新闻展示效果
    jquery应用实现博客个性主页布局拖拽功能
  • 原文地址:https://www.cnblogs.com/xieyuan/p/3787338.html
Copyright © 2020-2023  润新知