1、git的工作空间
- workspace:工作区,文件改动的区域。
- staging area:暂存区,执行 git add 命令后,保存修改的区域,存放在 .git 目录下的 index 文件中。
- local repository:本地仓库,存放在 .git 目录下,管理本地仓库。
- remote repository:远程仓库。
2、git中文件的几种状态
- untracked:在 woking directory 中新创建了一个文件,这个文件的状态就是untracked。
- tracked:git 库上已存在的文件,就是 tracked,对于此类文件又可以做如下区分
- unmodifed:从远程库下载了此文件,但是还没有修改。
- modifed:修改了,还没有执行 git add 命令。
- staged:执行了git add命令后,此文件的修改已经被缓存到 staged area。
- committed:执行了 git commit 命令,此文件的修改被保存到本地库。
3、git 工作原理
记录快照,非差异比较
git 只关心文件数据的整体是否发生变化,而不关注文件的具体内容差异,它会把每次提交的文件全部内容都会记录下来,若文件没有变化,则不会再次保存,只会对上次保存的快照做一个索引链接。每个用来表示项目历史信息的文件,都是对其包含的内容做一个 sha-1 hash 的 40 个字符来索引的。
以某一次提交以下内容为例:
1 | |-- README |
在 git 仓库中保存的结构如下所示:
每个目录都创建了 tree对象 (包括根目录),每个文件都创建了一个对应的 blob对象 。最后有一个 commit对象 来指向根 tree 对象, 这样我们就可以追踪项目每一项提交内容.
- 一个 blob 用来存储文件的内容,它只是一块二进制数据,文件名是对内容做的 sha-1 hash,如果一个目录下有多个相同内容的文件,则他们会指向同一个 blob 对象。
- 一个 tree 对象有一串指向 blob 对象或是其它 tree 对象的指针,它用来表示内容之间的目录层次关系,tree 对象也是以其内容的 sha-1 hash 来命名的。
- “commit对象” 指向一个 “tree对象”,并且带有相关的描述信息。它的修改信息都是通过与父提交的内容比较得出。值得一提的是,,尽管 git 可以检测到文件内容不变而路径改变的情况, 但是它不会去显式的记录文件的更名操作,所以肯定不存在 svn 的树冲突。
分布式管理
1、分布式版本控制系统没有“中央服务器”,每个人的电脑上都有一个完整的版本库。因此工作的时候,可以不需要联网就可以提交本地仓库。
2、分布式版本控制系统的安全性要高很多,因为每个人电脑里都有完整的版本库,某一个人的电脑坏掉了可以直接从其他人那里复制一个。而集中式版本控制系统的中央服务器要是出了问题,所有人都没法提交和继续工作。
增加暂存区
- 实现部分提交
- 无需在工作区中创建状态文件,不会污染工作区。
- 暂存区记录文件的修改时间等信息,提高文件比较的效率
4、git操作流程
初始化
添加远程仓库
如果是一个空的工程,得先 git init,再用以下方式进行添加:
- $ git remote add origin git@github.com://yourName/yourRpo.git
- $ git remote add origin https://github.com/yourName/yourRepo.git
删除远程仓库
如果想更在同一个目录下,更换另一个仓库,则可以先删除再添加,也可以直接更换远程仓库,如下三种方式:
- 删除:git remote rm origin
- 更换:git remote set-url origin url
- 配置中手动修改:.git/config 的 url
拉取
git pull
拉取远程库上的最新代码更新合并到本地当前分支。
git fetch
只是将远程的数据拉到本地仓库,并不自动合并到当前分支,需要手动合并。
提交
git add
- git add -A:添加所有的修改到 staged area
- git add .:添加 untracked file 和 tracked file 文件的修改到缓存区,注意会忽略掉文件的删除操作,比如你删除了文件Android.mk,执行这个命令并不会把把删除操作提交到 staged area。
- git add -u:添加 tracked file 的修改到缓存区,注意会忽略掉 untracked file,也就是新增的文件。比如编译过程中产生了很多新的中间文件,使用此命令可以忽略掉这些中间文件。
git commit
git commit -m “BugID:XXX:Description” 常用的一种格式。注意 commit message 格式错误可能会导致入库失败。
还有一种方式是直接执行 git commit 命令,再打开的新窗口中输入 commit message。
git commit -m “message” | 提交暂存区到本地仓库,message代表说明信息 |
---|---|
git commit file1 -m “message” | 提交暂存区的指定文件到本地仓库 |
git commit -a | 提交本地暂存区和工作区的文件到本地仓库 |
git commit –amend -m “message” | 使用一次新的commit,替代上一次提交 |
git push
git push remote_repository loacl_branch:remote_branch
例如:git push orgin master:refs/for/master 提交本地的master分支的修改到远程库 origin 的 refs/for/master 分支
常用的格式如下
git push remote branch | 上传本地指定分支到远程仓库 |
---|---|
git push remote –force | 强行推送当前分支到远程仓库,即使有冲突 |
git push remote –all | 推送所有分支到远程仓库 |
查看
git log
常用的几种组合是:
- git log 查看提交记录。
- git log -p 查看每次提交的详细修改。
- git log –pretty=oneline 每个 commit 只显示一行,这个命令在处理代码冲突 conflict 时非常有用。
- git log –name-status 查看每次提交修改的文件。
git blame
查看修改记录:
- git blame “filename”:查看文件的每一行修改记录。
- git blame -L 开始,结束行 “filename”:查看文件从开始行到结束行的修改记录。
git status
查看文件处于什么状态,会显示 untracked,和 tracked 中的文件。
git 命令时带上目录,比如git status ./build 只查看build目录下的代码状态
回退
git checkout
回退在工作区中修改的文件,比如修改了文件a.txt,还没有执行git add命令,这时候要丢弃这些修改,可使用命令:git checkout – a.txt。
git reset
回退暂存区或仓库中的提交记录。常用的几种组合有:
- git reset –soft “commit”:回退到某个版本,只回退 local repository。
git reset –hard HEAD:回退暂存区的 add,让工作区回到上次提交时的状态
git reset –mixed “commit”:此为默认方式,同不带参数的 git reset,只保留 woking directory 的修改,回退 staging area 和 local repository的修改
- git reset –hard “commit”:彻底回退到某个版本,本地的源码也会变为上一个版本的内容,比如 git reset –hard HEADgit reset –hard HEAD
git revert
撤销提交,是用一次新的 commit 来回滚之前的 commit,HEAD 继续前进。而 git reset 是直接删除指定的 commit,并把 HEAD 向后移动了一下。
暂存
git stash
- git stash save ‘message’:保存当前工作进度,即保存在工作区,还未提交的
- git stash list:显示保存进度的列表
- git stash apply “stash_id”:恢复进度列表,不删除
- git stash drop “stash_id”:删除某个进度
- git stash pop “stash_id”:恢复进度列表,并删除
- git stash clear:删除所有存储进度
分支操作
多人合作或有一些新需求时,往往需要开辟一些新功能的分支,此时若想把功能分支合并到主干上,如下所示,想把 feature 分支上的 C4 和 C6 提交合并到 master 分支上:
常用的有俩种方法:git merge 和 git rebase。
git merge
使用 git merge 把 feature 分支合并到 master 分支后,记录如下所示:
merge 时,会根据 mater 和 feature 的最新节点和共同的祖先节点进行合并,并生成一个新的提交。
- merge 分支的提交历史也被原样保存
- 会生成一个额外的合并提交
- 历史提交不是线性的
git rebase
在 master 使用 git rebase feature 后,记录如下所示:
在 master 上,把 rebase feature 分支的提交 C4,C6 移到共同祖先的起点 C2,但丢弃原本的,而是创建一个新的提交 C4’, C6’,重写了提交历史。
- 把 rebase 分支上的提交历史重写了
- 不会生成额外的提交
- 历史的提交记录是线性的
当改写了公有的 commit history,当 git push 时,本地和远程的 commit history 不一致时,commit 会被拒绝,尽量不要使用 -f 强制 commit,这会造导致别人工作成果的丢失。比较好的习惯是约定:拉取 git fetch 后,再用 git rebase origin/maste 修改本地自己的 commit ,而不影响别人的提交历史,最后再 git push 提交。
rebase 常用命令:
- git rebase –continue:当 rebase 出现冲突时,解决完冲突后 git add 添加暂存,就可以使用 git rebase 继续执行。
- git rebase –abort:放弃此次 rebase。
- git rebase -i HEAD~n:将几次提交合并为一次,再使用 squash 将几次提交合并到前一次。
git cherry-pick
选择某一个分支的一个或多个 commit 合并:
- git cherry-pick “commit id”:单独合并一个提交。
- git cherry-pick -x “commit id”:同上,但保留原提交者信息。
- git cherry-pick “start-commit-id”..”end-commit-id”:左开右闭,不包含 start-commit-id的提交cherry-pick到当前分支。
- git cherry-pick [start-commit-id]^..[end-commit-id]:闭区间,包含 start-commit-id 的提交 cherry-pick 到当前分支。
git branch
git branch | 列出所有本地分支 |
---|---|
git branch -r | 列出所有远程分支 |
git branch -a | 列出所有本地分支和远程分支 |
git branch “branch-name” | 新建一个分支,但依然停留在当前分支 |
git checkout -b “branch-name” | 新建一个分支,并切换到该分支 |
git branch –track “branch” remote-branch | 新建一个分支,与指定的远程分支建立追踪关系 |
git checkout “branch-name” | 切换到指定分支,并更新工作区 |
git branch -d “branch-name” | 删除分支 |
git push origin –delete “branch-name” | 删除远程分支 |