Git常用命令
1.Git的工作流程
以上包含了一些简单而实用的命令,但是先不关心这些,先来解释了解下面这4个专用名词
- Workspace:工作区
- Index / Stage:暂存区
- Repository:仓库区(或本地仓库)
- Remote:远程仓库
工作区
程序员进行开发改动的地方,是你当前看到的,也是最新的。
平常我们开发就是拷贝远程仓库中的一个分支,基于该分支进行开发。在开发过程中就是对工作区的操作。
暂存区
.git目录下的index文件, 暂存区会记录git add
添加文件的相关信息(文件名、大小、timestamp...),不保存文件实体, 通过id指向每个文件实体。可以使用git status
查看暂存区的状态。暂存区标记了你当前工作区中,哪些内容是被git管理的。
当你完成某个需求或功能后需要提交到远程仓库,那么第一步就是通过git add
先提交到暂存区,被git管理。
本地仓库
保存了对象被提交 过的各个版本,比起工作区和暂存区的内容,它要更旧一些。
git commit
后同步index的目录树到本地仓库,方便从下一步通过git push
同步本地仓库与远程仓库的同步。
远程仓库
远程仓库的内容可能被分布在多个地点的处于协作关系的本地仓库修改,因此它可能与本地仓库同步,也可能不同步,但是它的内容是最旧的。
小结
- 任何对象都是在工作区中诞生和被修改;
- 任何修改都是从进入index区才开始被版本控制;
- 只有把修改提交到本地仓库,该修改才能在仓库中留下痕迹;
- 与协作者分享本地的修改,可以把它们push到远程仓库来共享
下面这幅图更加直接阐述了四个区域之间的关系。
常用的Git命令
解释
HEAD
在掌握具体命令前,先理解下HEAD。
HEAD,它始终指向当前所处分支的最新的提交点。你所处的分支变化了,或者产生了新的提交点,HEAD就会跟着改变。
ADD
add相关命令很简单,主要实现将工作区修改的内容提交到暂存区,交由git管理。
git add . |
添加当前目录的所有文件到暂存区 |
---|---|
git add <dir> |
添加指定目录到暂存区,包括子目录 |
git add <file1> |
添加指定文件到暂存区 |
COMMIT
commit相关命令也很简单,主要实现将暂存区的内容提交到本地仓库,并使得当前分支的HEAD向后移动一个提交点。
git commit -m <message> |
提交暂存区到本地仓库,message代表说明信息 |
---|---|
git commit <file1> -m <message> |
提交暂存区的指定文件到本地仓库 |
git commit --amend -m <message> |
使用一次新的commit,替代上一次提交 |
Branch
涉及到协作,自然会涉及到分支,关于分支,大概有展示分支,切换分支,创建分支,删除分支这四种操作。
git branch |
列出所有本地分支 |
---|---|
git branch -r |
列出所有远程分支 |
git branch -a |
列出所有本地分支和远程分支 |
git branch <branch-name> |
新建一个分支,但依然停留在当前分支 |
git checkout -b <branch-name> |
新建一个分支,并切换到该分支 |
git branch --track <branch><remote-branch> |
新建一个分支,与指定的远程分支建立追踪关系 |
git checkout <branch-name> |
切换到指定分支,并更新工作区 |
git branch -d <branch-name> |
删除分支 |
git push origin --delete <branch-name> |
删除远程分支 |
关于分支的操作虽然比较多,但都比较简单好记。
merge
merge命令把不同的分支合并起来。如上图,在实际开放中,我们可能从master分支中切出一个分支,然后进行开发完成需求,中间经过R3,R4,R5的commit记录,最后开发完成需要合入master中,这便用到了merge。
git fetch <remote> |
merge之前先拉一下远程仓库最新代码 |
---|---|
git merge <branch> |
合并指定分支到当前分支 |
一般在merge之后,会出现conflict,需要针对冲突情况,手动解除冲突。主要是因为两个用户修改了同一文件的同一块区域。如下图所示,需要手动解除。
rebase
rebase又称为衍合,是合并的另外一种选择。
在开始阶段,我们处于new分支上,执行git rebase dev
,那么new分支上新的commit都在master分支上重演一遍,最后checkout切换回到new分支。这一点与merge是一样的,合并前后所处的分支并没有改变。git rebase dev
,通俗的解释就是new分支想站在dev的肩膀上继续下去。rebase也需要手动解决冲突。
rebase与merge的区别
现在我们有这样的两个分支,test和master,提交如下:
D---E test
/
A---B---C---F master
在master执行git merge test
,然后会得到如下结果:
D--------E
/ \
A---B---C---F----G test, master
在master执行git rebase test
,然后得到如下结果:
A---B---D---E---C'---F' test, master
可以看到,merge操作会生成一个新的节点,之前的提交分开显示。而rebase操作不会生成新的节点,是将两个分支融合成一个线性的提交。
如果你想要一个干净的,没有merge commit的线性历史树,那么你应该选择git rebase 如果你想保留完整的历史记录,并且想要避免重写commit history的风险,你应该选择使用git merge
reset
reset命令把当前分支指向另一个位置,并且相应的变动工作区和暂存区。
git reset —soft <commit> |
只改变提交点,暂存区和工作目录的内容都不改变 |
---|---|
git reset —mixed <commit> |
改变提交点,同时改变暂存区的内容 |
git reset —hard <commit> |
暂存区、工作区的内容都会被修改到与提交点完全一致的状态 |
git reset --hard HEAD |
让工作区回到上次提交时的状态 |
revert
git revert用一个新提交来消除一个历史提交所做的任何修改。
revert 和 reset的区别
- git revert是用一次新的commit来回滚之前的commit,git reset是直接删除指定的commit。
- 在回滚这一操作上看,效果差不多。但是在日后继续merge以前的老版本时有区别。因为git revert是用一次逆向的commit“中和”之前的提交,因此日后合并老的branch时,导致这部分改变不会再次出现,减少冲突。但是git reset是之间把某些commit在某个branch上删除,因而和老的branch再次merge时,这些被回滚的commit应该还会被引入,产生很多冲突。关于这一点,不太理解的可以看这篇文章。
- git reset 是把HEAD向后移动了一下,而git revert是HEAD继续前进,只是新的commit的内容和要revert的内容正好相反,能够抵消要被revert的内容。
push
上传本地仓库分支到远程仓库分支,实现同步。
git push <remote><branch> |
上传本地指定分支到远程仓库 |
---|---|
git push <remote> --force |
强行推送当前分支到远程仓库,即使有冲突 |
git push <remote> --all |
推送所有分支到远程仓库 |
其他命令
git status |
显示有变更的文件 |
---|---|
git log |
显示当前分支的版本历史 |
git diff |
显示暂存区和工作区的差异 |
git diff HEAD |
显示工作区与当前分支最新commit之间的差异 |
git cherry-pick <commit> |
选择一个commit,合并进当前分支 |
备注
设置账号和邮箱关联,账号和邮箱可以是码云、GitLab...的账号都行:
$ git config --global user.name "Your Name" $ git config --global user.email "email@example.com"
选择合适地方,创建空目录
$ mkdir test //创建空目录,目录名字为test $ cd test //进入test目录
初始化仓库,把目录变成git 可以管理的仓库:
$ git init
$ ls //查看文件
$ ls -ah //如果.git目录是影藏的话,可以通过这个命令查看.git目录
提交文件到git 上
$ git add . //告诉Git,把文件添加到仓库,此时是将修改添加到暂存区,可add 多次 $ git commit -m '本次提交的备注' //告诉Git把文件提交到仓库,此时是吧暂存区的所有内容提交到当前分支,可一次提交很多文件
查看当前仓库的状态
$ git status //查看版本库状态,什么被修改过但还没提交的
$ git diff //查看当前相对上一次提交修改的内容
版本回退
$ git log //显示从最近到最远的提交日志 $ git log --pretty== oneline //显示log,但是不显示很多凌乱的信息 q //显示log版本信息有很多,使用q键停止查看 git reset —hard head^ //回退到上一个版本 git reset —hard head^^ //回退到上上个版本 git reset —hard head~100 //回退到之前100个版本 git reset —hard +commit_id //回到某个版本号的版本 git reset — hard 版本号 //版本回退多次后需要恢复最新版本 $ git reflog //查看曾经使用过的命令
撤销修改
$ git checkout -- test.html
删除文件
$ rm test.index //可直接在文件管理中删除文件,要不用rm 命令去删除
$ git rm test.html //从版本库中删除
$ git commit -m '删除 test.html文件'
$ git branch -D <name> //
丢弃一个没有被合并过的分支,可以通过强行删除。
远程仓库
创建SSH Key(需要生成 id_rsa私钥 和 id_rsa.pub公钥 两个文件)
$ ssh-keygen -t rsa -C "youremail@example.com"
登录GitHub,设置"SSH Keys",复制 id_rsa.pub 内容去添加。可允许添加多个SSH。
关联远程仓库
$ git remote add origin git@github.com:账户名
将本地的内容推送到远程库分支上
$ git push -u origin 分支名字 //第一次推送分支所有内容
$ git push origin 分支名字 //推送最新修改
查看远程仓库信息
$ git remote $ git remote -v //查看更加详细的信息
克隆
$ git clone 需要克隆的仓库地址
创建分支,并且切换过去
$ git checkout -b 新分支的名字 //创建分支并且切入进分支
或者等同于
$ git branch 分支名 //创建分支
$ git checkout 分支名 //切换到分支
$ git branch //查看分支
合并分支
$ git checkout -b dev
$ git branch
$ git add .
$ git commit -m '提交test文件到dev分支'
$ git checkout master //切换到主分支
$ git merge dev //将dev分支上的内容合并到master分支上,合并 指定分支 到 当前分支
$ git merge --no-ff -m "merge with no-ff" dev //合并分支时加上--no-ff
参数就可以用普通模式合并,合并后的历史有分支,通过git log查看
$ git branch -d dev //删除dev分支
解决冲突
同一文件修改冲突,需要手动解决冲突后再提交。git status可查看冲突,根据标记可修改冲突部分,修改结束后再重新提交。
$ git pull //拉取远程内容
$ git log --graph //命令可以看到分支合并图。
关联本地仓库和远程仓库
$ git branch --set-upstream-to <branch-name> origin/<branch-name>
创建标签
$ git branch $ git checkout dev $ git tag v1.0 //为当前需要打标签的分支打新标签 $ git tag //查看所有标签 $ git tag -a 指定标签信息 -m "blablabla..." //可指定标签信息
操作标签
$ git push origin <tagname> //可以推送一个本地标签; $ git push origin --tags //可以推送全部未推送过的本地标签; $ git tag -d <tagname> //可以删除一个本地标签; $ git push origin :refs/tags/<tagname> //可以删除一个远程标签。
改变Git颜=色
$ git config --global color.ui true