GIT

来源:互联网 发布:手机淘宝闲鱼官网主页 编辑:程序博客网 时间:2024/06/05 02:22

Progit instant study note


File Status Lifestyle is showed below

[untracked]       [unmodified]       [modified]      [staged]

    add file ->       edit file ->            stage file->

<- remove file      <-----------------------------commit---


Local operations


working directory                staging area               git directory (repository)

<------------------checkout the project ---------------------------------------

---stage files--------------------->

                                                     ------------commit------------------------>


Git Basic Concept

<>repository & workspace


repository, 仓库, 包含了所有的代码,分支,代码历史等信息.

workspace, 工作区, 从repositorycheck out出来的代码.

 

git和CVS,SubVersion(SVN)最大的不同就在于仓库的位置,CVS,SVN(集中式版本控制系统)的仓库都是在服务器上,代码提交,branch, tag等操作都是在服务器上完成;相反,git的每个用户都有一份完整的repository,也就是说,clone下来的repository和服务器上的repository是一样的. 每个人都可以是一个服务器.这就是所谓的分布式版本控制系统.

 

正因为repository在本地, 所以几乎所有操作都可以本地进行,(e.g. branch, Commit, log, status ...), 只有你想和别人交换信息的时候才需要联网. 另外一个好处是速度, 所有的操作都在本地, 所以git的速度堪称飞快.

repository放置在顶层目录的.git目录下.

 

<> hash.

  进入.git/objects/中就能看到一大堆的16进制字符组成的文件名.所有的代码,所有的目录,所有的分支,所有的变更历史...所有的和代码相关的信息都在这些文件里.这些Objects有3类: Blob,Tree, Commit. 所有存储到objects下的文件都会被计算SHA1值, 然后以该SHA1值作为文件名, 而它原来的文件名则存放在下面要说到"Tree"里面.

<> Blob

  BLOB用来存储常规文件.这个概念很简单,把一个文件拷贝到object目录下, 重命名, 新的名字就是它的SHA1值.   需要注意是: 当一个文件的内容修改了, 它会以一个新的SHA1名字, 整个的重新存储到git库中, 而不单单是修改了部分. 这是git一个重要的特征, 虽然会带来一些存储上的浪费, 但是换来的很多其他方面的好处.

<> Tree

Tree用来表示目录,存储的是一个"文件名<-->SHA1文件名"的列表.根据上面的规则可以推出以下的重要结论:

    * 只要某个文件/目录发生了变化,所有的上级目录的Tree都要变化.

    * 一个顶级目录的Tree,代表了一个代码库的版本.

相当于文件夹。所包含的文件(blob对象)/文件夹(tree对象)的名字及其基本属性(比如权限、是否符号链接等)的列表。

<> Commit

  一个Commit包含一次代码的变更信息, 每git commit一次代码, 生成一个Commit. 除了log, Commiter等信息,Commit包含的最重要的信息就是两个topTree的SHA1名称. 一个是perantTree, 一个是currentTree. 比较这两个Tree之间的不同就能知道这个Commit包含的变更内容.

<> tag

可以指向blob、tree、commit并包含签名,最常见的是指向commit的PGP签名的标签

blob,tree,commit 都是用其存储内容的SHA-1 值命名的(不是简单的对整个文件取SHA-1 值),tag自然使用的是普通名字。

<> refs

    在.git/refs目录下有很多reference, 查看这些reference的内容, 你会发现都是SHA1值. 很简单,refs就是指向某个Commit的指针.  branch是refs, tag是refs, HEAD也是ref.

    随着你的pull, push, Commit, branch等操作, git会自动修改这些refs.

<> stage

在git库和workspace之间还有一个index(stage)[JC:stage is same as index], 可以把它看做是临时的中转仓库,在代码真正放入仓库前,先集中放在这里.在用gitstatus 和git diff的时候对这个概念最有体会.

<> remote

打开.git/config,就明白remote是什么了.

   [remote "origin"]

       fetch =+refs/heads/*:refs/remotes/origin/*

       url =git://git.xxx.org/xxx.git

fetch 字段用来说明远端git库中refs和本地refs的对应关系.

url 字段是远端git库的地址.

remote通常只有一个,origin, 指向你clone的来源, 但也可以有很多个,比如你和甲乙丙丁都做同一个项目,那么你可以把他们都加到remote里面, 这样能fetch他们的任何一个人的改动.

<> pack

   其实就是把objects压缩打包, 在git fetch/pull/push/clone中就要用到.git gc也用来减少磁盘空间的占用量.

Summary:

 

    file ==hash==>Blob

    目录信息(文件列表) ==hash==> Tree

    牵一发动全身, new Tree of top dir=== Commit

    指向Commit的指针  === refs

    在这中转, 再搬到仓库区 === stage

    其他仓库的位置 ==> remotes

    打包 ==> pack

Git diff 工作机制分析

 

用以上的概念可以解释所有的git操作, 先用gitdiff作为例子吧.

git diff master dev

这个命令用来比较master分支(主分支) 和dev分支的不同.

 

git内部的流程如下:

 

    通过.git/refs/heads/master得到该分支最新的Commit:

        比如:602088ec1f420f19e0c8f76715d7c035f8383f9f

    可以用git show 来查看Commit的详细信息.

    也可以用”git ls-tree $commit_hash”来查看该Commit包含的目录信息.

 

    同理得到dev分支的Commit,

    对比Commit中包含的Tree, 由于SHA1相同的objects内容一定相同. 所以只需要对比SHA1不同的objects.

    如果objects是Tree, 递归比较.

    如果是Blob, diff 之.

    输出结果.

 

支持5种数据传输协议:

**本地目录**:git-clone /root/workspace/projects/kernel/kernel-2f/

下载,单向操作

 

**SSH服务**:git-clone git@172.16.2.56:/root/workspace/projects/kernel/kernel-2f/   

上传下载,双向操作

 

**GIT服务**:git-clone git://172.16.2.56/root/workspace/projects/kernel/kernel-2f/

    下载,单向操作

 

**Rsync**:git-clone rsync://172.16.2.56/root/workspace/projects/kernel/kernel-2f/

    上传下载,双向操作

 

**HTTP**:git-clone http://172.16.2.56/root/workspace/projects/kernel/kernel-2f/

    下载,单向操作

Git Commands

QUICK QUIDE OF GIT OPERATION

HOW TO GET GIT SERVER CODES

(1)   Clone GITrepository: “git clone git://109.123.123.221/SC8835_setuptw.git”

(2)   Config your localsetting:

a.    Set name: “gitconfig --global user.name Serker”

b.    Set mail box:“git config --global user.email”

c.    Set git-pushdefault value: “git config --global push.default simple”

 

HOW TO SYNC SERVER CODES

(1)   Get server codes:“git pull”

(2)   Submit yourcodes: “git add *; git commit *; git commit *; git push”

 

HOW TO GET AND VIEW TAG

(3)   Get code relatedwith specific tag: “git fetch origin tag <tagname>”

(4)   View tag list:“git tag -ln”

(5)   View tag’sdetailed info: “git show ${tag_name}”

TIPS

(6)   Before you gitpush your changed codes, you’d better git pull first to avoid conflicting

 

To be noted

每个分支都有一个HEAD

远程仓库分支也有一个HEAD,叫做FETCH_HEAD

架设GIT中心仓库

如何架设git服务给client使用

 

On git server side

安装git-core后,执行:

#nohup git daemon --verbose --export-all--enable=receive-pack --detach --base-path=$LOCAL_PATH > /dev/null2>&1 &

NOTE: (git仓库路径为$LOCAL_PATH/$GIT_PATH)

NOTE: git服务自动启动设置

sudo vim /etc/rc.local 加入以下内容

/usr/bin/git daemon --export-all --enable=receive-pack--detach

 

On git client side

git clone git://$IP/$GIT_PATH

 

For example, git clone git://localhost/$GIT_PATH

 

git-clone

git clone user@192.168.13.244:/work/android/common -bremotes/origin/archive/android-2.6.32 hardware/intel/linux-2.6

 

git clonegit://192.168.13.210/Intel_OakTrail_android2.3/hardware/intel/linux-2.6 -bmaster

git-config

three types of config file from low to high priority

/etc/gitconfig //config for global

~/.gitconfig // configonly for current user

.git/config // config only for current repository

 

配置全局gitconfig信息:

$git-config --global user.name xxx

$git-config --global user.email xxx@archermind.com

$git-config --global core.editor vi

$git config --global merge.tool vimdiff

 

查看对git的配置命令如下:

git-config --list

.gitignore

overview

创建一个名为.gitignore 的文件,列出要忽略的文件模式,不希望它们总出现在未跟踪文件列表

 

实例1:

# 此为注释 – 将被Git 忽略

*.a       # 忽略所有 .a 结尾的文件

!lib.a    # 但 lib.a 除外

/TODO     # 仅仅忽略项目根目录下的TODO 文件,不包括subdir/TODO

build/    # 忽略build/ 目录下的所有文件

doc/*.txt # 会忽略 doc/notes.txt 但不包括 doc/server/arch.txt

 

实例2:

对于gitstatus 在untrackedfiles里面显示很多不需要查看的.a,.o,.cmd,.order之类文件的隐藏方法:

在clone下来的git仓库下新建文件.gitignore

在此文件中写入不希望在gitstatus的untrackedfiles中显示的文件类型,如

*.o

*.a

*.order

这样,运行gitstatus时就不会在untrackedfiles中显示这些文件类型

 

ignore file mode

git config --add core.filemode false

忽略掉文件权限检查

Git ssh 应用实例

#fragment for ssh git usage.

生成ssh公钥:

$ ssh-keygen

//在~/.ssh/目录下生成id_rsa.pub文件,把这个文件发给我就行。

$ repo init -u archermind@192.168.13.71:android_ics/platform/manifest.git

$repo sync

 

Patch build/apply

//create patch file, 在old和new的上一层目录

diff -Naur /old /new > *.patch

//apply patch, 在old目录中

patch –Np1 < *.patch

注意:

如果对目录进行打patch操作时,patch文件中的old源码路径一定要和当前待打patch的源码路径一致,否则要加入-p?参数,?取决于过滤掉几层目录;

如果在当前目录用-pN0,如果在上层目录,用-pN1

例如:

chuan.jiang:~/tmp$ mkdir 1

chuan.jiang:~/tmp$ mkdir 2

chuan.jiang:~/tmp$ vi 1/1.c

chuan.jiang:~/tmp$ vi 2/1.c

chuan.jiang:~/tmp$ diff -Naur 1/ 2/ > 1.diff

chuan.jiang:~/tmp$ vi 1.diff

chuan.jiang:~/tmp$ patch -Np0 < 1.diff

OR

chuan.jiang:~/tmp$ cd 1

chuan.jiang:~/tmp/1$ patch -Np1 < ../1.diff

 

Git fetch 应用实例

git fetch user@192.168.13.244:/project/githubremotes/origin/android-3.0

 

git checkout -b oaktrail FETCH_HEAD

NOTE:FETCH_HEAD指向抓取的远程仓库的HEAD

 

 

远程仓库操作

git-remote

察看跟踪的远程分支:gitremote -v

git-fetch

从远程仓库抓取数据,只是将远端的数据拉到本地仓库(只是以objects保存而已),并不自动合并到当前工作分支

git-push

git push [remote-name] [branch-name]

 

跟踪分支:

从远程分支检出的本地分支,称为_跟踪分支(trackingbranch)

在跟踪分支里输入git push,Git会自行推断应该向哪个服务器的哪个分支推送数据。

反过来,在这些分支里运行git pull 会获取所有远程索引,并把它们的数据都合并到本地分支中来。

 

从本地分支创建远程仓库的分支

eg1 : git push origin update: update

eg2: git push origin ashare-sdk:ashare-sdk

 

//删除远程分支

experimental is branch name you wanted to deleted

git push origin :experimental

           Find a refthat matches experimental in the origin repository (e.g.  refs/heads/experimental)

举个例子:

---------------------------------------------------------------

$ git branch -a

* ashare-sdk

remotes/origin/remotes/origin/ashare-sdk

$ git push origin :remotes/origin/ashare-sdk

To git@10.11.18.130:ishare/platform/external/ishare

 - [deleted]         remotes/origin/ashare-sdk

---------------------------------------------------------------

 

git-pull

git-pull = git fetch + git merge

 

git-pull: 在commit中diff的代码会checkout到本地,如果没有冲突的话;如果有冲突gitpull失败;其他代码只是提示需要更新

 

NOTE 1 : git pull :仅仅拉下跟踪的远程分支,并非所有的远程分支都更新到本地

NOTE 2 : e.g. git pull origin hanjie : master //originhanjie is (remote) , master is (local)

本地仓库操作

 

git-log

-p //view diff

-(n) 仅显示最近的 n 条提交

--name-only //show changed file name only

--author 仅显示指定作者相关的提交。

--graph 用oneline 或format 时结合--graph 选项,可以看到开头多出一些ASCII 字符串表示的简单图形

--pretty=format         //e.g.--pretty=oneline

 

可以定制要显示的记录格式,这样的输出便于后期编程提取分析

选项              说明

%H  提交对象(commit)的完整哈希字串

%h  提交对象的简短哈希字串

%an               作者(author)的名字

%ad               作者修订日期(可以用-date= 选项定制格式)

%cn               提交者(committer)的名字

%cd               提交日期

%s   提交说明

 

eg:

$ git log --pretty=format:"%h - %an, %ar : %s"

ca82a6d - Scott Chacon, 11 months ago : changed the verisonnumber

$ git log file1.c

//check all of history of file1.c

Git-reflog

1.    The command takesvarious subcommands [找回各个commit的hash值的方法]

2.    Use command “cat.git/logs/refs/heads/branchName|grep commit” to fetch all of commit’s HASHvalue in certain branch.

 

git-checkout

git checkout PATH //检出当前目录下HEAD中的文件

git checkout HEAD^^ PATH

git-checkout branchname //切换分支操作,会修改本地代码(包括新建,变更和删除),如果冲突checkout失败

 

git-add

git add x.file

(1 每次修改都需要add,这个和svn不同,切记; 2OR, use git-commit -a)

(git diff --cached : check modified files to be commited)

git commit -m "my log"

git push(如果需要提交到中心仓库)

use "git reset HEAD filexxx" to unstaged.

git-commit

--amend //修改最后一次提交,从stagedfile取出快照并提交,同时可修改commitmessage

git-commit PATH //自动判断文件改动和删除,PATH目录

git-commit -a //自动判断文件改动和删除, 所有目录

git diff

git-diff                                         // workspace vs index

git-diff --cached   //index vs HEAD

git-diff HEAD               // workspace vs HEAD

//memo: workspace -> index -> HEAD

//A vs B means show A differ with B

区别见mangit-diff ; searching “EXAM”

 

Eg: git diff HEAD^ HEAD 1.c

Means HEAD vs HEAD^, i.e. HEAD differ with HEAD^

 

git-diff --name-only

 

git diff master dev

这个命令用来比较master分支(主分支) 和dev分支的不同.

 

git diff HEAD linux/kernel/linux/drivers/usb/gadget

 

git-show

git show XXX : 来查看Commit的详细信息

git show HEAD

 

git-rm

remove file from workspace AND staged files

git rm --cached //remove file form only from staged

git rm \*~ //会递归删除当前目录及其子目录中所有 ~ 结尾的文件

 

git-stash

储藏工作目录的中间状态:

储藏命令:gitstash

还原命令:gitstash apply stash@{*}

移除命令:gitstash drop stash@{*}

git stash pop 来重新应用储藏,同时立刻将其从堆栈中移走                           

 

git-reset

逆转与恢复命令(git-reset)

项目跟踪工具的一个重要任务之一,就是使我们能够随时逆转(Undo)和恢复(Redo)某一阶段的工作。它可以将当前的工作分支的“HEAD”定位到以前提交的任何版本中。

 

git reset (parameter)(commits) <paths>...

--mixed (default)

--soft

--hard

view man git-reset to understand the differences among threeones

what I found:

     --mixed: modifyHEAD and index(staged space)

     --soft: onlymodify HEAD

     --hard: modifyHEAD, index and workspace

注意:

   使用git show HEAD可以看到当前HEAD指向哪次commit

   版本标号通常可以用 HEAD, HEAD^, andHEAD~2 之类的标号表示。

   ORIG_HEAD: the lastHEAD

   对于merge commit,用HEAD^^会跳过mergecommit,最好用HASHvalue

 

git revert

撤销某次提交

比如gitrevert HEAD~1  ,那么会撤销倒数第二次的提交结果。而倒数第一次的提交记录,仍然在。

分支操作

git branch -v //很有用的命令 -v

创建分支:gitbranch *;但是不切换到新建分支

创建并切换分支:gitcheckout -b

创建/切换/跟踪分支

git checkout -b win32 --track emotes/origin/001894_mfc2Win32_merge_test

 

git checkout [-b <new_branch>] [<start_point>]

e.g. git checkout -b win32 --track remotes/origin/win32 等价于

git checkout --track remote/origin/win32

 

如何将本地分支 关联(TRACK)到远程分支:

e.g.

git checkout -b --track branch-one remotes/origin/branch-one

git checkout -b branch-one-copy

git branch -f --track branch-one-copyremotes/origin/branch-one

 

显示分支:git branch -r -a

删除分支:gitbranch -d

 

冲突解决

git status 查看unmerged

git mergetool 修改源码冲突部分

git add 标记为已解决的冲突

 

合并AB两个分支的两种方式:merge和rebase

rebase是将一个分支的所有改动当作patches依次应用到另一个分支上,而merge是把最终结果合在一起

 

For example, I committed two modifications on each branch.

master : @init  -----------------> @m1.1     -------------------------> @m1.2

feature :             \_________> @f1.1 ----------->@f1.2

we want to merge f1.1 and m1.2

 

#git merge master                   //onfeature branch

.... reslove the confliction

#git add conflicted files

#git commit -m “new merge comments”

master : @init ----->@m1.1 --->@m1.2------------------------------------------ merge OK

feature :           \___>@f1.1 --->@f1.2 ---->@m1.1 ---->@m1.2  ______/


#git rebase master  //on feature branch

.... reslove the confliction

#git add conflicted files

#git rebase --continue

@init ---> @m1.1 ----> @master m1.2 ----->@f1.1----->@feature f1.2

 

 

 

JC:总结

git rebase比gitmerge在自动解决代码冲突方面智能很多,而且不会像merge那样多提交出一次冗余commit。例如上面的实例中,多出一次commit“mergeok”

打标签

查询标签

$ git tag -l 'v1.4.2.*'

$ git show v1.2

 

新建标签

Git 使用的标签有两种类型:轻量级的(lightweight)和含附注的(annotated)。

建立含附注的标签:

$ git tag -a v1.4 -m 'my version 1.4'

建立轻量级的标签:

$ git tag v1.4-lw

后期加注标签

$ git tag -a v1.2 9fceb02

   在打标签的时候跟上对应提交对象的校验和(或前几位字符)

 

Git Tools

Gitg

Graphic git tools

Patch

通常patch生成和应用的方法:

Git format-patch $tag

git apply 或者gitam

【特别注意:gitam可以自动产生你的gitlog和commit的提交记录】

 

另一种便捷方法:

git-diff > *.patch

patch –Np1 < *.patchs

 

特别注意:

git apply和patch都可以反打(reverse)patch

 

注意:

git apply 不需要当前目录存在.git仓库;gitam 需要存在.git仓库(或者.git父仓库)

git am只能用来合并gitformat-patch生成的patch

patch -Np1对存在binary的patch无法合并binary差异,

但是gitapply可以合并binary差异

 

GitWeb

sudo apt-get install lighttpd

sudo /etc/init.d/lighttpd start(restart)

under the directory of .git repository, use “git instaweb”,

then, visit http://127.0.0.1:1234/

 

also we could vim .git/gitweb/gitweb.cgi

or init empty git repository and add ln of others codes intogit folder 

 

git推送tag到远端服务器

默认情况下,gitpush并不会把tag标签传送到远端服务器上,只有通过显式命令才能分享标签到远端仓库。

1.push单个tag,命令格式为:gitpush origin [tagname]

例如:

git push origin v1.0 #将本地v1.0的tag推送到远端服务器

2.push所有tag,命令格式为:gitpush [origin] --tags

例如:

git push --tags

git push origin --tags

 

 

Windows git

git config core.quotepath false

core.quotepath设为false的话,就不会对0x80以上的字符进行quote。中文显示正常


0 0
原创粉丝点击