文章参考:http://git.oschina.net/progit/
简而言之,就是可以保存你所有的修改,所有的历史版本;有了它,就可以将某个文件回溯到之前的状态,甚至可以将整个项目回退到过去某个时间点的状态;你可以比较文件的变化细节,查出最后是谁修改了哪个地方,从而找出导致怪异问题出现的原因,又是谁在何时报告了某个功能缺陷等等
集中化的版本控制系统,例如:SVN
分布式版本控制系统,例如:Git
对于任何一个文件,在 Git 内都只有三种状态:
1、已提交(committed),已提交表示该文件已经被安全地保存在本地数据库中了;
2、已修改(modified,已修改表示修改了某个文件,但还没有提交保存;
3、已暂存(staged)。已暂存表示把已修改的文件放在下次提交时要保存的清单中。
git管理项目时,文件流转的三个工作区域:git的工作目录,暂存区域,本地仓库
1、每个项目都有一个Git目录(如果 git clone 出来的话,就是其中 .git 的目录)
2、从项目中取出某个版本的所有文件和目录,用以开始后续工作的叫做工作目录
3、所谓的暂存区域只不过是个简单的文件,一般都放在 Git 目录中
有两种方法:
1,在现存的目录下,通过导入所有文件来创建新的Git仓库;
2,从已有的Git仓库克隆出一个新的镜像仓库
在工作目录中初始化新仓库
git init // 初始化后,在当前目录下会出现一个名为 .git 的目录,所有 Git 需要的数据和资源都存放在这个目录中
git add README // 如果当前目录下有几个文件想要纳入版本控制,需要先用`git add`命令告诉git开始对这些文件进行跟踪,并进行提交
git commit -m 'initial project version'
从现有仓库克隆
git clone git://github.com/solaris/grit.git
当前目录下创建一个名为grit的目录,其中包含一个.git的目录用于保存下载下来的所有版本记录,然后从中取出最新版本的文件拷贝
如果希望在git clone的时候,自己定义要新建的项目目录的名称,可以再上面的命令的末尾指定新的名字
git clone git://github.com/schacon/grit.git mygrit
查看文件目前处于什么状态
git status
git add xx
这是一个多功能命令,根据目标文件的状态不同,此命令的效果也不同;可以用它开始跟踪新文件,或者把已跟踪的文件放到暂存区,还能用于合并时把有冲突的文件标记为已解决状态
我们可以创建一个.gitignore的文件,列出要忽略的文件模式
.gitignore的格式规范如下:
1、所有空行或者以注释符号#开头的行都会被Git忽略
2、可以使用标准的glob模式匹配(shell所使用的简化了的正则表达式)
3、匹配模式最后跟反斜杠(/)说明要忽略的是目录
4、要忽略指定模式以外的文件或目录,可以再模式前加上(!)取反
git diff
git diff --cached
git commit
git commit -m'docs: change readme' // -m参数后跟提交的方式
git 提供了一个跳过使用暂存区域的方式,只要在提交的时候给git commit加上-a选项,git就会自动把所有已经跟踪过的文件暂存起来一并提交,从而跳过 git add步骤
git commit -a -m'feat: add new tasks'
从git中移除某个文件,必须要从已跟踪文件清单移除(从暂存区域移除),然后提交,git rm命令完成此项工作,并连带从工作目录中删除制定的文件,这样以后就不会出现在未跟踪文件清单了
git rm .test
如果是简单从工作目录中手工删除文件,仅删除了工作目录中的,仍在追踪名单中
然后再运行 git rm记录此次移除文件的操作
最后提交就不会被跟踪了。但是如果删除文件之前修改过且已经放到暂存区,则必须要加-f(即force的首字母)
在实际项目中,经常会遇到下面的情况需要删除文件
想把文件从git仓库中删除,但是仍希望保留在工作目录中,就是仅从跟踪清单中删除,比如一些大型日志或一堆.a的编译文件,不小心纳入仓库,但是要移除追踪但不删除文件,以便稍后在.gitignore文件中补上,加参数–cached
git rm --cached readme.txt
后面可以列出文件或者目录的名字,也可以使用 glob 模式。
注意到星号 * 之前的反斜杠 \,因为 Git 有它自己的文件模式扩展匹配方式,
git rm log/\*.log // 此命令删除所有 log/ 目录下扩展名为 .log 的文件
git rm \*~ //会递归删除当前目录及其子目录中所有 ~ 结尾的文件。必须加反斜杠
git mv file_from file_to
相当于运行
mv README.txt README
git rm README.txt
git add README
git log -p -2 // -p选项展开每次提交的内容差异, -2则仅显示最近两次更新, 做代码审查,或者快速浏览其他写作者提交的更新都做了哪些
git log --stat // 仅显示简要的增改行数
git log --pretty // 指定使用完全不同于默认风格的方式展示提交历史,比如`git log --pretty=oneline`将每个提示放在一行显示,另外还有short, full和fuller
git log --pretty=format:"%h - %an, %ar : %s"
ca82a6d - Scott Chacon, 11 months ago : changed the version number
085bb3b - Scott Chacon, 11 months ago : removed unnecessary test code
a11bef0 - Scott Chacon, 11 months ago : first commit
用 oneline 或 format 时结合 –graph 选项,可以看到开头多出一些 ASCII 字符串表示的简单图形,形象地展示了每个提交所在的分支及其分化衍合情况
$ git log --pretty=format:"%h %s" --graph
* 2d3acf9 ignore errors from SIGCHLD on trap
* 5e3ee11 Merge branch 'master' of git://github.com/dustin/grit
|\
| * 420eac9 Added a method for getting the current branch.
* | 30e367c timeout code and tests
* | 5a09431 add timeout protection to grit
* | e1193f8 support for heads with slashes in them
|/
* d6016bc require time for xmlschema
* 11d191e Merge branch 'defunkt' into local
选项 说明
%H 提交对象(commit)的完整哈希字串
%h 提交对象的简短哈希字串
%T 树对象(tree)的完整哈希字串
%t 树对象的简短哈希字串
%P 父对象(parent)的完整哈希字串
%p 父对象的简短哈希字串
%an 作者(author)的名字
%ae 作者的电子邮件地址
%ad 作者修订日期(可以用 -date= 选项定制格式)
%ar 作者修订日期,按多久以前的方式显示
%cn 提交者(committer)的名字
%ce 提交者的电子邮件地址
%cd 提交日期
%cr 提交日期,按多久以前的方式显示
%s 提交说明
选项 说明
-p 按补丁格式显示每个更新之间的差异。
--stat 显示每次更新的文件修改统计信息。
--shortstat 只显示 --stat 中最后的行数修改添加移除统计。
--name-only 仅在提交信息后显示已修改的文件清单。
--name-status 显示新增、修改、删除的文件清单。
--abbrev-commit 仅显示 SHA-1 的前几个字符,而非所有的 40 个字符。
--relative-date 使用较短的相对时间显示(比如,“2 weeks ago”)。
--graph 显示 ASCII 图形表示的分支合并历史。
--pretty 使用其他格式显示历史提交信息。可用的选项包括 oneline,short,full,fuller 和 format(后跟指定格式)。
git log --since=2.weeks // 列出所有最近两周内的提交
选项 说明
-(n) 仅显示最近的 n 条提交
--since, --after 仅显示指定时间之后的提交。
--until, --before 仅显示指定时间之前的提交。
--author 仅显示指定作者相关的提交。
--committer 仅显示指定提交者相关的提交。
如果要查看 Git 仓库中,2018 年 10 月期间,Junio Hamano 提交的但未合并的测试脚本(位于项目的 t/ 目录下的文件),可以用下面的查询命令
git log --pretty="%h - %s" --author=gitster --since="2018-10-01" \
git commit -m 'initial commit'
git add forgotten_file
git commit --amend
如果刚才提交时忘了暂存某些修改,可以先补上暂存操作,然后再运行 –amend 提交:上面的三条命令最终只是产生一个提交,第二个提交命令修正了第一个的提交内容。
有两个修改过的文件,我们想要分开提交,但不小心用 git add . 全加到了暂存区域。该如何撤消暂存其中的一个文件呢?
git reset HEAD benchmarks.rb
如果觉得刚才对 benchmarks.rb 的修改完全没有必要,该如何取消修改,回到之前的状态(也就是修改之前的版本)呢
git checkout -- benchmarks.rb
1、查看当前的远程库git remove -v
,名为 origin 的远程库,Git 默认使用这个名字来标识你所克隆的原始仓库
2、添加远程仓库git remote add [shortname] [url]
3、从远程仓库抓取数据git fetch [remote-name]
4、推送数据到远程仓库 git push [remote-name] [branch-name]
5、查看某个远程仓库信息git remote show [remote-name]
6、远程仓库的删除和重命名 git remote rename pb paul
git remote rename rm [remote-name]
git remove -v
git remote add pb git://github.com/paulboone/ticgit.git
git fetch pb //
git push origin master //把本地的 master 分支推送到 origin 服务器上
git remote show origin // 要看所克隆的 origin 仓库
$ git remote rename pb paul
$ git remote
origin
paul
git remote rm paul
$ git remote
origin
git fetch 命令只是将远端的数据拉到本地仓库,并不自动合并到当前工作分支,git pull 命令自动抓取数据下来,然后将远端分支自动合并到本地仓库中当前分支。
1、列显已有的标签 git tag
2、新建标签,含附注的标签
简单的分支与合并,实际工作中大体的工作流程
1,开发某个网站
2,为了实现某个需求,创建一个分支
3,在这个分支上开展工作;
假设此时,突然有个紧急的问题要修复,那么你可以按照下面的方式处理:
1,返回原先已经发布到生产服务器上的分支;
2,为这次紧急修补创建一个新分支,并在其中修复问题
3,通过测试后,回到生产服务器所在的分支,将修补分支合并进来,然后再推送到生产服务器上
4,切换到之前实现新需求的分支,继续工作
新建分支 git branch xx
,这条命令是新建了一个分支,但是当前工作分支仍在mater分支上,要想把当前工作分支切换到新建的分支上,要执行git checkout xx
新建并切换到某分支git checkout -b xx
相当与下面这两条命令
git branch xx
git checkout xx
切换分支的时候要确保你当前分支不存在没有提交的修改,否则git会阻止你切换分支
删除分支 git branch -d xx
分支的合并,比如master分支要合并xx分支,首先切换到master分支,然后执行git merge xx
,此时xx分支已经合并到master分支上,接下来删除xx分支
git checkout master
git merge xx
git branch -d xx
遇到冲突时的合并,如果在不同的分支中都修改看同一个文件,git就无法将两者合并到一起
<<<<<<< HEAD:index.html
"footer">contact : email.support@github.com</div>
=======
"footer">
please contact us at support@github.com
</div>
>>>>>>> iss53:index.html
分支的管理
git branch // 列出当前所有分支,注意看master分支前的 * 字符:它表示当前所在的分支
git branch -v // 查看各个分支最后一个提交对象的信息
git branch --merged // 筛选与当前分支合并的分支
git branch --no-merged // 筛选与当前分支尚未合并的分支,此时如果使用`git branch -d xx`删除该分支会提示错误,因为这样会丢失数据,如果你确实想删除该分支上的改动,运行`git branch -D xx`强制删除
利用分支开发的工作流程
长期分支
1、在master分支中保留完全稳定的代码,即已经发布或即将发布的代码,与此同时,还有一个名为develop或next的平行分支,专门用于后续的开发。
2、或仅用于稳定性测试 — 当然并不是说一定要绝对稳定,不过一旦进入某种稳定状态,便可以把它合并到 master 里。这样,在确保这些已完成的特性分支(短期分支,比如之前的 iss53 分支)能够通过所有测试,并且不会引入更多错误之后,就可以并到主干分支中,等待下一次的发布。
3、你可以用这招维护不同层次的稳定性。某些大项目还会有proposed(建议)或 pu(proposed updates,建议更新)分支,它包含着那些可能还没有成熟到进入 next 或 master 的内容。这么做的目的是拥有不同层次的稳定性:当这些分支进入到更稳定的水平时,再把它们合并到更高层分支中去。
特性分支
一个特性分支是指一个短期的,用来实现单一特性或与其相关工作的分支。
远程分支
远程分支是对远程仓库中分支的索引。
(远程仓库)/(分支名)表示远程分支
推送远程分支
git push (远程仓库名) (分支名)
git push origin serverfix
Git 自动把 serverfix 分支名扩展为 refs/heads/serverfix:refs/heads/serverfix,意为“取出我在本地的 serverfix 分支,推送到远程仓库的 serverfix 分支中去”。
仓库中去,仍旧称它为 server
git push origin serverfix:serverfix
上传我本地的 serverfix 分支到远程仓库中去,仍旧称它为 serverfix 分支
git push origin serverfix:awesomebranch
上传我本地的 serverfix 分支到远程仓库中去,称它为 awesomebranch 分支
如果要把该远程分支的内容合并到当前分支,可以运行git merge origin/serverfix
想要基于远程分支上新建一个新的分支 git checkout -b serverfix origin/serverfix
跟踪远程分支
从远程分支checkout
出来的本地分支,成为跟踪分支。跟踪分支是一种和某个远程分支有直接联系的公司;
克隆仓库时,git通常会自动创建一个名为master
分支来跟踪origin/master
;这正是 git push
和 git pull
一开始就能正常工作的原因
git checkout -b serverfix origin/serverfix
可以用 –track 简化:git checkout –track origin/serverfix
本地分支设定不同于远程分支的名字,只需在第一个版本的命令里换个名字:git checkout -b sf origin/serverfix
删除远程分支
git push [远程名] :[分支名]
git push [远程名] [本地分支]:[远程分支],如果省略 [本地分支],如果省略 [本地分支]
分支的衍合
把一个分支整合到另一个分支的办法有两种: merge rebase
使用衍合的目的是想要得到一个能在远程分支上干净应用的补丁,简单的说就是修改提交历史
一旦分支中的提交对象发布到公共仓库,就千万不要对该分支进行衍合操作。
git rebase --onto master server client
取出 client 分支,找出 client 分支和 server 分支的共同祖先之后的变化,然后把它们在 master 上重演一遍”
git rebase [主分支] [特性分支] 命令会先取出特性分支 server,然后在主分支 master 上重演:
git rebase master server