基本了解
git作为支持分布式版本管理的工具,它管理的仓库(repository)分为本地仓库、远程仓库。
Git有四大区(工作区、暂存区、版本库、git仓库)以及几个状态(modified、staged、committed、tracked)。
工作区(Working Directory):就是平时存放项目代码的地方,在电脑里能看到的文件夹目录。
暂存区(Stage/Index):英文叫stage, 或index。一般存放在 “.git目录下” 下的index文件(.git/index)中,所以我们把暂存区有时也叫作索引(index)。用于临时存放你的改动,事实上它只是一个文件,保存即将提交的文件列表信息
版本库(Repository或Git Directory):工作区有一个隐藏目录.git
,这个不算工作区,而是Git的版本库。版本库里存了很多东西,其中最重要的有stage和git自动创建的第一个分支master,以及刚初始的时候指向本地仓库master的指针HEAD。就是安全存放数据的位置,这里面有你提交的所有版本的数据。而其中HEAD之后会指向最新放入仓库的版本
git仓库(Remote Directory):远程仓库,托管代码的服务器。
工作流程
git的工作流程一般是这样的:
1、在工作区中添加、修改文件;
2、将需要进行版本管理的文件放入暂存区;
3、将暂存区的文件提交到版本库;
4、将版本库推送到git仓库,在远程仓库做一种代码托管。
因此,git管理文件有四种状态:已跟踪(tracked),已修改(modified),已暂存(staged),已提交(committed)
常用命令
- 查看本地分支
git branch
前面带有*号的表示当前所在分支
- 创建分支
git branch [branchname]
- 切换分支
git checkout [branchname]
- 查看当前工作区和暂存区文件的状态
git status
- 将工作区的内容添加到暂存区
git add [file] # 指定文件添加到暂存区
git add . # 将工作区所有内容一次性添加到暂存区
- 将暂存区里的文件提交到本地仓库
git commit -m "[描述信息]" # 将暂存区文件提交到本地仓库里,一般来说,我们都会用-m参数来给这次提交加上描述信息,这样就可以明确知道这次提交到底做了什么
- 将当前分支推送到远程仓库对应的分支
git push origin [branchname]
- 将本地master分支推送到远程仓库某分支
git push origin master:[branchname]
- 分支合并
git merge [branchname]
一般来说,我们是会切换到主分支上,合并其他的分支,保持主分支为主导地位
- 从远程获取最新代码版本并merge到本地
git pull origin master
- 从远程获取最新代码版本拉到本地,并不会自动merge,用户在检查了以后决定是否合并到本机分支中
git fetch origin master
- 显示当前文件修改之后但还没有暂存起来的内容变化
git diff [file]
- 删除本地某分支
git branch -D [branchname]
注意:删除分支时不能删除当前所处分支,就是说可以删除非当前所处分支
- 删除远程某分支
git push origin --delete [branchname]
注意: 在删除远程分支时,同名的本地分支并不会被删除,所以还需要单独删除本地同名分支
- 查看提交历史
git log
可以通过这个命令来查看我们的所有提交历史。下图标红的一长串就是commit id
,通过commit id
我们还可以做很多事情。而这个commit id
就可以认为是当前分支的版本号
- 查询当前分支的版本号
git rev-parse HEAD
版本号的概念实际上是以git commit
为界限的,就是说只要没有经过git commit
,那么不管代码变动了多少,版本号始终不变
- 隐藏当前分支代码的全部改动,在不提交本地当前分支的情况下切换到其它分支进行操作,两个本地分支的操作互不影响
git stash
先来说说场景,假设我们本地有两个分支,分别是test/master
和demo/master
,而且两个分支都是由本地master分支分别创建出来的,而且两个暂时没有任何增删改操作。而我们给这两个分支分别有不同定位,test/master
专门用来做测试,而demo/master
专门用来写一些小demo,而且这两个分支我们都是不打算上传到远程仓库的,都是自己个人专用分支,想做什么就做什么的。
那么就有个问题了,在git中,两个刚从同一个master创建出来的分支的版本号是完全相同的,只要没有经过git commit
没有形成分支的版本号,只要版本号还是相同那么这两个分支就还不是分别独立的分支,也就是说你在test/master
的任何修改都会影响到demo/master
,这就不能达到我们的要求了。
所以就有了git stash
将我们的代码改动先暂时隐藏起来,再切换到别的分支,那么分支就可以保持互不影响了。
- 隐藏当前分支代码的全部改动,并添加注释
git stash save
- 隐藏当前分支某些文件的代码改动
git stash -p
直接git stash
的话,会将当前所有文件的代码改动都隐藏起来,而我只想隐藏几个或一个文件的代码改动,这应该怎么办呢?所以用到这条命令,它是一个交互式命令,我们可以一个文件一个文件的遍历,决定哪个文件的代码改动要不要隐藏起来。
能看到上图蓝色框的刚开始是有三个文件有代码改动的,而最后查文件状态的时候发现只剩下一个文件有代码改动了,原因就是隐藏了两个文件的代码改动。而红色框就是我们决定对哪个文件是否隐藏的操作。
关于[y,n,q,a,d,/,?]
分别代表的含义如下:
y - stage this hunkn - do not stage this hunkq - quit; do not stage this hunk nor any of the remaining onesa - stage this hunk and all later hunks in the filed - do not stage this hunk nor any of the later hunks in the fileg - select a hunk to go to/ - search for a hunk matching the given regexj - leave this hunk undecided, see next undecided hunkJ - leave this hunk undecided, see next hunkk - leave this hunk undecided, see previous undecided hunkK - leave this hunk undecided, see previous hunks - split the current hunk into smaller hunkse - manually edit the current hunk? - print help
所以,遇到我们需要隐藏的文件,我们就输入y并回车,不需要隐藏的文件,我们就输入n并回车,如果接下来没有需要隐藏的文件,则直接输入q并回车退出就行。
- 查看“隐藏”列表
git stash list
- 删除“隐藏”列表的记录
git stash drop stash@{id}
- 恢复上一次隐藏的代码改动,并把这条记录从“隐藏”列表中删除
git stash pop
- 恢复指定的某一次的代码改动隐藏
git stash apply stash@{id}
注意这条命令的隐藏代码恢复,并不会删除相应的“隐藏”列表的记录,所以要自己手动删除隐藏列表的记录
总结
①文件状态git status
版本控制就是对文件的版本控制,要对文件进行修改、提交等操作,首先要知道文件当前在什么状态,不然可能会提交了现在还不想提交的文件,或者要提交的文件没提交上。
分为未跟踪(untracked)、已跟踪(tracked)、未修改(unmodified)、已修改(modified)、未暂存(unstaged)、已暂存(staged)、未提交(uncommitted)、已提交(committed)。
- Untracked:当在工作目录中新加入一个文件时,它处于未跟踪状态,这表示其没有纳入Git的版本控制。通过 git add命令可以将其加入跟踪,并同时放入暂存区。
- Unmodify:未修改,即版本库中的文件快照内容与工作区中完全一致。这种类型的文件有两种去处,如果它被修改,就变为Modified。如果使用git rm移出版本库,则成为Untracked文件。
- Modified:文件已修改, 仅仅是修改,并没有进行其他的操作。 这个文件也有两个去处,通过git add可进入暂存staged状态, 使用git checkout 则丢弃修改返回到unmodify状态。
- Staged:暂存状态,git commit 命令会将暂存区中的文件提交至HEAD所指向的分支。当被commit之后,暂存区的文件将回到未修改状态。
②git commit
和git push
的区别
git commit
是将本地修改过的文件提交到本地仓库中,操作的是本地仓库
git push
是将本地仓库中的最新内容发送给远程仓库,操作的是远程仓库
那么,为什么要分本地commit和远程的push呢?
因为如果本地不commit的话,修改的纪录可能会丢失。而有些修改是不需要同步至远程服务器的,所以什么时候同步过去由用户自己选择,什么时候需要同步,再push到远程服务器。
③git fetch
和git pull
的区别
git pull
从远程获取最新代码版本并自动merge到本地
git fetch
从远程获取最新代码版本拉到本地,并不会自动merge,用户在检查了以后决定是否合并到本机分支中
两者不同就在于是否会自动merge,而git pull = git fetch + git merge
④撤销修改有以下几种情况
(1)还没使用 git add 将本地代码放到暂存区时
使用git checkout -- filepathname
放弃本地某个文件的修改
git checkout -- filepathname
使用git checkout .
放弃本地所有文件的修改
git checkout .
(2)已经使用了git add 将本地代码放到暂存区了,但是还未commit的
使用git reset HEAD^ filepathname
来撤销某个文件已经被放到暂存区的操作
git reset HEAD^ filepathname
可是这时这个文件在本地的修改还是存在的,所以可以用上面用到的git checkout -- filepathname
命令来放弃这个文件在本地的修改
(3)已经用 git commit 将暂存区的代码提交了,但是还未push到远程个人分支的
使用git reset --soft HEAD^
撤回commit操作,但是修改的代码还会保留
git reset --soft HEAD^
关于git reset --[mixed、soft、hard]
的几个参数
--mixed
:不撤销工作区改动的代码,只撤销commit操作,并且撤销git add 操作。这个为默认参数,git reset --mixed HEAD^
和git reset HEAD^
效果是一样的。
--soft
:不撤销工作区改动的代码,只撤销commit操作,但不撤销git add操作
--hard
:撤销工作区改动的代码,会撤销commit操作,也会撤销git add操作。注意:使用了这个参数相当于就恢复到了上一次的commit状态
注:HEAD^的意思是上一个版本,也可以写成HEAD~1
(如果想撤销2次commit,可以使用HEAD~2)
(4)已经push到远程的个人分支,但是还未merge到远程公共的master分支
如果这个远程的个人分支是自己一个人用的,那么我觉得最方便的方法就是把远程的这个个人分支删除就好,但是如果不是单独使用的话,那就要用别的方法了
git push origin --delete [branchname] # 删除远程某分支
参考
https://www.cnblogs.com/roychenyi/p/9471453.html
https://www.cnblogs.com/runnerjack/p/9342362.html
https://my.oschina.net/inchlifc/blog/1563337
https://www.cnblogs.com/lfxiao/p/9378763.html
https://www.cnblogs.com/qdhxhz/p/9757390.html
https://www.jianshu.com/p/fe4d54cb6244