前言:最近自己在做一个博客项目,每天要在公司和家之家来回拷贝代码,非常麻烦,所以学习一下git
我是在廖雪峰大神的官方网站进行的学习,本篇博客只是学习笔记,如果想看详细的教程,可以到大神网站学习
廖雪峰的官方网站Git教程
1.Git简介
1.1 Git是什么
Git是分布式版本控制系统
1.2 Git和SVN的区别
SVN是集中式版本控制系统,版本库是集中放在中央服务器的,而干活的时候,用的都是自己的电脑,所以首先要从中央服务器哪里得到最新的版本,然后干活,干完后,需要把自己做完的活推送到中央服务器。集中式版本控制系统是必须联网才能工作,如果在局域网还可以,带宽够大,速度够快,如果在互联网下,如果网速慢的话,就很郁闷了。集中式版本控制如下图
Git是分布式版本控制系统,那么它就没有中央服务器的,每个人的电脑就是一个完整的版本库,这样,工作的时候就不需要联网了,因为版本都是在自己的电脑上。既然每个人的电脑都有一个完整的版本库,那多个人如何协作呢?比如说自己在电脑上改了文件A,其他人也在电脑上改了文件A,这时,你们两之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。分布式版本控制如下
2.Git的安装
2.1.在Windows环境下安装
-
在Windows上使用Git,可以从Git官网直接下载安装程序,然后按默认选项安装即可。
-
安装完成后,在开始菜单里找到“Git”->“Git Bash”,蹦出一个类似命令行窗口的东西,就说明Git安装成功!
-
安装完成后,还需要最后一步设置,在命令行输入:
$ git config --global user.name “Your Name”
$ git config --global user.email "email@example.com"因为Git是分布式版本控制系统,所以,每个机器都必须自报家门:你的名字和Email地址。你也许会担心,如果有人故意冒充别人怎么办?这个不必担心,首先我们相信大家都是善良无知的群众,其次,真的有冒充的也是有办法可查的。
注 :git config命令的–global参数,用了这个参数,表示你这台机器上所有的Git仓库都会使用这个配置,如果不加–global是仓库级权限,是对某个仓库指定不同的用户名和Email地址。
2.2 Linux下安装
-
Debian或Ubuntu Linux
sudo apt-get install git
-
老版本Debian或Ubuntu Linux
sudo apt-get install git-core
-
其他版本Linux,官网下载源码解压,然后依次输入
./config ——> make ——> sudo make install
3.创建版本库
3.1什么是版本库
版本库又名仓库,英文名repository,你可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。
3.2创建
在这里我们在Window环境下讲解,
-
选择一个合适的地方,右击—>Git Bash Here(Bash的命令与Linux同步),创建一个空目录,并进入
$ mkdir ,创建库名
$ cd ,进入库内注:如果你使用Windows系统,为了避免遇到各种莫名其妙的问题,请确保目录名(包括父目录)不包含中文。
-
通过git init命令把这个目录变成Git可以管理的仓库:
瞬间Git就把仓库建好了,而且告诉你是一个空的仓库(empty Git repository),细心的读者可以发现当前目录下多了一个.git的目录,这个目录是Git来跟踪管理版本库的,没事千万不要手动修改这个目录里面的文件,不然改乱了,就把Git仓库给破坏了。如果你没有看到.git目录,那是因为这个目录默认是隐藏的,用ls -ah命令就可以看见。
创建成功之后,可以使用git status命令查看当前仓库状态git status
当前没有分支,也没有可提交的文件
3.3把文件添加到版本库
-
使用vim创建一个read.me文件 ,随便输入一些内容:
aaaaaaaaaa. bbbbbbbbbb.
再次查看状态
提示我们使用git add命令将将要提交的文件包含到暂存区 -
使用git add命令,把文件添加到暂存区
$ git add readme.txt
再次查看状态 -
用命令git commit告诉Git,把文件提交到仓库:
$ git commit -m "wrote a readme file" read.me
参数-m后面输入的是本次提交的说明,可以输入任意内容,当然最好是有意义的,这样你就能从历史记录里方便地找到改动记录
4.时光穿梭(版本的回退与前进)
多次修改提交read.me文件
查看使用git log 命令查看read.me文件的历史版本(按q直接退出查看)
$ git log
如果嫌输出信息太多,看得眼花缭乱的,可以试试加上–pretty=oneline或者直接加上–oneline参数:
我们看到的那一大串黄色的字符串就是commit id(版本号),和SVN不一样,Git的commit id不是1,2,3……递增的数字,而是一个SHA1计算出来的一个非常大的数字,用十六进制表示,而且你看到的commit id和我的肯定不一样,以你自己的为准。为什么commit id需要用这么一大串数字表示呢?因为Git是分布式的版本控制系统,后面我们还要研究多人在同一个版本库里工作,如果大家都用1,2,3……作为版本号,那肯定就冲突了。
而我们看到的第一行数据显示的HEAD就是Git的指针,指向当前所处的版本
4.1 Git的前进和后退
-
使用^符号
$ git reset --hard HEAD^
可以看到,我们执行回退命令之后,版本回到了“7 commit”这个版本
注:一个^ 代表一个版本,n个 ^ 代表n个版本 -
使用~符号
当我们回退版本较多时,比如5个版本,那使用^符号就很麻烦,我们可以使用~符号来回退$ git reset --hard HEAD~5
可以看到版本直接回退了5个版本 -
基于索引值的操作
通过上面操作我们发现,当我们回退之后,git log只能看到当前所处版本之前的版本,之后的版本都不见了,那如果我们想重新回到之前的版本怎么办呢
首先我们可以使用$ git reflog
就可以查看到所有的版本
然后使用所引值,就可以去到其中的任意版本了
注:黄色部分字符串就是索引值的一部份,通过这一部分索引值,Git会自动去找。当然也不能只写前一两位,因为Git可能会找到多个版本号,就无法确定是哪一个了。$ git reset --hard 9e4e2d9
现在总结一下:
HEAD指向的版本就是当前版本,因此,Git允许我们在版本的历史之间穿梭,使用命令git reset --hard commit_id。
穿梭前,用git log可以查看提交历史,以便确定要回退到哪个版本。
要重返未来,用git reflog查看命令历史,以便确定要回到未来的哪个版本。
4.2 Git的撤销修改
- 撤销修改操作
$ git checkout -- filename
命令git checkout -- read.me
意思就是,把read.me文件在工作区的修改全部撤销,这里有两种情况:
一种是read.me自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;
一种是read.me已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。
总之,就是让这个文件回到最近一次git commit或git add时的状态。
git checkout -- filename
命令中的--
很重要,没有--
,就变成了“切换到另一个分支”的命令,我们在后面的分支管理中会再次遇到git checkout命令。
git checkout
其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。 - 撤销添加工作区
git reset HEAD <file>
我们可以看到,暂存区中的文件,重新放回工作区
4.3 Git的文件删除
在Git中,删除也是一个修改操作,我们实战一下,先添加一个新文件test.txt到Git并且提交:
一般情况下,你通常直接在文件管理器中把没用的文件删了,或者用rm命令删了rm test.txt
这个时候,Git知道你删除了文件,因此,工作区和版本库就不一致了,git status命令会立刻告诉你哪些文件被删除了:
现在你有两个选择,一种情况是删错了,因为版本库里还有呢,所以可以使用$ git checkout -- test.txt
很轻松地把误删的文件恢复到最新版本;
一是确实要从版本库中删除该文件,那就用命令git rm
删掉,并且git commit
5.添加远程库
你已经在本地创建了一个Git仓库后,又想在GitHub创建一个Git仓库,并且让这两个仓库进行远程同步,这样,GitHub上的仓库既可以作为备份,又可以让其他人通过该仓库来协作,真是一举多得。
-
登陆GitHub,然后,在右上角找到“New repositor”按钮,创建一个新的仓库:
在Repository name填入gitStudy,其他保持默认设置,点击“Create repository”按钮,就成功地创建了一个新的Git仓库:目前,在GitHub上的这个gitStudy仓库还是空的,GitHub告诉我们,可以从这个仓库克隆出新的仓库,也可以把一个已有的本地仓库与之关联,然后,把本地仓库的内容推送到GitHub仓库。 -
根据GitHub的提示,在本地的gitStudy仓库下运行命令:
git remote add origin git@github.com:wmx1234/gitStudy.git
请千万注意,把后面替换成你自己的GitHub账户名,否则,你在本地关联的就是我的远程库,关联没有问题,但是你以后推送是推不上去的,因为你的SSH Key公钥不在我的账户列表中。
添加后,远程库的名字就是origin,这是Git默认的叫法,也可以改成别的,但是origin这个名字一看就知道是远程库。 -
把本地库的所有内容推送到远程库上
$ git push -u origin master
把本地库的内容推送到远程,用git push
命令,实际上是把当前分支master推送到远程。由于远程库是空的,我们第一次推送master分支时,加上了-u
参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。推送成功后,可以立刻在GitHub页面中看到远程库的内容已经和本地一模一样:
6.从远程仓库克隆
上面我们讲了先有本地库,后有远程库的时候,如何关联远程库。但是假设我们从零开发,那么最好的方式是先创建远程库,然后,从远程库克隆。
-
登陆GitHub,创建一个新的仓库,名字叫gitskills:
我们勾选Initialize this repository with a README,这样GitHub会自动为我们创建一个README.md文件。创建完毕后,可以看到README.md文件:
-
远程库已经准备好了,用命令
git clone
克隆一个本地库
$ cd gitskills $ ls
如果有多个人协作开发,那么每个人各自从远程克隆一份就可以了。
你也许还注意到,GitHub给出的地址不止一个,还可以用https://github.com/wmx1234/gitskills.git这样的地址。实际上,Git支持多种协议,默认的git://使用ssh,但也可以使用https等其他协议。使用https除了速度慢以外,还有个最大的麻烦是每次推送都必须输入口令,但是在某些只开放http端口的公司内部就无法使用ssh协议而只能用https。 -
小结
要克隆一个仓库,首先必须知道仓库的地址,然后使用git clone命令克隆。
Git支持多种协议,包括https,但通过ssh支持的原生git协议速度最快。
7.分支管理
在版本回退里,你已经知道,每次提交,Git都把它们串成一条时间线,这条时间线就是一个分支。截止到目前,只有一条时间线,在Git里,这个分支叫主分支,即master分支。HEAD严格来说不是指向提交,而是指向master,master才是指向提交的,所以,HEAD指向的就是当前分支。
一开始的时候,master分支是一条线,Git用master指向最新的提交,再用HEAD指向master,就能确定当前分支,以及当前分支的提交点:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190422112254448.png
每次提交,master分支都会向前移动一步,这样,随着你不断提交,master分支的线也越来越长:
当我们创建新的分支,例如dev时,Git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev上:
你看,Git创建一个分支很快,因为除了增加一个dev指针,改改HEAD的指向,工作区的文件都没有任何变化!
不过,从现在开始,对工作区的修改和提交就是针对dev分支了,比如新提交一次后,dev指针往前移动一步,而master指针不变:
假如我们在dev上的工作完成了,就可以把dev合并到master上。Git怎么合并呢?最简单的方法,就是直接把master指向dev的当前提交,就完成了合并:
所以Git合并分支也很快!就改改指针,工作区内容也不变!
合并完分支后,甚至可以删除dev分支。删除dev分支就是把dev指针给删掉,删掉后,我们就剩下了一条master分支:
真是太神奇了,你看得出来有些提交是通过分支完成的吗?
下面开始实战。
- 创建dev分支,然后切换到dev分支
$ git checkout -b dev
git checkout
命令加上-b
参数表示创建并切换,相当于以下两条命令:
$ git branch dev
$ git checkout dev
- 用
git branch
命令查看当前分支:
$ git branch
git branch命令会列出所有分支,当前分支前面会标一个*号。
然后,我们就可以在dev分支上正常提交,新增一个README.me文件并保存
现在,dev分支的工作完成,我们就可以切换回master分支$ git checkout master
切换回master分支后,发现并没有readme.me文件,刚才添加的内容不见了!因为那个提交是在dev分支上,而master分支此刻的提交点并没有变:
现在,我们把dev分支的工作成果合并到master分支上:
$ git merge dev
git merge命令用于合并指定分支到当前分支。合并后,再查看readme.me的内容,就可以看到,和dev分支的最新提交是完全一样的。
合并完成后,就可以放心地删除dev分支了:
$ git branch -d dev
因为创建、合并和删除分支非常快,所以Git鼓励你使用分支完成某个任务,合并后再删掉分支,这和直接在master分支上工作效果是一样的,但过程更安全。
小结
Git鼓励大量使用分支:
查看分支:git branch
创建分支:git branch <name>
切换分支:git checkout <name>
创建+切换分支:git checkout -b <name>
合并某分支到当前分支:git merge <name>
删除分支:git branch -d <name>
其他分支问题见廖雪峰老师的官方网站
8.标签管理
8.1创建标签
在Git中打标签非常简单,首先,切换到需要打标签的分支上,命令:
$ git tag <name>
可以用命令git tag
查看所有标签:
默认标签是打在最新提交的commit上的。有时候,如果忘了打标签,比如,现在已经是周五了,但应该在周一打的标签没有打,怎么办?
方法是找到历史提交的commit id,然后打上就可以了:
$ git tag v0.9 <index>
注意,标签不是按时间顺序列出,而是按字母排序的。可以用git show <tagname>
查看标签信息:
还可以创建带有说明的标签,用-a
指定标签名,-m
指定说明文字:
$ git tag -a v0.1 -m "version 0.1 released" <index>
注意:标签总是和某个commit挂钩。如果这个commit既出现在master分支,又出现在dev分支,那么在这两个分支上都可以看到这个标签。
小结
命令git tag <tagname>
用于新建一个标签,默认为HEAD,也可以指定一个commit id;
命令git tag -a <tagname> -m "blablabla..."
可以指定标签信息;
命令git tag
可以查看所有标签。
8.2删除标签
如果标签打错了,也可以删除:
$ git tag -d <tagname>
Deleted tag ‘v0.1’ (was f15b0dd)
因为创建的标签都只存储在本地,不会自动推送到远程。所以,打错的标签可以在本地安全删除。
如果要推送某个标签到远程,使用命令git push origin <tagname>
或者,一次性推送全部尚未推送到远程的本地标签:
如果标签已经推送到远程,要删除远程标签就麻烦一点,先从本地删除:
然后,从远程删除。删除命令也是push,命令如下:
$ git push origin :refs/tags/v1.0
要看看是否真的从远程库删除了标签,可以登陆GitHub查看。
小结
命令git push origin <tagname>
可以推送一个本地标签;
命令git push origin --tags
可以推送全部未推送过的本地标签;
命令git tag -d <tagname>
可以删除一个本地标签;
命令git push origin :refs/tags/<tagname>
可以删除一个远程标签。
9.自定义Git
9.1忽略特殊文件
有些时候,你必须把某些文件放到Git工作目录中,但又不能提交它们,比如保存了数据库密码的配置文件啦,等等,每次git status都会显示Untracked files …,有强迫症的童鞋心里肯定不爽。
好在Git考虑到了大家的感受,这个问题解决起来也很简单,在Git工作区的根目录下创建一个特殊的.gitignore文件,然后把要忽略的文件名填进去,Git就会自动忽略这些文件。
不需要从头写.gitignore文件,GitHub已经为我们准备了各种配置文件,只需要组合一下就可以使用了。所有配置文件可以直接在线浏览:https://github.com/github/gitignore
常用的配置
#eclipse files
.classpath
.project
# Built application files
*.apk
*.ap_
# Files for the Dalvik VM
*.dex
# Java class files
*.class
# Generated files
/bin/
/gen/
/out/
# Gradle files
.gradle/
build/
# Local configuration file (sdk path, etc)
local.properties
# Proguard folder generated by Eclipse
proguard/
# Log Files
*.log
# Android Studio Navigation editor temp files
.navigation/
# Android Studio captures folder
captures/
# Intellij
*.iml
# Keystore files
*.jks
使用Windows的童鞋注意了,如果你在资源管理器里新建一个.gitignore文件,它会非常弱智地提示你必须输入文件名,但是在文本编辑器里“保存”或者“另存为”就可以把文件保存为.gitignore了。
有些时候,你想添加一个文件到Git,但发现添加不了,原因是这个文件被.gitignore忽略了:
如果你确实想添加该文件,可以用-f强制添加到Git:
或者你发现,可能是.gitignore写得有问题,需要找出来到底哪个规则写错了,可以用git check-ignore命令检查:
$ git check-ignore -v app.class
小结
忽略某些文件时,需要编写.gitignore;
.gitignore文件本身要放到版本库里,并且可以对.gitignore做版本管理!
9.3配置别名
有没有经常敲错命令?比如git status
,status这个单词真心不好记。
如果敲git st就表示git status那就简单多了,当然这种偷懒的办法我们是极力赞成的。
我们只需要敲一行命令,告诉Git,以后st就表示status:
$ git config --global alias.st status
好了,现在敲git st看看效果。
–global参数是全局参数,也就是这些命令在这台电脑的所有Git仓库下都有用。
在撤销修改一节中,我们知道,命令git reset HEAD file可以把暂存区的修改撤销掉(unstage),重新放回工作区。既然是一个unstage操作,就可以配置一个unstage别名:
$ git config --global alias.unstage 'reset HEAD'
当你敲入命令:
$ git unstage test.txt
实际上Git执行的是:
$ git reset HEAD test.txt
配置一个git last,让其显示最后一次提交信息:
$ git config --global alias.last 'log -1'
这样,用git last就能显示最近一次的提交:
甚至还有人丧心病狂地把lg配置成了:
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"
来看看git lg的效果:
配置文件
配置Git的时候,加上–global是针对当前用户起作用的,如果不加,那只针对当前的仓库起作用。
配置文件放哪了?每个仓库的Git配置文件都放在.git/config文件中:
$ cat .git/config
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
ignorecase = true
precomposeunicode = true
[remote "origin"]
url = git@github.com:michaelliao/learngit.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
remote = origin
merge = refs/heads/master
[alias]
last = log -1
别名就在[alias]后面,要删除别名,直接把对应的行删掉即可。
而当前用户的Git配置文件放在用户主目录下的一个隐藏文件.gitconfig中:
$ cat .gitconfig
[alias]
co = checkout
ci = commit
br = branch
st = status
[user]
name = Your Name
email = your@email.com
配置别名也可以直接修改这个文件,如果改错了,可以删掉文件重新通过命令配置。
小结
给Git配置好别名,就可以输入命令时偷个懒。我们鼓励偷懒。
10.搭建Git服务器
11.本地库既关联GitHub,又关联码云
如原来已经关联了默认名origin的GitHub
-
删除已关联的名为origin的远程库:
$ git remote rm origin
-
先关联GitHub的远程库:
$ git remote add github git@github.com:username/repositoryname.git
注意,远程库的名称叫github,不叫origin了
-
再关联码云的远程库:
$ git remote add gitee git@gitee.com:username/repositoryname.git
同样注意,远程库的名称叫gitee,不叫origin了
注意 多个关联后以上所以命令含的origin都换成相应的github或gitee
- 要推送到GitHub,使用命令:
$ git push github master
如果要推送到码云,使用命令:
$ git push gitee master