每次碰到Git的问题都要去Google,索性整理记录下,基本的安装和使用就不介绍了...
0x01 Basic
Git是创建快照而不是记录不同:
传统VCS的存储方式:
0x02 Git storage
- Git的存储方式导致Git类似一个文件系统,在创建Git分支的时候非常有用;
- Git是一个分布式代码管理软件,故每个git端上都会保存完整的所有版本的代码,故在本地端就会有一个代码的副本,故可以在本地进行操作;
- Git存在完整性校验;
- Git通常只添加数据,而不会抹除数据,避免了代码丢失的风险;
0x03 Git state
三个状态:committed, modified, staged
- Committed表示已经安全的存储在本地;
- Modified表示已经修改但是还没有提交commit存储到本地数据库中;
- Staged表示标志了modified文件在当前的版本将会提交到下次创建快照中;
下图描述了git的通常工作流程:
- Modified文件;
- staged文件,添加他们的快照到staging area;
- 将staging area中的文件添加到本地git数据库中;
0x04 Setup & usage
- 安装和配置git直接参照书或git笔记的说明即可;
- 子目录中git的配置会覆盖全局配置;
- 文件的状态有两类:tracked和untracked,tracked又分为上面说的三种;
- gitignore文件的语法详见第二章;
git config #配置用户名和邮箱以及默认的编辑器
git config --list #列出配置参数
git help XXX #查找帮助
git remove #会将tracked file列表和实际存在的本地文件统统删除,如果只想不追踪,可以使用gitignore或者git rm --cached XXX
git mv #移动文件而不会重新记录
git log -p #显示每次提交的不同地方。log中还有很多参数可以选择;
git commit --amend #在提交漏交文件之后只提交一次commit,而不会有两次;
git reset HEAD <file> #可以将staged文件设置为unstaged文件;
git checkout -- [file] #是一个危险命令,可以将文件还原为未修改状态;他的工作原理是将老的文件直接覆盖掉新的文件,故会将所做的修改抹去;
git的生命周期为:
Tips:
- untracked files为未添加跟踪的文件状态,即未git add xxxx.xx的文件;
- 添加跟踪未被修改的文件状态为Unmodified,即经过上次的git commit之后未修改的文件;
- Changes not staged for commit: (modified)为添加跟踪且被修改过的文件状态
- Changes to be committed为添加跟踪且被修改过并被提交到暂存区的(也就是图上的staged),可通过git add命令将文件添加到暂存区;
- git add是个多功能命令,可以用它开始跟踪新文件,或者把已跟踪的文件放到暂存区,还能用于合并时把有冲突的文件标记为已解决状态等。将这个命令理解为“添加内容到下一次提交中”而不是“将一个文件添加到项目中”要更加合适。
复原文件的方法,恢复到Modified之前的文件;
# 在文件被Modified但是未被staged的前提下,可使用checkout放弃对该文件的修改
git checkout xxx.xx
查看git的存储文件目录;
- .git是个隐藏文件夹,包含在项目目录下;
- .git/objects下是2个字母的若干文件夹,分别代表了每个sha1 hash的前两位;
- .git/objects/
的下为38位的文件,为objects的压缩并编码值; - .git/config为该项目的配置文件
- .git/refs/xxx下有heads和tags文件夹,heads表示现在使用的分支,tags表示tag的版本号
0x05 Remote
git remote #查看配置了的远端服务器的参数,-v可以查看详细信息;
git remote add [shortname] [url] #显式的添加配置信息;
git fetch [remote-name] #会将从远端的数据拉过来,但是不会主动合并,pull则会主动合并;(此处的remote-name就是git remote中显示出来的参数)
git push [remote-name] [branch-name] #会将code推送到相对应的分支上去;当然同时只能有一个人正在push;如果别人push完毕后,由于代码的不一致,你需要先pull下别人的代码,才能push上去;
git push origin master --force #强行push,Dangerous!
git remote show [remote-name] #会展示远端服务器的情况,包括远端服务器的分支有哪些还未被同步,有哪些可以合并等;
git remote rename [old-name] [new-name] #修改远端的名称;
git remote rm [name] #删除一个远端
0x06 Tag
Git中有两种tag,轻量级tag和带注释的tag; 轻量级tag像一个不会改变的分支,只适用于特殊的标记;带注释的tag则五脏俱全;
git tag #使用tag来标记版本,-l可以搜索关键字tag;
git tag -a v1.4 -m 'my version 1.4' #-m提示书写注释信息,如同commit中的-m,-a表示添加annotated tags
git tag v1.4-lw #轻量级tag
git tag -a v1.2 9fceb02 #支持对之前的版本添加tag,方法是记住加上校验码的部分(如9fceb02就是某个版本校验码的前7位)
git push origin v1.5 #默认git push 是不会将tag上传到服务器端的,如果需要可以使用
git push origin --tags #一次性上传所有的tags
Git alias
可以在全局模式下设置别名,故可以使用git 别名,如:
git config --global alias.unstage 'reset HEAD --'
如下两个等价:
$ git unstage fileA
$ git reset HEAD -- fileA
或者直接修改配置文件~/.gitconfig
[alias]
hist = log --pretty=format:'%h %ad | %s%d [%an]' --graph --date=short
0x07 Branching
参考:很详细的讲解了git branch的过程;
Notice:
- 添加分支不会主动修改HEAD的指向;
- git的快照是采用指针的方式,每个指针指向其“母版本”;
- 由于是存储快照,故在创建分支是非常迅速的,每个只需要增加41bytes(40字节的校验码和一个空行),不会像其他VCS那样存储一个副本,节省了时间;
- 与其他VCS不同,他不需要用户选择更倾向于哪个分支,而会将他们两个选择为共同的祖先,也就是同时指向他们两个;
- 未经merge的分支是不建议删除的,如果需要强制删除,需要使用-D;
- 记住merge和branch都是在本地,没有与远端的服务器通信;
git branch [branch name] #创建一个新分支
git checkout [branch name] #选择一个分支
git checkout -b [branch name] #等同于上面两个操作
git merge [branch name] #将老分支与之前的snapshot合并(要checkout一个分支,merge另一个分支)
git branch -d [branch name] #删除某个branch分支(这里个人理解为删除某个快照名)
git mergetool #当某个文件被两个分支同时修改过时,merge他就会有冲突,可以手动修改冲突之后,在进行合并;也可使用图形工具(需要实现配置,使用opendiff):
git branch #查看现在所处的分支,-v查看详细内容;--merged查看合并的内容;
git ls-remote (remote) #查看远端服务器分支情况
git remote show (remote)
- 远端的分支采用(remote)/(branch)的形式,如origin/master表示远端master的位置;
- 常用名origin不是固定的,可以修改; remote branch还有很多货,不是很理解,以后再过一遍!
0x08 rebase
- rebase(中文翻译变基)的作用就是将提交到某一个分支的所有操作用到另一个上去;也就是将两个分支合并为一个分支; 选中一个分支,然后将另一个分支变基过来…
变基的原理是首先找到这两个分支(即当前分支 experiment、变基操作的目标基底分支 master)的最近共同祖先 C2,然后对比当前分支相对于该祖先的历次提交,提取相应的修改并存为临时文件,然后将当前分支指向目标基底 C3, 最后以此将之前另存为临时文件的修改依序应用。
git checkout experiment
git rebase master
git checkout master
git merge experiment
不要对在你的仓库外有副本的分支执行变基,因为会造成混乱
- merge vs rebase 翻译里面说的:只对尚未推送或分享给别人的本地修改执行变基操作清理历史,从不对已推送至别处的提交执行变基操作. merge不会改变历史记录,使用merge会记录实际发生过的内容;rebase则会修改历史记录,如果你认为提交历史是项目过程中发生的故事,则使用rebase更合适;
0x09 Distributed Git
分布式工作流程大致可以分为三类:集中式工作流、集成管理者工作流和司令官与副官工作流;
- 集中式工作流
集中式系统中通常使用的是单点协作模型——集中式工作流。 一个中心集线器,或者说仓库,可以接受代码,所有人将自己的工作与之同步。 若干个开发者则作为节点——也就是中心仓库的消费者——并且与其进行同步。
这是最常用的工作流。多人合作项目时,要求后人将前人数据抓取下来并且合并后才能推送到中心仓库中,即是非快进式(non-fast-forward)的方式推送
- 集成管理者工作流
Git 允许多个远程仓库存在,使得这样一种工作流成为可能:每个开发者拥有自己仓库的写权限和其他所有人仓库的读权限。 这种情形下通常会有个代表“官方”项目的权威的仓库。 要为这个项目做贡献,你需要从该项目克隆出一个自己的公开仓库,然后将自己的修改推送上去。 接着你可以请求官方仓库的维护者拉取更新合并到主项目。 维护者可以将你的仓库作为远程仓库添加进来,在本地测试你的变更,将其合并入他们的分支并推送回官方仓库。 这一流程的工作方式如下所示:
- 项目维护者推送到主仓库。
- 贡献者克隆此仓库,做出修改。
- 贡献者将数据推送到自己的公开仓库。
- 贡献者给维护者发送邮件,请求拉取自己的更新。
- 维护者在自己本地的仓库中,将贡献者的仓库加为远程仓库并合并修改。
- 维护者将合并后的修改推送到主仓库。
- 司令官与副官工作流
般拥有数百位协作开发者的超大型项目才会用到这样的工作方式,例如著名的 Linux 内核项目。 被称为副官(lieutenant)的各个集成管理者分别负责集成项目中的特定部分。 所有这些副官头上还有一位称为司令官(dictator)的总集成管理者负责统筹。 司令官维护的仓库作为参考仓库,为所有协作者提供他们需要拉取的项目代码。 整个流程看起来是这样的:
- 普通开发者在自己的特性分支上工作,并根据 master 分支进行变基。 这里是司令官的master分支。
- 副官将普通开发者的特性分支合并到自己的 master 分支中。
- 司令官将所有副官的 master 分支并入自己的 master 分支中。
- 司令官将集成后的 master 分支推送到参考仓库中,以便所有其他开发者以此为基础进行变基。
实际并不常用,只有像Linux内核这类的大项目才会用到...
0x0A Contributing to a project
两个开发者编辑了不同的文件时,Subversion 会对编辑的不同文件在服务器上自动进行一次合并,但 Git 要求你在本地合并提交。
一个简单的多人 Git 工作流程的通常事件顺序
0x0B One step to Github
apt-get install git
- 生成SSH-key ,
ssh-keygen -t rsa -C "your_email@youremail.com"
,your_email是你的email,默认生成的文件在用户的家目录下.ssh/id_rsa.pub文件里面,复制全部内容; - 粘贴到github,进入Account Settings,左边选择SSH Keys
- 测试ssh key是否成功,使用命令“ssh -T git@github.com”
- 配置Git的配置文件,username和email
git config --global user.name "your name" //配置用户名
git config --global user.email "your email" //配置email
git config --global core.editor vim //配置编辑器
git config --global color.ui true //配置颜色
总的来说Git的帮助文档很强大,忘记了git xx -h并且看看它的反馈提示基本就能解决;
0x0C Git config
待续...
Comments
comments powered by Disqus