一、基础名词解释
workspace:工作区
stage/index:暂存区
repository:仓库
remote:远程仓库
二、Git文件状态
文件的状态通常可以分为:
- 不受版本控制的
untracked状态 - 受版本控制并且已修改的
modified状态 - 受版本控制已修改并提交到暂存区的
staged状态 - 从暂存区已经提交到本地仓库的
committed状态 - 提交到本地仓库未修改或者从远程仓库克隆下来的
unmodified状态
三、Git回退命令
通过命令实现文件状态的“倒退”,进而达到回退操作的目的。
git checkout
这个命令的作用就是它单词的本义——检出,他的常用操作也取自这个意思,比如 git checkout branch_name 切换分支操作,实际上就是把指定分支在仓库中对应的所有文件检出来覆盖当前工作区,最终表现就是切换了分支。
而针对于文件的检出可以使用 git checkout -- file_name,当不指定 commit id 就是将暂存区的内容恢复到工作区,也就可以达到回退本地修改的作用。
不过,这个身兼数职的 git checkout 命令现在可以轻松一些了,从 Git 2.23 版本开始引入了两个新的命令:git switch 用来切换分支,git restore用来还原工作区的文件。
git revert
revert 这个词的意思是:归还,复原,回退,它和后面即将提到的 restore 在意思上简直无法区分,为了区别他们两个这里可以把 git revert 看成归还的意思,对某次提交执行 git revert 命令就是对这次修改执行一个归还操作,其实就是反向再修改一次。
要理解 git revert 就要从反向修改的含义来看,当我们再一个文件中添加一行内容,并提交到版本库后,产生一个提交id——commit-id-a,如果这时使用 git revert commit-id-a 命令,就相当于在工作区中的那个文件将刚在新加的一行内容删除掉,然后再进行一个提交。
注意,这个操作是会改变分支记录的,因为产生了新的提交。
git restore
这个命令是 Git 2.23 版本之后新加的,用来分担之前 git checkout 命令的功能,作用就是用暂存区或者版本库中的文件覆盖本地文件的修改可以达到回退修改的目的,同时也可以使用版本库中的文件覆盖暂存区的文件,达到回退git add 命令的目的。
注意,这个操作是不会影响分支记录的,就是相当于之前的 git checkout 命令重新检出一份文件来覆盖本地的修改。
git reset
reset 重新设置的意思,其实就是用来设置分支的头部指向,当进行了一系列的提交之后,忽然发现最近的几次提交有问题,想从提交记录中删除,这是就会用到 git reset 命令,这个命令后面跟 commit id,表示当前分支回退到这个 commit id 对应的状态,之后的日志记录被删除,工作区中的文件状态根据参数的不同会恢复到不同的状态。
-
--soft: 被回退的那些版本的修改会被放在暂存区,可以再次提交。
-
--mixed: 默认选项,被回退的那些版本的修改会放在工作目录,可以先加到暂存区,然后再提交。
-
--hard: 被回退的那些版本的修改会直接舍弃,好像它们没有来过一样。
这样来看,git reset 命令好像是用来回退版本的,但是如果使用 git reset HEAD file_name 命令就可以将一个文件回退到 HEAD 指向版本所对应的状态,其实就是当前版本库中的状态,也就相当于还原了本地的修改。
git rm
临时插播的命令,本来删除不能算是回退,但是如果它和某些命令反着来就是一种回退,比如对一个新文件使用 git add newfile_name 命令,然后再使用git rm --cached newfile_name 就可以将这个文件从暂存区移除掉,但是在工作区里没有消失,如果不加 --cached 参数,就会从工作区和版本库暂存区同时删除,相当于执行了 rm newfile_name 和 git add new_file 两条命令。
四、Git常用指令
1、新建代码库
在当前目录新建一个Git代码库
git init
新建一个目录,将其初始化为Git代码库
git init [project-name]
下载一个项目和它的整个代码历史
git clone [url]
2、增加/删除文件
添加指定文件到暂存区
git add [file1] [file2] ...
添加指定目录到暂存区,包括子目录
git add [dir]
添加当前目录的所有文件到暂存区
git add .
对于同一个文件的多处变化,可以实现分次提交
git add -p
删除工作区文件,并且将这次删除放入暂存区
git rm [file1] [file2] ...
3、代码提交
提交暂存区到仓库区
git commit -m [message]
提交暂存区的指定文件到仓库区
git commit [file1] [file2] ... -m [message]
提交工作区自上次commit之后的变化,直接到仓库区
git commit -a
提交时显示所有diff信息
git commit -v
将add和commit合为一步
git commit -am 'message'
使用一次新的commit,替代上一次提交,如果代码没有任何新变化,则用来改写上一次commit的提交信息
git commit --amend -m [message]
重做上一次commit,并包括指定文件的新变化
git commit --amend [file1] [file2] ...
4、分支
列出所有本地分支
git branch
列出所有远程分支
git branch -r
列出所有本地分支和远程分支
git branch -a
新建一个分支,但依然停留在当前分支
git branch [branch-name]
新建一个分支,并切换到该分支
git checkout -b [branch]
新建一个分支,指向指定commit
git branch [branch] [commit]
新建一个分支,与指定的远程分支建立追踪关系
git branch --track [branch] [remote-branch]
切换到指定分支,并更新工作区
git checkout [branch-name]
切换到上一个分支
git checkout -
建立追踪关系,在现有分支与指定的远程分支之间
git branch --set-upstream [branch] [remote-branch]
合并指定分支到当前分支
git merge [branch]
git rebase [branch]
注意二者的区别git rebase 和 git merge 的区别
选择一个commit,合并进当前分支
git cherry-pick [commit]
删除分支
git branch -d [branch-name]
删除远程分支
git push origin --delete [branch-name]
git branch -dr [remote/branch]
检出版本v2.0
git checkout v2.0
从远程分支develop创建新本地分支devel并检出
git checkout -b devel origin/develop
检出head版本的README文件(可用于修改错误回退)
git checkout -- README
5、标签
列出所有tag
git tag
新建一个tag在当前commit
git tag [tag]
新建一个tag在指定commit
git tag [tag] [commit]
删除本地tag
git tag -d [tag]
删除远程tag
git push origin :refs/tags/[tagName]
查看tag信息
git show [tag]
提交指定tag
git push [remote] [tag]
提交所有tag
git push [remote] --tags
新建一个分支,指向某个tag
git checkout -b [branch] [tag]
6、查看信息
显示有变更的文件
git status
显示当前分支的版本历史
git log
显示commit历史,以及每次commit发生变更的文件
git log --stat
搜索提交历史,根据关键词
git log -S [keyword]
显示某个commit之后的所有变动,每个commit占据一行
git log [tag] HEAD --pretty=format:%s
显示某个commit之后的所有变动,其"提交说明"必须符合搜索条件
git log [tag] HEAD --grep feature
显示某个文件的版本历史,包括文件改名
git log --follow [file]
git whatchanged [file]
显示指定文件相关的每一次diff
git log -p [file]
显示过去5次提交
git log -5 --pretty --oneline
显示所有提交过的用户,按提交次数排序
git shortlog -sn
显示指定文件是什么人在什么时间修改过
git blame [file]
显示暂存区和工作区的差异
git diff
显示暂存区和上一个commit的差异
git diff --cached [file]
显示工作区与当前分支最新commit之间的差异
git diff HEAD
显示两次提交之间的差异
git diff [first-branch]...[second-branch]
显示今天你写了多少行代码
git diff --shortstat "@{0 day ago}"
显示某次提交的元数据和内容变化
git show [commit]
显示某次提交发生变化的文件
git show --name-only [commit]
显示某次提交时,某个文件的内容
git show [commit]:[filename]
显示当前分支的最近几次提交
git reflog
7、远程同步
下载远程仓库的所有变动
git fetch [remote]
显示所有远程仓库
git remote -v
显示某个远程仓库的信息
git remote show [remote]
增加一个新的远程仓库,并命名
git remote add [shortname] [url]
取回远程仓库的变化,并与本地分支合并
git pull [remote] [branch]
上传本地指定分支到远程仓库
git push [remote] [branch]
强行推送当前分支到远程仓库,即使有冲突
git push [remote] --force
推送所有分支到远程仓库
git push [remote] --all
8、撤销
恢复暂存区的指定文件到工作区
git checkout [file]
恢复某个commit的指定文件到暂存区和工作区
git checkout [commit] [file]
恢复暂存区的所有文件到工作区
git checkout .
重置暂存区的指定文件,与上一次commit保持一致,但工作区不变
git reset [file]
重置暂存区与工作区,与上一次commit保持一致
git reset --hard
重置当前分支的指针为指定commit,同时重置暂存区,但工作区不变
git reset [commit]
重置当前分支的HEAD为指定commit,同时重置暂存区和工作区,与指定commit一致
git reset --hard [commit]
重置当前HEAD为指定commit,但保持暂存区和工作区不变
git reset --keep [commit]
新建一个commit,用来撤销指定commit
后者的所有变化都将被前者抵消,并且应用到当前分支
git revert [commit]
暂时将未提交的变化移除,稍后再移入
git stash
git stash pop
五、Git回撤操作
1、工作区新增文件没有被add过的回撤
因为是新文件没有被加入过暂存区,没有进入版本管理,所以没办法回撤
2、工作区新增文件有被add过的回撤
单文件
git add abc.txt
git rm --cached abc.txt或
git restore --staged abc.txt或
git reset HEAD abc.txt
多文件
git reset HEAD
移出暂存区,文件还在
3、工作区中已在版本库中的文件,修改或删除后未add的回撤
单文件
git restore abc.txt或
git checkout -- abc.txt
多文件
git restore .或
git checkout .或
git reset --hard HEAD
会修改工作区文件,谨慎操作
4、工作区中已在版本库中的文件,修改或删除后已经add的回撤
单文件
git restore --staged abc.txt或
git reset HEAD abc.txt
多文件
git reset HEAD
5、工作区中已在版本库中的文件,修改或删除后已经add、commit的回撤
分三种情况
①返回到未add的状态
git reset HEAD^
②返回到已经add但是未commit的状态
git reset --soft HEAD^
③返回到抹除工作区修改的状态
git reset --hard HEAD^
这里的 HEAD^ 表示最新版本的前一版,也就是倒数第二版本,可以类推,HEAD^^ 表示倒数第三版本,HEAD^^^ 表示倒数第四版本。
另外还有另一种写法 HEAD~1 表示最新版本的前一版,也就是倒数第二版本,HEAD~2 表示倒数第三版本,HEAD~3 表示倒数第四版本。
6、工作区中已在版本库中的文件,修改或删除后已经add、commit、push的回撤
回退版本
git reset HEAD^
然后重新push
git push
如果远程仓库的记录领先,无法直接推送,此时可以添加 -f 参数,用本地提交记录覆盖远程分支记录:
git push -f
六、Git分支管理
1、Bug分支
有时候开发到一半需要去修复Bug,这个时候就需要创建Bug分支。
隐藏工作区
git stash
创建Bug分支
git checkout -b bug_feature_name
修复问题后add、commit,再然后切换到开发分支dev
git checkout dev 或
git switch dev
合并Bug分支的代码
git rebase --no-ff bug_feature_name
合并后将代码push到dev
git push origin dev
删除Bug分支
git branch -d bug_feature_name
恢复工作区
git stash pop
一般情况下在自己的开发分支下创建Bug分支来解决Bug,比如张三的开发分支为zhangsan,张三创建的Bug分支为zhangsan_bug,解决完Bug,zhangsan合并了zhangsan_bug,但是这个时候共同的开发分支dev上一般也有这个Bug,张三可以选择push到dev分支,也可以切换到dev用git的快速命令git cherry-pick commit_id来快速提交修复bug。
2、强行删除未合并的分支\关联远端分支
有时候开发到一半的分支不想要了
git branch -D feature_name
将本地分支(比如dev)推送到远端让它们相关联,远端也会创建一个命名为dev的仓库
git push origin dev
七、多人协作
多人是如何协作的:
假设开发人员有张三、李四还有一个居家办公的王五,张三的开发分支为zhangsan,李四的开发分支为lishi,王五的开发分支为wangwu,项目的开发分支为dev,远程仓库的开发分支为origin dev,以张三为例说明。
张三今天干完活了,要提交代码
git add .
git commit -m "添加说明"
切换到dev分支去拉取王五提交的远程仓库origin dev的代码
git switch dev
git pull origin dev
回到自己的分支合并本地开发分支dev的代码
git switch zhangsan
git rebase dev
发现合并本地开发分支dev出现冲突,有人在代码里下毒(编辑了同一份文件),查看冲突的文件
git status
手动解决完冲突,add文件后继续合并操作(add后不要习惯commit)
git add .
git rebase --continue
切换到本地开发分支dev合并张三开发分支zhangsan的代码
git switch dev
git rebase zhangsan
将本地dev分支的代码推到远端仓库给居家办公的王五
git push origin dev
张三切换回自己的分支继续开发
git switch zhangsan
八、Git-Flow
1、经典Git-Flow
Git Flow是一个经典的Git工作流,如下图所示:(图来源于参考的博客git-flow工作流程侵删)
master 生产主分支,发布到生产环境使用这个分支,由hotfix或者release分支合并过来,不直接提交代码。
develop 主开发分支 , 基于master分支克隆,由feature分支合并过来,一般不直接提交代码。
feature 功能开发分支 , 基于develop分支克隆 , 主要用于新需求新功能的开发,同时存在多个。
release 预发布分支 , 基于feature分支合并到develop之后 , 从develop分支克隆,测试完成后合并到master并打上版本号,同时也合并到develop。
hotfix 补丁分支 , 基于master分支克隆 , 主要用于对线上的版本进行BUG修复,完成后合并到master分支和develop分支。
但对于一般的公司使用偏重。
2、常用Git-Flow
第一种(图来源于博客git-flow工作流程侵删)
第二种(图来源于博客git-flow工作流程侵删)
参考了以下文章,表示感谢:
git checkout/git reset/git revert/git restore常用回退操作 [AlbertS]