git基本使用

来源:互联网 发布:怎么自己装修淘宝店铺 编辑:程序博客网 时间:2024/05/24 04:14

 

开发者信息注册

git config user.name “zhangle”

git config user.email zhangle@eastaeon.com

Ex:Author部分显示了提交者信息

全局配置: git config --global user.name "xxx"

三种下载方法:

1.git 协议git clone git://192.168.110.230/库名称 
2.http协议git clone http://192.168.110.230/gitweb/库名称 
3.SSH协议 git clone username@192.168.110.230:/home/git/库名称

以下git 官方文档截图


例如:

git clone ssh://git@192.168.0.242/~/gitweb/ALPS.L0.MP2.V1_AEON6582_WT_L_INHOUSE

git clone ssh://git@192.168.0.242/github/ALPS.L0.P45.2_K35V1_64_OP01_PRE_INHOUSE

下载步骤:

 1.先下载基础版本在checkout

git clone ssh://git@192.168.0.22/home/git/<版本库名称>

 红色部分在于同一git服务器都是相同的。

<版本库名称>.git 代表项目在服务器上的版本库命名。

2.直接获取

git clone ssh://git@192.168.0.119/home/git/ALPS.ICS.MP.V2.19 -b Android_Malata_K509-I10_Thailand Android_Malata_K509-I10_Thailand

获取开发branch最新代码

 git clone完之后获取到的代码是服务器上版本库当前的branch,

 查询当前branch的方法:git branch

 Ex:加*代表的就是当前所在branch

 

 git branch 经常用到的参数还有:

1.git branch –a    显示全部branch,包括远程和本地

 

2.git branch –r    只显示远程branch

 

 

如果想切换到其他branch,比如我们想切刀基础版本branch工作,在服务器上branch k50xv4是基础版本的branch,所以使用:

git checkout –b k50xv4 origin/ k50xv4

origin/ k50xv4 代表上图红色字体的远程分支

checkout成功后会得到一个和服务器上branch k50xv4一样的本地branch k50xv4。

git checkout BRANCHNAME


创建一个新分支

       git branch newbranchname    创建完并没有立即切换到这个分支,要使用

       git checkout newbranchname  切换新分支,不存在时就先创建再切换到新分支

 

恢复工作区某个文件修改

       git checkout <path>

vi常用命令(处理merge 冲突时用):

dd //删除(但是必须要连按2个d)

u  //回退,也就是如果用了dd之后就可以用u来回复

n //查看下一个

: //按这个:之后才可以输入字符,如x

x  //在按了:之后再按x就表示保存当前修改保存修改完成的冲突

vi //vi的后面加该修改的文件名称就表示要修改这个文件了,比如删除文件冲突

 

Ctrl+r 恢复上一步被撤销的操作

 

解决冲突

git reset --hard HEAD            //恢复到当前分支最后提交的那个commit的状态

git fetch      

git merge origin/Driver_YOULITONG_K502-PM910//merge

git branch --no-merged   //看看哪些文件没有合并成功

git status > status.info  //将当前的状态信息导入到status.info文件中(搜索unmerged)

less status.info  或者  more status.info    //查看status.info文件中的信息

vi mediatek/config/ztenj75_sz_cu_ics/ProjectConfig.mk   //查看编辑解决冲突,/HEAD回车 查看冲突,下一处 n, 删除一行dd,保存退出 :x,不保存退出 :q!

git add mediatek/config/ztenj75_sz_cu_ics/ProjectConfig.mk   //上传冲突文件

git commit -m "fix meger"                                    //提交

git merge origin/Driver_YOULITONG_K502-PM910                 //再次merge

git whatchanged//查看修改记录

git push origin  Android_HK_K501_77-W916:Android_HK_K501_77-W91

 // 把本地修改提交到远程服务器上面去

git push

$ git push origin test:master       

 // 提交本地test分支作为远程的master分支

 

$ git push origin test:test            

 // 提交本地test分支作为远程的test分支

如果想删除远程的分支呢?类似于上面,如果:左边的分支为空,那么将删除:右边的远程的分支。

 

$ git push origin :test              

// 刚提交到远程的test将被删除,但是本地还会保存的,不用担心。

举个例子:

git push origin  :origin/Android_HK_K501_77-W916

//由于:前面为空所以本来在服务器上面存在的分支origin/Android_HK_K501_77-W916和Android_HK_K501_77-W916现在就只有一个了,因为分支origin/Android_HK_K501_77-W916被删除了,但是本地的还在

 

常见错误:

1.error:failed to push some refs to ...

当要push代码到git时,出现提示:

error:failed to push some refs to ...

Dealing with “non-fast-forward” errors

From time to time you may encounter this error while pushing:

$ git push origin master 

To ../remote/ 

 ! [rejected]        master -> master (non-fast forward) 

error: failed to push some refs to '../remote/' 

To prevent you from losing history, non-fast-forward updates were rejected

Merge the remote changes before pushing again.  See the 'non-fast forward'

section of 'git push --help' for details.

 

这种情况通常由以下的原因产生:
你可以强制git-push在上传修改时先更新,只要在分支名前面加一个加号。
- 用 `git-reset --hard` 删除了一个已经发布了的一个提交,或是
- 用 `git-commit --amend` 去替换一个已经发布的提交,或是
- 用 `git-rebase` 去rebase一个已经发布的提交.
$ git push ssh://yourserver.com/~you/proj.git +master

 

解决方法:

方法1.强推,即利用强覆盖方式用你本地的代码替代git仓库内的内容

git push -f

方法2. 先把git的东西fetch到你本地然后merge后再push

$ git fetch

$ git merge

这2句命令等价于

$ git pull 

可是,这时候又出现了如下的问题:

上面出现的 [branch "master"]是需要明确(.git/config)如下的内容

[branch "master"]

    remote = origin

    merge = refs/heads/master

这等于告诉git2件事:

1,当你处于master branch, 默认的remote就是origin。

2,当你在master branch上使用git pull时,没有指定remote和branch,那么git就会采用默认的remote(也就是origin)来merge在master branch上所有的改变

如果不想或者不会编辑config文件的话,可以在bush上输入如下命令行:

$ git config branch.master.remote origin 

$ git config branch.master.merge refs/heads/master 

之后再重新git pull下。最后git push你的代码吧。


2. error: dst refspec Android_T600_liandai_S28A_W1_98M matches more than one.

error: failed to push some refs to 'ssh://git@192.168.0.119/home/git/ALPS.JB2.MP.V1.3'

出现这个问题的原因是本地的tag和分支名称相同,或者远程有和分支名称一样的tag,要删除本地和远程与要提交的分支名称相同的tag,才能继续push.

git tag –d 删除本地和分支名称相同的tag

git push origin :refs/tags/[tag名称]  删除远程tag


3. Git – fatal: Unable to create ‘/path/my_project/.git/index.lock’: File exists.

fatal: Unable to create ‘/path/my_proj/.git/index.lock’: File exists.

If no other git process is currently running, this probably means a
git process crashed in this repository earlier. Make sure no other git
process is running and remove the file manually to continue.

可以试着删除 index.lock

rm -f ./.git/index.lock

 

4.error: src refspec XXX matches more than one

在用repo管理代码时遇到了error: src refspec XXX matches more than one  这样的错误,一个是在删除一个远程的tag时遇到的,

一个是在将一个tag push到服务器时遇到的,两个错误的提示是完全一样的。遇到这样的问题该怎么解决,经过研究后找到了

解决的方法,下面就将解决的方法和大家分享!

第一种情况,删除远程branch时遇到这种情况的解决方法:

比如删除服务器上的testtag 这个tag时,输入如下命令

 

git push origin :testtag

 

提示 error: src refspec XXX matches more than one

         error: failed to push some refs to 'git@xxx:android/text.git'

出现这个错误的原因是在服务器上有个tag的分支是testtag这个名有个branch的分支也是这个名,

也就是说tag分支和branch分支同名了,在执行 git push origin :testtag这个命令时不知道是删除那个

所以会提示错误。解决办法:

git push origin :refs/tags/testtag

这就是明确告诉服务器删除的tag的分支,

删除branch分支

git push origin :refs/heads/testtag

第二种情况,将一个tag分支push到服务器时遇到这种情况的解决方法:

还那testtag这个tag分支为例,将tag分支push到服务器

git push origin testtag

提示: error: src refspec XXX matches more than one

     error: failed to push some refs to 'git@xxx:android/text.git'

出现这个错误主要是因为本地也有个branch的分支名为testtag,这样在push时不知道是将branch的分支push到

服务器还是将tag的分支push到服务器,如果是将tag分支push到服务器,那就将branch的分支删掉,如果是将

branch的分支push到服务器就将tag的分支删掉。

删除branch分支的方法:

git branch -D testtag

删除tag分支的方法:

git tag -d testtag

git 开发人员日常基本操作

(1)将本地代码与服务器同步命令:git pull origin 分支名称 (我们目前的分支名称为br_dev)
(2)修改需要修改的文件,修改完毕查看当前修改的文件命令为:git status
(3)将修改的文件添加到版本树:
a.单个文件 git add filename 
b.添加工作目录下的所有文件 git add –A
(4)提交代码到本地版本库 git commit –m “commit comment”,

如果注释比较长也可以用以下命令:git commit  回车,在弹出的界面中输入你的注释,书写完毕后按ctrl+X 然后按YES 保存修改即可
如果不小心写错了注释用一下命令修改最近的提交注释 git commit -amend
(5)注释写完后就需要将自己的修改打成patch发给代码提交人员

打patch的命令为:git format-patch origin 将目前的修改打成patch。
如果想只将一个提交打成patch则命令为:git format-patch -1 commintid提交号
(6)将本地代码推送到远程版本库 git push origin master
origin 是代码的源可以自己添加默认的名称为origin 
       master 是远程版本库的分支名称,可以根据实际情况写上分支名称,默认为master

git branch 分支操作

(1)创建分支 git branch branchname
以某个分支为基础创建新的分支 git branch newbranch oldbranch 
以某个tag为基准创建分支:git branch branchname tagname
(2)删除分支

git branch –d branchname  

       //git branch -d只能删除那些已经被当前分支的合并的分支. 如果你要强制删除某个分支的话就用git branch –D

删除远程分支:git push origin :远程分支名称。
(3)切换分支

git checkout branchname 

//切换到本地的分支,branchname 为本地分支名称.

git checkout –b k50xv4 origin/ k50xv4 

//以远程分支k50xv4为基础创建一个本地分支
(4)分支合并

 git merge 需要合并的分支名称 –squash 
此参数表示将另一条分支的所有提交合并为当前分支上的一个提交,然后git commit –m “commit comment ”
合并分支但是不提交:git merge --no-commit branchname
拣选合并 cherry-pick
git checkout master

git cherry-pick 其他分支的提交版本号
(5)分支重命名
Git branch –m oldbranchname newbranchname

 

git checkout

主要功能就是迁出一个分支的特定版本。默认是迁出分支的HEAD版本
示例:
git checkout master     //取出master版本的head。
git checkout tag_name    //在当前分支上 取出 tag_name 的版本
git checkout  master file_name  //放弃当前对文件file_name的修改
git checkout  commit_id file_name  //取文件file_name的 在commit_id是的版本。commit_id为 git commit 时的sha值。
$ git checkout -- hello.rb
这条命令把hello.rb从HEAD中签出.
$ git checkout .
这条命令把 当前目录所有修改的文件 从HEAD中签出并且把它恢复成未修改时的样子.
注意:在使用git checkout 时,如果其对应的文件被修改过,那么该修改会被覆盖掉。

 

git log日志

 查看日志:git whatchanged

 git show HEAD  //显示当前分支的最新版本的更新细节  //git show HEAD^^等

 退出看日志:ctrl + z  或者q

git show commitid  //显示某一个修改的具体细节


git log 帮助

参数说明:
-n      (n是一个正整数),查看最近n次的提交信息

$ git log -2    查看最近2次的提交历史记录

-- fileName     fileName为任意文件名,查看指定文件的提交信息。(注:文件名应该放到参数的最后位置,通常在前面加上--并用空格隔开表示是文件。)

$ git log file1 file2   查看file1文件file2文件的提交记录$ git log file/         查看file文件夹下所有文件的提交记录

--branchName    branchName为任意一个分支名字,查看莫个分支上的提交记录。同上,需要放到参数中的最后位置处。(注:如果分支名与文件名相同,系统会提示错误,可通过--选项来指定给定的参数是分支名还是文件名。)例:在当前分支中有一个名为v1的文件,同时还存在一个名为v1的分支,则:

$ git log v1 -- 此时的v1代表的是分支名字$ git log -- v1 此时的v1代表的是名为v1的文件$ git log v1 -- v1

tagName或branchame  查询指定标签/分支中的提交记录信息

$ git log v1.0..        查询从v1.0以后的提交历史记录(不包含v1.0)$ git log test..master  查询master分支中的提交记录但不包含test分支记录$ git log master..test  查询test分支中的提交记录但不办含master分支记录$ git log master...test 查询master或test分支中的提交记录。$ git log test --not master  屏蔽master分支

根据commit查询日志  

$ git log commit    查询commit之前的记录,包含commit$ git log commit1 commit2 查询commit1与commit2之间的记录,包括commit1和commit2$ git log commit1..commit2 同上,但是不包括commit1

其中,commit可以是提交哈希值的简写模式,也可以使用HEAD代替。HEAD代表最后一次提交,HEAD^为最后一个提交的父提交,等同于HEAD~1,HEAD~2代表倒数第二次提交
--pretty 
       按指定格式显示日志信息,可选项有:oneline,short,medium,full,fuller,email,raw以及format:<string>,默认为medium,可以通过修改配置文件来指定默认的
方式。

$ git log (--pretty=)oneline

常见的format选项:

选项     说明

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

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

%T      树对象(tree)的完整哈希字串

%t      树对象的简短哈希字串

%P      父对象(parent)的完整哈希字串

%p      父对象的简短哈希字串

%an     作者(author)的名字

%ae     作者的电子邮件地址

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

%ar     作者修订日期,按多久以前的方式显示

%cn     提交者(committer)的名字

%ce     提交者的电子邮件地址

%cd     提交日期

%cr     提交日期,按多久以前的方式显示

%s      提交说明

注:作者是指最后一次修改文件的人;而提交者是指提交该文件的人。

$ git log --pretty=format:"%an %ae %ad %cn %ce %cd %cr %s" --graph

--mergs 查看所有合并过的提交历史记录

--no-merges查看所有未被合并过的提交信息

--author=someonet查询指定作者的提交记录

$ git log --author=gbyukg

--since,--affter 仅显示指定时间之后的提交(不包含当前日期)

--until,--before仅显示指定时间之前的提交(包含当前日期)

$ git log --before={3,weeks,ago} --after={2010-04-18}

--grep  通过提交说明信息过滤提交日志

$ git log --grep=hotfix 该命令会列出所有包含hotfix字样的提交信息说明的提交记录

注意:如果想同时使用--grep和--author,必须在附加一个--all-match参数。

-S通过查询文件的变更内容来检索出指定提交日志 注:-S后没有"=",与查询内容之间也没有空格符

$ git log --Snew

-p查看提交时的补丁信息

$ git log -p --no-merges -2

--stat  列出文件的修改行数
--sortstat  只显示--stat中最后行数修改添加移除的统计
--graph 以简单的图形方式列出提交记录
--abbrev-commit 仅显示 SHA-1 的前几个字符,而非所有的 40 个字符。
--relative-date 使用较短的相对时间显示(比如,“2 weeks ago”)。
--name-only 仅在提交信息后显示已修改的文件清单。
--name-status 显示新增、修改、删除的文件清单。

GIT Blame
用来查看文件的每个部分修改详情

$git blame index.php

 

例子:

git log -2 -p   显示最近两次commit的log 和 diff

git log -p    查看历次的log详细修改信息及更改情况

git log frameworks/    查看关于frameworks/目录修改相关的log信息

git log --stat    查看log显示文件修改情况, 如果用--stat选项使用'git log',它会显示在每个提交(commit)中哪些文件被修改了, 这些文件分别添加或删除了多少行内容.

git log --stat packages/apps/Contacts/   

查看关于packages/apps/Contacts/目录修改相关的log显示的文件修改情况

显示最近6小时的提交:git log --since="6 hours"

显示两天之前的提交:git log --before="2 days"

 

git log - -author="Author Name" 筛选特定作者的log

git log - -since="2012-2-23" --before="2012-2-24" 筛选时间段

git log - -grep="key word" 在commit 的message中查找关键字

git log branch --not master 查看在branch上的,但不在master上的记录。 

 

git log -S"func_name"  查找某个字符出现,或者移出的commit。 比如可以查找一个函数是什么时候添加,或者删除的。

git show sha1   这个sha1是每个commit的sha1,这样显示某个commit的完全信息,包括diff

 git log --pretty=oneline 一列一版本查看版本一目瞭然.

效果如下:


git log v2.5.. Makefile fs/    找出所有从"v2.5“始在fs目录下的所有Makefile的修改.

$ git log v2.5..        # commits since (not reachable from) v2.5
$ git log test..master  # commits reachable from master but not test

$ git log master..test  # commits reachable from test but not master
$ git log master...test # commits reachable from either test or
                        #    master, but not both

 

git log --no-merges

    Show the whole commit history, but skip any merges:不要显示merge分支

 

git log v2.6.12.. include/scsi drivers/scsi

    Show all commits since version v2.6.12 that changed any file in the include/scsi or drivers/scsi subdirectories

 

git log --since="2 weeks ago" -- gitk

    Show the changes during the last two weeks to the file gitk. The "--" is necessary to avoid confusion with the branch named gitk

 

git log --name-status release..test

     Show the commits that are in the "test" branch but not yet in the "release" branch, along with the list of paths each  commit modifies.

 

it log --follow builtin-rev-list.c

      Shows the commits that changed builtin-rev-list.c, including those commits that occurred before the file was given its present name.

 

git log --branches --not --remotes=origin

           Shows all commits that are in any of local branches but not in any of remote tracking branches for origin (what you

have that origin doesn’t).

 

git log master --not --remotes=*/master

           Shows all commits that are in local master but not in any remote repository master branches.

 

git log 好用的配置

1.打开gitconfig文件
vi .gitconfig
2.
配置gitconfig
在打开的文件中加入下面的命令:
[alias]


 lg = log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit
保存文件
3.
查看配置后的log
git lg

 

在配置上面的git log 之后.如果搜索整个工程的关键字很方便

git lg --all packages/apps/Launcher2/ | grep "搜索"


然后使用git branch -r --contains 1be4784  可以找到包含改id 的所有分支 //1be4784   是commit id

 

Git shortlog

这个命令会返回这个 git repository 底下每个用户进行 commit 的次数,以及每次 commit 的注释。

 

-s 参数省略每次 commit 的注释,仅仅返回一个简单的统计。

-n 参数按照 commit 数量从多到少的顺利对用户进行排序

 

 

git reset 撤销

git reset --soft  V2 //commit 提交了V1 、V2 、V3 三次版本,该命令撤销了 V3 的提交日志信息,但是具体开发内容不变。可修改后再次提交 V3

 

git reset --hard V2 //恢复到 V2 版本,彻底删除V3 的所有信息,如想保留V3 的信息,则不使用该命令,而是使用 git branch exp1 V2 命令创建分支

要是想撤销当前修改,恢复到最近的一次修改就用:git reset –hard HEAD

 

git reset –hard commitid 

//回到任意指定的commitId 的版本(可能出现无法提交的问题,使用git push –f  xxxx:xxx)

 

 git reset HEAD^   a.py  

#回退a.py这个文件的版本到上一个版本  

 

git revert <commitid>


一般是按照某一次的commit完全反向的进行一次commit,如果commitid是最近一 次commit的commitid,

那么他的效果和 git-reset —hard HEAD~1 && git-commit -a -m ‘revert commit <commitid> xxx....' 完全一样。

git revert -n hashcode : git撤销某次历史提交; -n 不加的话,相当于撤销后的树状态也提交了,加了-n只是工作树回退了那次提交的内容,工作树处于待提交状态

git diff 比较提交

查看工作目录和本地仓库的差异或者本地仓库各个版本的差异

例子:

git diff packages/apps/Contacts/AndoridManifest.xml

查看工作目录中AndoridManifest.xml和本地仓库中AndoridManifest.xml的不同

 

git diff b46cae3b9a377bcd9cfc249a5778fce647feb961    dc94bf29aab18168e79d6496a89e47dba7a1d494

查看这两个版本的不同(git diff history_old history_current)

 

git diff 84d7c8bf6fde87316f693015d4a541a1adf037b3   b39cf58eea2f7733723ad90d104b83774136efa8   packages/apps/Phone/src/com/android/phone/CallCard.java  

查看两个版本之间针对特写文件的变化

 

git diff 6af41d3  d67778  packages/apps/Music/>2.patch

这个非常有用, 6af41d3 比 d67778 新, 上句这样做的好处是可以产生从 6af41d3 到 d67778的反向diff ,

把这个反向diff 写入2.patch,这样谁打了2.patch,谁就等于作了一次6af41d3 版本在对packages/apps/Music上所做修改的文本回退

(如果该版本对这个目录的改动是有错的需要回退的,这是个好办法).回退,千万少用 revert和reset ,这两个动作和危险,容易导致结点丢失.

 

显示当前工作目录树和暂存区间的差别:git diff
显示暂存区和版本库间的差别:git diff –cached

 
你可以用 git diff 来比较项目中任意两个版本的差异。
$ git diff master..test
上面这条命令只显示两个分支间的差异,如果你想找出‘master’,‘test’的共有 父分支和'test'分支之间的差异,你用3个‘.'来取代前面的两个'.' 。
$ git diff master...test
 
如果不是查看每个文件的详细差别,而是统计一下有哪些文件被改动,有多少行被改 动,就可以使用‘--stat' 参数 
你可以用 git diff 来比较项目中任意两个版本的差异。
$ git diff master..test
上面这条命令只显示两个分支间的差异,如果你想找出‘master’,‘test’的共有 父分支和'test'分支之间的差异,你用3个‘.'来取代前面的两个'.' 。
$ git diff master...test
 
如果不是查看每个文件的详细差别,而是统计一下有哪些文件被改动,有多少行被改 动,就可以使用‘--stat' 参数


git format-patch

1. git format-patch -1

打一个当前提交的补丁,也就是最后一次的提交改动, 相当于svn diff

2.git fromat-patch -1 6525c43add803bfee37cf5c1cb573ed8aecf529e

 打一个指定具体某一次的补丁

3.git format-patch -2 6525c43add803bfee37cf5c1cb573ed8aecf529e

 打基于指定具体某个版本的接连两次的补丁

4.git format-patch –s HEAD~3..HEAD  //将最近3个提交转换为3个补丁文件

 -s  参数会在导出的补丁文件里面添加当前用户的签名

5. git  am mail-file//将mbox格式的从mail 发过来的patch应用回来.

6.git apply   patch-name//应用一般的patch,但是不能执行提交操作

Changes to be committed:

#   (use "git reset HEAD <file>..." to unstage) //reset 加--soft 会保持文件的stage状态,(to be committed,这往往是被撤消的提交中的文件,stage中的文件的修改是diff不出来的), 如果不加(默认:mixed)就会把所有mark to be committed的文件全unstage掉,这时可以diff出来该文件的改动了

#

#    modified:packages/apps/Contacts/src/com/android/contacts/ContactsUtils.java  //不会被diff出来,

#

 

# Changed but not updated:                        //会被diff出来

#   (use "git add <file>..." to update what will be committed)

#   (use "git checkout -- <file>..." to discard changes in working directory)

#

#    modified:frameworks/base/core/java/com/android/internal/app/RingtonePickerActivity.java

#    modified:frameworks/base/media/java/android/media/RingtoneManager.java

#

 

# Untracked files://不会参与版本管理,除非用git add进来

#   (use "git add <file>..." to include in what will be committed)

 

新建项目流程

服务器(可通过git push 该配置文件): 
1.修改gitosis.config 文件: 
增加{group 项目名称] 
       writable = 项目名称 
       memebers = 成员1 成员2 
本地: 

2.

git init

  git add *

  git commit -am "init project"

  git remote add origin git+ssh://git@服务器地址/项目.git

  git push origin master:refs/heads/master

 

3.ssh 远程登录,修改项目.git的可见性 
如:chmod -R 770 项目.git 


有rsa公钥的情况下,从服务器克隆一个项目 
git clone ssh://git@xxxxxx/xxx.git xxxx 
或者:git clone git@xxxx:xxx.git xxx 
其中的3个XXX,从左到右表示分别表示: 服务器名,git项目名,本地存储目录 
初始化一个新的仓库: git init
现在假设有一个叫”project.tar.gz”的压缩文件里包含了你的一些文件,你可以用下面的命令让它置于Git的版本控制管理之下.
$ tar xzf project.tar.gz
$ cd project
$ git init
Git会输出:
Initialized empty Git repository in .git/
如果你仔细观查会发现project目录下会有一个名叫”.git” 的目录被创建,这意味着一个仓库被初始化了。
 

远程仓库的删除和重命名

     git remote rename [old name] [new name]

     git remote rm [remote-name]


查看远程仓库信息

     git remote show [remote-name]

 

重新替换一个模块如:EngineerCode

rm –rf packages/apps/EngineerCode //先删除

git checkout –b Android_Base origin/Android_Base //下载

git add packages/apps/Engineercode //提交到本地库


提交修改

git add xxx

git commit –m “some coments for this update” //完成了想本地仓库提交修改

 这里的修改包括,添加,修改。删除 需要使用git rm,不能直接rm


git commit –a:

有一个快捷的方式:git commit –a 这个命令可以直接提交所有的修改, 省去了你git add和git commit的工序,但是如果新建了一个目录,还是要进入那个目录git add .后再git commit,无法使用这个快捷方式。

 

在merge某个分支之后,解决完冲突问题,可以使用git commit –a 来完成所有的提交。

 

git add .

git add .这个命令要求git给我目前的这个项目制作一个快照snapshot(快照只是登记留名,快照不等于记录在案,git管快照叫做索引index)。快照一般会暂时存储在一个临时存储区域中。

 

提交代码到中心仓库的方法

1.>#git add some-file

     #git commit -m "some word"

适合添加简单的注释时使用

2. # git commit -m "some word" -a

提交本地所有改变的代码到中心库

3 # git commit -m " some word" some-file

提交指定文件名的文件到中心库


修改前一次提交的方法

方法一:用–amend选项

#修改需要修改的地方。

git add .

git commit - - amend

注:这种方式可以比较方便的保持原有的Change-Id,推荐使用。

git commit --amend --no-edit   //不修改message

git commit –amend –m “commit message”   //不带参数m的话,就会打开编辑页面

git使用amend选项提供了最后一次commit的反悔。但是对于历史提交呢,就必须使用rebase了。

       git rebase -i HEAD~3

       表示要修改当前版本的倒数第三次状态。

        这个命令出来之后,会出来三行东东:

        pick:*******

        pick:*******

        pick:*******

        如果你要修改哪个,就把那行的pick改成edit,然后退出。

 

        这时通过git log你可以发现,git的最后一次提交已经变成你选的那个了,这时再使用:

        git commit-amend

        来对commit进行修改。

        修改完了之后,要回来对不对?

        使用git rebase --continue

        OK,一切都搞定了。


方法二:先reset,再修改

这是可以完全控制上一次提交内容的方法。但在与Gerrit配合使用时,需特别注意保持同一个commit的多次提交的Change-Id是不变的。

否则,就需要Abondon之前的Change,产生一些垃圾不说,操作得不对,会使得简单的事情复杂化,甚至无法合并。

git reset HEAD^

#重新修改

git add .

git commit -m “MSG”

特别注意:为了保持提交到Gerrit的Change不变,需要复制对应的Change-Id到commit msg的最后,可以到Gerrit上对应的Change去复制,参见图1。

 

方法三:只是修改作者

如果email不对,会无法提交到Gerrit,所以这个命令也可能用到。

git commit –amend –author=<user-email>

注:如果该email地址从未有过成功的提交,这个修改会不成功。在别的分支做一次成功提交之后,就可以修改了。

 

git cherry-pick                

1.git fetch

2.git cherry-pick  //合并指定id的commitId

例子:

当cherry-pick 其他人的记录,但是不想马上提交还想继续修改

git cherry-pick -n 5798ss

git show

git show 查看当前提交的版本

git show ffd98b291e0caa6c33575c1ef465eae661ce40c9 查看指定版本的文件

.git show 9f5202b77bdd33f885207b618b7b2a78b6671813 packages/apps/FM/src/com/hymost/fm/ui/FMRadio.java

 查看特定版本特定文件的修改git show 2010-Aug-12 查看指定tag的文件

git remote show 查看远程仓库的信息

git remote show origin 查看某个远程仓库的详细信息,比如要看所克隆的 origin仓库


git stash 暂存当前工作区和恢复暂存的工作区

git stash  //将当前没有提交的内容存入git工作zai中,需要的时候再将某一版本应用回来
git stash apply  //将以前的工作作用应用回来,加@{ 数字}就可以应用回指定的版本
git stash pop   //恢复最近的一次保存
多次使用命令git stash之后,可以使用git stash list 把当前的git 的zai里面的信息全部打印出来,使用命令git stash apply stash@{1} 就可以把指定版本号为stash@{1}的工作取出来
首先,用git add把所有的改动加到staging area。
git add .
接着用git stash把这些改动搁置。
git stash
到这里,当前工作平台就回复到改动之前了。该干嘛干嘛,此处省略1万字。
需要找回之前搁置的改动继续先前的工作了?
git stash apply 即可。
也可以用 git stash list 来查看所有的搁置版本(可能搁置了很多次,最好不要这样,容易搞混)
在出现一个搁置栈的情况下,比如如果你想找回栈中的第2个,可以用 git stash apply stash@{1}
如果想找回第1个,可以用 git stash pop
如果想删除一个stash,git stash drop <id>
删除所有stash,git stash clear


Git自动补全

假使你使用命令行工具运行Git命令,那么每次手动输入各种命令是一件很令人厌烦的事情。

  为了解决这个问题,你可以启用Git的自动补全功能,完成这项工作仅需要几分钟。

  为了得到这个脚本,在Unix系统下运行以下命令:

cd ~

curl https://raw.github.com/git/git/master/contrib/completion/git-completion.bash -o ~/.git-completion.bash

 然后,添加下面几行到你的 ~/.bash_profile 文件中:

if [ -f ~/.git-completion.bash ]; then

    . ~/.git-completion.bash

Fi

 

git blame

这个命令可以将文件中的每一行的作者、最新的变更提交和提交时间展示出来。


git tag

1 . 查看标签:$ git tag

列出现有标签的命令非常简单,直接运行 git tag 即可:

$ git tag

v0.1

v1.3

显示的标签按字母顺序排列,所以标签的先后并不表示重要程度的轻重。

我们可以用特定的搜索模式列出符合条件的标签。在 Git 自身项目仓库中,有着超过240 个标签,如果你只对 1.4.2 系列的版本感兴趣,可以运行下面的命令:

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

v1.4.2.1

v1.4.2.2

v1.4.2.3

v1.4.2.4

 

2 .  创建标签:$ git tag [name]

  Git 使用的标签有两种类型:轻量级的(lightweight)和含附注的(annotated)。轻量级标签就像是个不会变化的分支,实际上它就是个指向特定提交对象的引用。而含附注标签,实际上是存储在仓库中的一个独立对象,它有自身的校验和信息,包含着标签的名字,电子邮件地址和日期,以及标签说明,标签本身也允许使用 GNU Privacy Guard (GPG) 来签署或验证。一般我们都建议使用含附注型的标签,以便保留相关信息;当然,如果只是临时性加注标签,或者不需要旁注额外信息,用轻量级标签也没问题。

 

含附注的标签

创建一个含附注类型的标签非常简单,用 -a (译注:取 annotated 的首字母)指定标签名字即可:

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

$ git tag

v0.1

v1.3

v1.4

而 -m 选项则指定了对应的标签说明,Git 会将此说明一同保存在标签对象中。如果在此选项后没有给出具体的说明内容,Git 会启动文本编辑软件供你输入。

轻量级的标签

要创建轻量级的标签,一个 -a,-s 或 -m 选项都不用,直接给出标签名字即可:
$ git tag v1.4


3 . 删除标签:$ git tag -d [name]

4 . 删除远程标签:$ git push origin :refs/tags/[name]

5 . 查看远程标签:$ git tag –r

6 . 查看标签具体信息:$ git show v1.2

$ git show v1.5

tag v1.5

Tagger: Scott Chacon <schacon@gee-mail.com>

Date:   Mon Feb 9 15:22:20 2009 -0800

 

现在运行 git show 查看此标签信息,就只有相应的提交对象摘要:

$ git show v1.4-lw

commit 15027957951b64cf874c3557a0f3547bd83b3ff6

Merge: 4a447f7... a6b4c97...

Author: Scott Chacon <schacon@gee-mail.com>

Date:   Sun Feb 8 19:02:46 2009 -0800


7 . 一次推送所有(本地新增的)标签上去:$ git push origin --tags

8  . 创建远程标签(本地标签push到远程):$ git push origin [name]

//默认情况下,git push 并不会把标签传送到远端服务器上,只有通过显式命令才能分享标签到远端仓库。其命令格式如同推送分支,运行git push origin [tagname] 即可:

9  . 后期加注标签 : $ git tag -a v1.2  9fceb02

可以在后期对早先的某次提交加注标签。比如在下面展示的提交历史中:

$ git log --pretty=oneline

15027957951b64cf874c3557a0f3547bd83b3ff6 Merge branch 'experiment'

a6b4c97498bd301d84096da251c98a07c7723e65 beginning write support

0d52aaab4479697da7686c15f77a3d64d9165190 one more thing

6d52a271eda8725415634dd79daabbc4d9b6008e Merge branch 'experiment'

0b7434d86859cc7b8c3d5e1dddfed66ff742fcbc added a commit function

4682c3261057305bdd616e23b64b0857d832627b added a todo file

166ae0c4d3f420721acbb115cc33848dfcc2121a started write support

9fceb02d0ae598e95dc970b74767f19372d61af8 updated rakefile

964f16d36dfccde844893cac5b347e7b3d44abbc commit the todo

8a5cbc430f1a9c3d00faaeffd07798508422908a updated readme

我们忘了在提交 “updated rakefile” 后为此项目打上版本号 v1.2,没关系,现在也能做。只要在打标签的时候跟上对应提交对象的校验和(或前几位字符)即可:

$ git tag -a v1.2 9fceb02

可以看到我们已经补上了标签:


Git rebase

操作前图如下,现在准备执行rebase变基操作


执行命令如下:

获取远程版本库的提交到本地的远程分支。

incredible$ git fetch origin

执行变基操作,将本地master分支的提交变基到新的远程分支中。

incredible$ git rebase origin/master

如果一切顺利,变基后推送到共享版本库。

incredible$ git push

操作之后图如下:

 

如果希望在执行git pull时自动使用git rebase取代默认的git merge操作,可以在git pull命令行添加参数--rebase如下:

$ git pull --rebase

或者通过配置变量设置当前分支使用变基策略,即每次执行git pull命令时对于master分支,采用变基操作取代默认的合并操作。

$ git config branch.master.rebase true

如果希望本地所有克隆版本库在执行git pull时都改变默认行为,将变基作为首选,则如下设置全局变量。

$ git config --global branch.autosetuprebase true

 

rebase的过程中,也许会出现冲突(conflict). 在这种情况,Git会停止rebase并会让你去解决冲突;
在解决完冲突后,用"git-add"命令去更新这些内容的索引(index), 然后,你无需执行 git-commit,只要执行:$ git rebase --continue
 

这样git会继续应用(apply)余下的补丁。

在任何时候,你可以用--abort参数来终止rebase的行动,并且"mywork" 分支会回到rebase开始前的状态。

$ git rebase --abort

 

git rebase -i HEAD~3

比如: git rebase -i HEAD~10

pick 2eb9797 FN08092 Base 合入Emmc falsh 可安装应用到外置SD

squash 1460b40 Link FN08092 编译不过修改

squash 1c3326a Link FN08092 Base 编译不过

squash 0d659d8 Link FN08092 切换存储位置后,文件管理器图标未跟着切换

squash 05b2d55 Base 默认存储器改变时,FM录音存储位置相应改变

squash d3ddbbc Base 修改默认浏览器的下载文件保存位置

squash 34a25a4 Base 默认存储器改变时  电影工作室的导出电影的存储位置相应改变

squash 13080fd FN08107 Base Memery.java文件损坏编译不过

squash fb025f2 FN08111 Base SD SWAP之后,存储中各功能显示异常

squash dd6904d Link FN08111 字串修改错误

子模块(submodule)相关操作命令

添加子模块:$ git submodule add [url] [path]

如:$ git submodule add git://github.com/soberh/ui-libs.git src/main/webapp/ui-libs

初始化子模块:$ git submodule init ----只在首次检出仓库时运行一次就行

更新子模块:$ git submodule update ----每次更新或切换分支后都需要运行一下

删除子模块:(分4步走哦)

1)$ git rm --cached [path]

2) 编辑“.gitmodules”文件,将子模块的相关配置节点删除掉

3) 编辑“.git/config”文件,将子模块的相关配置节点删除掉

4) 手动删除子模块残留的目录

 

忽略一些文件、文件夹不提交

在仓库根目录下创建名称为“.gitignore”的文件,写入不需要的文件夹名或文件,每个元素占一行即可,如

target

bin

*.db

git gerp

1.查找字符串:git grep –a  “text” packages/apps/        

//在 packages/apps/下面的所有文件查找字符串text

 

git-忽略某些文件

一般我们总会有些文件无需纳入 Git 的管理,也不希望它们总出现在未跟踪文件列表。通常都是些自动生成的文件,像是日志或者编译过程中创建的等等。我们可以创建一个名为 .gitignore 的文件,列出要忽略的文件模式,来看一个简单的例子:

$ cat .gitignore

*.[oa]

*~

第一行告诉 Git 忽略所有以 .o 或 .a 结尾的文件。一般这类对象文件和存档文件都是编译过程中出现的,我们用不着跟踪它们的版本。第二行告诉 Git 忽略所有以波浪符(~)结尾的文件,许多文本编辑软件(比如 Emacs)都用这样的文件名保存副本。此外,你可能还需要忽略 log,tmp 或者 pid 目录,以及自动生成的文档等等。要养成一开始就设置好 .gitignore 文件的习惯,以免将来误提交这类无用的文件。

你可以点这里 gitignore 查看一下详细的语法解释. 你也可以把".gitignore" 这个文件放到工作树(working tree)里的其它目录中,这就会在它和它的子目录起忽略(ignore) 指定文件的作用。.gitignor文件同样可以像其它文件一样加到项目仓库里( 直接用 git add .gitignore 和 git commit等命令), 这样项目里的其它开发者也能共享同一套忽略 文件规则。

如果你想忽略规则只对特定的仓库起作用,你可以把这些忽略规则写到你的仓库下 .git/info/exclude文件中,或是写在Git配置变量core.excludesfile中指定的 文件里。有些Git命令也可在命令行参数中指定忽略规则,你可以在这里:gitignore 查看详细的用法。

 

需要注意的是:.gitignore 中的规则只对 未提交且 未缓存的文件有效。因此,如果在"未缓存的改动"中发现有需要忽略的文件, 马上修改 .gitignore,再重新扫描就会发现该文件被忽略了。

 

文件 .gitignore 的格式规范如下:

• 所有空行或者以注释符号 # 开头的行都会被 Git 忽略。

• 可以使用标准的 glob 模式匹配。

• 匹配模式最后跟反斜杠(/)说明要忽略的是目录。

• 要忽略指定模式以外的文件或目录,可以在模式前加上惊叹号(!)取反。

所谓的 glob 模式是指 shell 所使用的简化了的正则表达式。星号(*)匹配零个或多个任意字符;[abc] 匹配任何一个列在方括号中的字符(这个例子要么匹配一个 a,要么匹配一个 b,要么匹配一个 c);问号(?)只匹配一个任意字符;如果在方括号中使用短划线分隔两个字符,表示所有在这两个字符范围内的都可以匹配(比如[0-9]表示匹配所有 0 到 9 的数字)。

 

注:如果要忽略的文件已被git管理,需要先移除,命令如下:

e.g.:

git rm -r --cached  WebRoot/WEB-INF/classes/**/*

-r:递归

git commit

然后.gitignore中的忽略,起作用

.gitignore 文件的例子:

# 此为注释– 将被 Git 忽略

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

!lib.a # 但 lib.a 除外

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

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

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

 

# 忽略*.o和*.a文件

 *.[oa]

# 忽略*.b和*.B文件,my.b除外

*.[bB]

!my.b

# 忽略dbg文件和dbg目录

dbg

# 只忽略dbg目录,不忽略dbg文件

dbg/

# 只忽略dbg文件,不忽略dbg目录

dbg

!dbg/

# 只忽略当前目录下的dbg文件和目录,子目录的dbg不在忽略范围内

/dbg

 

修改了 .ignored 文件之后,如果使用git status查看文件状态,是不能看到被忽略文件的状态的,如果需要查看,请使用命令: git status --ignored

Git文档摘抄:

.gitignore

If you create a file in your repo named .gitignore git will use its rules when looking at files to commit. Note that git will not ignore a file that was already tracked before a rule was added to this file to ignore it. In such a case the file must be un-tracked, usually with git rm --cached filename

This file can be committed into the repo, thus sharing the rule list with any other users that clone the repo.

Note that you can create a .gitignore in any subpath to have its rules applied at that path. Sometimes an empty .gitignore file is used as a placeholder for an empty path, for example to force git to generate a log/ path for your development environment to use.

Global .gitignore

A global .gitignore file can also be used by adding one to your global git config. For example, you might create the file ~/.gitignore_global and add some rules to it. To add this to your config, run git config --global core.excludesfile ~/.gitignore_global

Some good rules to add to this file:

# Compiled source #
###################
*.com
*.class
*.dll
*.exe
*.o
*.so
 
# Packages #
############
# it's better to unpack these files and commit the raw source
# git has its own built in compression methods
*.7z
*.dmg
*.gz
*.iso
*.jar
*.rar
*.tar
*.zip
 
# Logs and databases #
######################
*.log
*.sql
*.sqlite
 
# OS generated files #
######################
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
Icon?
ehthumbs.db
Thumbs.db

Repo exclude

Local per-repo rules can be added to the .git/info/exclude file in your repo. These rules are not committed with the repo so they are not shared with others. This method can be used for locally-generated files that you don't expect other users to generate, like files created by your editor.


git clean

例子:

git clean –n mediatek/        //提示在mediatek目录下面应该删除什么,不应该删除什么

删除 一些没有 git add 的 文件;

 

git clean 参数

    -n 显示 将要删除的 文件 和  目录

     -f 删除 文件,-df 删除 文件 和目录

git clean -n

git clean -df

git clean -f

git add

1 git  addxxx   //add 后面是文件路径

2 git  add      //add 后面加 . 可以弹出vi窗口

3 git add –u  //将所有修改过的文件加入到暂存区

4 git add –A  //可以将本地删除文件盒新增加的文件登记到提交暂存区

5 git add –p   //可以对一个文件内的修改进行选择性的暂存


 常见问题:

1.fatal: This operation must be run in a work tree

[core]

repositoryformatversion = 0

filemode = false

bare = true

symlinks = false

ignorecase = true

解决方法:

1.   vi .git/config

2.   会弹出上面的的窗口,修改[core]里面的bare为false,保存退出

 

交互式添加 git add -i

交互式添加提供友好的界面去操作Git索引(index),同时亦提供了可视化索引的能力。只需简单键入'git add -i',即可使用此功能。Git会列出所有修改过的文件及它们的状态。

$>git add -i

           staged     unstaged path

1:    unchanged        +4/-0 assets/stylesheets/style.css

2:    unchanged      +23/-11 layout/book_index_template.html

3:    unchanged        +7/-7 layout/chapter_template.html

4:    unchanged        +3/-3 script/pdf.rb

5:    unchanged      +121/-0 text/14_Interactive_Rebasing/0_ Interactive_Rebasing.markdown

 

*** Commands ***

1: status   2: update   3: revert4: add untracked

5: patch    6: diff     7: quit8: help

What now>

在这个例子中,我们可以看到有5个修改过的文件还没有被加入到索引中(unstaged),甚至可以看到每个文件增加和减少的行数。紧接着是一个交互式的菜单,列出了我们可以在此模式中使用的命令。

 

如果我们想要暂存(stage)这些文件,我们可以键入'2'或者'u'进入更新(update)模式。然后我们可以通过键入文件的范围(本例中是1-4)来决定把哪些文件加入到索引之中。

What now> 2

           staged     unstaged path

1:    unchanged        +4/-0 assets/stylesheets/style.css

2:    unchanged      +23/-11 layout/book_index_template.html

3:    unchanged        +7/-7 layout/chapter_template.html

4:    unchanged        +3/-3 script/pdf.rb

5:    unchanged      +121/-0 text/14_Interactive_Rebasing/0_ Interactive_Rebasing.markdown

Update>> 1-4

           staged     unstaged path

* 1:    unchanged        +4/-0 assets/stylesheets/style.css

* 2:    unchanged      +23/-11 layout/book_index_template.html

* 3:    unchanged        +7/-7 layout/chapter_template.html

* 4:    unchanged        +3/-3 script/pdf.rb

5:    unchanged      +121/-0 text/14_Interactive_Rebasing/0_ Interactive_Rebasing.markdown

Update>>

如果键入回车,我会回到主菜单中,同时可以看到那些指定文件的状态已经发生了改变:

What now> status

           staged     unstaged path

1:        +4/-0      nothing assets/stylesheets/style.css

2:      +23/-11      nothing layout/book_index_template.html

3:        +7/-7      nothing layout/chapter_template.html

4:        +3/-3      nothing script/pdf.rb

5:    unchanged      +121/-0 text/14_Interactive_Rebasing/0_ Interactive_Rebasing.markdown

现在我们可以看到前4个文件已经被暂存,但是最后一个没有。基本上,这是一个更加紧凑的查看状态的方式,实质上的信息与我们在命令行中运行'git status'是一致的:

$ git status

# On branch master

# Changes to be committed:

#   (use "git reset HEAD <file>..." to unstage)

#

#   modified:assets/stylesheets/style.css

#   modified:layout/book_index_template.html

#   modified:layout/chapter_template.html

#   modified:script/pdf.rb

#

# Changed but not updated:

#   (use "git add <file>..." to update what will be committed)

#

#   modified:text/14_Interactive_Rebasing/0_ Interactive_Rebasing.markdown

#

我们可以进行数个有用的操作,包括取消文件的暂存(3: revert),加入未跟踪的文件(4: add untracked)和查看差异(6: diff)。这些功能都很易懂。还有一个很“酷”的功能,就是暂存补丁(staging patches)(5: patch)。

 

如果你键入'5'或者'p',git会一个一个补丁(一块一块)地显示出差异,然后询问是否对每一块进行暂存操作。通过这个方法,你可以暂存文件修改中的一部分。如果你编辑了一个文件,只想提交其中一部分而不包括其他未完成编辑的部分,或者把文档、空白字符从大量的修改中分开提交,你可以使用'git add -i'去相对轻松地完成任务。

 

这里我暂存了book_index_template.html的部分修改,而不是全部修改:

         staged     unstaged path

1:        +4/-0      nothing assets/stylesheets/style.css

2:       +20/-7        +3/-4 layout/book_index_template.html

3:        +7/-7   nothing layout/chapter_template.html

4:        +3/-3      nothing script/pdf.rb

5:    unchanged      +121/-0 text/14_Interactive_Rebasing/0_ Interactive_Rebasing.markdown

6:    unchanged       +85/-0 text/15_Interactive_Adding/0_ Interactive_Adding.markdown

当你通过'git add -i'完成对索引的改动后,你只需要退出(7: quit),然后'git commit'去提交暂存的修改。切记不要运行'git commit -a',它会忽视你刚才辛辛苦苦做的修改而把所有东西都提交到仓库中去。


向一个项目提交补丁

如果你只做了少量的改动, 最简单的提交方法就是把它们做成补丁(patch)用邮件发出去:

首先, 使用git format-patch; 例如:

$ git format-patch origin

这会在当前目录生成一系统编号的补丁文件, 每一个补丁文件都包含了当前分支和origin/HEAD之间的差异内容.

然后你可以手工把这些文件导入你的Email客户端. 但是如果你需要一次发送很多补丁, 你可能会更喜欢使用git send-email脚本去自动完成这个工作. 在发送之前, 应当先到项目的邮件列表上咨询一下项目管理者, 了解他们管理这些补丁的方式.

 

向一个项目中导入补丁

Git也提供了一个名为git am的工具(am是"apply mailbox"的缩写)去应用那些通过Email寄来的系列补丁. 你只需要按顺序把所有包含补丁的消息存入单个的mailbox文件, 比如说"patches.mbox", 然后运行

$ git am -3 patches.mbox

Git会按照顺序应用每一个补丁; 如果发生了冲突, git会停下来让你手工解决冲突从而完成合并. ("-3"选项会让git执行合并操作;如果你更喜欢中止并且不改动你的工作树和索引, 你可以省略"-3"选项.)

在解决冲突和更新索引之后, 你不需要再创建一个新提交, 只需要运行

$ git am --resolved

这时git会为你创建一个提交, 然后继续应用mailbox中余下的补丁.

最后的效果是, git产生了一系列提交, 每个提交是原来mailbox中的一个补丁, 补丁中的作者信息和提交日志也一并被记录下来.

 



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

以下内容是保存作为参考,自己暂时没有使用过,只是当初看书的时候查阅的网上资料.


维护Git

保证良好的性能

在大的仓库中, git靠压缩历史信息来节约磁盘和内存空间.

压缩操作并不是自动进行的, 你需要手动执行 git gc:

$ git gc

压缩操作比较耗时, 你运行git gc命令最好是在你没有其它工作的时候.

 

保持可靠性

git fsck 运行一些仓库的一致性检查, 如果有任何问题就会报告. 这项操作也有点耗时, 通常报的警告就是“悬空对象"(dangling objects).

$ git fsck

dangling commit 7281251ddd2a61e38657c827739c57015671a6b3

dangling commit 2706a059f258c6b245f298dc4ff2ccd30ec21a63

dangling commit 13472b7c4b80851a1bc551779171dcb03655e9b5

dangling blob 218761f9d90712d37a9c5e36f406f92202db07eb

dangling commit bf093535a34a4d35731aa2bd90fe6b176302f14f

dangling commit 8e4bec7f2ddaa268bef999853c25755452100f8e

dangling tree d50bb86186bf27b681d25af89d3b5b68382e4085

dangling tree b24c2473f1fd3d91352a624795be026d64c8841f

...

“悬空对象"(dangling objects)并不是问题, 最坏的情况只是它们多占了一些磁盘空间. 有时候它们是找回丢失的工作的最后一丝希望.

 

建立一个公共仓库

假设你个人的仓库在目录 ~/proj. 我们先克隆一个新的“裸仓库“,并且创建一个标志文件告诉git-daemon这是个公共仓库.

$ git clone --bare ~/proj proj.git

$ touch proj.git/git-daemon-export-ok

上面的命令创建了一个proj.git目录, 这个目录里有一个“裸git仓库" -- 即只有'.git'目录里的内容,没有任何签出(checked out)的文件.

 

下一步就是你把这个 proj.git 目录拷到你打算用来托管公共仓库的主机上. 你可以用scp, rsync或其它任何方式.

 

通过git协议导出git仓库    

用git协议导出git仓库, 这是推荐的方法.

如果这台服务器上有管理员,TA们要告诉你把仓库放在哪一个目录中, 并且“git:// URL”除仓库目录部分外是什么.

 

你现在要做的是启动 git daemon; 它会监听在 9418端口. 默认情况下它会允许你访问所有的git目录(看目录中是否有git-daemon-export-ok文件). 如果以某些目录做为 git-daemon 的参数, 那么 git-daemon 会限制用户通过git协议只能访问这些目录.

你可以在inetd service模式下运行 git-daemon; 点击 git daemon 可以查看帮助信息.

 

通过http协议导出git仓库

git协议有不错的性能和可靠性, 但是如果主机上已经配好了一台web服务器,使用http协议(git over http)可能会更容易配置一些.

 

你需要把新建的"裸仓库"放到Web服务器的可访问目录里, 同时做一些调整,以便让web客户端获得它们所需的额外信息.

$ mv proj.git /home/you/public_html/proj.git

$ cd proj.git

$ git --bare update-server-info

$ chmod a+x hooks/post-update

(最后两行命令的解释可以点击这里查看: git update-server-info & githooks.)

拼好了proj.git的web URL, 任何人都可以从这个地址来克隆(clone)或拉取(pull) git仓库内容. 下面这个命令就是例子:

$ git clone http://yourserver.com/~you/proj.git

 

 

建立一个私有仓库

如果不使用第三方的代码托管服务,而是要自己在服务器上建一个网上可访问的私有代码仓库, 你有几种选择:

 

通过SSH协议来访问仓库 

通常最简单的办法是通ssh协议访问Git(Git Over SSH). 如果你在一台机器上有了一个ssh帐号, 你只要把“git祼仓库"放到任何一个可以通过ssh访问的目录, 然后可以像ssh登录一样简单的使用它. 假设你现在有一个仓库,并且你要把它建成可以在网上可访问的私有仓库. 你可以用下面的命令, 导出一个"祼仓库", 然后用scp命令把它们拷到你的服务器上:

 

$ git clone --bare /home/user/myrepo/.git /tmp/myrepo.git

$ scp -r /tmp/myrepo.git myserver.com:/opt/git/myrepo.git

如果其它人也在 myserver.com 这台服务器上有ssh帐号,那么TA也可以从这台服务器上克隆(clone)代码:

 

$ git clone myserver.com:/opt/git/myrepo.git

上面的命令会提示你输入ssh密码或是使用公钥(public key).

 

译者注1:配置ssh公钥的方法可以参考这里,这样在ssh访问时就可以不要输入命令.

译者注2:git over ssh方式对仓库有读写权限, git://协议只能读仓库.

 

使用Gitosis的多用户访问

如果你不想为每个用户配置不同的帐号,你可以用一个叫Gitosis的工具. 在gitosis中, 有一个叫 authorized_keys 的文件,里面包括了所有授权可以访问仓库的用户的公钥(public key), 这样每个用户就可以直接使用'git'用户来推送(push)和拉(pull)代码.


查找问题的利器 - Git Bisect

假设你在项目的'2.6.18'版上面工作, 但是你当前的代码(master)崩溃(crash)了. 有时解决这种问题的最好办法是: 手工逐步恢复(brute-force regression)项目历史, 找出是哪个提交(commit)导致了这个问题. 但是 linkgit:git-bisect1 可以更好帮你解决这个问题:

$ git bisect start

$ git bisect good v2.6.18

$ git bisect bad master

Bisecting: 3537 revisions left to test after this

[65934a9a028b88e83e2b0f8b36618fe503349f8e] BLOCK: Make USB storage depend on SCSI rather than selecting it [try #6]

如果你现在运行"git branch", 会发现你现在所在的是"no branch"(译者注:这是进行git bisect的一种状态). 这时分支指向提交(commit):"69543", 此提交刚好是在"v2.6.18"和“master"中间的位置. 现在在这个分支里, 编译并测试项目代码, 查看它是否崩溃(crash). 假设它这次崩溃了, 那么运行下面的命令:

$ git bisect bad

Bisecting: 1769 revisions left to test after this

[7eff82c8b1511017ae605f0c99ac275a7e21b867] i2c-core: Drop useless bitmaskings

现在git自动签出(checkout)一个更老的版本. 继续这样做, 用"git bisect good","git bisect bad"告诉git每次签出的版本是否没有问题; 你现在可以注意一下当前的签出的版本, 你会发现git在用"二分查找(binary search)方法"签出"bad"和"good"之间的一个版本(commit or revison).

在这个项目(case)中, 经过13次尝试, 找出了导致问题的提交(guilty commit). 你可以用 git show 命令查看这个提交(commit),找出是谁做的修改,然后写邮件给TA. 最后, 运行:

$ git bisect reset

这会到你之前(执行git bisect start之前)的状态.

注意: git-bisect 每次所选择签出的版本, 只是一个建议; 如果你有更好的想法, 也可以去试试手工选择一个不同的版本.

运行:

$ git bisect visualize

这会运行gitk, 界面上会标识出"git bisect"命令自动选择的提交(commit). 你可以选择一个相邻的提交(commit), 记住它的SHA串值, 用下面的命令把它签出来:

$ git reset --hard fb47ddb2db...

然后进行测试, 再根据测试結果执行”bisect good"或是"bisect bad"; 就这样反复执行, 直到找出问题为止.

 

译者注: 关于"git bisect start"后的分支状态, 译文和原文不一致. 原文是说执行"git bisect start"后会创建一个名为"bisect"的分支, 但是实际情况却是处于"no branch"的状态.

 

查找问题的利器 - Git Blame

如果你要查看文件的每个部分是谁修改的, 那么 git blame 就是不二选择. 只要运行'git blame [filename]', 你就会得到整个文件的每一行的详细修改信息:包括SHA串,日期和作者:

 

译者注: Git采用SHA1做为hash签名算法, 在本书中,作者为了表达方便,常常使用SHA来代指SHA1. 如果没有特别说明, 本书中的SHA就是SHA1的代称.

$ git blame sha1_file.c

...

0fcfd160 (Linus Torvalds  2005-04-18 13:04:43 -0700    8)*/

0fcfd160 (Linus Torvalds  2005-04-18 13:04:43 -0700    9) #include "cache.h"

1f688557 (Junio C Hamano  2005-06-27 03:35:33 -0700   10) #include "delta.h"

a733cb60 (Linus Torvalds  2005-06-28 14:21:02 -0700   11) #include "pack.h"

8e440259 (Peter Eriksen   2006-04-02 14:44:09 +0200   12) #include "blob.h"

8e440259 (Peter Eriksen   2006-04-02 14:44:09 +0200   13) #include "commit.h"

8e440259 (Peter Eriksen   2006-04-02 14:44:09 +0200   14) #include "tag.h"

8e440259 (Peter Eriksen   2006-04-02 14:44:09 +0200   15) #include "tree.h"

f35a6d3b (Linus Torvalds  2007-04-09 21:20:29 -0700   16) #include "refs.h"

70f5d5d3 (Nicolas Pitre   2008-02-28 00:25:19 -0500   17) #include "pack-revindex.h"628522ec (Junio C Hamano              2007-12-29 02:05:47 -0800   18) #include "sha1-lookup.h"

...

如果文件被修改了(reverted),或是编译(build)失败了; 这个命令就可以大展身手了.

你也可以用"-L"参数在命令(blame)中指定开始和结束行:

$>git blame -L 160,+10 sha1_file.c

ace1534d (Junio C Hamano 2005-05-07 00:38:04 -0700       160)}

ace1534d (Junio C Hamano 2005-05-07 00:38:04 -0700       161)

0fcfd160 (Linus Torvalds 2005-04-18 13:04:43 -0700       162)/*

0fcfd160 (Linus Torvalds 2005-04-18 13:04:43 -0700       163) * NOTE! This returns a statically allocate

790296fd (Jim Meyering   2008-01-03 15:18:07 +0100       164) * careful about using it. Do an "xstrdup()

0fcfd160 (Linus Torvalds 2005-04-18 13:04:43 -0700       165) * filename.

ace1534d (Junio C Hamano 2005-05-07 00:38:04 -0700       166) *

ace1534d (Junio C Hamano 2005-05-07 00:38:04 -0700       167) * Also note that this returns the location

ace1534d (Junio C Hamano 2005-05-07 00:38:04 -0700       168) * SHA1 file can happen from any alternate

d19938ab (Junio C Hamano 2005-05-09 17:57:56 -0700       169) * DB_ENVIRONMENT environment variable if i


Git Hooks

钩子(hooks)是一些在"$GIT-DIR/hooks"目录的脚本在被特定的事件(certain points)触发后被调用。当"git init"命令被调用后,一些非常有用的示例钩子文件(hooks)被拷到新仓库的hooks目录中但是在默认情况下这些钩子(hooks)是不生效的。 把这些钩子文件(hooks)".sample"文件名后缀去掉就可以使它们生效了。

applypatch-msg

GIT_DIR/hooks/applypatch-msg

'git-am'命令执行时,这个钩子就被调用。它只有一个参数:就是存有提交消息(commit log message)的文件的名字。如果钩子的执行结果是非零,那么补丁(patch)就不会被应用(apply)

The hook is allowed to edit the message file in place, and can be used to normalize the message into some project standard format (if the project has one). It can also be used to refuse the commit after inspecting the message file. The default applypatch-msg hook, when enabled, runs the commit-msg hook, if the latter is enabled.

这个钩子用于在其它地方编辑提交消息,并且可以把这些消息规范成项目的标准格式(如果项目些类的标准的话)。它也可以在分析(inspect)完消息文件后拒绝此次提交(commit)。在默认情况下,当 applypatch-msg 钩子被启用时。。。。

()

pre-applypatch

GIT_DIR/hooks/pre-applypatch

'git-am'命令执行时,这个钩子就被调用。它没有参数,并且是在一个补丁(patch)被应用后还未提交(commit)前被调用。如果钩子的执行结果是非零,那么刚才应用的补丁(patch)就不会被提交。

It can be used to inspect the current working tree and refuse to make a commit if it does not pass certain test. The default pre-applypatch hook, when enabled, runs the pre-commit hook, if the latter is enabled.

它用于检查当前的工作树,当提交的补丁不能通过特定的测试就拒绝将它提交(commit)进仓库。 ()

post-applypatch

GIT_DIR/hooks/post-applypatch

This hook is invoked by 'git-am'. It takes no parameter, and is invoked after the patch is applied and a commit is made.

'git-am'命令执行时,这个钩子就被调用。它没有参数,并且是在一个补丁(patch)被应用且在完成提交(commit)情况下被调用。

This hook is meant primarily for notification, and cannot affect the outcome of 'git-am'.

这个钩子的主要用途是通知提示(notification),它并不会影响'git-am'的执行和输出。

pre-commit

GIT_DIR/hooks/pre-commit

这个钩子被 'git-commit' 命令调用而且可以通过在命令中添加\--no-verify 参数来跳过。这个钩子没有参数,在得到提交消息和开始提交(commit)前被调用。如果钩子执行结果是非零,那么 'git-commit' 命令就会中止执行。

译注:此钩子可以用来在提交前检查代码错误(运行类似lint的程序)

当默认的'pre-commit'钩子开启时,如果它发现文件尾部有空白行,那么就会中止此次提交。

译注:新版的默认钩子和这里所说有所有不同。

All the 'git-commit' hooks are invoked with the environment variable GIT_EDITOR=: if the command will not bring up an editor to modify the commit message.

下面是一个运行 Rspec 测试的 Ruby 脚本,如果没有通过这个测试,那么不允许提交(commit)

 

html_path = "spec_results.html" 

`spec -f h:#{html_path} -f p spec` # run the spec. send progress to screen. save html results to html_path 

 

# find out how many errors were found 

html = open(html_path).read 

examples = html.match(/(\d+) examples/)[0].to_i rescue 0 

failures = html.match(/(\d+) failures/)[0].to_i rescue 0 

pending = html.match(/(\d+) pending/)[0].to_i rescue 0 

 

if failures.zero? 

  puts "0 failures! #{examples} run, #{pending} pending" 

else 

  puts "\aDID NOT COMMIT YOUR FILES!" 

  puts "View spec results at #{File.expand_path(html_path)}" 

  puts 

  puts "#{failures} failures! #{examples} run, #{pending} pending" 

  exit 1 

end

prepare-commit-msg

GIT_DIR/hooks/prepare-commit-msg

'git-commit'命令执行时:在编辑器(editor)启动前,默认提交消息准备好后,这个钩子就被调用。

It takes one to three parameters. The first is the name of the file that the commit log message. The second is the source of the commit message, and can be: message (if a -m or -F option was given); template (if a -t option was given or the configuration option commit.template is set); merge (if the commit is a merge or a .git/MERGE_MSG file exists);squash (if a .git/SQUASH_MSG file exists); or commit, followed by a commit SHA1 (if a -c-C or \--amend option was given).

它有三个参数。第一个是提交消息文件的名字。第二个是提交消息的来源,它可以是:().

如果钩子的执行結果是非零的话,那么'git-commit'命令就会被中止执行。

The purpose of the hook is to edit the message file in place, and it is not suppressed by the \--no-verify option. A non-zero exit means a failure of the hook and aborts the commit. It should not be used as replacement for pre-commit hook.

The sample prepare-commit-msg hook that comes with git comments out the Conflicts: part of a merge's commit message.

commit-msg

GIT_DIR/hooks/commit-msg

'git-commit'命令执行时,这个钩子被调用;也可以在命令中添加\--no-verify参数来跳过。这个钩子有一个参数:就是被选定的提交消息文件的名字。如这个钩子的执行結果是非零,那么'git-commit'命令就会中止执行。

The hook is allowed to edit the message file in place, and can be used to normalize the message into some project standard format (if the project has one). It can also be used to refuse the commit after inspecting the message file.

这个钩子的是为提交消息更适当,可以用于规范提交消息使之符合项目的标准(如果有的话);如果它检查完提交消息后,发现内容不符合某些标准,它也可以拒绝此次提交(commit)

The default 'commit-msg' hook, when enabled, detects duplicate "Signed-off-by" lines, and aborts the commit if one is found.

默认的'commit-msg'钩子启用后,它后检查里面是否有重复的签名结束线(Signed-off-by lines),如果找到它就是中止此次提交(commit)操作。

post-commit

GIT_DIR/hooks/post-commit

'git-commit'命令执行时,这个钩子就被调用。它没有参数,并且是在一个提交(commit)完成时被调用。

这个钩子的主要用途是通知提示(notification),它并不会影响'git-commit'的执行和输出。

pre-rebase

GIT_DIR/hooks/pre-rebase

'git-base'命令执行时,这个钩子就被调用;主要目的是阻止那不应被rebase的分支被rebase(例如,一个已经发布的分支提交就不应被rebase)

post-checkout

GIT_DIR/hooks/post-checkout

'git-checkout'命令更新完整个工作树(worktree)后,这个钩子就会被调用。这个钩子有三个参数:前一个HEAD ref,新HEAD ref,判断一个签出是分支签出还是文件签出的标识符(分支签出=1,文件签出=0)。这个钩子不会影响'git-checkout'命令的输出。

这个钩子可以用于检查仓库的一致性,自动显示签出前后的代码的区别,也可以用于设置目录的元数据属性。

post-merge

GIT_DIR/hooks/post-merge

This hook is invoked by 'git-merge', which happens when a 'git-pull' is done on a local repository. The hook takes a single parameter, a status flag specifying whether or not the merge being done was a squash merge. This hook cannot affect the outcome of 'git-merge' and is not executed, if the merge failed due to conflicts.

它有一个参数:

This hook can be used in conjunction with a corresponding pre-commit hook to save and restore any form of metadata associated with the working tree (eg: permissions/ownership, ACLS, etc). See contrib/hooks/setgitperms.perl for an example of how to do this.

pre-receive

GIT_DIR/hooks/pre-receive

This hook is invoked by 'git-receive-pack' on the remote repository, which happens when a 'git-push' is done on a local repository. Just before starting to update refs on the remote repository, the pre-receive hook is invoked. Its exit status determines the success or failure of the update.

当用户在本地仓库执行'git-push'命令时,服务器上运端仓库就会对应执行'git-receive-pack'命令,而'git-receive-pack'命令会调用 pre-receive 钩子。在开始更新远程仓库上的ref之前,这个钩子被调用。钩子的执行结果(exit status)决定此次更新能否成功。

This hook executes once for the receive operation. It takes no arguments, but for each ref to be updated it receives on standard input a line of the format:

每执行一个接收(receive)操作都会调用一次这个钩子。它没有命令行参数,但是它会从标准输入(standard input)读取需要更新的ref,格式如下:

SP SP LF

译者注:SP是空格,LF是回车。

where <old-value> is the old object name stored in the ref, <new-value> is the new object name to be stored in the ref and <ref-name> is the full name of the ref. When creating a new ref, <old-value> is 40 0.

<old-value>是保存在ref里的老对象的名字,<new-value>是保存在ref里的新对象的名字,<ref-name>就是此次要更新的ref的全名。如果是创建一个新的ref,那么<old-value>就是由400组成的字符串表示。

If the hook exits with non-zero status, none of the refs will be updated. If the hook exits with zero, updating of individual refs can still be prevented by the <<update,'update'>> hook.

如果钩子的执行结果是非零,那么没有引用(ref)会被更新。如果执行结果为零,更新操作还可以被后面的<<update,'update'>> 钩子所阻止。

Both standard output and standard error output are forwarded to 'git-send-pack' on the other end, so you can simply echomessages for the user.

钩子(hook)的标准输出和标准错误输出(stdout & stderr)都会通'git-send-pack'转发给客户端(other end),你可以把这个信息回显(echo)给用户。

If you wrote it in Ruby, you might get the args this way:

如果你用ruby,那么可以像下面的代码一样得到它们的参数。

rev_old, rev_new, ref = STDIN.read.split(" ")

Or in a bash script, something like this would work:

bash脚本中,下面代码也可能得到参数。

#!/bin/sh

# <oldrev> <newrev> <refname>

# update a blame tree

while read oldrev newrev ref

do

    echo "STARTING [$oldrev $newrev $ref]"

    for path in `git diff-tree -r $oldrev..$newrev | awk '{print $6}'`

    do

      echo "git update-ref refs/blametree/$ref/$path $newrev"

      `git update-ref refs/blametree/$ref/$path $newrev`

    done

done

update

GIT_DIR/hooks/update

当用户在本地仓库执行'git-push'命令时,服务器上运端仓库就会对应执行'git-receive-pack',而'git-receive-pack'会调用update 钩子。在更新远程仓库上的ref之前,这个钩子被调用。钩子的执行结果(exit status)决定此次update能否成功。

每更新一个引用(ref),钩子就会被调用一次,并且使用三个参数:

·the name of the ref being updated, # 要被更的ref的名字

·the old object name stored in the ref, # ref 中更新前的对象名

·and the new objectname to be stored in the ref. # ref 中更新后的对象名

如果 update hook 的执行结果是零,那么引用(ref)就会被更新。如果执行结果是非零,那么’git-receive-pack'就不会更新这个引用(ref)

This hook can be used to prevent 'forced' update on certain refs by making sure that the object name is a commit object that is a descendant of the commit object named by the old object name. That is, to enforce a "fast forward only" policy.

这个钩子也可以用于防止强制更新某些 refs,确保old objectnew object的父对象。这样也就是强制执行"fast forward only"策略。

It could also be used to log the old..new status. However, it does not know the entire set of branches, so it would end up firing one e-mail per ref when used naively, though. The <<post-receive,'post-receive'>> hook is more suited to that.

它也可以用于跟踪(log)更新详情。但是由于它不知道每次更新的ref全体集合,尽管可以傻傻的每个ref更新就发送email;但是<<post-receive,'post-receive'>>钩子更适合这种情况。

在邮件列表(mailing list)上讲了另外一种用法:用这个 update hook 实现细粒度(finer grained)权限控制。

钩子(hook)的标准输出和标准错误输出(stdout & stderr)都会通'git-send-pack'转发给客户端(other end),你可以把这个信息回显(echo)给用户。

当默认的 update hook 被启用,且hooks.allowunannotated选项被打开时,那么没有注释(unannotated)的标签就不能被推送到服务器上。

post-receive

GIT_DIR/hooks/post-receive

This hook is invoked by 'git-receive-pack' on the remote repository, which happens when a 'git-push' is done on a local repository. It executes on the remote repository once after all the refs have been updated.

当用户在本地仓库执行'git-push'命令时,服务器上运端仓库就会对应执行'git-receive-pack'命令;在所有远程仓库的引用(ref)都更新后,这个钩子就会被'git-receive-pack'调用。

This hook executes once for the receive operation. It takes no arguments, but gets the same information as the <<pre-receive,'pre-receive'>> hook does on its standard input.

服务器端仓库每次执行接收(receive)操作时,这个钩子就会被调用。此钩子执行不带任何命令行参数,但是和<<pre-receive,'pre-receive'>>钩子一样从标准输入(standard input)读取信息,并且读取的信息内容也是一样的。

This hook does not affect the outcome of 'git-receive-pack', as it is called after the real work is done.

这个钩子不会影响'git-receive-pack'命令的输出,因为它是在命令执行完后被调用的。

This supersedes the <<post-update,'post-update'>> hook in that it gets both old and new values of all the refs in addition to their names.

这个钩子可以取代 <<post-update,'post-update'>>钩子;因为后者只能得到需要更新的ref的名字,而没有更新前后的对象的名字。

Both standard output and standard error output are forwarded to 'git-send-pack' on the other end, so you can simply echomessages for the user.

钩子(hook)的标准输出和标准错误输出(stdout & stderr)都会通'git-send-pack'转发给客户端(other end),你可以把这个信息回显(echo)给用户。

The default 'post-receive' hook is empty, but there is a sample script post-receive-email provided in thecontrib/hooks directory in git distribution, which implements sending commit emails.

默认的'post-receive'的钩子是空的,但是在git distribution contrib/hooks 目录里有一个名为 post-receive-email的示例脚本,实实了发送commit emails的功能。

post-update

GIT_DIR/hooks/post-update

This hook is invoked by 'git-receive-pack' on the remote repository, which happens when a 'git-push' is done on a local repository. It executes on the remote repository once after all the refs have been updated.

当用户在本地仓库执行'git-push'命令时,服务器上运端仓库就会对应执行'git-receive-pack'。在所有远程仓库的引用(ref)都更新后,post-update 就会被调用。

It takes a variable number of parameters, each of which is the name of ref that was actually updated.

它的参数数目是可变的,每个参数代表实际被更新的 ref

This hook is meant primarily for notification, and cannot affect the outcome of 'git-receive-pack'.

这个钩子的主要用途是通知提示(notification),它并不会影响'git-receive-pack'的输出。

The 'post-update' hook can tell what are the heads that were pushed, but it does not know what their original and updated values are, so it is a poor place to do log old..new. The <<post-receive,'post-receive'>> hook does get both original and updated values of the refs. You might consider it instead if you need them.

'post-update'可以行诉我们哪些 heads 被更新了,但是它不知道head更新前后的值,所以这里不大适合记录更新详情。而<<post-receive,'post-receive'>>钩子可以得到ref(也可说是head)更新前后的值,如果你要记录更详情的话,可以考虑使用这个钩子。

When enabled, the default 'post-update' hook runs 'git-update-server-info' to keep the information used by dumb transports (e.g., HTTP) up-to-date. If you are publishing a git repository that is accessible via HTTP, you should probably enable this hook.

如果默认的'post-update'钩子启用的话,它们执行‘git-update-server-info'命令去更新一些dumb协议(http)所需要的信息。如果你的git仓库是通http协议来访问,那么你就应该开启它。

Both standard output and standard error output are forwarded to 'git-send-pack' on the other end, so you can simply echomessages for the user.

钩子(hook)的标准输出和标准错误输出(stdout & stderr)都会通'git-send-pack'转发给客户端(other end),你可以把这个信息回显(echo)给用户。

pre-auto-gc

GIT_DIR/hooks/pre-auto-gc

当调用'git-gc --auto'命令时,这个钩子(hook)就会被调用。它没有调用参数,如果钩子的执行結果是非零的话,那么'git-gc --auto'命令就会中止执行。

参考

Git Hooks * http://probablycorey.wordpress.com/2008/03/07/git-hooks-make-me-giddy/

 

找回丢失的对象

在玩git的过程中,常有失误的时候,有时把需要的东东给删了。 不过没有关系,git给了我们一层安全网,让们能有机会把失去的东东给找回来。

Let's go!

准备

我们先创建一个用以实验的仓库,在里面创建了若干个提交和分支。 BTW:你可以直接把下面的命令复制到shell里执行。

mkdir recovery;cd recovery

git init

touch file

git add file

git commit -m "First commit"

echo "Hello World" > file

git add .

git commit -m "Greetings"

git branch cool_branch

git checkout cool_branch

echo "What up world?" > cool_file

git add .

git commit -m "Now that was cool"

git checkout master

echo "What does that mean?" >> file

恢复已删除分支提交

现在repo里有两个branch

$ git branch

cool_branch

* master

存储当前仓库未提交的改动

$ git stash save "temp save"

Saved working directory and index state On master: temp save

HEAD is now at e3c9b6b Greetings

删除一个分支

$ git branch -D cool_branch

Deleted branch cool_branch (was 2e43cd5).

$ git branch

 * master

git fsck --lost-found命令找出刚才删除的分支里面的提交对象。

$git fsck --lost-found

  dangling commit 2e43cd56ee4fb08664cd843cd32836b54fbf594a

git show命令查看一个找到的对象的内容,看是否为我们所找的。

git show 2e43cd56ee4fb08664cd843cd32836b54fbf594a

  commit 2e43cd56ee4fb08664cd843cd32836b54fbf594a

  Author: liuhui <liuhui998[#]gmail.com>

  Date:   Sat Oct 23 12:53:50 2010 +0800

  Now that was cool

 

  diff --git a/cool_file b/cool_file

  new file mode 100644

  index 0000000..79c2b89

  --- /dev/null

  +++ b/cool_file

  @@ -0,0 +1 @@

  +What up world?

这个提交对象确实是我们在前面删除的分支的内容;下面我们就要考虑一下要如何来恢复它了。

使用git rebase 进行恢复

  $git rebase 2e43cd56ee4fb08664cd843cd32836b54fbf594a

  First, rewinding head to replay your work on top of it...

  Fast-forwarded master to 2e43cd56ee4fb08664cd843cd32836b54fbf594a.

现在我们用git log命令看一下,看看它有没有恢复:

  $ git log

  commit 2e43cd56ee4fb08664cd843cd32836b54fbf594a

  Author: liuhui <liuhui998[#]gmail.com>

  Date:Sat Oct 23 12:53:50 2010 +0800

 

  Now that was cool

  commit e3c9b6b967e6e8c762b500202b146f514af2cb05

  Author: liuhui <liuhui998[#]gmail.com>

  Date:Sat Oct 23 12:53:50 2010 +0800

 

  Greetings

  commit 5e90516a4a369be01b54323eb8b2660545051764

  Author: liuhui <liuhui998[#]gmail.com>

  Date:Sat Oct 23 12:53:50 2010 +0800

 

  First commit

提交是找回来,但是分支没有办法找回来:

  liuhui@liuhui:~/work/test/git/recovery$ git branch

  * master

使用git merge 进行恢复

我们把刚才的恢复的提交删除

  $ git reset --hard HEAD^

  HEAD is now at e3c9b6b Greetings

再把刚删的提交给找回来:

  git fsck --lost-found

  dangling commit 2e43cd56ee4fb08664cd843cd32836b54fbf594a

不过这回我们用是合并命令进行恢复:

  $ git merge 2e43cd56ee4fb08664cd843cd32836b54fbf594a

  Updating e3c9b6b..2e43cd5

  Fast-forward

  cool_file |1 +

  1 files changed, 1 insertions(+), 0 deletions(-)

  create mode 100644 cool_file

git stash的恢复

前面我们用git stash把没有提交的内容进行了存储,如果这个存储不小心删了怎么办呢?

当前repo里有的存储:

$ git stash list

stash@{0}: On master: temp save

把它们清空:

$git stash clear

liuhui@liuhui:~/work/test/git/recovery$ git stash list

再用git fsck --lost-found找回来:

$git fsck --lost-found

dangling commit 674c0618ca7d0c251902f0953987ff71860cb067

git show看一下回来的内容对不对:

$git show 674c0618ca7d0c251902f0953987ff71860cb067

 

commit 674c0618ca7d0c251902f0953987ff71860cb067

Merge: e3c9b6b 2b2b41e

Author: liuhui <liuhui998[#]gmail.com>

Date:   Sat Oct 23 13:44:49 2010 +0800

 

    On master: temp save

 

diff --cc file

index 557db03,557db03..f2a8bf3

--- a/file

+++ b/file

@@@ -1,1 -1,1 +1,2 @@@

  Hello World

  ++What does that mean?

看起来没有问题,好的,那么我就把它恢复了吧:

$ git merge 674c0618ca7d0c251902f0953987ff71860cb067

Merge made by recursive.

 file |1 +

  1 files changed, 1 insertions(+), 0 deletions(-)



0 0
原创粉丝点击