原理
svn等CVCS(集中版本控制系统)的保存方式,基于变化比对
git(DVCS,分布式版本控制系统)的保存方式
所有保存在 Git 数据库中的东西都是用此哈希值来作索引的,而不是靠文件名
对于任何一个文件,在 Git 内都只有三种状态:已提交(committed),已修改(modified)和已暂存(staged)。已提交表示该文件已经被安全地保存在本地数据库中了;已修改表示修改了某个文件,但还没有提交保存;已暂存表示把已修改的文件放在下次提交时要保存的清单中。
基础配置
配置文件位置
- /etc/gitconfig 文件:系统中对所有用户都普遍适用的配置。若使用 git config 时用 --system 选项,读写的就是这个文件。
- ~/.gitconfig 文件:用户目录下的配置文件只适用于该用户。若使用 git config 时用 --global 选项,读写的就是这个文件。
- 当前项目的 Git 目录中的配置文件(也就是工作目录中的 .git/config 文件):这里的配置仅仅针对当前项目有效。每一个级别的配置都会覆盖上层的相同配置,所以 .git/config 里的配置会覆盖 /etc/gitconfig 中的同名变量。
- 在 Windows 系统上,Git 会找寻用户主目录下的 .gitconfig 文件。主目录即HOME 变量指定的目录,一般都是 C:\Documents and Settings$USER。此外,Git 还会尝试找寻 /etc/gitconfig 文件,只不过看当初 Git 装在什么目录,就以此作为根目录来定位。
用户基础信息配置
查看已有配置信息(如果配置有重复,实际采用的是最后一个)
git config --list
查看单个配置信息
git config property
用户信息配置:
$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com
默认编辑器设置(输入额外消息是git会自动调用)
$ git config --global core.editor emacs
基本使用
仓库使用
初始化仓库
git init
添加新文件到修改列表
git add fileName
commit到本地
git commit -m 'info'
克隆一个仓库
git clone (git|http(s))://[url]
克隆一个仓库并设置项目目录名称
git clone [url] directoryName
更新操作
追踪新文件/保存更改,并更新到stage状态
git add filename
commit所有已修改文件
git commit -a
附加本次修改到上次commit
git commit --amend
ignore
文件 .gitignore 的格式规范如下:
- 所有空行或者以注释符号 # 开头的行都会被 Git 忽略。
- 可以使用标准的 glob 模式匹配。
- 匹配模式最后跟反斜杠(/)说明要忽略的是目录。
- 要忽略指定模式以外的文件或目录,可以在模式前加上惊叹号(!)取反。
example:
# 此为注释 – 将被 Git 忽略
# 忽略所有 .a 结尾的文件
*.a
# 但 lib.a 除外
!lib.a
# 仅仅忽略项目根目录下的 TODO 文件,不包括 subdir/TODO
/TODO
# 忽略 build/ 目录下的所有文件
build/
# 会忽略 doc/notes.txt 但不包括 doc/server/arch.txt
doc/*.txt
# 忽略 doc/ 目录下所有扩展名为 txt 的文件
doc/**/*.txt
将文件从vcs中移除
git rm filename
重置修改的文件
git reset HEAD <file>
git checkout -- <file>
远程仓库
显示远程仓库信息
git remote -v
添加远程仓库
git remote add [shortname] [url]
拉取远程仓库,不会对当前分支进行任何处理
git fetch [remote-name]
将远端分支自动合并到本地仓库中当前分支
git pull
推送本地分支到远程分支
git push [remote-name] [branch-name]
显示所有远程和本地分支
git remote show [remote-name]
远程仓库重命名
git remote rename [remote-name] [new-remote-name]
移除远程仓库
git remote rm [remote-name]
标签
显示所有标签
git tag
寻找特定标签,支持模糊匹配
git tag -l 'v1.2.*'
创建包含附注的标签
git tag -a v1.4 -m 'information'
创建轻量级标签
git tag [tag-name]
显示标签详细信息
git show [tag-name]
分支
一次提交包含的信息
多次提交之间的关联
Git 中的分支,其实本质上仅仅是个指向 commit 对象的可变指针。Git 会使用 master 作为分支的默认名字。在若干次提交后,你其实已经有了一个指向最后一次提交对象的 master 分支,它在每次提交的时候都会自动向前移动。
创建分支,实质如下图
git branch [brance-name]
Git 是如何知道你当前在哪个分支上工作的呢?其实答案也很简单,它保存着一个名为 HEAD 的特别指针。请注意它和你熟知的许多其他版本控制系统(比如 Subversion 或 CVS)里的 HEAD 概念大不相同。在 Git 中,它是一个指向你正在工作中的本地分支的指针(译注:将 HEAD 想象为当前分支的别名。)。运行 git branch 命令,仅仅是建立了一个新的分支,但不会自动切换到这个分支中去,所以在这个例子中,我们依然还在 master 分支里工作
切换到分支
git checkout [brance-name]
创建分支并切换
git checkout -b [branch-name]
如果顺着一个分支走下去可以到达另一个分支的话,那么 Git 在合并两者时,只会简单地把指针右移,因为这种单线的历史分支不存在任何需要解决的分歧,所以这种合并过程可以称为快进(Fast forward)
删除分支,由于这些分支中还包含着尚未合并进来的工作成果,所以简单地用 git branch -d 删除该分支会提示错误,因为那样做会丢失数据
git branch -d [branch-name]
强制删除
git branch -d [branch-name]
将[branch-name]上的修改合并到当前分支
git merge [branch-name]
分支管理
列出本地分支
git branch
列出本地分支最后一次提交
git branch -v
哪些分支是当前分支的直接上游
git branch --merged
尚未合并的
git branch --no-merged
推送本地分支到远程,如果远程与本地命名相同,可以省略远程分支名
git push [remote-name] [local-brance-name]:[remote-branch-name]
将远程分支合并到本地当前分支
git merge [remote-name]/[remote-branch-name]
根据远程分支创建本地分支
git checkout -b [local-branch-name] [remote-name]/[remote-branch-name]
根据远程分支创建本地分支
git checkout --trace [remote-name]/[branch-name]
删除远程分支
git push [remote-name]:[remote-branch-name]
实际上是在这里提取空白然后把它变成[远程分支]
git push [远程名] [本地分支]:[远程分支]
变基
在experiment分支执行
git rebase master
另类变基
不用切换分支的rebase方式
git rebase [target-branch] [feature-branch]
一旦分支中的提交对象发布到公共仓库,就千万不要对该分支进行变基操作
在进行变基的时候,实际上抛弃了一些现存的提交对象而创造了一些类似但不同的新的提交对象。如果你把原来分支中的提交对象发布出去,并且其他人更新下载后在其基础上开展工作,而稍后你又用 git rebase 抛弃这些提交对象,把新的重演后的提交对象发布出去的话,你的合作者就不得不重新合并他们的工作,这样当你再次从他们那里获取内容时,提交历史就会变得一团糟。
stash
储藏”“可以获取你工作目录的中间状态——也就是你修改过的被追踪的文件和暂存的变更——并将它保存到一个未完结变更的堆栈中,随时可以重新应用
git stash
查看储藏列表
git stash list
应用最近的储藏
git stash apply
置顶储藏并应用
git stash apply stash@{2}
丢弃储藏
git stash drop stash@{0}
保存具名储藏
git stash save "content"
正则应用储藏
git stash apply stash^{/content}