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。中文显示正常
- git
- git
- Git
- Git
- Git
- Git
- git
- git
- Git
- GIT
- git
- GIT
- Git
- git
- git
- Git
- GIt
- git
- RRDTool(二)--update,graph
- TImer定时器的方法schedule和scheduleAtFixedRate区别已经动态修改定时计划的实现
- 拓扑排序
- 浅谈apache防盗链
- poj 1789 Truck History(先让我静静)
- GIT
- maven的安装和配置(手动和eclipse插件)
- Lua中的模块(module)和包(package)详解
- VC++中的.ncb文件
- 申请苹果加急审核
- js this指向问题
- android studio 更改背景和设置字体大小
- std::string用法总结
- string - memset源码