Learn Git

集中式vs分布式

SVN和CVS都是集中式的版本控制系统, GIT是分布式的版本控制系统

集中式版本控制系统

版本库集中存放在中央服务器, 干活的时候用的都是自己的电脑, 先从中央服务器取得最新的版本, 然后开始干活, 干完活再把自己的活推送给中央服务器.
最大的缺点就是需要联网才能工作, 如果在互联网商网速慢的话, 提交一个文件花费的时间就会很长

分布式版本控制系统

在每一个人的电脑上都是一个版本库, 同时有一台服务器充当中央服务器的角色, 用来方便交换大家的修改

git的安装

现在git可以运行在linux、unix、mac、windowsuoge平台上
如果是linux平台, 根据不同的系统, 使用apt-get install git或者yum install git在命令行中就可以安装. 或者在git官网上下载源码进行编译安装(./configure make && make install)
如果是其他平台的话, 自行在官网上下载对应的安装包

git的配置

安装完git之后, 你需要配置你的信息name以及email
git config –global user.name “your name”
git config –global user.email “your email”
–gloabl这个参数表示所有的库都会用这个参数, 但是也可以对某个仓库使用指定的用户名等信息
如果要使用github的话, 还需要配置你的账号密码, 并且在github中添加你这台设备的ssh key, 这样才可能通过本地git访问到github.

创建版本库

可以在本地创建一个空文件夹, 并进入到该文件夹下使用git init将目录变成git可以管理的仓库, 这个时候可以看到该文件夹下多了一个.git的隐藏文件夹, 这里隐藏的是版本控制信息, 不要轻易修改里面的内容.

git的基本操作步骤

git add xx & git commit

如果说在新建的仓库中新建了一个readme.txt文件

  1. 首先使用git add readme.txt, 将文件添加到仓库
  2. 再使用git commit -m ‘备注信息’, 将文件提交到仓库, 同时每次提交都需要commit信息, 主要是用来描述此次提交涉及到的修改信息.

git status

使用命令git status命令可以查看该仓库的状态, 是否和服务器上的仓库有差别.当你再次修改readme.txt文件的内容后, git status就会提示你有修改后的内容没有commit, 这个时候需要再次执行git add以及git commit操作.同时我们也可以用git diff来查看文件和当前服务器上的文件修改了哪些内容.

git log

git log命令可以查看从最近到最远的提交日志.

git reset

git reset命令可以使仓库回退到指定版本, 当前版本为HEAD, 前一个版本是HEAD^, 以此类推前100个版本就是HEAD~100.
git reset –hard HEAD^表示回退到前一个版本, 这个时候查看git log可以看到当前版本已经回退到前一个版本了
这个时候如果要再回退到最新的版本只需要用git reset –hard . 因为使用git reset命令的时候, 只是把HEAD的指针指到了指定的版本, 并没有做什么其他操作

git reflog

git reflog可以显示多次commit的信息, 包括了每次的commit id

工作区和暂存区

git相比其他版本控制系统多了一个暂存区的概念. 我们在创建git版本库的时候, git自动为我们创建了一个master分支, 所以git commit就是往master分支上提交更改
git add是将文件修改添加到暂存区, git commit将暂存区的文件提交到当前分支

管理和修改

git commit只会将暂存区的内容提交到当前分支
比如修改了readme.txt文件, 使用git add命令添加到暂存区, 再次修改reademe.txt文件, 使用git commit提交. 这个时候可以看到当前仓库内readme.txt文件的内容是第一次修改后的, 第二次修改的内容没有commit. 所以在git commit之前用git add将readme.txt文件添加到暂存区就可以了.这样最新的就是第二次修改的readm.txt

撤销修改

git checkout – 可以丢弃工作区的修改, 这里有两种情况:

  1. readme.txt修改后还没有放到暂存区, 现在撤销修改就回到版本库的状态
  2. readme.txt添加到暂存区后, 又做了修改, 现在撤销修改就回到了暂存区的状态

简单的说git checkout – 就是将文件回复到最近的一次git commit或者git add时候的状态
如果文件已经放到暂存区了, 可以使用git reset HEAD 将暂存区的文件回退到工作区, 然后再使用git checkout – 来丢弃工作区的修改

删除文件

git rm 可以删除版本库中的文件, 同时使用git checkout – 可以将删除的恢复(但是只能恢复文件到最新版本, 如果已经提交到版本库的话可以恢复到修改后的, 但是如果没有提交就将丢失最新一次的修改)

远程仓库

使用github来保存你的仓库时, 要先生成SSH Key.
ssh-keygen -t rsa -C “youremail@example.com
然后可以在用户的主目录下.ssh文件夹内找到id_rsa和id_rsa.pub, 这是生成的一对密钥. 然后需要将公钥的内容贴到github上, 这样机器就可以远程连接到github的服务器了.

添加远程仓库

在github上新建一个仓库名为learngit, 这个时候仓库还是空的.
这个时候我们将本地仓库与之关联, git remote add origin git@github.com:chris/learngit.git
使用命令git push -u origin master将本地的内容推送到远程库中, 第一次推送的时候需要添加-u参数, 之后就不需要添加-u参数了.

分支管理

创建与合并分支

一开始, master分支是一条线, Git用master指向最新的提交, 在用HEAD指向master, 就能确定当前分支, 以及当前分支的提交点.
每一次提交master分支都会向前移动一步.
master
当我们创建新的分支dev, Git新建了一个指针dev, 指向master相同的提交, 再把HEAD指向dev, 表示当前分支在dev上.
dev
现在进行的修改都是针对dev分支, 新提交一次后, dev指针往前移动一步, 而master指针不变
dev-1
如果我们在dev分支上的工作完成了, 就可以把dev合并到master上. 只需要将master的指针指向dev当前的提交就可以了.
master-1
合并完成后, 删除dev分支(就是删除dev指针), 这样我们就剩下一条master分支

1
2
3
4
5
6
7
8
git checkout -b dev
# 创建并切换到dev分支, 相当于git branch dev && git checkout dev
git branch
#查看所有的分支, 并显示当前所在的分支
git merge dev
#合并指定分支到当前分支, 合并的时候有多种方式,(fast-forward模式, 直接把master的指针知道dev指针所在的提交)
git branch -d dev
#删除dev分支

解决冲突

新建分支dev, 修改readme.txt文件并提交; 切换到master分支, 同样修改readme.txt并提交.
conflict
这个时候执行git merge dev, 会提示我们有冲突. 使用git status可以查看相关信息.
当Git无法自动合并分支时, 必须首先解决冲突. 解决冲突后再提交合并.
用git log –graph命令可以查看分支合并图

分支康策略

一般情况下, 合并分支会用fast forward模式, 这种模式下, 删除分支后, 会丢失分支信息.
如果强制禁用fast forward模式(–no-ff), Git就会在merge的时候生成一个新的commit. 这样从分支历史上就可以看出分支信息.

1
2
3
4
5
6
git checkout -b dev
#修改readne.txt文件
git add readme.txt
git commit -m 'add merge'
git checkout master
git merge --no-ff -m 'merge with --no-ff' dev

不使用fast forward模式, merge后就像这样
no-ff

Bug分支

可以创建一个分支issue-101来修复bug, 但是当前正在dev上进行的工作还没有完成提交, 这个时候可以使用git stash功能保存当前工作状态. 再用git status可以看到工作区内是干净的.
要在哪个分支修复bug, 就需要在哪个分支上创建临时分支. 修复bug后提交后merge就可以了. 这个时候回到工作的dev分支使用git stash list查看, 之前保存的状态.
git stash apply 可以恢复之前工作的状态, 但是不删除stash内容, 需要使用git stash drop来手动删除
git stash pop可以恢复之前的工作状态同时也把stash内容删除
可以使用多次使用stash, 然后恢复的时候指定某一次的保存内容就可以了 git stash apply stash@{0}

feature分支

如果开发一个新的feature最好新建一个分支, 如果要删除一个没有合并的分支, 需要使用-D参数才可以

多人协作

git remote -v查看远程信息
$ git remote -v
origin git@github.com:Chris-huangxw/algorithms-learning.git (fetch)
origin git@github.com:Chris-huangxw/algorithms-learning.git (push)
只有有push权限才能看到上面的信息
git push orign <分支>默认master 推送本地内容到远端仓库中, 指定特定的分支
多人合作的冲突

Rebase

xxx

标签管理

Git的标签虽然是版本库的快照, 但其实它就是指向某个commit的指针(但是和分支不一样, 分支可以移动, 但是标签不能移动).
tag可以和某个commit绑在一起

创建标签

首先切换到需要打标签的分支上
git branch
git checkout master
git tag v1.0
使用git tag查看所有标签. 默认标签是打在最新提交的commit上的. 如果要在之前的commit上打上标签就需要之前commit的commit id就可以了.
git log –pretty=oneline –abbrev-commit
12a631b (HEAD -> master, tag: v1.0, origin/master) merged bug fix 101
4c805e2 fix bug 101
e1e9c68 merge with no-ff
f52c633 add merge
cf810e4 conflict fixed
5dc6824 & simple
git tag v0.9 f52c633
标签不是按时间顺序列出的, 是按照字母排序的. git show 可以查看某一标签的详细信息.
git tag -a v0.1 -m ‘release note’ f52c633
-a参数指定标签名, -m参数指定说明内容

操作标签

git tag -d v0.1 可以删除指定标签, 而且标签操作默认都是在本地操作, 删除标签不会推送到远程库.
如果需要推送某个标签到远程, 使用命令git push origin (推送指定标签) 或者git pus origin –tags(推送所有未推送到远程的本地标签)
如果要删除远程库中的标签, git push origin :refs/tags/v0.9