一,git基础概念
- Working Tree 当前的工作区域
- Index/Stage 暂存区域,和git stash命令暂存的地方不一样。使用git add xx,就可以将xx添加近Stage里面
- Repository 提交的历史,即使用git commit提交后的结果
二,基本操作命令:
git status # 查看状态
git add . # 将变动文件添加 从到工作区添加到 缓存区
git commit -m "提交信息" # 提交代码到 本地仓库
git push origin master # 将本地仓库代码 推送到 远程仓库
git pull # 默认参数为 --merge 将远程仓库代码 拉取到 本地仓库后 merge 到本地代码
git pull --rebase # 将远程仓库代码 拉取到 本地仓库后 rebase 到本地代码
三,进阶命令 - - - 包括分支切换、合并等操作:
1,git clean
命令用来从你的工作目录中删除所有没有tracked过的文件
用法:
git clean -n
是一次clean的演习, 告诉你哪些文件会被删除。记住他不会真正的删除文件,只是一个提醒。
git clean -f
删除当前目录下所有没有track过的文件。他不会删除.gitignore文件里面指定的文件夹和文件, 不管这些文件有没有被track过。
git clean -d
删除指定路径下的没有被track过的文件夹。
git clean -df
删除当前目录下没有被track过的文件和文件夹。
git clean -xf
删除当前目录下所有没有track过的文件,不管他是否是.gitignore文件里面指定的文件夹和文件。
git reset --hard和git clean -f是一对好基友. 结合使用他们能让你的工作目录完全回退到最近一次commit的时候。
git clean -df && git reset --hard && git pull --rebase
2,git reset
参考自:https://www.jianshu.com/p/c2ec5f06cf1a
适用场景: 如果想恢复到之前某个提交的版本,且那个版本之后提交的版本我们都不要了,就可以用这种方法。
原理: git reset的作用是修改HEAD的位置,即将HEAD指向的位置改变为之前存在的某个版本,如下图所示,假设我们要回退到版本。
1)reset --hard (重置stage区和工作目录)
你的stage区和工作目录里的内容会被完全重置为和HEAD的新位置相同的内容。换句话说,就是你的没有commit的修改会被全部擦掉。
使用场景:
- (1) 要放弃目前本地的所有改变時,即去掉所有add到暂存区的文件和工作区的文件,可以执行 git reset -hard HEAD 来强制恢复git管理的文件夹的內容及状态;
- (2) 真的想抛弃目标节点后的所有commit(可能觉得目标节点到原节点之间的commit提交都是错了,之前所有的commit有问题)。
注意:
此命令为重置 工作区域和缓存区域的已有文件的修改,对工作区域内的新增文件不做处理,对缓存区域的新增文件进行重置。这是因为add是将文件纳入版本管理并缓存修改。如果没有纳入版本控制是不会进行缓存修改的。
# 查看版本号的两种方法
git log
git reflog
git reset --hard
git reset --hard HEAD # 删除当前版本中 工作区域和缓存区域的新增文件
git reset --hard HEAD^ # 切换到上一个commit版本
git reset --hard 版本号 # 切换到指定的版本号
2)reset --soft:保留工作目录和暂存区,并把重置 HEAD 所带来的新的差异放进暂存区
此模式下会保留 working tree工作目录的內容,不会改变到目前所有的git管理的文件夹的內容;也会保留 index暂存区的內容,让index 暂存区与 working tree 工作目录的內容是一致的。就只有 repository 中的內容的更变需要与 reset 目标节点一致,因此原始节点与reset节点之间的差异变更集合会存在与index暂存区中(Staged files),所以我们可以直接执行 git commit 將 index暂存区中的內容提交至 repository 中。当我们想合并「当前节点」与「reset目标节点」之间不具太大意义的 commit 记录(可能是阶段性地频繁提交)時,可以考虑使用 Soft Reset 来让 commit 演进线图较为清晰点。
使用场景:
原节点和reset节点之间的【差异变更集】会放入index暂存区中(Staged files),所以假如我们之前工作目录没有改过任何文件,也没add到暂存区,那么使用reset --soft后,我们可以直接执行 git commit 將 index暂存区中的內容提交至 repository 中。为什么要这样呢?这样做的使用场景是:假如我们想合并「当前节点」与「reset目标节点」之间不具太大意义的 commit 记录(可能是阶段性地频繁提交,就是开发一个功能的时候,改或者增加一个文件的时候就commit,这样做导致一个完整的功能可能会好多个commit点,这时假如你需要把这些commit整合成一个commit的时候)時,可以考虑使用reset --soft来让 commit 演进线图较为清晰。总而言之,可以使用–soft合并commit节点。
git reset --soft 版本号 # 切换到指定的版本,保留当前工作区、缓存区数据,
# 并把版本之间差异存入到缓存区中。
3)reset 不加参数(mixed):保留工作目录,并清空暂存区
reset 如果不加参数,那么默认使用 --mixed 参数。它的行为是:保留工作目录,并且清空暂存区。也就是说,工作目录的修改、暂存区的内容以及由 reset 所导致的新的文件差异,都会被放进工作目录。简而言之,就是「把所有差异都混合(mixed)放在工作目录中」。
使用场景:
- (1)使用完reset --mixed后,我們可以直接执行 git add 将這些改变果的文件內容加入 index 暂存区中,再执行 git commit 将 Index暂存区 中的內容提交至Repository中,这样一样可以达到合并commit节点的效果(与上面–soft合并commit节点差不多,只是多了git add添加到暂存区的操作);
- (2)移除所有Index暂存区中准备要提交的文件(Staged files),我们可以执行 git reset HEAD 来 Unstage 所有已列入 Index暂存区 的待提交的文件。(有时候发现add错文件到暂存区,就可以使用命令)。
- (3)commit提交某些错误代码,或者没有必要的文件也被commit上去,不想再修改错误再commit(因为会留下一个错误commit点),可以回退到正确的commit点上,然后所有原节点和reset节点之间差异会返回工作目录,假如有个没必要的文件的话就可以直接删除了,再commit上去就OK了。
git reset 版本号
git reset --mixed 版本号
git reset --mixed 与git reset --soft之间的差异:
工作目录的内容和 –soft 一样会被保留,但和 –soft 的区别在于,它会把暂存区清空,并把原节点和reset节点的差异的文件放在工作目录,总而言之就是,工作目录的修改、暂存区的内容以及由 reset 所导致的新的文件差异,都会被放进工作目录
4)总结
a> reset 的本质:
移动 HEAD 以及它所指向的 branch
b>区别:
- 1,–hard: 重置位置的同时,直接将 working Tree工作目录、 index 暂存区及 repository 都重置成目标Reset节点的內容,所以效果看起来等同于清空暂存区和工作区。
- 2,–soft: 重置位置的同时,保留working Tree工作目录和index暂存区的内容,只让repository中的内容和 reset 目标节点保持一致,因此原节点和 reset 节点之间的【差异变更集】会放入index暂存区中(Staged files)。所以效果看起来就是工作目录的内容不变,暂存区原有的内容也不变,只是原节点和 Reset 节点之间的所有差异都会放到暂存区中。
- 3,–mixed(默认): 重置位置的同时,只保留 Working Tree 工作目录 的內容,但会将 Index暂存区 和 Repository 中的內容更改和reset目标节点一致,因此原节点和Reset节点之间的【差异变更集】会放入Working Tree工作目录中。所以效果看起来就是原节点和Reset节点之间的所有差异都会放到工作目录中。
3,git stash
git stash这个命令可以将当前的工作状态保存到git栈,在需要的时候再恢复
1)git stash
保存当前的工作区与暂存区的状态,把当前的工作隐藏起来,等以后需要的时候再恢复,git stash 这个命令可以多次使用,每次使用都会新加一个stash@{num},num是编号。
git stash # 缓存
git stash save "add test_njh" # 缓存并mark
2)git stash pop
默认恢复git栈中最新的一个,也可以指定缓存stash@{num},pop后将自动删除选中缓存。
git stash pop # 默认为最新的缓存
git stash pop stash@{0} # 指定最新的缓存
3)git stash list
查看所有被隐藏的文件列表
git stash list
4)git stash apply
恢复被隐藏的文件,但是git栈中的这个不删除,用法:git stash apply stash@{0},如果我们在git stash apply 的时候工作目录下的文件一部分已经加入了暂存区,部分文件没有,
当我们执行git stash apply之后发现所有的文件都变成了未暂存的,如果想维持原来的样子,即暂存过的依旧是暂存状态,那么可以使用 git stash apply --index。pop后将继续保存选中缓存。
git stash apply stash@{0}
5)git stash drop
删除指定的一个进度,默认删除最新的进度,使用方法如git stash drop stash@{0}
git stash drop stash@{0}
6)git stash clear
删除所有存储的进度
git stash clear
7)git stash show
显示stash的内容具体是什么,使用方法如 git stash show stash@{0}
git stash show stash@{0}
git stash show stash@{1}
8)查看帮助
git stash --help
4,git revert
适用场景: 如果我们想撤销之前的某一版本,但是又想保留该目标版本后面的版本,记录下这整个版本变动流程,就可以用这种方法。
原理: git revert是用于“反做”某一个版本,以达到撤销该版本的修改的目的。比如,我们commit了三个版本(版本一、版本二、 版本三),突然发现版本二不行(如:有bug),想要撤销版本二,但又不想影响撤销版本三的提交,就可以用 git revert 命令来反做版本二,生成新的版本四,这个版本四里会保留版本三的东西,但撤销了版本二的东西。
# 1,查看log版本
git log # 或者git reflog
# 2,revert版本
git revert -n 版本号
# 3,commit提交
git commit -m "***"
# 4,push
git push origin devlop:devlop
5,git diff
1)git diff < filename >
意义:查看文件在工作目录与暂存区的差别。工作目录 vs 暂存区
git diff <filename>
也可查看和另一分支的区别。
git diff <branch> <filename>
2)git diff < commit > < filname >
意义:查看工作目录同Git仓库指定 commit 的内容的差异。工作目录 vs Git仓库<commit>=HEAD
时:查看工作目录同最近一次 commit 的内容的差异。
git diff <commit> <filename>
3)git diff --cached
意义:表示查看暂存区与本地仓库内容的差异。暂存区 vs Git仓库
git diff --cached <filename>
也可查看和另一分支的区别。
git diff --cached <commit> <filename>
4)git diff < commit > < commit >
意义:Git仓库任意两次 commit 之间的差别。Git仓库 vs Git仓库
git diff <commit> <commit>
5)扩展:
以上命令可以不指定 ,则对全部文件操作。
以上命令涉及和 Git仓库 对比的,均可使用git log 或者 git reflog 指定 commit 的版本。
- HEAD 最近一次 commit
- HEAD^ 上次提交
- HEAD~100 上100次提交
- 每次提交产生的哈希值
6,git checkout
Git 中的 HEAD 可以理解为一个指针,我们可以在命令行中输入 cat .git/HEAD 查看当前 HEAD 指向哪儿,一般它指向当前工作目录所在分支的最新提交。
cat .git/HEAD
# -----
ref: refs/heads/devlop # 指针指向devlop分支
1)git checkout(后面不加任何参数)
意义:表示查看工作区和缓存区中,加入到版本管理的文件的修改。
2)git checkout filename
意义:表示当没有提交版本号时将工作区的指定文件的内容恢复到暂存区的状态.
git checkout .
将工作区的所有文件的内容恢复到暂存区的状态。(工作区新增的文件不做修改)
3)git checkout + 分支名
意义:表示切换分支.
4)git checkout -b 分支名
意义:表示以当前分支的当前状态创建新分支并切换到新分支 -b 表示创建新分支
5)git checkout -b 分支名 commitID
意义:表示以当前分支的commitID提交节点创建新的分支并切换到新分支。此时工作区的内容和切换分之前commitID提交节点的内容一样。
6)git checkout commitID
意义:是以指定的提交节点创建了一个临时性分支,此临时性分支可用于做实验性修改。
7)git checkout < commit > filename
意义:当有提交版本号时,表示将工作区和暂存区都恢复到版本库指定提交版本的指定文件的状态,此时HEAD指针不变,此时的状态相当于把工作区的内容修改到指定版本的文件内容后,再把修改的内容添加到暂存区。因此git checkout < commit > filename后,可以直接执行git commit而不需要先执行git add。
7,git merge 和 git rebase
在分支合并时,有两种方式:git merge 和git rebase
# git merge:
git merge 分支名
# git rebase:
git rebase 分支名
例如:
现在在master分支上创建一个dev分支,然后在dev分支上进行两次提交,添加dev1.txt,dev2.txt,日志信息如下:
同时在master分支上进行两次提交,添加master1.txt,master2.txt,日志信息如下:
现在要把dev分支合并到master分支
使用merge命令合并:git merge dev
使用rebase命令合并:git rebase dev
Git 会从两个分支的共同祖先8eda20d开始提取 master 分支(当前所在分支)上的修改,即 e0779e1、ae0decb,再将 master 分支指向 dev的最新提交(目标分支)即 e45d38f处,然后将刚刚提取的修改依次应用到这个最新提交后面。操作会舍弃 master 分支上提取的 commit,同时不会像 merge 一样生成一个合并修改内容的 commit,相当于把 master 分支(当前所在分支)上的修改在 dev分支(目标分支)上原样复制了一遍。
总结
- merge 是一个合并操作,会将两个分支的修改合并在一起
- merge 的提交历史忠实地记录了实际发生过什么,关注点在真实的提交历史上面
- rebase 并没有进行合并操作,只是提取了当前分支的修改,将其复制在了目标分支的最新提交后面
9,git fetch
1)git fetch <远程主机名>
git fetch <远程主机名>
上面命令将某个远程主机的更新,全部取回本地;通常用来查看其他人的代码进程,因为它取回的代码对你本地的开发代码没有影响;
2)git fetch <远程主机名> <分支名>
git fetch <远程主机名> <分支名>
上面命令取回特定分支的更新;
例如(取回origin主机的master分支 ):
git fetch origin master
# 取回的更新,在本地主机上要用"远程主机名/分支名"的形式读取。
# 比如origin主机的master,就要用origin/master读取;
3)代码合并
## 在本地新建一个temp分支,并将远程origin仓库的master分支代码下载到本地temp分支;
$ git fetch origin master:temp
## 比较本地代码与刚刚从远程下载下来的代码的区别;
$ git diff temp
## 合并temp分支到本地的master分支;
$ git merge temp
## 如果不想保留temp分支,删除;
$ git branch -d temp
4) 总结
git fetch
创建并更新本地远程分支。即创建并更新origin/xxx 分支,拉取代码到origin/xxx分支上;
在FETCH_HEAD中设定当前支-origin/当前分支对应,如直接到时候git merge就可以将origin/abc合并到abc分支上;
git fetch origin
手动指定了要fetch的remote。在不指定分支时通常默认为master;
git fetch origin dev
指定远程remote和FETCH_HEAD,并且只拉取该分支的提交;
5)参看文档如下:
https://www.cnblogs.com/runnerjack/p/9342362.html
https://www.jianshu.com/p/d07f5a8f604d
10,git pull
意义:git pull包含有两个操作,一个是fetch远程的代码,一个是将本地当前的代码和远程代码进行merge,即git fetch + git merge。
其实git pull还有一个参数可以加,即git pull -rebase,其最终效果和git pull一样,也会fetch到远程代码。即git pull默认使用的是merge模式,那么git pull -rebase指定使用rebase模式。
git pull
git pull --rebase / gitpull -r / git pull origin devlop --rebase
11,git branch
1)git branch
意义:查看本地所有分支和所在分支
2) git branch -r
意义:查看远程所有分支
3) git branch -a
意义:查查看本地和远程分支
4)git branch
意义:新建分支
5)git branch -d 分支名
意义:删除分支
6)git branch -d -r
意义:删除远程分支,删除后还需推送到服务器
7)git push origin --delete 分支名
意义:删除远程的分支
8)git branch -m
意义:重命名本地分支
四,常见问题解决
1,版本回退
方法一:git reset
原理: git reset的作用是修改HEAD的位置,即将HEAD指向的位置改变为之前存在的某个版本,如下图所示,假设我们要回退到版本。
适用场景: 如果想恢复到之前某个提交的版本,且那个版本之后提交的版本我们都不要了,就可以用这种方法。
1)git log 或 git reflog
查看commit提交版本
2)git reset --hard 版本号
命令版本回退到目标版本号
3)git push -f 强制推送
使用git push -f 强制推送
注意:
1, git push 直接提交会报错。
2, 主干master上不能执行此操作。
方法二:git revert
原理: git revert是用于“反做”某一个版本,以达到撤销该版本的修改的目的。比如,我们commit了三个版本(版本一、版本二、 版本三),突然发现版本二不行(如:有bug),想要撤销版本二,但又不想影响撤销版本三的提交,就可以用 git revert 命令来反做版本二,生成新的版本四,这个版本四里会保留版本三的东西,但撤销了版本二的东西。
适用场景: 如果我们想撤销之前的某一版本,但是又想保留该目标版本后面的版本,记录下这整个版本变动流程,就可以用这种方法。
1)查看版本号:
使用 git log 查看版本
2)使用“git revert -n 版本号”反做,并使用“git commit -m 版本名”提交:
(1)revert,使用“git revert -n 版本号”命令。
git revert -n 0f7f2bdffa3775b65561625f4d7a68dfeccd6c69
注意: 这里可能会出现冲突,那么需要手动修改冲突的文件。而且要git add 文件名。
(2)提交,使用“git commit -m 版本名”,如:
git commit -m "revert add b.py"
3)使用“git push”推上远程库:
git push origin devlop:devlop
来源:oschina
链接:https://my.oschina.net/u/4259099/blog/4330109