前言

Git在现在应该是使用得最多的版本管理工具了,本片博客将持续更新它的使用方法,以及在平时开发中遇到的问题及解决方法,至于它与SVN或者其它的工具有什么区别这里就不谈了,不是重点

仓库(repository)

在Git中,我们将需要控制的文件目录叫做一个仓库,每个项目的所在文件夹可以简单理解成一个仓库。假如现在建立一个仓库,那这个文件夹中就有以下文件

  • WorkSpace文件夹:需要通过git进行版本控制的项目文件,通常是你的项目文件夹,除了.git文件夹之外的都属于工作区

  • .git 文件夹:创建仓库的时候自动创建,所有的版本信息,操作记录全在这个文件夹里面,尽量不要修改或者删除里面的文件
    一个仓库分区图如下:
    ​​在这里插入图片描述

    其中的
    Index/Stage:暂存区或者待提交更新区,在提交进入仓库前,所有add命令操作的更新放在暂存区
    Local Repository:存放在本地的仓库,指当前的开发分支
    Stash:工作状态保存栈,用于保存或者恢复工作区的临时状态,后续会有样例进行使用

在.git目录下有以下文件

  • config: 包含了项目特有的配置选项
  • info: 目录保存了一份不希望在 .gitignore 文件中管理的忽略模式的全局可执行文件
  • hooks:保存了客户端或者服务端脚本
  • objects:存储所有数据内容
  • refs:存储指向数据的提交对象的指针,里面既有stash栈指针和tag等
  • HEAD:文件指向当前分支
  • index:文件保存了暂存区信息

git文件颜色

在开发工具中,在版本管理工具支持下,被纳入版本管理的文件通常有一些不同的颜色

  • 白色:正常文件的颜色
  • 红色:指定仓库路径后,未Add的文件
  • 绿色:已Add,但未commit的文件
  • 蓝色,commit后修改的文件

git clone

在公司里我们做的最多的就是拿到远程仓库地址,然后使用命令将远程仓库拉到本地
先进入你要存放仓库的目录,然后右键,选中git bash,这是一个git的命令行工具,输入以下命令:

git clone https://github.com/xxxxx/xxxxxx.git 或者

git clone ssh://github.com/xxxxx/xxxxxx.git

git支持多种协议,但通过ssh支持的原生git协议速度最快

这样拉取仓库会把所有的历史提交记录全拉下来,导致本地.git目录非常大,这时候如果不考虑回滚的情况可以在后面追加–depth命令,如下

git clone https://github.com/xxxxx/xxxxxx.git --depth=1

这样就只会clone最后一次commit记录

git branch

代码拉下来后,我们一般不在master分支提交代码,需要切换到自己的开发分支进行操作,可以通过以下命令进行操作

列举分支

  • git branch : 查看本地当前分支
  • git branch -r:查看远程仓库分支
  • git branch -a:查看所有分支,包括本地和远程的

比如所有分支情况如下:

~/mxnet$ git branch -a
* master
  devp
  remotes/origin/HEAD -> origin/master
  remotes/origin/master
  remotes/origin/devp

可以看到 * master 表示我们本地当前分支,remotes/origin/master和remotes/origin/devp是远程仓库的两个分支,第三行意思是指向当前远程分支

切换分支
这时候我们需要切换到devp分支,使用如下命令

$ git checkout devp 

新建分支

如果需要新建分支,使用如下命令

$ git branch new_branch

新建并切换分支

在上面的例子中,分别使用两个命令创建和切换分支。 Git为checkout命令提供-b选项; 此操作将创建一个新的分支,并立即切换到新分支。

$ git checkout -b devp 

接下来还可以将这个新建的分支推送到远程,如下:

$  git push --set-upstream origin devp

还可以基于某个commit创建分支,例如当前分支的某个commit id = 12345678,我们可以基于这个id创建本地分支

git checkout 12345678 -b newBranch

删除分支

可以通过向git branch命令提供-D选项来删除分支。,但在删除现有分支之前,请切换到其他分支

$ git branch -d new_branch

删除远程分支

git push origin --delete <branchName>

重命名分支

假设需要在项目中添加对宽字符的支持。并且已经创建了一个新的分支,但分支名称需要重新命名。那么可通过使用-m选项后跟旧的分支名称和新的分支名称来重新命名分支名称

$ git branch -m new_branch wchar_support

推送新分支到远程

git push origin 本地分支:远端希望创建的分支 //先将分支推送到远程,顺便在远程创建新分支
git branch --set-upstream-to=origin/远程分支名 本地分支名  //将两个分支简历追踪关系

git tag

  1. 查看本地分支标签
    git tag
    git tag -l
    git tag --list
    
  2. 查看远程所有标签
    git ls-remote --tags
    git ls-remote --tag
    
  3. 给当前分支打标签
    git tag 《标签名》
    例如
    git tag v1.1.0
    
  4. 给特定的某个commit版本打标签,比如现在某次提交的id为 039bf8b
    git tag v1.0.0 039bf8b
    
    或者可以添加注释
    
    git tag v1.0.0 -m "add tags information" 039bf8b
    
    或者
    
    git tag v1.0.0 039bf8b -m "add tags information"
    
  5. 删除本地某个标签
    git tag -d v1.0.0
    
  6. 删除远程的某个标签
    git push origin -d v1.0.0
    
  7. 将本地标签一次性推送到远程
    git push origin --tags
    或者
    git push --tags
    
  8. 将本地某个特定标签推送到远程
    git push origin v1.0.0
    
  9. 查看某一个标签的提交信息
    git show v1.0.0
    
  10. 拉取远程tag
    git fetch origin tag <tag name>
    
  11. 从tag切分支
    git checkout tag-name -b newBranch
    

git log

想查看git的提交信息可以通过该命令及扩展形式

  • git log

    该命令按提交时间列出所有的更新,最近的更新排在最上面
    在命令行界面会列出每个提交的 SHA-1 校验、作者的名字和电子邮件地址、提交时间以及提交说明
    
  • git log -n

    上面的命令会列出所有的更新信息,但是有时候你只要看最近的几条,
    那就在后面接 -n 表示查看最近n此的提交概要信息,这个n可以是1,2,3......
    
  • git log --oneline

    这个命令如同名字一样,每个提交展示的信息只有一行,可以让你快速浏览提交信息
    
  • git log --pretty=oneline

    这个命令展示commitid信息是全的,其它的跟git log --oneline一样
    
  • git log --stat

    该命令包含上面的命令的信息,除此之外还能展示每次提交的一些简略的统计信息,比如哪些文件被修改了,
    多少文件有变化,增加了多少行,删除了多少行
    
  • git log --name-only

    该命令会显示已修改的文件清单,没有 --stat命令的统计信息
    
  • git log -p -n

    上面展示的只是概要信息,你如果想看具体提交的内容,可以加上-p参数
    该选项除了显示基本信息之外,还附带了每次 commit 的变化,比如某个文件哪一行代码被修改了,
    就会在那一行列出修改前的内容和修改后的内容,修改前的用红色-开头,修改后的用绿色+开头
    当进行代码审查,或者快速浏览某个搭档提交的 commit 所带来的变化的时候,这个参数就非常有用了
    
  • git show commitid

    通过上面的命令你可以获取到每次提交的校验码,比如:
    commit dc6b155e824ec6300e292f16c434620ac9ce10e7
    然后就可以通过show命令查看某次提交的具体内容
    你并不需要将校验码全部输入,只用将开头的几个字母输入就行了,git会以这个输入内容作为开头进行匹配,比如
    git show dc6b
    
  • git log --author

    查看指定作者的简要提交信息,author后接提交者名字;可以使用git log --stat --author xxx 查看具体提交文件信息,
    其它命令也可以组合使用
    
  • git log --since

    查看指定时间之后的提交信息,since后接时间,比如2019.02.20,包含指定时间
    
  • git log --until

    查看指定时间之前的提交信息,until后接时间,比如2019.02.20,包含指定时间
    
  • git blame file

    查看指定文件里的内容,用具体文件名或者文件路径替代file
    
  • git log – file

    查看指定文件的提交历史
    
  • git log -p – file

    查看指定文件的每次提交的具体修改信息
    
  • git show commitid – file

    查看某次提交中指定文件的修改信息
    

git reflog

这个也是查看日志,但是可以查看所有分支的所有操作记录(包括已经被删除的 commit 记录和 reset 的操作),例如执行 git reset --hard HEAD~1,退回到上一个版本,用git log则是看不出来被删除的commitid,用git reflog则可以看到被删除的commitid,我们就可以买后悔药,恢复到被删除的那个版本

git pull

git pull命令的作用是:取回远程主机某个分支的更新,再与本地的指定分支合并,它的完整格式如下:

$ git pull [options] [<repository> [<refspec>…]]
$ git pull <远程主机名> <远程分支名>:<本地分支名>
  • 比如,要取回origin主机的next分支,与本地的master分支合并,需要写成下面这样

    $ git pull origin next:master
    
  • 如果远程分支(next)要与当前分支合并,则冒号后面的部分可以省略

    $ git pull origin next
    

    上面命令表示将远程origin主机的next分支拉取过来和本地的当前分支进行合并。实质上,这等同于先做git fetch,再执行git merge

    $ git fetch origin next:master
    $ git merge master
    

在某些场合,Git会自动在本地分支与远程分支之间,建立一种追踪关系(tracking)。比如,在git clone的时候,所有本地分支默认与远程主机的同名分支,建立追踪关系,也就是说,本地的master分支自动”追踪”origin/master分支

如果当前分支与远程分支存在追踪关系,git pull就可以省略远程分支名

$ git pull origin

上面命令表示,本地的当前分支自动与对应的origin主机”追踪分支”(remote-tracking branch)进行合并

如果当前分支只有一个追踪分支,连远程主机名都可以省略

$ git pull

上面命令表示,当前分支自动与唯一一个追踪分支进行合并


git fetch和git pull的区别

  • git fetch:相当于是从远程获取最新版本到本地,不会自动合并

    $ git fetch origin master
    $ git log -p master..origin/master
    $ git merge origin/master
    

    以上命令的含义:

    • 首先从远程的origin主机的master分支下载代码到本地的origin master
    • 然后比较本地的master分支和origin/master分支的差别
    • 最后把远程下载下来的代码合并到本地仓库

    上述过程其实可以用以下更清晰的方式来进行:

    $ git fetch origin master:tmp //从远程的origin仓库的master分支下载到本地并新建一个分支temp
    $ git diff tmp //比较master分支和temp分支的不同
    $ git merge tmp//合并temp分支到master分支
    $ git branch -d temp//删除temp分支
    
  • git pull:相当于是从远程获取最新版本并merge到本地

    git pull origin master
    

    上述命令其实相当于git fetch 和 git merge
    在实际使用中,git fetch更安全一些,因为在merge前,我们可以查看更新情况,然后再决定是否合并

git add

当我们正常进行项目开发后需要将修改的文件和新增的文件推送到远程仓库,首先进行add命令,将内容添加到暂存区

add命令有如下几种:

  • git add msg.txt:将msg.txt文件添加到暂存区

  • git add document/:将document整个目录提交到暂存区

  • git add document/*.txt:将document目录下以.txt结尾的文件提交到暂存区

  • git add . :这个 . 表示当前目录所有文件及文件夹,会监控工作区的状态树,包括所有内容修改的文件和新文件,但不包括被删除的文件,然后提交到暂存区

  • git add -u . :仅监控已经被add过的文件(即tracked file),会将被修改的文件和删除的文件提交到暂存区,

  • git add -A . :第4个命令和第5个命令的合集,表示将所有已跟踪的文件的修改和删除,未被跟踪的新增文件都提交到暂存区

  • git add -i . :查看所有文件的状态信息,不包括新增且没被提交到暂存区的文件

  • git add -f filename :强制提交文件

当我们习惯性的通过git add . 命令将所有文件添加到了暂存区,但是其实我们想其中一个文件不要被提交到暂存区,这就需要撤销这个文件的add操作,这时使用 git reset HEAD 文件名 进行撤销。该文件就回到了add之前的状态。
当我们对已被追踪的文件进行错误的修改后,希望取消这些修改(这些修改没有被add),回到修改前的状态,使用git checkout – 文件名

git commit

当将修改的文件,新增的文件,删除的文件进行add操作添加到暂存区后,需要提交到本地仓库,提交命令如下

  • git commit -m “此次提交描述”

      -m 表示在后面追加此次提交的备注信息,
    
      当我们要输入的这个备注信息很长,可以使用如下命令
    
      git commit -m '
    
      message1
    
      message2 '
    
      这样提交操作就完成了;
    
      如果不加这个 -m 参数,只有git commit ,那么敲回车键后会调用一个编辑器,默认是vim来让你输入这个 备注信息;
    
      输入后怎么退出这个编辑器回到命令行呢,按下 esc ,这样就会退出编辑状态,然后连续按两次大写字母 Z ,这样就会
    
      正常回到命令行界面。
    
  • git commit -a -m “此次提交描述”

      加-a参数可以将所有已跟踪文件中的执行修改或删除操作的文件都提交到本地仓库,即使它们没有经过git add添加到暂
    
      存区,注意,新加的文件(即没有被git系统管理的文件)是不能被提交到本地仓库的。建议一般不要使用-a参数,正
    
      常的提交还是使用git add先将要改动的文件添加到暂存区,再用git commit 提交到本地版本库。
    

git push

当代码提交到本地仓库后要做的就是推送到远程仓库,推送命令如下

git push 的一般形式为 git push <远程主机名> <本地分支名> : <远程分支名>

  • git push origin master: master

    意思是将本地master分支推送到远程主机origin上的master分支,
    
    origin是主机名,第一个master是本地分支名,第二个是远程分支名。
    
    可以使用git branch 查看本地分支,git branch -r查看远程分支
    
  • git push origin master

    如果远程分支名忽略,表示将本地分支推送到与之存在追踪关系的远程分支(通常两者同名),如果远程分支不存在,
    
    则会被新建一个远程分支,可以通过git branch -vv 命令 查看本地分支与远程分支的追踪关系
    
* git push origin : master

      如果本地分支名省略,表示删除指定的远程分支,因为这等同于推送一个空的本地分支到远程分支,

      等同于git push origin --delete master (master是远程分支名)

* git push origin

      如果本地分支和远程分支都省略,表示将当前分支推送到origin主机对应的分支,前提是当前分支和远程分支存在追踪关系

* git push

      如果当前分支只有一个远程分支,那么主机名都可以省略

* git push -u origin master 

      如果当前分支与多个主机存在追踪关系,则可以使用 -u 指定一个远程主机,

      意思就是将本地master分支推送到origin主机,同时指定origin为默认主机,这样之后就可以不加参数直接使用git push

* git push --all origin

      表示将所有本地分支推送到远程主机上

      如果远程主机的版本比本地版本更新,推送时Git会报错,要求先在本地做git pull合并差异,然后再推送到远程主机

* git push  origin master --force

      强制将本地master分支推送到远程主机上的master分支,可能会导致在远程主机产生一个”非直进式”的合并,不建议这么做

* git push origin master : refs/for/master

      表示推送到远程master分支的代码需要经过code review之后才能进行merge的,而使用refs/heads/ 就不会检查,

      直接推送到远程分支

git stash

该命令是用来对工作区的文件做备份的,git中由于可能存在多个Stash的内容,所以用栈来管理,stash只会保存在本地

  • git stash

    这个命令做的就是将工作区的代码恢复到上次提交的内容,并且将你本地所做的修改进行备份;
    如果要添加备份信息,可以使用git stash save "本次备份原因"
    
  • git stash list

    显示Git中stash栈内的所有备份,可以利用这个列表来决定从哪个stash恢复
    
  • git stash drop

    删除指定stash,后面接stash名字,比如git stash drop stash@{0}
    
  • git stash clear

    清空Git中stash栈,删除所有stash。此时使用gitg等图形化工具会发现,原来stash的那些节点都消失了
    
  • git stash pop

    这个命令就是从最近的一个stash中读取内容并应用到当前的工作目录下,同时删除该stash备份
    
  • git stash apply

    git stash pop命令使用完stash后会删除该stash,而这个命令也是使用stash但不会删除stash,
    后面还可以跟stash名字,比如git stash apply stash@{0},默认使用第一个stash
    
  • git stash show

    查看stash中具体备份的文件信息,后面可接stash名字,默认查看第一个;后面接-p参数可以查看文件内容信息
    
  • git stash -u

    git stash默认只会备份添加到暂存区的修改(staged changes)和 Git跟踪的但并未添加到暂存区的
    修改(unstaged changes),而新增加的文件(untracked files)不会备份,而该命令可以stash untracked files
    
  • git stash -a

    上面一条命令不会备份被忽略的文件(ignored files),使用该命令是备份所有文件
    

查看远程仓库地址及信息

使用git remote -v查看远程仓库地址

在这里插入图片描述
使用git remote show origin查看仓库信息

在这里插入图片描述


建立分支关联关系

建立本地分支与远程分支的追踪关系命令格式如下:

git branch --set-upstream-to origin/

比如下面,将本地dev分支和远程dev分支建立追踪关系

git branch --set-upstream-to origin/dev dev

如果是将当前分支与远程分支建立追踪关系,可以这样写

git branch --set-upstream-to origin/dev

最后可以使用如下命令查看所有分支关联关系

git branch -vv

建立关联关系还可以使用这个命令:git branch -u origin/dev dev


合并分支

比如你突然接到一个紧急电话,产品出了一个大bug,需要立即修复,这时候就可以这样:

  • 从正在开发新需求的分支devnew切换到已经发布到生产服务器上的分支master

    git checkout master
    
  • 为这次紧急修复新建一个分支devbug,并进入这个分支,然后在这个分支上修复问题

    git checkout -b devbug // 在生产服务器上新建一个devbug分支并进入该分支,在这个分支上进行bug修复
    
  • 测试通过后回到生产服务器上的分支master,将新分支devbug合并过来,然后再推送到生产服务器上

    git checkout master //回到生产服务器上的分支
    git pull origin master //如果master分支有更新,需要先把代码拉下来
    git merge --no-ff devbug -m "合并描述信息" //将修复分支合并到master分支
    git push origin master //将修复代码推送到远程master分支,如果有冲突,需要先解决冲突
    git branch -d devbug //删除修复bug的分支,当然你也可以不删除
    
  • 切换到之前开发新需求的分支继续工作

    git checkout devnew
    

这里要注意下git merge命令后面有几种选项:

  • –ff :即 fast-forward 方式,fast-forward方式就是当条件允许的时候,git直接把HEAD指针指向合并分支的头,完成合并。属于“快进方式”,不过这种情况如果删除分支,则会丢失分支信息。因为在这个过程中没有创建commit
  • –no-ff:即不使用fast-forward方式合并,保留分支的commit历史
  • –squash:把一些不必要commit进行压缩,比如说,你的feature在开发的时候写的commit很乱,那么我们合并的时候不希望把这些历史commit带过来,于是使用–squash进行合并,此时文件已经同合并后一样了,但不移动HEAD,不提交。需要进行一次额外的commit来“总结”一下,然后完成最终的合并。
  • –no-squash:即不压缩

如果merge命令后面不加,默认是–ff

差异如图
在这里插入图片描述
merge的不同行为,向后看,其实最终都会将代码合并到master分支,而区别仅仅只是分支上的简洁清晰的问题;然后向前看,也就是我们使用reset 的时候,就会发现,不同的行为就带来了不同的影响

通常我们把 master 作为主分支,上面存放的都是比较稳定的代码,提交频率也很低,而 develop 是用来开发特性的,上面会存在许多零碎的提交,快进式合并会把 develop 的提交历史混入到 master 中,搅乱 master 的提交历史。所以如果你根本不在意提交历史,也不爱管 master 干不干净,那么 –no-ff 其实没什么用。不过,如果某一次 master 出现了问题,你需要回退到上个版本的时候,你就会发现退一个版本居然退到了分支的某次版本,而不是想要的master分支的上一个版本,因为 feature 的历史合并进了 master 里。这也就是很多人都会推荐 –no-ff 的原因了吧。

合并提交

上面说的是合并分支,但是有时候你的代码需要提交到多个分支上去,那怎么办呢?总不能每个分支都拷贝下代码然后提交吧,这时候就需要使用cherry-pick命令了

首先假如你在dev-11分支上,做了add、commit、push操作到远程dev-11分支了,然后你又想把这次提交的代码再提交到dev-22分支上,那么先使用git log命令查看你这次提交的commitid,这个很重要

接下来使用git checkout命令切换到dev-22分支上,再使用git cherry-pick命令将这个commit提交到dev-22分支上,比如

git cherry-pick 27ff9daccd0d6ca6419ba4d0849436ef47f92f6b

最后再使用git push origin dev-22命令推送到远程分支上

rebase和merge的区别

GIT使用rebase和merge的正确姿势


比较两个分支的差异

git diff branch1 branch2

显示出所有有差异的文件的详细差异,它是在git bash命令框内展示

git diff branch1 branch2 --stat

仅显示出所有有差异的文件列表

git diff branch1 branch2 >>diff.diff

在当前目录生成一个diff.diff文件,导出所有差异内容

强制覆盖分支

这里分两种情况:
第一种就是本地进行分支合并的时候,比如将A分支合并到B分支上,这时候需要强制将A分支内容覆盖B分支,具体操作如下:

git checkout B//先切换到B分支
git reset --hard A//将本地B分支重置成A
git push origin B -f//将本地重置后的B分支强制推送到远程B分支上

第二种情况就是在拉取代码的时候需要用远程分支代码强制覆盖本地分支代码,命令格式如下:

git pull --force  <远程主机名> <远程分支名>:<本地分支名>

一般就简写成git pull -f

还有一种方法:

git fetch --all//从远程下载最新的,而不尝试合并或rebase任何东西。
git reset --hard origin/master //将master分支重置为您刚刚获取的内容, 当然这里可以是其他分支

修改分支名

修改本地分支名很简单,比如我要将本地分支dev-11修改为dev-22:

git branch -m dev-11 dev-22

如果要修改远程分支名的话,有个前提是先把远程分支拉到本地,接下来的操作其实就是先删除远程分支,然后修改本地分支名,接着推送到远程仓库,最后就是切换到这个远程分支,并将本地分支与远程分支建立追踪关系

git branch -m dev-11 dev-22//重命名本地分支
git push --delete origin dev-11//删除远程分支
git push --set-upstream origin dev-22  //把修改后的本地分支推送到远程

恢复被删除的本地分支

有时候误删了本地还没推到仓库的分支,怎么恢复呢?分两步:
第一步:查看日志

git reflog show --date=iso

git reflog用来记录你的每一次命令,–date=iso 表示以标准时间显示,这里要注意的是不能用git log,git log 命令显示从最近到最远的提交日志,当分支被删掉就找不到记录了。

在这里插入图片描述
可以使用git show commitid查看这次提交记录,以便查看是不是自己要恢复的。
第二步:根据id创建分支

git checkout -b  要恢复的分支名  commitId

恢复被删除/被编辑的文件

假如在操作过程中误删了文件或文件夹,也有可能是你就想删除这个文件夹;删除了以后怎么恢复呢?

这时候需要使用git checkout 命令

  • 第一步

    通过git status命令查看文件状态

    lenovo@DESKTOP-L1PKA9E MINGW64 /d/Web/ISP/ISPServerv1.0 (master)
    $ git status
    On branch master
    Your branch is up-to-date with 'origin/master'.
    Changes not staged for commit:
      (use "git add/rm <file>..." to update what will be committed)
      (use "git checkout -- <file>..." to discard changes in working directory)
    
            deleted:    sql/isp.sql
            modified:   src/main/resources/application.properties
    
    no changes added to commit (use "git add" and/or "git commit -a")
    
    

    可以看到这里我将isp.sql这个文件删掉了

  • 第二步

    使用git checkout sql/isp.sql,这个命令的意思就是放弃对工作目录中的更改

    lenovo@DESKTOP-L1PKA9E MINGW64 /d/Web/ISP/ISPServerv1.0 (master)
    $ git checkout -- sql/isp.sql
    

    这样这个被你删除的文件就又恢复了,这里我试过不输入 – 直接使用git checkout sql/isp.sql也是可以的

    其实不光被删除的文件,包括对已被追踪的文件进行的修改都可以使用这个命令恢复到修改前的状态,前提是没有对这些修改使用add命令


撤销add命令

有时候你会碰到这种情况,我修改了某些文件,并将其通过add命令添加到暂存区了,但是此刻我发现提错了,需要撤回,这时候就可以使用git reset命令了,如下:

  • 查看状态

    lenovo@DESKTOP-L1PKA9E MINGW64 /d/Web/ISP/ISPServerv1.0 (master)
    $ git status
    On branch master
    Your branch is up-to-date with 'origin/master'.
    Changes not staged for commit:
      (use "git add <file>..." to update what will be committed)
      (use "git checkout -- <file>..." to discard changes in working directory)
     
            modified:   sql/isp.sql
     
    no changes added to commit (use "git add" and/or "git commit -a")
    
    

    可以看到isp.sql文件被修改了

  • 接下里通过 git add sql/isp.sql 命令添加到暂存区,再次查看状态

    lenovo@DESKTOP-L1PKA9E MINGW64 /d/Web/ISP/ISPServerv1.0 (master)
    $ git status
    On branch master
    Your branch is up-to-date with 'origin/master'.
    Changes to be committed:
      (use "git reset HEAD <file>..." to unstage)
     
            modified:   sql/isp.sql
    

    可以看到这个文件正在等待commit

  • 这时候发现文件有错误,想要撤回刚才的add操作,就可以通过reset命令,如下

    lenovo@DESKTOP-L1PKA9E MINGW64 /d/Web/ISP/ISPServerv1.0 (master)
    $ git reset HEAD sql/isp.sql
    Unstaged changes after reset:
    M       sql/isp.sq
    

    这时候再查看状态

    lenovo@DESKTOP-L1PKA9E MINGW64 /d/Web/ISP/ISPServerv1.0 (master)
    $ git status
    On branch master
    Your branch is up-to-date with 'origin/master'.
    Changes not staged for commit:
      (use "git add <file>..." to update what will be committed)
      (use "git checkout -- <file>..." to discard changes in working directory)
     
            modified:   sql/isp.sql
     
    no changes added to commit (use "git add" and/or "git commit -a")
    
    

    这样就回到了add操作前的状态了

注意:这时候你要想把文件内容也恢复到修改前的内容,可以通过checkout命令将本地仓库的内容覆盖掉该文件


lenovo@DESKTOP-L1PKA9E MINGW64 /d/Web/ISP/ISPServerv1.0 (master)
$ git checkout sql/isp.sql

这时候再查看状态

lenovo@DESKTOP-L1PKA9E MINGW64 /d/Web/ISP/ISPServerv1.0 (master)
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working tree clean

该文件就跟仓库里的一模一样了,抹除了你的修改


撤销commit命令

当我们进行了一次错误的提交commit,但是还未进行push操作,那么如何将这个commit撤销呢?
方法很简单,使用git log或者git reflog命令查看提交记录,找到你要找的那次提交的commit id,然后就是回退版本:

git reset --hard Obf3564

Obf3564就是commit id


版本回退

版本回退分两种情况:

第一种就是远程分支只有自己使用,这种情况下因为没有同事的提交记录,只有自己的commit,进行版本回退比较简单;通常情况下就是我们push了一次错误的代码或者无用的代码到远程分支,那么就需要回滚到之前的某个版本,操作如下:

本来本地分支和对应的远程分支版本下的README.md文件内容如下

在这里插入图片描述

然后在本地修改该文件内容

在这里插入图片描述

接下来将其推送到远程分支,然后看看log
在这里插入图片描述
但是我们发现最近的提交【readme】没有用,需要回退到最近一个正常的版本,怎么做呢?如下

$ git reset --hard 2055dc2c963848

这就是先将本地分支回退到上一个版本,看看该文件内容

在这里插入图片描述
可以看到文件内容已经恢复了,但是远程分支还没有变化,所以需要进行如下操作:

$ git push -f

这句命令意思是将本地分支内容强制推送到远程分支,也就是覆盖远程分支的意思,这个命令在多人开发时慎用,除非这个分支只有你一个人用;这样操作后,版本就回滚了

第二种情况就是远程分支是多人使用的,这时候就稍微麻烦点了,就不能再像上面那样回退版本了,因为公共分支包含同事提交的代码,你一回退,很可能就直接把别人的提交给弄丢了

版本回退
reset、revert


处理冲突Please commit your changes or stash them before you merge

有时候使用git pull命令会出现以下提示

lenovo@DESKTOP-L1PKA9E MINGW64 /d/Web/ISP/ISPServerv1.0.local (master)
$ git pull
error: Your local changes to the following files would be overwritten by merge:
        sql/isp.sql
        src/main/resources/mybatis/mybatis-config.xml
Please commit your changes or stash them before you merge.
Aborting
Updating 086076a..e2b5535

出现这个的原因就是同一个文件同事修改过并且将修改提交到了远程仓库,这时候你也对这个文件的同一处进行了修改,那么直接拉取代码会覆盖掉本地你做的修改,所以你要做的就是要么先commit你的修改,要么使用stash命令先备份

一般情况下不直接使用commit,因为会导致冲突,且会将冲突提交到远程仓库

所以就是用stash命令,使用方法如下:

  • 第一步:备份

    lenovo@DESKTOP-L1PKA9E MINGW64 /d/Web/ISP/ISPServerv1.0.local (master)
    $ git stash save "本次备份原因"
    

    这个命令做的就是将工作区的代码恢复到上次提交的内容,并且将你本地所做的修改进行备份(包括add到暂存区的和未add到暂存区的),如果不加stash信息,可以直接使用git stash

  • 第二步:恢复且备份后就可以拉取代码了

    lenovo@DESKTOP-L1PKA9E MINGW64 /d/Web/ISP/ISPServerv1.0.local (master)
    $ git pull
    
  • 第三步:恢复备份

    lenovo@DESKTOP-L1PKA9E MINGW64 /d/Web/ISP/ISPServerv1.0.local (master)
    $ git stash pop
    

    这个命令就是从最近的一个stash中读取内容并恢复工作区的相关内容,同时删除该stash备份;也就是将第一步备份的代码合并到当前工作区代码,有可能会产生冲突,需要手动在文件中进行修改


dst ref refs/heads/master receives from more than one src

git push origin master : master

当我使用这个命令进行提交的时候,报错如下

error: dst ref refs/heads/master receives from more than one src.
error: failed to push some refs to 'http://xx.xx.xx.xx/xx/xxv3.00.xx.git'

出现这种情况是因为我们的命令里出现了两个空格,即冒号与分支名之间存在空格

其实对于用户来说,是由于空格导致的问题,毕竟在shell中由于空格出现的问题不少
但是对于git来说,多一个空格就多了一个参数,
本来只需要【push】 【origin】 【master:master】 三个参数
但是我却给了5个参数【push】 【origin】 【master】 【:】 【master】

You have not concluded your merge (MERGE_HEAD exists)

使用git pull的时候报了这个错,这是因为在之前某次pull代码自动合并出现错误,在【git fetch和git pull的区别】这一节可以知道,git pull相当于是先fetch再merge;所以这里再次pull操作之前需要将上次的合并完成,做法如下:

$:git merge --abort
$:git reset --merge
$:git pull

这里是保留本地的更改并中止合并;然后重新合并;最后拉取代码
接下来就可以将你的代码提交了

其实还有一种更残暴的做法,比如你出现这种错误后,可以不保留自己本地的修改,直接将远程仓库代码合并到本地,那就使用如下方法

$:git fetch --all
$:git reset --hard origin/master
$:git fetch

git reset --hard ORIG_HEAD这个命令会清空你的working tree,即丢弃你的本地未add的那些修改


error: The following untracked working tree files would be overwritten by merge:------ Please move or remove them before you can merge.

某次在使用pull命令拉取代码的时候报这个错,字面意思就是一些untracked文件将会被此次合并操作覆盖掉,也就是,想合并代码就需要先删除这些文件,删除命令是:git clean -d -fx,这个命令会将所有未track过的文件删除,包括.gitignore文件里面指定的文件夹和文件,需要慎用;其中

  • clean:删除untracked文件
  • d:删除未被添加到git路径中的文件夹
  • f:删除未被添加到git路径中的文件
  • x:移除.gitignore文件里面指定的文件夹和文件

还有其它命令形式:

  • git clean -n:列举出当前目录所有待删除的文件
  • git clean -df -n:列举出所有待删除的文件及文件夹
  • git clean -dfx -n:列举出所有待删除的文件及文件夹,包括.gitignore文件里面指定的文件夹和文件
  • git clean -f:删除当前目录下所有没有track过的文件. 他不会删除.gitignore文件里面指定的文件夹和文件
  • git clean -f < path>:删除指定路径下的没有被track过的文件
  • git clean -df:删除整个工程下没有被track过的文件和文件夹,同时不在.gitignore里
  • git clean -fx:删除当前目录下所有没有track过的文件. 不管他是否在.gitignore文件里面

通常建议使用git clean -f和git clean -df两个命令

git clean经常和git reset --hard一起结合使用. 记住reset只影响被track过的文件, 所以需要clean来删除没有track过的文件. 结合使用这两个命令能让你的工作目录完全回到一个指定的的状态

remote: GitLab: You are not allowed to push code to protected branches on this project. To

某个新加入的小伙伴在push代码的时候遇到了这个错误

remote: GitLab: You are not allowed to push code to protected branches on this project.
To http://code.admaster.co/social-base/buzzextractor.git
 ! [remote rejected] master -> master (pre-receive hook declined)
 error: failed to push some refs to “xxxxxxxxx”

看英文意思就是不允许你往这个工程受保护的分支上提交代码

看起来是被拒绝了,其实就是没有master分支的权限,一般这个分支普通开发者是不能提交代码的,如果需要权限需要git管理员开通

update were rejected because the tip of you current branch is behind it’s remote counterpart

在某次push代码的时候,报了这样一个错

error: failed to push some refs to 'xxxxxxxxxxx.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

字面意思是本次更新被拒绝了,因为当前分支的tip是在对应远程分支的后面,所以在push之前先要整合远程修改

其实意思就是远程分支有更新了,但是本地分支没有先合并这些修改就去push,这样是不行的

解决办法:

  • 使用强制push的方法:git push -u origin master -f ;这样会使远程修改丢失,一般是不可取的,尤其是多人协作开发的时候

  • 先将远程修改拉下来,再push代码

    $ git pull origin master
    
    $ git push -u origin master
    

failed to push some refs to

某次使用push的时候报错如下

error: failed to push some refs to 'http://xxxxxx.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

意思是远程工程有本地工程没有的更新,需要先合并再提交
所以解决方法就是先使用git pull更新代码再使用git push提交代码

将本地新建工程推送到git远程仓库

情况是我本地新建了一个工程,然后写了一些代码,想把它推送到git上一个毫不相关的仓库上(可以是新建的或者已经存在的),怎么操作呢?见下方

  • 在文件管理器中进入到新建工程里,打开git bash
  • 通过git init 命令创建本地仓库
  • 通过git add . 命令将文件添加到暂存区,你也可以选择别的add命令添加某些文件
  • 通过git commit 命令将文件添加到本地仓库
  • 通过git remote add origin git仓库地址 命令关联远程仓库
  • 通过使用git pull origin master --allow-unrelated-histories 命令拉取代码
  • 通过git branch --set-upstream-to origin/master master 将远程仓库的master分支和本地master分支建立追踪关系,以后就可以使用git pull命令拉远程仓库代码
  • 通过git push origin master 或者直接使用 git push 命令将本地代码推送到远程仓库

如果远程仓库是空的,也就是只是一个空仓库,那么直接在关联仓库地址后可以直接将分支推送到远程仓库,即
git remote add origin git仓库地址执行后,就可以使用如下命令将代码推送到远程仓库对应的分支,实际上就是在远程仓库新建一个对应的分支

git push --set-upstream origin master

避免每次git push 推送代码到github输入用户名密码

在%HOME%目录中,一般为C:\users\Administrator,也可以是你自己创建的系统用户名目录,反正都在C:\users\xxx中;由于在Window中不允许直接创建以"."开头的文件,所以需要借助git bash进行,打开git bash客户端,进入%HOME%目录,执行如下命令:

touch .git-credentials
vim .git-credentials
https://{username}:{password}@github.com

注:第一行是用于创建文件.git-credentials,第二句是用git bash内置的vim工具编辑此文件;这里进入vim后需要按"a"进入编辑模式,按第三行的模版键入git信息,之后按下ESC退出编辑模式,再输入:wq!(wq!是保存并退出,vim里还有一个是q!,不保存直接退出),回到git bash,再输入以下命令:

git config --global credential.helper store

此时重启git bash,再使用push就不需要输入用户名和密码了

配置用户名和代理信息

在团队多人开发时,经常要查看日志信息,所以这时候如果每个提交者的名称不清晰或者很乱,没办法一眼看出来是谁提交的那就很头疼了,所以就需要每位开发者在git终端中设置下自己的用户名(也可以配置下邮箱)

git config user.name "myname"
git config user.email "1213132123@qq.com"

// 查看当前代理设置
git config --global http.proxy
//设置HTTP代理
git config --global http.proxy 'http://127.0.0.1:1080'
//设置HTTPS代理
git config --global https.proxy 'http://127.0.0.1:1080'
# 取消代理
git config --global --unset http.proxy
git config --global --unset https.proxy

解决github clone慢

1.首先第一步前提是已经打开了SS代理。
2.如果要设置全局代理,可以依照这样设置
git config --global http.proxy http://127.0.0.1:1080
git config --global https.proxy https://127.0.0.1:1080

需要查看自己的端口是不是也是1080,可以打开你的SS查看代理设置

这里是针对http协议进行代理,如果是ssh协议的仓库进行clone的话,还是很慢

上面这种是设置全局代理,这里不推荐,建议针对github设置代理;因为如果需要克隆coding之类的国内仓库,会奇慢无比;
如果设置了全局代理,可以先取消
git config --global --unset http.proxy
git config --global --unset https.proxy

接下来针对github进行代理
git config --global http.https://github.com.proxy https://127.0.0.1:1080
git config --global https.https://github.com.proxy https://127.0.0.1:1080

查看config配置信息

config 配置有system级别 global(用户级别) 和local(当前仓库)三个

  • git config --system --list:查看系统config
  • git config --global --list:查看当前用户(global)配置
  • git config --local --list:查看当前仓库配置信息

使用git config --list查看所有配置信息

生成ssh key

打开远程git仓库可能会看到这样一个提示信息

git  You won't be able to pull or push project code via SSH until you add an SSH key to your profile

或者

Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

这是因为远程的代码管理是基于SSH的,而本地用的是Http的,所以要使用远程的Git仓库则需要SSH的配置,生成公钥和私钥,实现本地和服务器的认证

首先需要配置下user name和email:

$ git config --global user.name "you name"
$ git config --global user.email "you email"

然后使用如下命令

ssh-keygen -t rsa -C "you email"

在这里插入图片描述
上面三个箭头处默认直接敲回车就行了,但是若需要使用多个 SSH 密钥对(您可能同时在多个代码托管平台工作),在提示“Enter file in which to save the key” 时,输入一个新的文件名称就不会覆盖默认的密钥对。
这样就在如图所示的目录生成了两个文件
在这里插入图片描述
第一个是私钥,保存在本地,第二个是公钥,最后就是把公钥文件的内容复制到GitLab服务器,如下
在这里插入图片描述
最后点击add key就可以了

可以通过如下命令进行测试,首次建立链接会要求信任主机
ssh -T git@github.com

这里有一种情况是如果你的电脑有多个git环境,比如有github的,有coding的,那么再生成密钥的时候还需要多做一步。
前提是有多个git环境且生成密钥的时候配置了自定义名称,比如 github_rsa,你需要再配置一个 config 文件:

cd ~/.ssh/

touch config

open config

在config文件里输入

Host github
    User git  
    HostName github.com
    PreferredAuthentications publickey
    IdentityFile ~/.ssh/github_rsa
    ServerAliveInterval 300
    ServerAliveCountMax 10

接着保存退出,最后测试下

ssh -T git@github.com

注意⚠️:@ 符号前后的参数要与上面 User 和 HostName对应上,一般其它平台或者公司内部的代码仓库都是自定义的,注意修改上面的参数再进行测试

切换https和ssh协议

比如我当前是https协议,需要切换成ssh,那么先添加

git remote set-url --add origin git@github.com/xxx.git

然后再删除https

git remote set-url --delete origin https://github.com/xxx.git

最后通过命令查看

mango@mangodeMacBook-Pro Android-DeepLearning % git remote -v
origin	git@github.com/xxx.git (fetch)
origin	git@github.com/xxx.git (push)

这就切换了,其实也可以打开当前工程.git目录下的config文件,直接修改里面的内容


使用vim编辑器

git默认使用vim进行文本编辑,比如在commit的时候,或者进行pull合并代码的时候会进入vim编辑器输入信息,那具体应该怎么输入信息呢?

首先进入vim的时候默认是命令行模式,这时候你不管怎么弄都没办法输入内容,不知道的还以为自己电脑出问题了;
这时候就需要进行如下操作:

  • 按 a, i 或 o 进入输入(Insert)模式,其中i表示在光标当前位置插入,a表示在光标下一个位置插入,o表示在新一行插入
  • 按下ESC键或者 Ctrl + [ 退出输入模式,进入命令行模式,这时候连按两下Z键或者输入:wq就可以保存退出了,其中
    • :w表示保存
    • :q表示离开(如果未保存会有提示)
    • :q! 不保存退出
    • :wq表示保存并离开

参考文章
https://git-scm.com/book/zh/v2
http://gitbook.liuhui998.com/4_9.html
https://blog.csdn.net/NEUQ_zxy/article/details/75267997
https://www.cnblogs.com/kevingrace/p/5690241.html

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐