导航
导航
文章目录
  1. 工作区和暂存区
    1. 概念
    2. 流程
    3. 命令
      1. 提交
      2. 查看
      3. 回退
      4. 删除
    4. 实践
  2. 版本
    1. 命令
    2. 实践
  3. 分支
    1. 命令
      1. 查看
      2. 合并
      3. 暂存和恢复
      4. 删除
    2. 实践
      1. 合并
      2. 切换
      3. 暂存
      4. 删除
  4. 远程仓库
    1. 简介
    2. 实践
    3. 1、git clone
      1. 简介
      2. 协议
      3. 实践
    4. 2、git remote
      1. 查看
      2. 添加
      3. 改名
      4. 删除
    5. 3、git fetch
      1. 命令
      2. 实践
    6. 4、git pull
      1. tracking
      2. 命令
      3. 实践
    7. 5、git push
      1. 命令
      2. 实践
  5. 本地分支与远程分支实践
    1. 本地分支
    2. 远程分支
  6. 标签
    1. 命令
      1. 查看
      2. 添加
      3. 删除
      4. 推送
    2. 实践
      1. 添加标签
      2. 删除远程标签
  7. 自定义Git
    1. 1、git config
    2. 2、git ignore
    3. 3、配置别名
  8. 继续深入
  9. 拓展阅读

Git核心概念

工作区和暂存区

Git和其他版本控制系统的不同之一就是有暂存区的概念。

概念

工作区(Working Directory),电脑里的工作目录
版本库(Repository),工作区下的隐藏目录.git
版本库.git包括暂存区(stage,或index),git自动创建的master分支,以及指向当前分支的指针HEAD等

流程

在本地修改文件后,先提交到暂存区,再从暂存区提交到当前分支

命令

提交

添加文件修改到暂存区:git add <file(s)>
提交暂存区的所有内容到当前分支:git commit -m “<description>”

查看

当前仓库状态,并提示可选的操作:git status
查看工作文件与暂存区的区别:git diff
查看暂存区与上一次提交的区别:git diff –cached

回退

从暂存区到工作区(回退工作区文件到上一次git add):git checkout – <file>
从当前分支到暂存区(回退暂存区文件到某一版本的git commit):git reset <commit id> <file>
当前分支回退版本(如下节):git reset –hard <commit id>

删除

删除工作区和暂存区:git rm <file>

实践

先在工作区中修改文件,然后利用git status命令查看当前仓库状态(git status命令在仓库状态的同时,会提示目前可以采取的动作),然后用git add命令将一个或多个改动添加到暂存区,最后用git commit命令将暂存区所有改动提交到当前分支。
如果在git add后、git commit之前,又更改了工作区文件,则此时git add会覆盖第一次add,工作区和暂存区一致,与最近的commit不一致;git commit会提交第一次add,暂存区和最近commit一致,与工作区不一致
删除文件时,可在本地删除,然后提交到暂存区,再提交到分支;或使用git rm命令同时删除本地和暂存区文件,然后提交到分支

版本

每次commit都会生成一个版本
每个版本都对应着一个版本号(commit id),Git使用SHA1计算出的一个十六进制表示的数字作为commit id
HEAD表示当前版本,上一个版本为HEAD^,上上个版本为HEAD^^,往上100个版本为HEAD~100
当在Git中回退版本时,Git内部只是移动了HEAD指针,并可以通过参数,选择是否重置暂存区和工作树

命令

显示历史版本信息:git log
显示历史版本信息(每个版本一行,只显示版本号和注释):git log –pretty=oneline
回退到上一个版本(回退HEAD):git reset –soft HEAD^
回退到上一个版本(回退HEAD,暂存区):git reset HEAD^
回退到上一个版本(回退HEAD,暂存区和工作树):git reset –hard HEAD^
回退到某一个版本:git reset <coimmit id>
查看所有动作:git reflog

实践

一般使用git log查看历史版本信息,然后回退到某一版本,此时再使用git log命令则只能显示当前回退到的版本的历史版本,如果想恢复到相对当前版本较新的版本,需要使用git reflog命令,查看历史动作,其中包含版本号,利用版本号进行版本“前进”

分支

分支功能可以使产品保证稳定版本,同时开发新功能版本,并且可以实现多个新功能并行开发
很多版本管理系统都有分支的功能,然而SVN等工具创建分支时会拷贝整个工作区,所以效率很低,Git使用类似指针的概念,无论是上述版本回退,还是创建分支等功能,在Git中都只是一个指针移动的操作,效率非常高
Git版本库中的指针名称叫HEAD,指向当前分支的当前版本。如前所述,可以用HEAD^、HEAD~100来表示前几个版本
当commit时,改动被提交到HEAD,HEAD再提交到其指向的分支,因此,改动HEAD指向即可改变提交的分支
HEAD默认指向Git自动生成的master分支,可以通过命令新建分支、切换分支、合并分支

命令

查看

查看本地分支:git branch,当前分支前以星号标记
查看远程分支:git branch -r
查看本地和远程分支:git branch -a
创建和切换:
创建分支:git branch <branch-name>
切换分支:git checkout <branch>
创建并切换分支:git checkout -b <branch>

合并

合并指定分支到当前分支:git merge <branch>
禁用Fast-forward模式merge:git merge
查看分支合并图:git log –graph –pretty=oneline –abbrev-commit
放弃合并:git merge –abort

暂存和恢复

暂存工作区:git stash
查看暂存:git stash list
恢复暂存:git stash apply
删除暂存:git stash drop
恢复并删除暂存:git stash pop

删除

删除分支:git branch -d <branch>
强制删除分支:git branch -D <branch>

实践

合并

合并分支后,可以通过有两种情况(以从master分支上新建dev分支为例):
1、dev改动并commit之后merge,master还没有commit过
1.a Fast-forward模式merge
1.b 禁用Fast-forward模式merge
2、dev改动并commit之后merge,而master也被改动并commit过
2.a 没有冲突,直接merge
2.b 有冲突,手动解决,merge
2.c 有冲突,放弃merge
对于1.a,master与dev其实是在一条线上开发,只不过dev比master超前一个commit,所以移动master指针到dev指针即可
对于1.b,因为1.a中只是简单移动,dev的信息并没有保存,所以在删除dev后,dev的分支信息将被丢弃,且分支合并图没有体现,可以使用git merge的–no-ff参数,强制禁用Fast-forward模式
对于2.a,两个分支分别有commit,行成两条分叉线,如果文件中没有冲突(即都有内容且不相同的行),则可以直接合并
对于2.b,当提交merge命令后,Git中会存在一个MERGE_HEAD,此时分支处于合并过程中的状态,使用git status可以查看冲突,手动解决文件冲突后,使用git commit合并
对于2.c,如果不想解决冲突,可以选择放弃merge,使用git merge –abort删除MERGE_HEAD,恢复到使用merge命令之前的状态

切换

工作树、暂存区和commit会随着分支切换而变化

暂存

git stash命令可以将目前的工作区、暂存区改动存储起来,此时使用git status命令查看,工作区是干净的
例如在dev分支开发一半,突然有bug修复工作,可以先暂存dev分支,然后从master新建一个bug修复分支,修复并提交到master后,切换回dev分支,恢复刚才的暂存,继续工作

删除

当前分支无法删除
使用-d普通删除
对于有改动的分支,使用-D强制删除

远程仓库

简介

Git是分布式版本控制系统
同一个Git仓库,可以通过克隆分布到不同的机器上 每台机器的版本库都一样,没有主次之分
可以从任何机器上克隆或拉取文件,例如本地目录、局域网服务器、GitHub等

实践

通过git init生成的仓库没有远程仓库连接
可以直接git clone,或在git init后通过git remote add命令,与远程主机连接
一个本地仓库可与多个远程仓库连接
本地以远程主机名对主机进行区分,主机名只是本地对远程的称呼
git clone默认命名为origin,可手动指定;git remote add必须手动指定

1、git clone

简介

git clone命令从远程主机克隆一个版本库:git clone <repo> [<dir>]
第一个参数是远程主机的版本库地址
第二个参数是可选的,指定本地新建目录的名称,默认是远程主机版本库的名称
例如:git clone https://github.com/jquery/jquery.git

协议

git clone支持多种协议,包括HTTP(s)、SSH、Git、本地文件协议等
例如:
git clone http[s]://example.com/path/to/repo.git/
git clone ssh://example.com/path/to/repo.git/
git clone git://example.com/path/to/repo.git/
git clone /opt/git/project.git
git clone file:///opt/git/project.git
git clone ftp[s]://example.com/path/to/repo.git/
git clone rsync://example.com/path/to/repo.git/
SSH协议还有一种写法:git clone [user@]example.com:path/to/repo.git/
通常,Git协议下载速度最快,SSH协议用于需要用户认证的场合
具体内容可见 https://git-scm.com/book/en/v2/Git-on-the-Server-The-Protocols

实践

一般直接使用如上命令进行clone,此时远程主机默认命名为origin,如果想要指定名称(例如需要添加多台主机时),可以使用-o, –origin参数
格式:git clone -o <name> <repo> [<dir>] 或 git clone –origin <name> <repo> [<dir>]
例子:git clone -o jQuery https://github.com/jquery/jquery.git

2、git remote

用来执行远程主机添加和移除,和对远程主机名的增删改查

查看

查看所有远程主机名:git remote
查看所有远程主机名及其网址:git remote -v
查看远程主机详细信息:git remote show <name>,指定远程主机名

添加

添加远程主机:git remote add <name> <url>,分别指定远程主机名和主机地址

改名

重命名远程主机:git remote rename <old> <new>,分别指定原主机名、新主机名

删除

删除远程主机:git remote rm <name>,指定远程主机名

3、git fetch

当远程主机有了更新(commit)时,将远程主机的更新取回本地
git fetch对本地分支没有影响
取回本地远程分支要以 远程主机名/分支名 的形式访问,例如 origin/master

命令

取回:
取回默认名为origin远程主机的所有分支:git fetch
取回指定远程主机的某一分支:git fetch <repo> <branch>,分别指定远程主机名和分支名
合并:
在远程分支的基础上新建本地分支(并建立追踪关系):git checkout -b <branch name> <remote branch name>
在本地已有分支上合并远程分支:git merge <remote branch name> 或 git rebase <remote branch name>
回忆:
查看所有远程分支:git branch -r
查看所有分支:git branch -a

实践

通过git fetch获取到远程分支后,只能用git checkout -b在其基础上新建分支,并建立追踪;或用git merge/rebase合并到已有的本地分支,但不建立追踪

4、git pull

取回远程主机某个分支的更新,再与本地的指定分支合并
可理解为先git fetch,再git merge

tracking

在拉下和推送之前,本地分支与远程分支之间必须有追踪关系(tracking)
git clone <repo>和git checkout -b <branch name> <remote branch name>会自动建立相应分支之间的追踪关系
可使用git branch –set-upstream <branch name> <remote branch name>

命令

取回某个远程主机的某个分支,并与本地的某个分支合并,但不建立追踪:
git pull <remote name> <remote branch name>:<branch name>

实践

1、如果与当前分支合并,则可省略branch name:git pull <remote name> <remote branch name>
2、如果已经建立分支追踪关系,则可省略remote branch name:git pull <remote name>
3、如果当前分支只追踪了一个远程分支,则可省略remote name:git pull
4、使用rebase模式:git pull –rebase <remote name> <remote branch name>:<branch name>
5、如果远程分支已经删除,git pull不会删除本地分支,如果想删除,使用-p:
git pull -p,等于先git fetch –prune origin,再git fetch -p

5、git push

将本地更新,推送到远程主机,与git pull命令相仿

命令

推送本地的某个分支,到某个远程主机的某个分支,但不建立追踪:
git push <remote name> <branch name>:<remote branch name>
(本地分支和远程分支的熟悉怒与git pull命令相反)

实践

1、推送策略
1.a 如果省略远程分支名,此时如果存在追踪关系直接推送,如果不存在则会新建远程分支:
git push <remote name> <branch name>
1.b 如果省略本地分支名,则删除指定的远程分支(可理解为推送一个空的本地分支到远程分支):
git push <remote name> :<remote branch>,等于git push <remote name> –delete <remote branch>
1.c 如果当前分支与远程分支有追踪关系,则可省略本地分支和远程分支:git push <remote name>
1.d 如果当前分支只有一个追踪分支,则可继续省略主机名:git push
1.e 如果当前分支与多个主机存在追踪关系,可使用-u指定一个默认主机,进而直接使用git push而不加参数:git push -u <remote name> <branch name>,将指定本地分支推送到指定远程主机,并指定该远程主机为默认主机
2、推送模式
git push有两种模式,simple和matching;simple只推送当前分支,matching会推送所有对应分支;Git 2.0以前默认采用matching,现在默认使用simple;可使用git config更改:
git config –global push.default matching 或 git config –global push.default simple
还有一种可选模式,是不管是否存在远程分支,将本地分支都推送到远程主机:git push –all <remote name>
3、解决冲突
当远程分支版本较新时,需要先git pull,手工合并差异,再push
但可以使用–force强制推送:git push –force <remote name>,覆盖远程分支的文件,谨慎使用
4、推送标签
默认不会推送标签,使用–tags:git push <remote name> –tags

本地分支与远程分支实践

本地分支

1、通过git init生成本地仓库,本地是无分支的,可以新建分支,或commit文件后生成默认的master分支
2、通过git clone生成本地仓库,会取回所有远程分支,并默认在本地新建远程仓库的HEAD指向的分支,以远程分支的名称命名,并连接;可以使用-b或–branch参数指定远程分支

远程分支

1、通过git checkout <remote branch name>,切换到远程分支时,会进入detached HEAD状态,以“(HEAD detached at <remote branch name>)”标记,工作树会显示远程分支的文件,可以修改提交,但不会造成修改,当切换到本地分支后,该分支立即消失
2、通过git checkout -b <branch name> <remote branch name>,则会在本地新建分支,并拷贝远程分支文件,并建立两个分支之间的连接

标签

指向commit的一个指针,与commit id功能一样,但名称更加容易记忆,好找
git push的时候默认不会推送标签,除非使用–tag参数

命令

查看

查看所有标签(按名称排序):git tag
查看某个标签详细信息:git show <tag name>

添加

打在最新的commit上:git tag <tag name>
打在某一个commit上:git tag <tag name> <commit id>

删除

删除标签:git tag -d <tag name>

推送

推送标签到远程主机:git push <remote name> <tag name>
推送所有标签到远程主机:git push <remote name> –tags

实践

添加标签

使用-a指定标签名,-m添加有说明的标签:git tag -a <tag name> -m “<description>” <commit id>
使用-s使用GPG签名(不可伪造,可验证)的标签:git tag -s <tag name> -m “<description>” <commit id>

删除远程标签

先删除本地标签,git tag -d <tag name>,再删除远程主机标签,git push <remote name> :refs/tags/<tag name>

自定义Git

1、git config

例如username和email,例如开启颜色:git config –global color.ui true

2、git ignore

通过在仓库根目录放置 .gitignore 文件,可以配置Git忽略的不追踪的文件,如class文件、操作系统生成的文件、包含敏感信息的文件等
文件模板可见: https://github.com/github/gitignore
add被ignore的文件类型时,会提示已经ignore并失败,如果一定要上传,有两种选择:
一是添加-f参数强制添加:git add -f <filename>
二是删除相应规则,可以先查看对应的是哪条规则:git check-ignore -v <filename>

3、配置别名

添加别名:
git config –global alias.<别名> <命令>,–global针对当前用户起效果,不加则只针对当前仓库
例如,
git config –global alias.st status,st表示status
git config –global alias.co checkout,co表示checkout
git config –global alias.ci commit,ci表示commit
git config –global alias.br branch,br表示branch
git config –global alias.unstage ‘reset HEAD’,unstage表示撤销暂存区
git config –global alias.last ‘log -1’,last显示最后一次提交信息
git config –global alias.lg “log –color –graph –pretty=format:’%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset’ –abbrev-commit”,lg显示提交图
删除别名:
Git仓库配置文件:打开 .git/config/.gitconfig
Git用户配置文件:~/.gitconfig
在[alias]段落中配置了别名规则,修改文件内容即可

继续深入

1、命令详解
参见Git官网: https://git-scm.com/docs
2、Pro Git
官网推荐书籍,内容详实
豆瓣读书: https://book.douban.com/subject/26208470/
官网阅读: https://git-scm.com/book/en/v2

拓展阅读

《常用 Git 命令清单》 http://www.ruanyifeng.com/blog/2015/12/git-cheat-sheet.html
《Git 工作流程》 http://www.ruanyifeng.com/blog/2015/12/git-workflow.html
《Git 使用规范流程》 http://www.ruanyifeng.com/blog/2015/08/git-use-process.html
《Git分支管理策略》 http://www.ruanyifeng.com/blog/2012/07/git.html
《GitHub Flow》 http://scottchacon.com/2011/08/31/github-flow.html
《Commit message 和 Change log 编写指南》 http://www.ruanyifeng.com/blog/2016/01/commit_message_change_log.html
《Github 的清点对象算法》 http://www.ruanyifeng.com/blog/2015/09/git-bitmap.html

参考:
http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000
http://www.ruanyifeng.com/blog/2014/06/git_remote.html