直接快照,而非比较差异
Git只关心文件数据的整体是否发生变化,而大多数其他系统则只关心文件内容的具体差异。Git更像是一个小型的文件系统,它保存每次更新时的文件快照。所以Git近乎所有的操作都可以在本地执行。
三种状态
- 已提交(committed):该文件已经被安全地保存在本地数据库中了
- 已修改(modified):修改了某个文件,但还没有提交保存
- 已暂存(staged):把已修改的文件放在下次提交时要保存的清单中
分支
- 创建分支
git checkout -b newBranch
相当于:
1 | git branch newBranch |
- 删除分支
1 | git branch -d newBranch |
- 基本合并
1 | git checkout master |
- 冲突的合并
任何包含未解决冲突的文件都会以未合并(unmerged)状态列出。可以手动或通过图形工具来解决冲突:
1 | git mergetool |
冲突解决之后再add提交。
1 | git branch // 查看所有分支 |
分支式的工作流程
长期分支
master分支中保留完整稳定的代码,develop或next分支专门用于后续的开发,仅用于稳定性测试,当然并不是说一定要绝对稳定,不过一旦进入某种稳定的状态,便可以把它合并到master里。
特性分支
一个特性分支是指一个短期的,用来实现单一特性或与其相关工作的分支
远程分支
当我们从远程仓库克隆时,git会自动将你仓库命名为origin,并下载其中所有数据,建立一个指向它的master分支,在本地命名为origin/master,你无法在本地更改其数据。
接着,git建立一个本地属于你的master分支,始于origin上master分支相同的位置。只要你不和服务器通讯,你的origin/master分支不会移动。
可以通过git fetch origin
命令来进行同步。
推送
如果你有个叫 serverfix 的分支需要和他人一起开发,可以运行 git push (远程仓库名) (分支名) :
1 | git push origin serverfix |
Git 自动把 serverfix 分支名扩展为 refs/heads/serverfix:refs/heads/serverfix ,意为“取出我的 serverfix 本地分支,推送它来更新远程仓库的 serverfix 分支”
也可以运行 git push origin serverfix:serferfix 来实现相同的效果,它的意思是“提取我的 serverfix 并更新到远程仓库的 serverfix”
值得注意的是,在 fetch 操作抓来新的远程分支之后,你仍然无法在本地编辑该远程仓库。换句话说,在本例中,你不会有一个新的 serverfix 分支,有的只是一个你无法移动的 origin/serverfix 指针。
如果要把该内容合并到当前分支,可以运行 git merge origin/serverfix 。如果想要一份自己的 serverfix 来开发,可以在远程分支的基础上分化出一个新的分支来:
1 | git checkout -b serverfix origin/serverfix |
跟踪分支
从远程分支检出的本地分支,称为跟踪分支(tracking branch)。跟踪分支是一种和远程分支有直接联系的本地分支。在跟踪分支里输入 git push ,Git 会自行推断应该向哪个服务器的哪个分支推送数据。反过来,在这些分支里运行 git pull 会获取所有远程索引,并把它们的数据都合并到本地分支中来。
在克隆仓库时,Git 通常会自动创建一个 master 分支来跟踪 origin/master 。这正是 git push 和 git pull 一开始就能正常工作的原因。当然,你可以随心所欲地设定为其它跟踪分支,比如 origin 上除了 master 之外的其它分支。刚才我们已经看到了这样的一个例子: git checkout -b [分支名] [远程名]/[分支名] 。如果你有 1.6.2 以上版本的 Git,还可以用 –track 选项简化:
1 | $ git checkout --track origin/serverfix |
要为本地分支设定不同于远程分支的名字,只需在前个版本的命令里换个名字:
1 | $ git checkout -b sf origin/serverfix |
删除远程分支
1 | $ git push origin :serverfix |
衍合
把一个分支整合到另一个分支的办法有两种: merge(合并) 和 rebase(衍合)
衍合基础
rebase命令可以把在一个分支里提交的改变在另一个分支里重放一遍:
1 | git checkout experiment |
你可以经常使用衍合,确保在远程分支里的提交历史更清晰。比方说,某些项目自己不是维护者,但想帮点忙,就应该尽可能使用衍合:先在一个分支里进行开发,当准备向主项目提交补丁的时候,再把它衍合到origin/master 里面。这样,维护者就不需要做任何整合工作,只需根据你提供的仓库地址作一次快进,或者采纳你提交的补丁。
更多有趣的衍合
1 | $ git rebase --onto master server client |
检出 client 分支,找出 client 分支和 server 分支的共同祖先之后的变化,然后把它们在 master 上重演一遍
git rebase [主分支][特性分支]命令会先检出特性分支 server ,然后在主分支 master 上重演:
1 | git rebase master server |
衍合的风险
永远不要衍合那些已经推送到公共仓库的更新
如果把衍合当成一种在推送之前清理提交历史的手段,而且仅仅衍合那些永远不会公开的 commit,那就不会有任何问题。如果衍合那些已经公开的 commit,而与此同时其他人已经用这些 commit 进行了后续的开发工作,那你有得麻烦了。