每次碰到Git的问题都要去Google,索性整理记录下,基本的安装和使用就不介绍了...

0x01 Basic

Git是创建快照而不是记录不同: Snapshots, Not Differences

传统VCS的存储方式: Differences

0x02 Git storage

  • Git的存储方式导致Git类似一个文件系统,在创建Git分支的时候非常有用;
  • Git是一个分布式代码管理软件,故每个git端上都会保存完整的所有版本的代码,故在本地端就会有一个代码的副本,故可以在本地进行操作;
  • Git存在完整性校验;
  • Git通常只添加数据,而不会抹除数据,避免了代码丢失的风险;

0x03 Git state

三个状态:committed, modified, staged

  • Committed表示已经安全的存储在本地;
  • Modified表示已经修改但是还没有提交commit存储到本地数据库中;
  • Staged表示标志了modified文件在当前的版本将会提交到下次创建快照中;

下图描述了git的通常工作流程: Three States

  1. Modified文件;
  2. staged文件,添加他们的快照到staging area;
  3. 将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的生命周期为: git lifecycle

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

  1. 添加分支不会主动修改HEAD的指向;
  2. git的快照是采用指针的方式,每个指针指向其“母版本”;
  3. 由于是存储快照,故在创建分支是非常迅速的,每个只需要增加41bytes(40字节的校验码和一个空行),不会像其他VCS那样存储一个副本,节省了时间;
  4. 与其他VCS不同,他不需要用户选择更倾向于哪个分支,而会将他们两个选择为共同的祖先,也就是同时指向他们两个;
  5. 未经merge的分支是不建议删除的,如果需要强制删除,需要使用-D;
  6. 记住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, 最后以此将之前另存为临时文件的修改依序应用。

rebase

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 允许多个远程仓库存在,使得这样一种工作流成为可能:每个开发者拥有自己仓库的写权限和其他所有人仓库的读权限。 这种情形下通常会有个代表“官方”项目的权威的仓库。 要为这个项目做贡献,你需要从该项目克隆出一个自己的公开仓库,然后将自己的修改推送上去。 接着你可以请求官方仓库的维护者拉取更新合并到主项目。 维护者可以将你的仓库作为远程仓库添加进来,在本地测试你的变更,将其合并入他们的分支并推送回官方仓库。 这一流程的工作方式如下所示:

  1. 项目维护者推送到主仓库。
  2. 贡献者克隆此仓库,做出修改。
  3. 贡献者将数据推送到自己的公开仓库。
  4. 贡献者给维护者发送邮件,请求拉取自己的更新。
  5. 维护者在自己本地的仓库中,将贡献者的仓库加为远程仓库并合并修改。
  6. 维护者将合并后的修改推送到主仓库。

集成管理者

  • 司令官与副官工作流

般拥有数百位协作开发者的超大型项目才会用到这样的工作方式,例如著名的 Linux 内核项目。 被称为副官(lieutenant)的各个集成管理者分别负责集成项目中的特定部分。 所有这些副官头上还有一位称为司令官(dictator)的总集成管理者负责统筹。 司令官维护的仓库作为参考仓库,为所有协作者提供他们需要拉取的项目代码。 整个流程看起来是这样的:

  1. 普通开发者在自己的特性分支上工作,并根据 master 分支进行变基。 这里是司令官的master分支。
  2. 副官将普通开发者的特性分支合并到自己的 master 分支中。
  3. 司令官将所有副官的 master 分支并入自己的 master 分支中。
  4. 司令官将集成后的 master 分支推送到参考仓库中,以便所有其他开发者以此为基础进行变基。

司令官与副官

实际并不常用,只有像Linux内核这类的大项目才会用到...

0x0A Contributing to a project

两个开发者编辑了不同的文件时,Subversion 会对编辑的不同文件在服务器上自动进行一次合并,但 Git 要求你在本地合并提交。

一个简单的多人 Git 工作流程的通常事件顺序

一个简单的多人 Git 工作流程的通常事件顺序

0x0B One step to Github

  1. apt-get install git
  2. 生成SSH-key ,ssh-keygen -t rsa -C "your_email@youremail.com",your_email是你的email,默认生成的文件在用户的家目录下.ssh/id_rsa.pub文件里面,复制全部内容;
  3. 粘贴到github,进入Account Settings,左边选择SSH Keys
  4. 测试ssh key是否成功,使用命令“ssh -T git@github.com”
  5. 配置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

待续...


Reference


Comments

comments powered by Disqus