Git学习笔记
IC 设计中常常使用 Git 做版本控制,本篇博客记录一下 Git 的学习和理解。
Git 本地有三个工作区域:工作目录(Working Directory)、暂存区(Stage/Index)、资源库(Repository或Git Directory)。如果在加上远程的 Git 仓库(Remote Directory)就可以分为四个工作区域。文件在这四个区域之间的转换关系如下:
- Workspace:工作区,就是你平时存放项目代码的地方。
- Index / Stage:暂存区,用于临时存放你的改动,事实上它只是一个文件,保存即将提交到文件列表信息。
- local repository:本地仓库,就是安全存放数据的位置,这里面有你提交到所有版本的数据。其中HEAD指向最新放入仓库的版本。
- Remote repository:远程仓库,托管代码的服务器,可以简单的认为是你项目组中的一台电脑用于远程数据交换。
绝大多数时候,可以只用下面4个命令就能完成简单的 Git 操作。
git add file1 file2
git commit -m "commit message"
git pull
git push
1、git创建和连接
1.1 注册Gitee/Github
推荐使用 Gitee,网速快,中文显示。熟练后可以去 Github 上操作,自由翱翔。注册账号后添加公钥,就可以开始了~
- gitee网址:https://gitee.com/
- github网址:https://github.com/
添加公钥的视频教学:【狂神说Java】Git最新教程通俗易懂, 视频同步笔记:狂神聊Git
1.2 下载Git工具
(1)下载 Git工具,除安装位置的选项外,其他选项可以一键到底,无脑安装;
(2)鼠标空白处点击右键可看到新增了Git选项;
- Git GUI Here 为 Git 的图像界面,不推荐使用
- Git Bash Here 为 Git 的命令行界面,可以在这使用 Git 或练习 Linux 命令
(3)鼠标右键点击 Git Bash Here,进入 Git 命令行界面,输入如下类似代码设置 Git。
git config --global user.name "xianyu"
git config --global user.email "xxx@qq.com"
1.3 连接仓库
在 Gitee 上点击右上角的 “➕”号新建仓库,命名“GitTest”,设置仓库地址。
(1)git clone(推荐)
不管远程仓库是不是空白的,git clone 都能适用。
(1)Windows 下鼠标右键选择“Git Bash here”进入 git 命令行。
(2)执行“git clone https://gitee.com/xianyu_IC/GitTest.git”,git 就会下载该仓库为本地目录,进入该目录就能正常进行 git 操作了。
(3)执行“ll -a”,可以看到本地目录多了个“.git”文件,表示该目录已处于被 git 版本管理的状态。
(2)git init
gitee 上新建仓库时,下面的选项勾选和不勾选是不一样的结果,如下所示:
- 不勾选“初始化仓库”和“设置模板”,创建的是完全空白的仓库,如果用 git init,需要提交新文件后才能 git push 成功。
- 勾选了“初始化仓库”和“设置模板”,创建的是已有文件的仓库,如果用 git init,后面需要执行 git pull --rebase origin master 后才能 git push 成功。
如果是空白仓库,那么需要为空白仓库创建第一个文件,并传到远程仓库上。
git init
touch README.md
git add README.md
git commit -m "first commit"
git remote add origin https://gitee.com/xianyu_IC/GitTest.git
git push -u origin master
执行“ll -a”,可以看到本地目录多了个“.git”文件,表示该目录已处于被 git 版本管理的状态。
如果不是空白仓库,自己本地仓库内容肯定和远程仓库不一样,那么 push 前需要先执行下面这条命令。
git pull --rebase origin master
这样能够把远程仓库同步到本地仓库,再执行 git push -u origin master 就能成功了。由于前面 git push 时加入了 -u 操作,即默认连接了此仓库,那么后续再有新文件需要上传,不用再敲那么长,只需要执行“git push”即可,不过仍然建议 git push 前先执行下 git pull,看看是否和远程仓库冲突。
2、git查询和比较
2.1 文件状态
Git 中的文件有 4 种状态,如下所示:
-
Untracked: 未跟踪, 此文件在文件夹中, 但并没有加入到git库, 不参与版本控制. 通过
git add
状态变为Staged
. -
Unmodify: 文件已经入库, 未修改, 即版本库中的文件快照内容与文件夹中完全一致. 这种类型的文件有两种去处, 如果它被修改, 而变为
Modified
. 如果使用git rm
移出版本库, 则成为Untracked
文件 -
Modified: 文件已修改, 仅仅是修改, 并没有进行其他的操作. 这个文件也有两个去处, 通过
git add
可进入暂存staged
状态, 使用git checkout
则丢弃修改过, 返回到unmodify
状态, 这个git checkout
即从库中取出文件, 覆盖当前修改 -
Staged: 暂存状态. 执行
git commit
则将修改同步到库中, 这时库中的文件和本地文件又变为一致, 文件为Unmodify
状态. 执行git reset HEAD filename
取消暂存, 文件状态为Modified
那么首先需要学会如何查询自己的 Git 状态,使用命令 git status,如下所示:
# 查看所有文件状态
$ git status
# 查看指定文件的状态
$ git status [file1] [file2] ...
2.2 常用查询
下面几个命令是常用的查询命令,文章后面内容也会提及,这里只是简单记录。
#============================================= 暂存区
# 查看暂存区的文件列表
$ git ls-files -s
# 指定编号查看暂存区文件内容
$ git cat-file -p 文件编号
# 打开git gui工具查看暂存区文件内容
$ git gui
#============================================= 提交记录
# 查看提交记录
$ git log
# 查看提交记录,简略方式
$ git log --oneline
# 查看提交记录,图形方式
$ git log --graph
# 查看提交记录,简略+图形
$ git log --oneline --graph
# 查看所有提交记录和HEAD编号,包括已撤销编号
$ git reflog
#============================================= 分支
# 查询所有本地分支
$ git branch
# 查询所有远程分支
$ git branch -v
# 查询所有本地和远程的分支
$ git branch -a
#============================================= 标签
# 查询所有tag
$ git tag
# 查询tag详细信息
$ git show [tag]
#============================================= 别名
# 显示远程仓库所有别名,默认是origin
$ git remote
# 显示远程仓库所有别名和其网址
$ git remote -v
2.3 文件比较
git diff 命令可以查看文件之间的差异。
# 显示暂存区和工作区的差异
$ git diff
# 显示暂存区和上一个commit的差异
$ git diff --cached [file]
# 显示工作区与当前分支最新commit之间的差异
$ git diff HEAD
# 显示两次提交之间的差异
$ git diff [first-branch]...[second-branch]
# 显示今天你写了多少行代码
$ git diff --shortstat "@{0 day ago}"
2.4 HEAD说明
进行撤销、回退、检出等操作时,经常使用到 HEAD,它只存在于仓库区,实际是一个指针,它的含义如下所示:
#查看HEAD版本号
git reflog
#当前版本
HEAD
HEAD^0
HEAD~0
#上一版本
HEAD^
HEAD^1
HEAD~
HEAD~1
#上上版本
HEAD^^
HEAD~~
HEAD~^
HEAD~2
#上n版本
HEAD~n
3、git工作区到暂存区
首先了解一下 Git 的工作区和版本库的区别:
- 工作区(Working Directory):即是你在电脑里能看到的目录。
- 版本库(Repository)工作区有一个隐藏目录
.git
,这个不算工作区,而是Git的版本库。
Git的版本库里存了很多东西,其中最重要的就是称为 stage(index)的暂存区,还有Git为我们自动创建的第一个分支master
,以及指向master
的一个指针叫HEAD
。
3.1 git add添加
新增文件或者修改了文件,该文件都会变成 untracked状态,即未跟踪状态。将 untracked 状态的文件添加到暂存区的语法格式如下:
#添加指定文件到暂存区
git add <file1> <file2> ...
#添加指定目录到暂存区,包括子目录
git add <dir>
#添加当前目录的所有文件到暂存区
git add .
3.2 git rm删除
执行了 git add,但希望删除某个文件的添加,可以执行下面几种方式:
#删除暂存区文件,不影响工作区原文件
git rm --cached <file>
#删除暂存区文件和工作区原文件,二者必须内容一致
git rm <file>
#强制删除暂存区文件和工作区原文件,二者可以内容不一致
git rm -f <file>
3.3 git reset/restore恢复
执行 git add 添加了很多文件到暂存区,想撤销又不想动到工作区原文件,可以用 git rm 一点点删除,也可以执行 reset 或 restore。恢复暂存区其实也就是撤销 git add。
#暂存区复位,可选版本和文件,不影响工作区
git reset [HEAD] <file>
#暂存区恢复,必须指定文件,不影响工作区
git restore --staged <file>
3.4 git checkout检出
工作区修改或删除了某个文件,想要恢复成原先的文件内容,可以执行 checkout。
#从暂存区检出所有文件到工作区
git checkout .
#从暂存区检出指定文件到工作区
git checkout <file>
git restore --<file>
#从仓库区检出所有文件到暂存区和工作区
git checkout HEAD .
#从本地仓库检出指定文件到暂存区和工作区
git checkout HEAD <file>
3.5 git clean清空
下面指令可以在工作区中,将所有未被 Git 跟踪的文件全部清空。
git clean -df
3.6 .gitignore忽略
有些时候我们不想把某些文件纳入版本控制中,比如数据库文件,临时文件,设计文件等,可以在主目录下建立".gitignore"文件,此文件有如下规则:
- 忽略文件中的空行或以井号(#)开始的行将会被忽略。
- 可以使用Linux通配符。例如:星号(*)代表任意多个字符,问号(?)代表一个字符,方括号([abc])代表可选字符范围,大括号({string1,string2,...})代表可选的字符串等。
- 如果名称的最前面有一个感叹号(!),表示例外规则,将不被忽略。
- 如果名称的最前面是一个路径分隔符(/),表示要忽略的文件在此目录下,而子目录中的文件不忽略。
- 如果名称的最后面是一个路径分隔符(/),表示要忽略的是此目录下该名称的子目录,而非文件(默认文件或目录都忽略)。
#为注释
*.txt #忽略所有 .txt结尾的文件
!lib.txt #但lib.txt除外
/temp #仅忽略项目根目录下的TODO文件,不包括其它目录temp
build/ #忽略build/目录下的所有文件
doc/*.txt #会忽略 doc/notes.txt 但不包括 doc/server/arch.txt
4、git暂存区到仓库区
4.1 git commit提交
通过 add 只是将文件或目录添加到了 index 暂存区,使用 commit 可以实现将暂存区的文件提交到本地仓库。
#提交暂存区到仓库区
git commit -m "commit message"
#提交暂存区的指定文件到仓库区
git commit [file1] [file2] ... -m "commit message"
#跳过add,直接提交工作区文件到仓库区,对新文件无效
git commit -am "commit message"
#提交时显示所有diff信息
git commit -v
#修订上一次提交,文件无变化则只修订提交信息
git commit --amend -m "commit message"
4.2 git reset回退
假如现在仓库区的版本为 v1、v2、v3、v4,执行 git reset 指令可以移动 HEAD 到指定的版本,例如移动到 v3。如果修改文件后重新提交,那么下一个版本会是 v5。输入 ”git log --oneline“会发现 v4 消失了,相当于 v5 是新的分支一样。其实 v4 还在,执行 ”git reflog“即可找到 v4 版本。
#仓库区的HEAD指向上一版本,不影响暂存区和工作区
git reset --soft HEAD~
#仓库区的HEAD指向上一版本,影响暂存区,不影响工作区
# --mixed可以省略
git reset [--mixed] HEAD~
#仓库区的HEAD指向上一版本,影响暂存区,影响工作区
git reset --hard HEAD~
这个操作进行”git push“时会报错,因为本地仓库HEAD指向的版本比远程仓库的要旧,可以改用“git push -f”强制推上去就行了。
4.3 git revert重交
如果不想出现这种 v4 不好找的问题,可以用指令 git revert,它会将回退的版本取出来,修改后再提交,就是对这个版本的重新提交,它不会让之前的这个版本消失,也不会让中间的某些版本消失。
#取出某个版本
git revert -n <commit_id>
#重新提交
git commit -m "commit message"
参考博客:git回滚reset、revert、四种模式,超级详细
4.4 git checkout游离
前面提到过,如果执行”git checkout [HEAD] file“可以将暂存区或仓库区文件,检出到工作区和暂存区。如果不加 file 选项,则是另一种现象。如下所示:
#HEAD游离到指定版本
git checkout HEAD~2
git checkout <commit_ID>
这时 HEAD 游离到"匿名分支",Git 界面提示现在处于 "detached HEAD" 阶段,当前的工作区和暂存区也都是那个版本的文件。我们可以在这里取出所需的文件到别的文件夹,也可以在这里做临时的实验并进行 commit 提交,但是这些提交是匿名分支的提交,不会破坏原先的提交记录,也无法进行 push。
如果需要回到正常的版本中,可以执行如下指令:
#HEAD回到master
git checkout master
如果希望这些 commit 提交变成真正的分支,可以根据 Git 界面提示,采用下面这个指令。
git checkout -b <new-branch-name>
该操作一般用于寻找之前的某个版本的文件,结束后又回去正常的分支。
参考博客:Git 图解剖析
5、git本地仓库到远程仓库
5.1 git clone克隆
git clone 可以拷贝一个 Git 仓库到本地,让自己能够查看该项目或者进行修改并提交。进入生成的目录下,里面工作区、暂存区、本地仓库区和远程仓库区的内容是一致的。
git clone [-b {tag}] [url] [本地目录名]
- [-b {tag}] 可以指定仓库的某个分支或tag,不写则默认master分支。
- [url] 是远程仓库地址,支持 HTTPS 协议和 SSH 协议。
- [本地目录名] 是可选项,如果不写则默认采用 [url] 中的名称。
5.2 git fetch取出
一旦远程主机的版本库有了更新(Git术语叫做commit),需要将这些更新取回本地,这时就要用到git fetch
命令。
#取回所有远程仓库的最新内容
git fetch
#取回指定仓库分支的最新内容
git fetch [远程仓库名] [分支名]
例如我和小明同时工作,小明上传了新文件,我执行 git fetch 后能把所有远程仓库的最新内容,取回的内容不会影响到工作区和暂存区,而是以匿名版本的形式存在我的本地仓库,那么我可以采用下面操作
#查询本地分支和远程分支的名称
git branch -r
#游离到取回的分支,例如 origin/master
#注意,HEAD处于游离状态
git checkout [仓库名/分支名]
#知晓更新后,可以为此新建为我本地分支
git checkout -b newBranch origin/master
#也可以回到我主分支,进行内容合并
git checkout master
git merge origin/master
#最后上传我合并后的内容
git push
5.3 git pull更新
git pull
命令的作用是,取回远程主机某个分支的更新,再与本地的指定分支合并。它的完整格式稍稍有点复杂。
#指定远程仓库分支拉到本地分支,并合并
git pull [远程仓库] [远程分支] : [本地分支]
#如果远程仓库和分支都已建立了追踪关系
git pull
#将更新的远程仓库同步到本地
git pull --rebase
其实 git pull 命令,旧等同于 “git fetch + git merge”
一般建议 git push 前先执行下 git pull,内容合并后再执行 git push。
5.4 git push推送
git push
命令用于将本地分支的更新,推送到远程主机。它的格式与git pull
命令相仿。
#指定本地分支推送到指定的远程仓库分支
git push [远程仓库] [本地分支] : [远程分支]
#如果远程仓库和分支都已建立了追踪关系
git push
#如果远程仓库的版本比本地仓库更新,可以强制推送
git push -f
#将标签一起推送
git push --tags
#设置默认仓库,之后可以直接git push
git push -u remote_name
5.5 git remote别名
使用了 git init 或者需要新增远程仓库时,就需要使用到 git remote 命令,它用于在远程仓库的操作,而远程仓库的默认名为 origin。
#显示远程仓库所有别名,默认是origin
git remote
#显示远程仓库所有别名和其网址
git remote -v
#新增远程仓库别名并连接远程仓库
git remote add name [url]
#删除远程仓库别名
git remote rm name
#修改远程仓库别名
git remote rename old_name new_name
实际使用时,往往用于本地仓库同时关联多个远程仓库,并希望同时推送,例如同时推送到 gitee 和 github:
#add gitee
git remote add gitee git@gitee.com:xxx/test-1.git
#add github
git remote add github git@github.com:xxx/test-1.git
#git push
git push gitee master && git push github master
如果希望默认只推送到gitee上,可以执行下面指令,以后执行 git pull 时旧默认推送到该远程仓库。
#设置默认连接关系
git push -u gitee
6、git分支与合并
项目常常需要多人开发,分支的出现很好的解决了这个问题。大家往往在分支上进行自己的开发,然后合入到主分支 master 上。如下所示:
6.1 git branch分支
git branch 可以对分支进行操作,如下所示:
#======================================================= 列出分支
# 列出所有本地分支
$ git branch
# 列出所有远程分支
$ git branch -r
# 列出所有本地分支和远程分支
$ git branch -a
# 图形方式查看分支图
$ git log --gpraph --oneline
#======================================================= 新建分支
# 新建一个分支,但依然停留在当前分支
$ git branch [branch]
# 新建一个分支,并切换到该分支
$ git checkout -b [branch]
# 新建一个分支,指向指定commit
$ git branch [branch] [commit]
# 新建一个分支,与指定的远程分支建立追踪关系
$ git branch --track [branch] [remote-branch]
# 建立追踪关系,在现有分支与指定的远程分支之间
$ git branch --set-upstream [branch] [remote-branch]
#======================================================= 删除分支
# 删除分支,该分支已合并
$ git branch -d [branch]
# 强制删除分支,该分支未合并
$ git branch -D [branch]
# 删除远程分支
$ git push origin --delete [branch]
$ git branch -dr [remote/branch]
6.2 git checkout切换
开始我们都是在主分支 master 上,执行新建分支后,仅仅是新增了一个指针,工作区和暂存区内容是没有变的。如果要到分支上,需要采用 git checkout 命令。
# 新建一个分支,并切换到该分支
$ git checkout -b [branch]
# 切换到指定分支,并更新工作区
$ git checkout [branch]
# 切换到上一个分支
$ git checkout -
注意:
- git checkout commit_ID/HEAD~/fetch_branch:HEAD 处于游离状态,可以新增和提交文件,但无法 push,必须新建该分支或者 merge 到主分支
- git checkout [~] file:用于从暂存区或仓库区检出文件到工作区和暂存区。
6.3 git merge合并
某个分支内容开发完毕,需要合并到当前分支,可以用 git merge。
记住要先进入到想合并进的分支上再执行,例如先执行下 git checkout master。
# 合并指定分支到当前分支
$ git merge [branch]
# 选择一个commit,合并进当前分支
$ git cherry-pick [commit]
# 舍弃合并过程,回到合并前状态
$ git merge --abort
如果分支上需要获取最新的master分支的文件,可以执行下面操作:
git pull origin master
6.4 git rebase变基
git rebase 类似 git merge,它将分支的起始位置添加到变基后的位置(原先分支记录隐匿,可以用git reflog找到)。git rebase 可以让项目提交历史变得非常干净整洁,它消除了git merge操作所需创建的没有必要的合并提交,造就一个线性的项目提交历史——也就是说你可以从 origin 分支的顶部开始向下查找到分支的起始点,而不会碰到任何历史分叉。不过rebase操作丢失了合并提交能够提供的上下文信息——所以你就很难知道功能分支是什么时候应用了上游分支的变更。
git rebase的命令格式如下所示,记住要先进入到想变基的分支上再执行,例如先执行下 git checkout master。
# 变基指定分支
$ git rebase [branch]
# 交互式变基,可以详细编辑提交信息
$ git rebase -i [branch]
# 放弃变基,回到变基之前状态
$ git rebade --abort
# 解决某个冲突后,继续变基进程
$ git rebase --continue
如果执行 git pull 时,远程仓库的版本更新,那么需要先merge,也可以先用下面指令同步远程仓库。
git pull --rebase
git rebase 时也会发生冲突,如果有 10 个冲突,解决第一个后需要“git add”然后执行“git rebase --continue”,然后继续解决下一个冲突,略微麻烦。
参考博客:深入理解git rebase 、深入理解git rebase(二)
6.5 解决冲突
如果同一个文件在两个分支上的内容不同,合并时就会报错说冲突(分支有新文件则不会报冲突),那就需要解决冲突后才能继续合并。例如 master 和 dev 分支的 file11.txt 内容不同,进行合并时出现了冲突:
之后我们处于特殊的“master|MERGING”状态,打开 file11.txt 文件,发现它是这样的:
手动修改该文件,然后重新添加和提交,就能够解决该冲突,并离开“master|MERGING”状态。
可以用下面指令查看分支合并图。
git log --graph --oneline
7、git标签
git tag 其实就是 commit 的标识符,它很简单也很常用。
#================================= 查看tag
# 列出所有tag
$ git tag
# 查看tag信息
$ git show [tagName]
#================================= 新建tag
# 新建一个tag在当前commit
$ git tag [tagName]
# 新建一个tag在指定commit
$ git tag [tagName] [commitID]
# 新建一个分支,指向某个tag
$ git checkout -b [branch] [tagName]
#================================= 提交tag
# 提交指定tag
$ git push origin [tagName]
# 提交所有tag
$ git push origin --tags
#================================= 删除tag
# 删除本地tag
$ git tag -d [tagName]
# 删除远程tag
$ git push origin :refs/tags/[tagName]
git tag 比较简单,不懂可以再去百度。
8、git图形工具
在安装 Git 的同时,你也装好了它提供的可视化工具,gitk
和 git gui
。
8.1 gitk使用
在命令行输入“gitk”就可以调出gitk工具了,它相当于 git log 的加强版。
#打开gitk工具
gitk
#打开gitk工具,查看所有提交记录
gitk -all
8.2 git gui使用
在命令行输入“git gui”就可以调出gui工具了,它可以方便的查看工作区和暂存区的文件和内容,也可以进行各种 git 操作。
9、git命令速查表
参考资料:
- 【狂神说Java】Git最新教程通俗易懂, 视频同步笔记:狂神聊Git
- 深入浅出Git教程(转载)
- git基础使用教程
- 菜鸟网-Git教程
- Git命令学习,过关式的学习Git命令
- Git大全,包含Git推荐资料和常用的Git命令,可以常常查阅。