转载:http://bbs.chinaunix.net/thread-4136014-1-1.html
【基本概念】
A) git本地由三个部分组成:工作区 和 暂存区 和 本地库。B) .git目录才是仓库的灵魂,.git目录里面包括 暂存区 和 本地库,.git目录外的地方是工作区。
C) git中包含4类对象 (commit 提交对象, tree 目录, blob 文件, tag 标记)
【git模型】
工作区 = working directory
暂存区 = snapshot/stage/index
本地库 = local repo
【.git目录】
HEAD 指向当前分支config 项目配置文件
description 供GitWeb程序使用
hooks/ 客户端与服务端钩子脚本
info/ 忽略模式
index 暂存区域信息
objects/ 所有数据内容
refs/ 指向所有commit的指针
【git对象】
git提交便产生一个commit对象,commit对象中包含一个tree对象,tree对象中又会包含其他的tree对象或是blob对象,blob对象是最小的组成单元,即独立的文件。
每个对象都对应一个唯一的SHA-1值,只有当文件或目录有修改时这个值才会重新计算发生改变。
$ git log 可以查看所有commit对象
$ git ls-tree <commit> 查看commit对象中的tree对象
$ git show <blob> 查看blob的具体内容
【参数解释】
HEAD = HEAD~0
HEAD^ = HEAD~1
HEAD^^ = HEAD~2
【git 命令】
git init // 如果仅仅在本地创建空配置库,不需要带任何参数
git init --bare // 在服务器上创建一个新的空配置库,比如是在repositories/prj/Code.git目录下执行。bare repository主要是用作分享版本库。
git clone git@YOUR_SERVER:prj/Code.git // 从远程服务器的 repositories/prj/Code.git 目录下克隆
git push // 上传所有内容,从 本地库 到 服务器
git push origin master // 上传master分支
git push origin --tags // 上传本地标签
git fetch // 从服务器上下载更新代码到 本地库,工作区和 暂存区 不会被改变。
git pull = git fetch + git checkout // 下载数据到 本地库,并更新到 暂存区 和工作区
git remote
git add
git rm
git commit
git diff
git diff --cached
git checkout
git status
git show
git log
git reset
git revert
git branch
git merge
git show-branch
git config
git tag
git stash
.gitignore 需要忽略的临时文件
【举例】
*.o
obj/
.svn/
【git remote】-- 远程操作命令
git remote -v // 显示远程库的路径
git remote add // git remote add <name> <url>
git remote rm
git remote show
【git add】-- 如果你新增了文件或文件夹,那么就要老老实实的先git add . 再git commit
git add file1 file2 file3 // 将新增加文件加入到 暂存区 中
git add . // 所有文件全部加入到 暂存区 中,包括子目录,不包括空目录
git add -i // 进入交互式add,尚未体验,有空试一下
【git rm】-- git 提供相应命令 (add,rm) 将工作区变更加入到 暂存区
git rm -rf xxx
git rm xxx.file
【git commit】-- 将 暂存区 的东西加入到 本地库,(注意:这里只是提交到本地库,还需要通过 push 命令才能将本地库的内容上传到服务器)
git commit -m “something” someFile //提交指定文件
git commit -m "写上描述" // 最常用的用法
git commit -a -m "写上描述" // -a 参数请谨慎处理,常见的错误结果是把某些编译中间文件也加入配置库。
commit和commit -a的区别
commit -a相当于:
第一步:自动地add所有改动的代码,使得所有的开发代码都列于index file中
第二步:自动地删除那些在index file中但不在工作树中的文件
第三步:执行commit命令来提交
【git diff】
git diff SHA_AAA // 比较工作目录和SHA_AAA之间的差异
git diff SHA_AAA..SHA_BBB // 比较两次不同的commit之间的差异
git diff // 比较工作区和 暂存区 的差异。 这个命令只在git add之前使用有效,如果已经add了,那么此命令输出为空。
git diff --cached // 比较 暂存区 和HEAD的差异。 在git add之后在git commit之前有效,如果已经commit了,那么此命令输出为空。
git diff --name-only // 只列出不同文件的名字,而不显示具体的差异之处
git diff -stat // 可以统计数据,比较特别的命令
【git checkout】 -- 恢复 工作区 的内容
git checkout -- test.txt // 从 暂存区 恢复到 工作区,相当于撤销工作区中 test.txt 文件尚未提交的修改
git checkout -f // 从 本地库 恢复到 暂存区和工作区, 强制修改工作区的内容,一般对于当前修改不满意,放弃修改后从头开始
git checkout HEAD test.txt // 从 本地库 恢复到 暂存区和工作区, 取HEAD中的这个文件test.txt
git checkout HEAD . // 从 本地库 恢复到 暂存区和工作区, 取HEAD
git checkout $(git rev-list master -n 1 --first-parent --before=2012-03-21)
// 取master分支,2012-03-21 00:00:00 的代码, 这个命令可以帮助取没打标签的版本代码,一般对应每日构建的版本。
git checkout SHA_value // 从 本地库 恢复到 暂存区和工作区, 取特定的commit id=SHA_value
【git status】-- 查看变化,变化包括工作区和暂存区的差异,暂存区和本地库的差异,本地库的提交记录,分支/合并的状态
【git show】
git show SHA_value // 显示特定commit的内容
【git log】
git log --name-only // 仅在提交信息后显示已修改的文件清单
git log --name-status // 显示文件名以及状态(新增、修改、删除)
git log -p // 会输出非常详细的日志内容,包括了每次git commit之后都做了哪些源码的修改,可以看到具体的差异。
git log -2 // 最近两次提交的日志。 -(n) 仅显示最近的n 条提交
git log --graph // 图形化方式呈现提交记录, ASCII 图形表示
git log --stat // 显示修改文件名以及修改统计信息(文件大小变化)
git log --raw -5 // 文件列表,文件属性
git log --grep=mouse // 按照关键字搜索
git log --relative-date // 使用较短的相对时间显示(比如,“2 weeks ago”)。
git log --pretty="%h:%s" --author=gke --since="2011-10-01" --before="2011-10-05" --no-merges -- t/
// 2011年10月期间,gke 提交的但未合并的测试脚本(位于项目的t/ 目录下的文件)
--since, --after // 仅显示指定时间之后的提交。
--until, --before // 仅显示指定时间之前的提交。
git log --author=g00196971 --after="2011-12-25" > 2011_12_25_gke.txt // 查看 2011-12-25之后g00196971 的提交记录
git log --after="2011-12-09" --before="2011-12-11" > git_log_1209_1211.txt // 查看 2011-12-09到2011-12-11 时间段内的提交记录
git log --since="1 day" // 可以给出各种时间格式,比如说具体的某一天(“2012-01-15”),或者是多久以前(“2 years 1 day 3 minutes ago”)。
git log --pretty=oneline // 提交记录格式 显示为一行。 可用的选项包括oneline,short,full,fuller 和format(后跟指定格式)。
git log 目录名 // 查看特定的目录的提交记录
【去除别人分支merge过来的提交记录】
git log --pretty=oneline --abbrev-commit master > master.log
git log --pretty=oneline --abbrev-commit > all.log
grep -vwFf master.log all.log > my_branch.log
【git revert和git reset的区别】
git reset // 是撤销某次提交,但是此次之后的修改都会被退回到暂存区
git revert // 是撤销 某一次/某中间几次 的操作,此次操作之前的commit都会被保留
1. git revert是用一次新的commit来回滚之前的commit,git reset是直接删除指定的commit。
2. 在回滚这一操作上看,效果差不多。但是在日后继续merge以前的老版本时有区别。
因为git revert是用一次逆向的commit“中和”之前的提交,因此日后合并老的branch时,导致这部分改变不会再次出现,但是git reset是之间把某些commit在某个branch上删除,
因而和老的branch再次merge时,这些被回滚的commit应该还会被引入。
3. git reset 是把HEAD向后移动了一下,而git revert是HEAD继续前进,只是新的commit的内容和要revert的内容正好相反,能够抵消要被revert的内容。
【git reset】
git reset --hard SHA_value // 销毁自己的修改, SHA_value可以从git log中查找
git reset --hard HEAD~3 // 最后三个commit(即HEAD, HEAD^和HEAD~2)提交有问题,你想永久删除这三个commit。
git reset –-mixed // --mixed可以省略,这是默认模式。
git reset --hard HEAD
A). --soft: 暂存区 和工作区中的内容不作任何改变,仅仅把HEAD指向<commit>。这个模式下可以在不改动当前工作环境情况下,改变head指针,即切到任意commit。
B). --mixed: 这是reset的default模式。 暂存区 中的内容会变化,但是工作区中的内容不变。
C). --hard: 暂存区 和工作区中的内容都会发生改变,就像刚clone出来一样,用来做还原操作且不想保存任何修改。
【git revert】
git revert HEAD // 撤销前一次 commit
git revert HEAD^ // 撤销前前一次 commit
git revert SHA_value // 撤销指定的版本,撤销也会作为一次提交进行保存。
A) git revert HEAD~3:丢弃最近的三个commit,把状态恢复到最近的第四个commit,并且提交一个新的commit来记录这次改变。
B) git revert -n master~5..master~2:丢弃从最近的第五个commit(包含)到第二个(不包含),但是不自动生成commit,这个revert仅仅修改working tree和 暂存区 。
【git branch】
git branch test_branch // 创建一个实验分支
git branch // 查看总共有哪些分支
git branch -r // 参看本地分支和远程分支的映射关系
git push origin test_branch // 把本地当前分支的改动推到服务器的新分支上, 如果 origin test_branch 不加的话,那么会默认推送本地的所有的branch
git branch -d test_branch // 合并成功之后,可以删除实验分支了。这个动作要谨慎,确定已经合并成功,不再需要这个分支了。
git checkout [branch_name] // 切换到实验分支
git_all.sh checkout -b test_branch origin/test_branch // git checkout -b [分支名] [远程名]/[分支名]
【git merge】
git merge test_branch // 从test_branch分支合并到当前分支。
// 如果两个分支中有相同的代码被改动,会提示冲突,需要手动修改。手动修改当前分支中的冲突内容,然后再次merge实验分支到当前分支。
【git show-branch】
git show-branch -a // 显示本地分支
git show-branch -r // 显示远程分支
【git config】-- 配置和查询 git 的基本信息
git config --global user.name "g00196971"
git config --global user.email guanke@huawei.com
git config --global color.ui true
git config --global core.autocrlf input
git config --global merge.tool vimdiff
git config --list // 检查已有的配置信息
【git tag】
git tag // 查询所有标签
git tag -a REL_B011 -m 'software version = B011' // 在本地打标签
git push origin --tags // 一次把本地打的标签全部上传
git tag -d REL_B011 // 删除标签
git show tag // 显示tag 的详细信息,包括标签的详细描述,对应的commit SHA_value
git checkout [tagname] // 和切换分支一样,可以切换到标签
【git stash】-- 使用场合:当前工作区内容已被修改,但是并未完成。这时Boss来了,说前面的分支上面有一个Bug,需要立即修复。可是我又不想提交目前的修改,因为修改没有完成。
但是,不提交的话,又没有办法checkout到前面的分支。此时用Git Stash就相当于备份工作区了。然后在Checkout过去修改,就能够达到保存当前工作区,并及时恢复的作用。
git stash: // 备份当前的工作区的内容,从最近的一次提交中读取相关内容,让工作区保证和上次提交的内容一致。同时,将当前的工作区内容保存到Git栈中。
git stash pop: // 从Git栈中读取最近一次保存的内容,恢复工作区的相关内容。由于可能存在多个Stash的内容,所以用栈来管理,pop会从最近的一个stash中读取内容并恢复。
git stash list: // 显示Git栈内的所有备份,可以利用这个列表来决定从那个地方恢复。
git stash clear: // 清空Git栈。此时使用gitg等图形化工具会发现,原来stash的哪些节点都消失了。
git stash apply 版本号 : // 取出特定的版本号对应的工作空间
【参数解释】
【git回车换行问题】
用git status命令查看的时候,一些没有更改过的文件也显示为modified。checkout到某个分支,什么都不做直接git status也会出现。
按理说能checkout到别的分支去说明现在这个分支已经是干净的了(实际上也是做过提交的),再跳回来的时候未做任何改动就会出现一堆已经修改过的文件。
用diff查看文件修改都是大段大段的修改,实际上代码都一样。不得已只好暂时commit上去。发现原来是行结束符惹的祸。
格式化是许多开发人员在协作时,特别是在跨平台情况下,遇到的令人头疼的细小问题。
由于编辑器的不同或者Windows程序员在跨平台项目中的文件行尾加入了回车换行符, 一些细微的空格变化会不经意地进入大家合作的工作或提交的补丁中。
熟悉 git的配置选项就可以解决这些问题。
在Windows上是CRLF来作为一行的结束符,而Linux上则是LF作为行结束符
在git中提供了autocrlf的设置,可以用来自动转换CRLF,它可以设置成true,false,input
$ git config --global core.autocrlf true
设置为true,在checkin时,行结束符被转换为LF。在checkout时,行结束符被转换为CRLF。
$ git config --global core.autocrlf input
设置为input,在checkin时,行结束符被转换为LF,但是checkout时,则不会转换。
$ git config --global core.autocrlf false
设置为false,无论checkin还是checkout时,都取消自动转换功能。
【文档】
git_community_book.pdf
pro_git_中文版本.pdf
【工具】
Git-1.7.9-preview20120201.exe
TortoiseGit-1.7.7.0-32bit.msi
【一些好网站】
Why Git is Better than X
http://thkoch2001.github.io/whygitisbetter/
A successful Git branching model
http://nvie.com/posts/a-successful-git-branching-model/
可视化方式学习git
http://pcottle.github.io/learnGitBranching/
【附件】
一些比较好的示意图
repo的用法(zz)
注:repo只是google用Python脚本写的调用git的一个脚本,主要是用来下载、管理Android项目的软件仓库。(也就是说,他是用来管理给git管理的一个个仓库的)
下载 repo 的地址: http://android.git.kernel.org/repo ,可以用以下二者之一来下载 repo
wget http://android.git.kernel.org/repo
或者
curl http://android.git.kernel.org/repo > ~/bin/repo
下载完成后须修改repo的权限: chmod a+x ~/bin/repo
用repo sync 在抓去 android source code 的时候,会经常出现一些错误导致 repo sync 中断,每次都要手动开始。 可以用如下的命令,来自动重复
$?=1;
while [ $? -ne 0 ] ;
do repo sync ;
done
获取帮助:
repo help [ command ] //显示command 的详细的帮助信息内容
示例: repo help init 来获取 repo init 的其他用法
repo init -u URL 用以在当前目录安装 repository ,会在当前目录创建一个目录 ".repo" -u 参数指定一个URL, 从这个URL 中取得repository 的 manifest 文件。
示例:repo init -u git://android.git.kernel.org/platform/manifest.git
获取的manifest文件放在.repo目录中。命名为manifest.xml。这个文件的内容其实就是所有被git管理的仓库的列表!
可以用 -m 参数来选择获取 repository 中的某一个特定的 manifest 文件,如果不具体指定,那么表示为默认的 namifest 文件 (default.xml)
repo init -u git://android.git.kernel.org/platform/manifest.git -m dalvik-plus.xml
(有诸多供我们选择的manifest文件,所有的manifest文件都放在目录.repo/manifests中,该目录本身亦被git所管理,你可以cd进去看看)
可以用 -b 参数来指定某个manifest 分支。
repo init -u git://android.git.kernel.org/platform/manifest.git -b release-1.0
你会发现.repo/manifests是个被git管理的仓库,这里放的是所有的manifest文件(*.xml),因为被git管理,固然有分支,-b可以切换到你想要的分支然后再下载相关的xml文件,当然具体下载那个xml还要看-m参数了,所以如果你仅仅指定-b而没有-m的话,就是下载-b指定分支下的default.xml文件
如果不指定-b参数,那么会默认使用master分支
4. repo sync [project-list]
下载最新本地工作文件,更新成功,这本地文件和repository 中的代码是一样的。 可以指定需要更新的project , 如果不指定任何参数,会同步整个所有的项目。
如果是第一次运行 repo sync , 则这个命令相当于 git clone ,会把 repository 中的所有内容都拷贝到本地。 如果不是第一次运行 repo sync , 则相当于 git remote update ; git rebase origin/branch . repo sync 会更新 .repo 下面的文件。 如果在merge 的过程中出现冲突, 这需要手动运行 git rebase --continue
5. repo update[ project-list ]
上传修改的代码 ,如果你本地的代码有所修改,那么在运行 repo sync 的时候,会提示你上传修改的代码,所有修改的代码分支会上传到 Gerrit (基于web 的代码review 系统), Gerrit 受到上传的代码,会转换为一个个变更,从而可以让人们来review 修改的代码。
6. repo diff [ project-list ]
显示提交的代码和当前工作目录代码之间的差异。
7. repo download target revision
下载特定的修改版本到本地, 例如: repo download pltform/frameworks/base 1241 下载修改版本为 1241 的代码
8. repo start newbranchname .
创建新的branch分支。 "." 代表当前工作的branch 分支。
9. repo prune [project list]
删除已经merge 的 project
10. repo foreach [ project-lists] -c command
对每一个 project 运行 command 命令
12. repo forall -c
这个命令会遍历所有的git仓库,并在每个仓库执行-c所指定的命令(这个被执行的命令就不限于仅仅是git命令了,而是任何被系统支持的命令,比如:ls 、 pwd 、cp 等等的 )
当我想通过这个命令遍历所有的仓库并在每个仓库执行"git checkout . "用以将每个仓库的改动都清除的时候,我这么输入命令:
repo forall -c git checkout .
我发现这样根本不行。看来repo不能遍历执行checkout这个命令。今天我终于想到了另外一个命令"git reset --hard HEAD" 哈哈
repo forall -c git reset --hard HEAD
再说一个新发现:以前用repo forall 执行一些命令的时候,可能再遍历到某个仓库的时候出了问题,但是我却苦于不知道这个仓库到底是哪个!一直也没有解决。今天终于找到了。。。。 关键时候还是要看命令自己带的帮助手册呀。。。
repo help forall 用这个命令查看下针对forall的帮助吧。说的很清楚,repo执行的时候加上-p参数就可以在遍历到每个仓库的时候先打印出当前的pwd,然后再继续执行-c所指定的命令。举例如下:
repo forall -p -c git branch
//该命令会遍历所有仓库并打印每个仓库的分支情况,由于有了-p参数,这样便会打印出每个仓库的路径!!!
11. repo status
显示 project 中每个仓库的状态,并打印仓库名称。
201111071237 更新
yasin.lee.x
———————————————————————————————————————————————————————
cpp@cpp:~$ repo
Traceback (most recent call last):
File "/home/cpp/bin/repo", line 91, in ?
import readline
ImportError: No module named readline
cpp@cpp:~$
———————————————————————————————————————————————————————
系统里明明有readline,可是repo脚本却无法导入,后来查到应该是python安装导致的错误,应该在python编译时加上关于readline的编译选项,应该按照如下操作安装python
首先安装readline软件包:
sudo apt-get install libreadline5-dev
sudo apt-get install zlib1g-dev
然后下载python源码进入python源码目录,编译并安装python:
1. make distclean
2. ./configure --enable-readline BASECFLAGS=-U_FORTIFY_SOURCE
3. make -j4
4. sudo make install
注意,我同时发现在python-2.4.3版本是支持该编译选项的,而在3.1.3版本中是不能识别这个--enable-readline编译参数的。所以我目前使用2.4.3版本
repo的命令集学习
repo子命令实际上是对GIT命令的封装。所有的repo命令都可以通过repo help <command>来获取帮助
1、repo init
repo init主要完成检出清单版本库,以及配置git用户的用户名和邮件地址的工作
如repo init -u ssh://android.huawei.com/platform/manifest.git -b hw/qcom/platform --no-repo-verify --repo-branch=stable
2、repo sync
repo sync用于参照清单文件克隆或同步版本库,相当于执行git clone,如果项目版本库已存在,则相当于执行了如下的二个命令:git remote update和git rebase origin/branch。
3、repo start
repo start实际上是对git checkout -b命令的封装,创建的分支应用到所有的项目库时,需使用--all参数。
如repo start hw/qcom/platform -all
4、repo status
repo status实际上是对git diff-index、git diff-files命令的封装,同时显示暂存区和本地修改文件的差异。
如:repo status repo/ti
5、repo checkout
repo checkout是对git checkout命令的封装,检出之间由repo start创建的分支。
如:repo checkout hw/qcom/platform repo/ti
6、repo branches
用于读取所有项目中的分支列表并汇总显示,该命令实际上通过读取.git/refs目录下的引用来获取分支列表,以及分支的发布状态信息等
如:repo branches repo/ti
7、repo diff
repo diff是对git diff的封装,用于分别显示各个项目工作区下的文件差异
8、repo stage
repo stage实际是对git add --interactive命令的封装,用于挑选各个项目工作区中的改动以加入暂存区中
如:reop stage -i repo/ti
9、repo upload
repo upload相当于git push,但repo upload不是将版本库的改动推送到克隆时的远程服务器,而是推送到代码审查服务器gerrit中,推送的数据传输使用的是SSH协议。
10、repo download
repo ownload用户代码的审核者下载和评估提交过来的修改文件内容,即上述通过repo upload过来的内容。
11、repo rebase
repo rebase是对git rebase命令的封装,该命令的参数加上-i时,只对当前的这个项目才生效。
12、repo prune
repo prune是对git branch -d命令的封装,该命令用于扫描项目的各个分支,并删除已经合并的分支。
13、repo forall
迭代器,可以对repo管理的项目进行迭代,可以将本机中所有的仓都一并执行相关git xxx的命令。
repo forall -c "git commit -m "commit new feature into project A""