目录
一、 git原理和工作方式
1、 git工作原理
2、 git和svn工作方式比较
3、 git和svn协同工作和权限控制
二、 git命令汇总
.git 文件结构
1)、仓库创建初始化
在SVN中,从仓库checkout的一个工作树,每个子目录下都维护着自己的.svn目录,记录着该目录中文件的修改情况以及和服务器端仓库的对应关系。所以SVN可以局部checkout部分路径下的内容,而不用checkout整个分支。 Git仓库中,项目根目录下的.git目录统一管理了所有的仓库数据和当前工作树的相关信息。
2)、Checkout仓库
在SVN中,创建仓库的地方并不是你日常使用的仓库的地方,你需要在别的地方checkout出特定的仓库路径作为你的日常工作的目录。在git中,仓库所在的目录也就是你的日常工作目录,没有服务器端和客户端之分。(严格的说.git目录才是仓库,.git目录外的地方是你的工作目录,
3)、将文件纳入版本管理
在SVN中,使用SVNadd,这样在以后的commit过程中,每次在提交数据之前,svn都会自动根据这些add过的对象的修改情况,构建一个committree,在git中,因为存在index的概念,要将一个文件纳入版本管理的范畴,首先是要用git-update-index–-add将文件纳入index的监控范围,只有更新到index中的内容才会在commit的时候被提交。另外,文件本身的改动并不会自动更新到index中,每次的任何修改都必须重新更新到index中去才会被提交。当然,通常会用gitadd这样的封装脚本来调用git-update-index
4)、查看log
svn log命令基本上就是用来查看版本提交时的所填写的log信息,git log可以做的事情会多很多,毕竟git log是对底层核心命令的再包装,通过它,不仅可以查看log信息,还可以输出特定版本的具体变更内容等等信息。
5)、版本回溯
在SVN中,不提供任何从仓库中删除对象的机制,任何的修改都会导致版本的递增,所以,如果想丢弃一个修改,你需要做的事是反向diff你的修改,再提交一个新的版本,在git中提供了重置committedtree对象索引的机制,所以,你可以通过例如git-reset这样的操作将当前分支的版本恢复到以前的某个状态。经常看见的例子就是回溯一个版本,然后修改内容,再次提交。不过这样做搞不好很容易出问题。包括在git-push之类的操作时会被reject,需要强行push之类的,如果只是想放弃一个修改,git的文档推荐使用git-revert操作,这个操作基本上和SVN的思路是一样的了,就是提交一个新的版本将需要revert的版本的内容再反向修改回去,版本会递增,不影响之前提交的内容。
6)、放弃当前修改
在SVN中,使用SVNrevert对目录或文件操作都可以将当前工作树上特定路径的修改恢复到服务器上的版本,放弃当前的修改,Git中,对特定文件使用不带其它参数的gitcheckout命令可以将文件恢复到index中的状态,如果你想恢复的特定的版本,那么类似: git checkout HEADfile这样的操作,将文件恢复到HEAD tree即最近一次提交的状态, Git中还有一种办法,可以快速彻底的放弃自从上次commit以来的所有变更,gitreset –hard HEAD
1)、远程提交
对于SVN来说,由于是中心式的仓库管理形式,所以并不存在特殊的远程提交的概念,所有的commit操作都可以认为是对远程仓库的更新动作,在git中,因为有本地仓库和remote仓库之分,所以也就区别于commit操作,存在额外的push命令,用于将本地仓库的数据更新到远程仓库中去。这种工作模式应该是大多数开源项目的维护者的工作模式之一。
git push 可以选择需要提交的更新的分支以及制定该分支在远程仓库上的名字。
2)、远程更新
在SVN中,因为只有一个中心仓库,所以所谓的远程更新,也就是svnupdate,对于git来说,别人的改动是存在于远程仓库上的,所以gitcheckout命令尽管在某些功能上和svn中的update类似(例如取仓库特定版本的内容),但是在远程更新这一点上,还是不同的,不属于gitcheckout的功能涵盖范围
Git使用git fetch和git pull来完成远程更新任务,fetch操作只是将远程数据库的object拷贝到本地,然后更新remotes head的refs,git pull的操作则是在git fetch的基础上对当前分支外加merge操作。
3)、多分枝协同工作
SVN中,我很喜欢的一个功能就是switch,使用Switch可以在同一个工作树上,对不同的模块checkout不同分支上的代码。举个例子:我从主干上checkout了整个内核树,然后使用switch命令将其中一个或几个驱动的目录或文件切换到我的个人分支或其它人的分支上去,这样,我可以使用一个update命令同时从几个不同的来源更新特定的文件,而我在工作树上对switch过的文件做的修改会自动提交到我的个人分支上,而不是主干的路径上。这样我的修改不会影响主干的内容,而同时又能随时更新主干上的最新内容。不仅方便工作,也有利于权限控制。一切都是自动的,方便!
在Git中,尽管也可以使用checkout命令checkout特定分支的特定文件到当前分支的工作树上,但是,这只是简单的更新当前工作树的文件内容而已,这些文件并不会被关联到他的来源上去,也就是说你做的任何修改,还是针对当前分支的。对于多分枝协同工作,常见的工作模式是fetch远程更新,然后merge到当前分支。
一)、git生成密钥:
生成git密钥
git config--global user.email "Your [email protected]"
git config--global user.name "Your Name"
ssh-keygen -t rsa
在~/.ssh目录下会生成id_rsa.pub文件,拷贝这个文件并修改为你的名字拼音.pub发送给git管理员,为自己创建git证号(demo)
二)、git检出代码操作
1、检出代码:
git [email protected]:SAGETEL82_V2.10_WET_KK
gitclone [email protected]:yaoming168/contentprovider.git
注:也可以自己本地创建
mkdir test –> cd test -> git init
2、查看服务器分支:
git branch-a
注:目前服务器上的分支:
* L7_Project (*表示当前工作区在L7_Project分支上)
3、检出分支 git checkoutL7_Project(可以对已有文件进行覆盖)如:
git checkout/home/L7_git/SAGETEL82_V2.10_WET_KK/alps/packages/apps/Dialer
三)、git提交命令
1、修改的代码与纯洁的分之代码比较
2、Git status 查看修改状态
3、
1)git add .(添加变动的所有代码,要保持分支代码的纯洁)
注:可以add指定文件如:git add./mediatek/configgetel82_wet_kk/ProjectConfig.mk
2)减法操作
将文件从版本库和本地同时删除
git rm a.txt
git commit –m“delete a.txt”
将文件从版本库中删除保留本地文件
git rm –-cacheda.txt
git commit –m“delete a.txt”
4、git commit -am "模块:通话 修改*+)通话记录中,陌生号码会显示归属地。 --补充修改"(进行提交操作)
注:
} Git保证只要commit过的内容绝不会丢失。
} 每个commit都作为一个对象存在
} 每个commit对象都有一个当前版本(也叫快照)的SHA1签名
} 多个commit对象通过父指针域串联,方便回溯历史
} 这个命令会让当前在暂存区里面的文件修改保存并且 commit,但是 untracted files(没有管理文件)不会被加入到仓库区。
} git commit –a 相等于 git add.和git commit(自动检查应该commit什么文件。如果是新增的文件,仍然要使用git add来添加。),一般都不推荐使用git commit -a,还是推荐先git add再git commit。
} 如果修改的文件需要全部提交,我一般都是git commit -am "commit messages"如果修改的文件只提交一部分,用git add -pgit commit -m "commit messages"
4.显示所做的改动
git diff
显示所有的改动。 没有add到index中的。
git diff --staged或者 git diff--cached
显示staged改动,也就是add的东东,也就是将要commit的东东。
git diff commit1 commit2
显示这两个commit之间的变动, 从commit1到commit2的变动。
git diff commit1..commit2
两个点,效果跟上面的一样
git diff commit1...commit2
三个点,表示的是发生在commit2分支,一直到commit1和commit2共同父亲的变化。
git blame -C file1.c
显示文件具体的改动。。。。恩,好像是用来找是谁的错?
git blame -Ln,m file1.c
查看n,m两行间的改动。
git blame commit1~1 -Ln,m file1.c
查看commit1版本前的改动. 追查之前的log。
git blame commit1~1 -Ln,m -- old/file.c
如果这个文件被重命名过,或者移动过位置,就要输入旧的文件的名字。
而且一定要加上 --,一定。
5、git pullorigin (更新代码,防止冲突)
6、git push origin(进行提交代码操作)
7、验证提交:
1)git log(显示提交log,找到对应得提交id)
2)git showaa2115732b7b36a2e813bf83bfb5fe7f6eb47d30(显示提交结果)
注:一、SHA
在git中,所有用来表示项目历史信息的文件,是通过一个40个字符的(40-digit)“对象名”来索引的,对象名看起来像这样:
6ff87c4664981e4397625791c8ea3bbb5f2279a3
你会在Git里到处看到这种“40个字符”字符串。每一个“对象名”都是对“对象”内容做SHA1哈希计算得来的,(SHA1是一种密码学的哈希算法)。这样就意味着两个不同内容的对象不可能有相同的“对象名”。
这样做会有几个好处:
A、Git只要比较对象名,就可以很快的判断两个对象是否相同。
B、因为在每个仓库(repository)的“对象名”的计算方法都完全一样,如果同样的内容存在两个不同的仓库中,就会存在相同的“对象名”下。
C、Git还可以通过检查对象内容的SHA1的哈希值和“对象名”是否相同,来判断对象内容是否正确。
四)、分支管理
如何利用分支管理非线性开发
查看分支:git branch
创建分支:git branchbranchName
切换分支:git checkoutbranchName(务必先commit)
创建同时切换分支:git checkout –b branchName
删除分支:git branch –d branchName
合并分支到当前分支:git mergebranchName
查看已并入当前分支的分支:git branch –-merged
查看尚未并入当前分支的分支:git branch –-no-merged
五)、merge时如何解决冲突
冲突产生的原因:在合并的两个分支上,对同一个文件都做了操作,Git无法决定保留哪个版本,必须要人工进行取舍,git会在索引和工作树里设置一个特殊的状态,提示你如何解决合并中出现的冲突。
有冲突(conflicts)的文件会保存在索引中,除非你解决了问题了并且更新了索引,否则执行 git commit都会失败:
$ git commit
file.txt: needs merge
如果执行 git status 会显示这些文件没有合并(unmerged),这些有冲突的文件里面会添加像下面的冲突标识符:
<<<<<<< HEAD:file.txt
Hello world
=======
Goodbye
>>>>>>>77976da35a11db4580b80ae27e8d65caf5208086:file.txt
你所需要的做是就是编辑解决冲突,(接着把冲突标识符删掉),再执行下面的命令:
$ git add file.txt
$ git commit
注意:提交注释里已经有一些关于合并的信息了,通常是用这些默认信息,但是你可以添加一些你想要的注释。
上面这些就是你要做一个简单合并所要知道的,但是git提供更多的一些信息来帮助解决冲突。
四)、git还原指定版本
1. 撤销改动
git checkout -- file.1
撤销了file.1的这次改动。只是撤销了没有staged的改动.
中间的 -- 表明了这是一个文件 而不是一个branch的名字
git reset --hard HEAD
撤销了所有没有commit的改动,包括了stage的和没有stage的。
这条命令的结果一样
git checkout HEAD file.1
包括了staged 和没有staged的都会清除。
有时候我们发现,之前做个一个commit有问题,不想要,想要去掉。
git revert HEAD 自动得重新做一个commit,将最后一次的commit返回回来。
git revert HEAD^ 自动得重新做一个commit,将最后第二次的commit返回回来。
删除一个commit
git reset --hard HEAD~1
删除了最近的commit
2、先删除 rm -rf *
git reset --hard ID
比如要还原到GIT ID为13ce8b7a6afd69cea242f8b15c1b1ef80006cc1b 的版本
命令行输入 git reset --hard 13ce8b7a6afd69cea242f8b15c1b1ef80006cc1b
注:这样方便版本回退查找问题
3、gitrevert和git reset区别
git revert 是撤销某次操作,此次操作之前的commit都会被保留
git reset 是撤销某次提交,但是此次之后的修改都会被退回到暂存区
具体一个例子,假设有三个commit, git st:
commit3: add test3.c
commit2: add test2.c
commit1: add test1.c
当执行git revert HEAD~1时, commit2被撤销了
git log可以看到:
commit1:add test1.c
commit3:add test3.c
git status 没有任何变化
如果换做执行git reset --soft(默认) HEAD~1后,运行git log
commit2: add test2.c
commit1: add test1.c
运行git status,则test3.c处于暂存区,准备提交。
如果换做执行git reset --hard HEAD~1后,
显示:HEAD is now at commit2,运行git log
commit2: add test2.c
commit1: add test1.c
运行git st,没有任何变化
另外:
git revert
五)、git图形化工具安装使用
1、第一次进入会叫你输入安装命令 apt-get install qgit
2、使用的时候一般在项目的根目录中输入 qgit开启
3、筛选,可以通过short log、Author、File、Patch这几种常用方式
4、File-> open 打开想浏览的工程
5、Edit-> settings -> extenel diff tools 添加对比工具
六)、git cherry-pick 小结
git cherry-pick可以选择某一个分支中的一个或几个commit(s)来进行操作。例如,假设我们有个稳定版本的分支,叫v2.0,另外还有个开发版本的分支v3.0,我们不能直接把两个分支合并,这样会导致稳定版本混乱,但是又想增加一个v3.0中的功能到v2.0中,这里就可以使用cherry-pick了。
简单用法:
git cherry-pick
注意:当执行完 cherry-pick以后,将会生成一个新的提交;这个新的提交的哈希值和原来的不同,但标识名一样;
例如:
$ git checkout old_cc
$ git cherry-pick 38361a68 # 这个 38361a68 号码,位于:
$ git log
commit 38361a68138140827b31b72f8bbfd88b3705d77a
Author: Siwei Shen
Date: Sat Dec 10 00:09:44 2011 +0800
三、git提交规范及注意事项
1、负责而谨慎的提交自己的代码
当某以功能模块完后,并测试无无问题,谨慎提交。
如果提交过程中产生了冲突,则需要同之前的开发人员联系,两个人一起协商解决冲突,解决冲突之后,需要两个人一次测试保证解决冲突以后,程序不会影响其他功能。
2、不要提交自动生成的文件
编译过程中会在build等目录下产生大量的编译文件,不要把这些文件提交,尽量做到每次提交选择提交确认提交的文件进行提交,而非点击根目录进行提交,并把所有文件都勾选上。
3、不能提交不能通过变异的代码
代码在提交之前,首先要确认自己能够在本地编译通过,禁止相等然的提交代码。
4、不要提交自己不明白的代码和文件
代码在提交git代码库后,你的代码将被项目成员所分享。如果提交了你不明白的代码,你看不懂,别人也看不懂,如果在以后出现了问题将会成为项目质量的隐患。因此在引入任何第三方代码之前,确认你对这个代码有一个很清晰地了解,同样的,不清楚的文件不要提交。
5、永远不要用外部文件覆盖版本库文件
当外部文件覆盖版本库同名文件时,git执行的是先删除后添加的操作,两个文件并不会享有相同的历史,如果上个文件有所更改,将不会在新文件上表示出来,使得更改丢失。
6、单则修改对应单个问题
单次提交的内容对应单个问题,严禁一次提交对应多个问题,这样会导致其他同时进行问题回溯时无法明确相关修改。
7、永远不要漏提交代码
修改验证有效后务必确保提交到git服务器上,不要漏提交代码,漏提交代码容易导致编译报错。