git 基础教程
原理
工作区和暂缓区
工作区就是指你电脑里面看到的目录,即电脑本地的修改,git还没有纳入到版本管理。 版本库即纳入git版本管理的内容,.git文件夹存放着版本库信息。版本库中存放了很多东西,其中最重要的是称为stage的暂存区。还有git默认为我们自动创建了一个master的分支,以及指向master的一个指针HEAD。
index &working tree&commit
working tree 表示工作区的改变,每当在代码中做了修改,working tree的状态就会改变。index file,是连接working tree和commit的桥梁。每当使用git add后,index file的状态就会改变。commit则表示代码库的状态。
操作
windows下安装git
msysgit是Windows版的Git,从http://msysgit.github.io/ 下载,然后按默认选项安装即可。 安装完成后,还需要最后一步设置,在命令行输入:
$ git config --global user.name "Your Name"
$ git config --global user.email "email@example.com"
$ git config --global core.autocrlf false #禁用crlf自动转换
$ git config --global core.safecrlf true #拒绝提交包含换行符的文件。
$ git config --global gui.encoding utf-8 #gui编码设置。
$ git config --global i18n.commitencoding utf-8 #提交编码设置。
$ git config --global i18n.logoutputencoding gbk #日志输出设置。
如果在windows下使用gitbash,右键点击,选择option,选择Text,地区选为zh_CN,字符集选为GBK。
git config
git的配置包括system global 和local三个级别,优先级从低到高。常用的为用户级别的global。local为当前仓库的配置信息。查看 配置使用如下命令:
git config --[system|global|local] --list
global的配置会生产在user目录下的.gitconfig文件中。
git add
用户将一个修改从工作区放到暂存区,这个过程也称为stage。
git add test.go
也可以使用正则表达式,如
git add *.txt
常用的是添加当前目录:
git add .
反之如果将暂存区的修改回退到工作区,称之为unstage。如
git reset test.go(状态变回modify)
unstage后,如果取消对test.go文件的修改,恢复为版本库中的状态,则使用
git checkout test.go
这个命令也可以用来恢复删除的文件。
git commit
- –amend:对上次的提交做修改,commitId也会被修改,不会产生新的提交。在修改很少的信息时,希望减少不必要的提交,amend很有用。 因为会对上次的提交改变commitId,所以在上次提交没有被推送时,才执行amend提交,否则会和远程库产生冲突。
git rm
删除文件。
git rm '*.txt'
git init
用于初始化一个git管理的文件夹,直接在命令行中,导向到目标文件夹中,执行git init
git diff
比如说,你早上上班记不清昨天修改了read.txt什么内容。可以使用命令查看:
git diff read.txt
git diff得到如下信息:
1 diff --git a/indexworkingtree.txt b/indexworkingtree.txt
2 index cb6c09d..e734c01 100644
3 --- a/indexworkingtree.txt
4 +++ b/indexworkingtree.txt
5 @@ -1,2 +1,5 @@
6 this is a test file
7 aim to understand working tree,index,commit
8 +
9 +add new line
10 +add new line second
第3-4行,—表示变动前的文件为a,+++表示变动后的文件为b。第5行中,-1,2表示a文件从第一行开始变动,一共改变了两行,+1,5表示b文件从第一行开始变动,一共修改了5行。6-10行表示两个文件改动部分的合并,前面为+表示增加,-表示删除,没有表示没有变动。
git diff –staged/git diff 显示working tree 和 index之间的不同, git diff –cached 表示index和commit之间的不同。 git diff HEAD 查看working tree 和commit之间的差别。
git log
git log命令可以查看到我们提交的历史记录
Administrator@SC-201506261217 MINGW64 /d/githubrepo/learndoc (master)
$ git log
commit c9893e7fd50f7a35df0f4be0a4a8c91c1a740117
Author: zhaoyu <zy4668@126.com>
Date: Thu Nov 26 10:55:03 2015 +0800
change markdown
commit da9a49e1117c31a2dd11d3585462d546892d2ab0
Merge: ce61285 2bb8e94
上面的显示可以看出我们最后一次提交为change markdown。 –pretty=oneline参数用于输出主要信息,省略其它信息:版本号和提交信息。
git reflog
如果你从最新的版本回退到旧的版本,然后再次退回到之前最新的版本,那么,就需要git reflog命令,git reflog命令记录了我们执行过的每一个命令。
$ git reflog
aacb99f HEAD@{0}: commit: chageit
cd4489f HEAD@{1}: commit (initial): init
根据上面显示的命令对应的版本号,我们可以回退到一个特定的版本。
git stash
git stash命令会将当前的工作空间“储存”起来,用HEAD重置working tree 和index。等以后恢复后继续工作,处理bug时非常有用,使用时:
git stash
在工作现场“储存”后,可以进行bug修复或者建立新分支等工作。恢复时使用
git stash apply
apply命令是保留了stash内容的,如果想恢复工作现场的同时删除stash内容,则使用pop命令:
git stash pop
使用list命令查看stash列表:
git stash list
如果有多个stash,则可以指定某个特定的恢复。
git stash apply stash@{0}
git ignore
git在工作区的目录下创建了一个.gitignore的文件,在这个文件中,把要忽略的文件名填进去,git自然会忽略这些文件。git文件需要提交到git库里。
有时候会碰到.gitignore无效,不能忽略某些文件, 现象:在.gitignore文件中添加了file1,以过滤该文件,但是通过git status查看,仍然能看到file1的状态。 原因:可能在file1在添加忽略文件之前,已经提交到git版本库。 解决方法:需要在git库中删除该文件,并更新。
git branch
git branch用于查看分支。
git branch #查看本地分支
git branch -a #查看所有分支,包括本地和远程的
如果后面跟分支名,就会创建一个新本地分支,如果分支已经存在,则返回错误。创建后依然停留在当前分支。
git branch dev
给分支重命名
git branch -m oldName newName
删除本地分支
git branch -d dev
强制删除本地分支
git branch -D dev
删除远程分支
git push origin --delete dev
推送本地分支到远程,有两个步骤:
-
创建远程分支。
git push origin branch1:branch1
-
关联远程分支。
git push -u origin remote_branch #-u 和--set-upstream相同
git checkout
git checkout可以操作文件和分支。
操作文件
git checkout filename # 从版本中检出某个文件,放弃对这个文件的修改。
git checkout . #放弃对当下目录的修改。
操作分支
git checkout master # 将当前分支切换到master。
git checkout -b dev # 如果dev分支存在,则只切换分支,如果不存在,创建dev本地分支,并切换到dev分支上。
git checkout -b dev origin/dev #将远程库上的dev分支拉去到本地,并建立关联。
detached-HEAD
detached-HEAD通常是由于执行了如下命令
git checkout origin/branch
导致HEAD指向了一个非本地分支,这种状态非常危险,解决方法是,将目前分支保存为一个临时分支,然后再合并到另一个分支。
git reflog
git branch temp 1ebf64
git checkout --track origin/anotherBranch
git merge temp
这样就可以放心操作了
git merge
如将dev分支合并到主分支 1, 切换到主分支
git checkout master
2, 合并分支
git merge dev
3, 如果有冲突,则手到解决冲突,所有冲突解决完,使用git status确认。
git status
4, 停止合并,在合并有错误或者自己想停止合并,则可以将合并取消。
git merge --abort #如果Git版本 >= 1.7.4
git reset --merge #如果Git版本 >= 1.6.1
5, 当git仓库的状态是Merging时,需要处理项目中冲突的文本,解决冲突并确认合并无误后,提交修改到暂缓区。
git add .
6, 提交。
git commit –m “info”
Fast Forward 快进模式,
默认的git merge 是快进模式,合并后只能看到合并分支的信息,而不能看到被合并分支的信息。
* 88d416f (HEAD -> master) merge dev
* 65d0477 add master
* 4855945 init
No Fast Forward(–no-ff)。
在merge的时候,带上–no-off参数,在合并的分支上,会看到被合并分支的信息。如下
* cde5be3 (HEAD -> master) merge dev
|\
| * e0c1d37 (dev) add dev info
* | 65d0477 add master
|/
* 4855945 init
–squash
默认的合并,会保留被合并分支中所有的提交,如果不想看到太多的无用commit信息,可以使用squash。 squash 参数,会将被合并分支的多个提交去除,在合并分支上只生产一次提交。
远程操作
远程操作需要本地关联远程库,默认在git clone时,会创建remotes/origin/master 分支,origin是运行clone时默认创建的远程仓库代码,可以使用-o修改。
git clone
- 登陆GitHub,创建一个新的仓库,如learndoc
-
查看GitHub的git库的地址,在客户端gitbash中输入如:
git clone git@github.com:michaelliao/learndoc.git
git clone会在本地创建一个master分支和remotes/origin/master 分支。
-
如果是使用ssh下载,有可能弹出如下错误
The authenticity of host 'github.com (192.30.252.129)'can't be established.
在接下来的命令中输入yes继续尝试。
git remote
git remote 用于操作远程库,默认本地关联的远程库名称为origin。
git remote -v
用于查看远程库的地址信息,有fetch和push。如下:
origin git@github.com:lovexiaoe/learndoc.git (fetch)
origin git@github.com:lovexiaoe/learndoc.git (push)
更新远程分支,让本地和远程同步。
git remote update origin --prune
将已有文件夹,提交到远程库:
- 在文件夹下初始化git:
git init
- 关联远程库
git remote add origin git@120.25.147.61:zhaoyu/helpdrive.git
- 提交本地代码
git add . & git commit -m "init"
- 推送到远程库
git push -u origin master
或者
git push --set-upstream origin master
第一条命令要保证远程库分支存在,如果不存在,无法进行关联,第二条即使远程库没有你关联的分支,它会自动创建并关联。
git fetch
将远程主机的最新内容拉到本地,用户在检查了以后决定是否合并到工作区中。如下,拉取master到本地库。
git fetch origin master
git pull
将远程库的最新内容直接拉到工作区中,git pull = git fetch + git merge。
git pull origin master --allow-unrelated-histories
git 库和操作之间的关系如下:
git tag
执行打标签的一些列操作。标签用于记录版本,主要用于发布等场景,通常在发布的时候打上标签。
查看所有的标签。显示的结果按字母排列。
git tag
如果对特定名称的标签感兴趣,可以使用-l结合通配符查询。
git tag -l 'v1.2.*'
使用-a添加一个标签,使用-m 表示标签注释。
git tag -a v1.2.3 -m "1.2.3发布版"
获取项目最后的tag
git describe --tags `git rev-list --tags --max-count=1`
git push 并不会将tags推送到远程库,需要使用下面的命令。
git push origin v1.0
git push --tagas #推送所有tags。
git revert
git revert 用于去除了参数指明的历史提交,并生产一次新的提交,以前的历史记录不变。具体操作如下。
- 假设我们现在有如下提交:
d3e93a7 (HEAD -> master) HEAD@{0}: commit: version4 306dbc7 HEAD@{1}: commit: version3 f6922a1 HEAD@{2}: commit: verions2 4c4b831 HEAD@{3}: commit: version1
- 提交version2和version3由于代码有问题,我们需要去除。那么我们可以使用如下命令进行处理。
git revert --no-commit 4c4b831..306dbc7
revert后面的表达式是一个前开后闭的区间。即包括4c4b831,而包括了306dbc7。所以去除的是verion2和version3。
注意:revert 命令会对每个去除的 commit 进行一次提交,–no-commit 后可以只生产一次提交。 如果revert的时候,代码有冲突,那么revert会报错,并且提交进入“REVERTING”状态 - 我们需要解决代码冲突,提交代码,执行
git revert --continue
-
重复以上两个步骤,直到REVERTING状态消失。
- 去除一组历史提交在代码冲突的情况下,操作过于复杂。所以建议每次去除单个提交,命令如下:
git revert 306dbc7
- 最常用的就是去除HEAD提交,不会存在代码冲突。可以回滚最后一次提交,并生产一次新的提交。
git revert HEAD
git reset
将HEAD指针指到指定提交,历史记录中不会出现放弃的提交记录。 git reset 一共有两种用法,
- 是在reset后加版本号,可以回退版本,如:
git reset c9893e 或者 get reset HEAD^ (HEAD^表示HEAD的上一个版本)
git reset 常用的参数有–soft,–mixed,–hard。
- –soft只回退commit信息。不会回退index,是git commit的反操作。如果要保留修改,推荐使用。
- –mixed(默认),回退commit信息,并回退index。并将修改回退到工作区,是git add和git commit都执行的反操作。比较麻烦,stash等操作会冲突。不推荐使用。
- –hard重置,回退commit信息,index,和工作区,所有的文件修改会丢失,谨慎使用。
- 是用于文件,将暂存区的文件unstage,将修改还原到工作区,相当于git add的反操作,如:
git reset test.go
如果本地库和远程库的版本保持一致,那么因为reset之后本地库落后于远程库一个版本,需要使用-f参数强制提交,才能推送到远程库。
git reset --hard HEAD^
git push origin master -f
SSH方式访问github
-
创建SSH Key。在用户主目录下,看看有没有.ssh目录,如果有,再看看这个目录下有没有id_rsa和id_rsa.pub这两个文件,如果已经有了,可直接跳到下一步。如果没有,打开Shell(Windows下打开Git Bash),创建SSH Key:
$ ssh-keygen -t rsa -C "your-email@example.com"
-
一路回车,使用默认值即可,由于这个Key也不是用于军事目的,所以也无需设置密码。如果成功,会在主用户目录下生成加密文件。
-
登陆GitHub,打开“Account settings”,“SSH Keys”页面。然后,点“Add SSH Key”,填上任意Title,在Key文本框里粘贴id_rsa.pub文件的内容:
-
点击Add key添加ssh key。一个账号可以添加多个key,用于在ssh方式访问github服务器时使用。
ssh方式访问速度快,不需要每次访问时认证。
-
检查SSH key是否有效,在git bash中输入:
ssh -T git@github.com
会出现如下的提示信息:The authenticity of host 'github.com (IP ADDRESS)' can't be established. RSA key fingerprint is 16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48. Are you sure you want to continue connecting (yes/no)?
输入yes,如果成功会出现如下提示信息:
Hi username! You've successfully authenticated, but GitHub does not provide shell access.
如果失败,则根据对应的信息解决。
-
对于HTTPS clone的项目,提交时不会使用SSH 方式。这就需要修改.git目录下的config文件,将url改为如下的git格式:
url = git@github.com:akmumu/retina-data.git
清除历史提交记录
有时候在历史中提交了密码等敏感信息,或者历史过多,那么,我们需要清楚提交历史。
- 创建独立的新分支
git checkout --orphan <branch_name>
–orphan 选项,创建一个独立分支并切换到该分支,该分支没有历史提交记录。
- 将文件进行提交
git add . git commit -m "<message>"
- 删除需要清除历史记录的分支,并将当前分支名修改为该分支
git branch -D master git branch -m master
- 关联本地分支到远程
git branch --set-upstream-to=origin/master
- 将本地更改推送到远程分支
git push -f origin master
错误以解决方法
index file smaller than expected
因为索引文件已经毁坏,我们可以重新建立。首先是移除它,然后重新添加到工作区
rm .git/index
git add .