第六节:Git指令汇总、常用场景、分支/标签/rebase的原理以及使用场景

一.  常用指令汇总

1.  指令图

2. 其它指令补充

 (1). 配置用户名和邮箱: 【git config --global user.name "xxx"】【git config --global user.email "xxxx"】

 (2). 查看设置的用户名和邮箱 : 【git config user.name】【git config user.email】

 (3). 查看所有配置信息:【git config --list】

 (4). 给指令设置别名: 【git config --global alias.st status】  达到的效果 【git st】等价于【git status】

 (5). 查看更简洁的状态:【git status -s】

 (6). 一次性将当前目录下所有的修改文件添加到暂存区: 【git add .】

 (7). 将修改后的文件添加到暂存区并且提交到本地仓库 : 【git commit -a -m "注释"】等价于【git add xx】+ 【git commit -m "注释"】

      PS:当这个文件已经提交后续修改的时候,可以使用上面的 -a -m 指令,如果是新增文件,还是需要分两步来执行的。

 (8). 以一行的模式查看历史提交记录: 【git log --pretty=oneline】,以图结构的形式查看: 【git log --pretty=oneline --graph】

 (9). 查看完整的历史记录,即使回退到某个版本,也可以查看该版本之后的记录 :【git reflog】

 (10). 根据commitId进行版本回退:【git reset --hard xxxxxxx】,一般commidId截取7位即可

 (11). 生成公钥和私钥的两种算法指令:【ssh-keygen -t ed25519 -C “xxxx"】或  【ssh-keygen -t rsa -b 2048 -C “xxxx"】,其中xxxx一般写email地址

 (12). 查看远程服务器地址:【git remote -v】

 (13). 将本地仓库和远程仓库建立连接: 【git remote add <remoteName> <url>】,下面是几点说明:

     A. 通过git clone下来的仓库无需操作,因为已经建立联系了。

     B.  remoteName,可以自定义命名,通常命名为:“origin”。

     C.  该指令只是建立了联系,并没有指定 本地的分支 和 远程的分支 的对应关系。

(14). 将本地的当前分支和远程某个分支建立联系 :【git branch --set-upstream-to=origin/master】,下面是几点说明:

     A. origin为远程仓库的名称,即上述的<remoteName>, master这里指的是本地当前分支和远程的master分支建立联系

     B. 建立联系后,就可以直接写 【git push】【git pull】了,不必再 【git push origin master】【git pull origin master】

     C. 【git clone】  下来的代码不需要进行这一步,默认已经进行了。

(15). 当合并的时候报错: fatal:refusing to merge unrelated histories, 需要添加 --allow-unrelated-histories, 强制执行。

    需要 【git merge --allow-unrelated-histories】  或者【git pull --allow-unrelated-histories】

(16).【git pull】 等价于 【git fetch】+ 【git merge】

(17). tag标签相关总结

       【git tag <tagName>】 在本地创建标签(在当前分支上),一般是commit之后创建标签

       【git tag -a <tagName> -m "标签备注"】 在本地当前分支上创建标签,并写备注

       【git tag】列出所有标签

       【git push <remoteName> <tagName>】将该标签推送到远程服务器 

       【git push <remoteName> --tags】将本地所有的标签推送到远程服务器

       【git tag -d <tagName>】删除本地的该标签

       【git push <remoteName> -d <tagName>】或 【git push origin :refs/tags/<tagName>】   删除远程服务器的该标签

       【git checkout <tagName>】迁出到该tag上。(存在一个问题,当前处于一个空分支上,不能进行提交代码,所以通常不这么进行)

       【git checkout -b <branchName> <tagName>】新建一个分支,并且迁出到该tag上

(18). branch分支相关总结

      【git branch <branchName>】创建一个新分支 ,但并没有切换过去

      【git checkout -b <branchName>】 创建一个新分支,并切换到新分支上(等价于  【git switch -c <branchName>】)

        分支查看相关:

         【git branch】查看所有分支                                                    【git branch –v】查看所有分支并且包含最后一次提交记录

         【git branch --merged 】查看所有合并到当前分支的分支       【git branch --no-merged】查看所有没有合并到当前分支的分支

      【git branch –d <branchName>】删除本地分支

      【git branch –D <branchName>】强制删除本地分支

      【git push origin -d <branchName>】删除远程分支

      【git push <remoteName> <branchName>】将该分支推送到远程仓库

      【git checkout --track <remoteName>/<branchName>】新建一个与远程分支相同名称<branchName>的本地分支,并且与远程分支建立起跟踪关系

      【git branch --set-upstream-to=origin/master】本地的当前分支和远程某个分支建立联系   (注:需要设置push的默认行为是 upstream,否则当本地分支和远程分支名称不同的时候,设置了也没用,详见:https://www.cnblogs.com/yaopengfei/p/17236496.html

      【git push --set-upstream origin <branchName>】等价于以下两句话:推送分支(包含当前最新的内容)并且建立跟踪

              【git push origin <branchName>  推送了分支并且将分支对应的最新内容也提交上去了

              git branch --set-upstream-to=origin/<branchName>  将当前分支远远程的origin/feature2分支建立跟踪关系,方便后期直接进行 【git push】提交即可。

      【git checkout <branchName>】

           ① 检查本地是否有该分支,有的话直接切换过去 (等价于 【git switch <branchName>】);如果没有,往后执行。

           ② 检查远程是否有同名 <remoteName>/<branchName>,如果没有,直接报错,无法match; 如果有,往后执行。

           ③ 在本地仓库新建一个<branchName>,并且与远程分支<remoteName>/<branchName>建立跟踪联系 ,并且切换到到该分支上去 (等价于 【git checkout --track <remoteName>/<branchName>】

       【git merge <branchName>】在当前分支上,合并 分支<branchName>的内容。

 

二.  Git的原理

    

   详见后面 分支  和  标签位置的 原理图

 

 

 

 

三. 常见场景

1. Git安装完,首先要进行的配置?

(1).  修改或者添加用户名和邮箱,即git服务器上将显示该用户名的提交记录。

 【git config --global user.name "yaopengfei"】

 【git config --global user.email "ypf@163.com"】

查看配置信息:【git config --list】

(2). 修改git push的默认配置为upstream

【git config --global push.default upstream】  设置全局所有仓库的 git push 默认行为是 upstream

PS:如果不设置,默认行为是simple,即推送到远程的同名分支,即使设置了【 git branch --set-upstream-to=origin/master】也没用,也就是说当前分支为feature分支,通过前面的配置,让它跟踪master分支,依旧无效

2. 有记录v1→v2→v3→v4,当前v4版本,如何回退到v2版本? 如何恢复到v4版本呢?

(1). 如何回退到v2版本 ?

   A. 先通过 【git reflog】查看日志  (或者 【git log】或者 【git log --pretty=oneline】)

  B. 通过指令【 git reset --hard cb4dde3】回退到v2版本

(2). 如何恢复到v4版本呢?

    A. 先通过 【git reflog】查看日志 (特别注意:这里不能通过【git log】查看日志了!!!,因为这种方式日志仅仅显示到v2版本以及之前的了)

  B. 通过指令【 git reset --hard b005ce7 】恢复到v4版本

3. 如何下载某个中间版本呢?

方案1:

    先把整个项目clone下来,然后  【 git reset --hard commitId 】, 回退到需要的这个版本。

    注:这个时候修改了代码不能直接提交,会报错,提示落后于最新版n次提交。需要先 【git pull】, 然后再进行本次仓库和远程仓库的提交。

方案2:

    通过tag的校验值进行回退 (同样存在无法直接提交的问题,详见 下面的 tag章节的 场景1

 

4. 服务器上有个一个git仓库,里面只有readme文件,本地有个vue项目(有些基础内容),想把vue项目和远程服务器建立联系并且把内容都推送到服务器?

方案1:【简单,没有各种问题,非常推荐】

   (1).  先通过【git clone https://gitee.com/ypf0806/vue-test1.git】的下载远程仓库到本地

   (2). 将vue项目中的文件手动复制到 vue-test1 文件夹下

   (3).  运行指令 【git add .】 【 git commit -m "初始化仓库内容"】,将复制进来的内容提交到本地仓库

         基本操作,不截图了

   (4). 运行指令 【git push】, 将本地仓库的内容推送到远程仓库 (git clone的模式,直接就将本地分支和远程分支建立联系了,所以不需要 【git push origin master】的写法了)

方案2:【繁琐啊,但有利于理解git】

(1). 先在本地的vue项目的文件夹里【git init】初始化Git

(2). 运行指令【git add .】 【 git commit -m "初始化仓库内容"】进行本地仓库的提交

(3). 将本地仓库与远程仓库建立联系  【git remote add origin https://gitee.com/ypf0806/vue-test2.git】

(4). 将本地当前分支与远程的某个分支建立跟踪关系   【git branch --set-upstream-to=origin/master】

   PS: 如果不执行上述指令,直接执行【git pull】,会报如下错误:即没有跟踪分支分支,

   解决方案:要么执行上述指令【git branch --set-upstream-to=origin/master】指定分支,一劳永逸,要么每次都写完成的指令【git pull origin master】

(5). 运行指令【git pull --allow-unrelated-histories】进行 拉取+合并 代码,然后输入 :wq 退出。

   PS:如果不执行上述指令,直接【git pull】 或者 先【git fetch】,然后【git merge】,报错如下图:

   原因可参考: https://stackoverflow.com/questions/37937984/git-refusing-to-merge-unrelated-histories-on-rebase

   即:过去git merge允许将两个没有共同基础的分支进行合并,这导致了一个后果:新创建的项目可能被一个毫不怀疑的维护者合并了很多没有必要的历史,到一个已经存在的项目中,目前这个命令已经被纠正,但是我们依然可以通过--allow-unrelated-histories选项来逃逸这个限制,来合并两个独立的项目;【git 2.9版本开始出现这个问题】

  解决方案:【git pull --allow-unrelated-histories】  或者  先【git fetch】,然后【git merge --allow-unrelated-histories

(6). 将本地仓库推送到远程服务器 【git push】

 

5.  同一个分支冲突的处理  

  (PS: 不同分支代码合并冲突处理 详见后面的 分支章节)

  前提:Git服务器上有一个 test.txt文件,默认内容为 111,用户A和用户B都clone下来。

  情况1:

       用户A不动,用户B改为 “111+222”,并push到远程服务器;用户A执行【git pull】,则用户A的内容变为:“111+222”。

  情况2:

      用户A改为: "111+333",并commit到本地仓库;  用户B改为 “111+222”,并push到远程服务器;用户A执行【git pull】,会报冲突,需要借助客户端进行解决。

 情况3:

      用户A改为: "111+333",不做任何提交;  用户B改为 “111+222”,并push到远程服务器;用户A执行【git pull】,直接报错,无法拉取,提示让先commit。

 

6.  关于删除文件的测试

   git pull指令是将远程服务器的内容 和 本地仓库中的最新一次快照相比较。

   比如:现在本地已经全部commit完了,且已经push了, 这个时候将本地的一个 test.txt文件删掉, 执行git pull, test.txt文件无法回来。

   再比如:把本地的test.txt文件删掉,git add ,git commit提交,然后执行git pull,是无法恢复的,这个时候借助本地仓库的提交记录, 使用git reset就可以恢复了。

 

 

三. 分支重点剖析

1.  分支的原理(本地分支)

(1). Git 的分支,其实本质上仅仅是指向提交对象的可变指针

     Git 的默认分支名字是 master,在多次提交操作之后,你其实已经有一个指向最后那个提交对象的 master 分支;  master 分支会在每次提交时自动移动 。

(2). Git 的 master 分支并不是一个特殊分支。

     它就跟其它分支完全没有区别; 之所以几乎每一个仓库都有 master 分支,是因为 git init 命令默认创建它,并且大多数人都懒得去改动它;

(3). 新建分支只是为你创建了一个可以移动的新的指针。

(4). Git 又是怎么知道当前在哪一个分支上呢? 是通过一个名为 HEAD 的特殊指针

(5). 如果我们指向某一个分支,并且在这个分支上提交,该分支的指针会指向最新的一条提交记录

(6). 如果切换回到master分支,继续开发,进行提交,如下图,会产生两条线路

(7). 分支的合并

(如下图:tag v1.0.0版本存在bug,需要在该处新建一个分支 hotfix,然后修改bug,进行提交(连续提交了两次:fix_01、fix_02),并标记为tag v1.0.1(该版本是bug修复的版本), 此时主分支已经提交到555,需要切换到主分支 master,然后对hotfix分支进行合并)

 

(8). 分支的删除

    接着上述合并完成后,hotfix分支已经不需要了,因为已经合并到master主分支上了,所以删掉hotfix分支,分支的删除只是把指向提交对象的指针删掉了,并没有删掉提交记录哦

2. 远程分支

(1). 什么是远程分支?

     远程分支是也是一种分支结构,Clone后,Git服务器上的分支 会以 <remoteName>/<branchName> 的形式命名的,存在于本地仓库里。

  A.  张三刚clone下来的代码,如下图,远程分支origin/master本地分支master指向最新的提交快照f4265  【注:clone后,远程分支origin/master 也存在本地仓库里】

  B. 张三在本地继续修改代码进行提交,本地的master分支指向 893cf 快照,领先于远程分支origin/master两个版本

 C. 其它组员李四也在执行上述步骤,开发其它功能,并且已经push到远程服务器了,此时服务器上master分支已经到了190a3版本了。

 D. 张三执行【git fetch】指令,拉取代码到本地,此时有两条线路。  远程分支origin/master 和 本地分支master 各自指向自己的最新版本快照。  (PS:这个时候服务器上的master分支中的最新内容  已经 以 远程分支 origin/master的形式下载到本地仓库里了,只是还没有同步到工作区间而已)

 E. 张三执行 【git merge】指令,即将 本地仓库中远程分支 origin/master  中的内容合并到本地分支master中。

(2). 分支推送到远程?

(这里指的是新建一个远程仓库中不存在的分支)

 A.  运行指令【git checkout -b feature】,新建一个feature分支,并切换过去,表示该分支是一个新内容,不一定最终是否使用

 B. 新增一个 test2.txt 文件,并且运行指令进行本地仓库的提交 【git add . 】和 【git commit -m "新功能text2的提交"】

 C. 直接运行指令 【git push】进行远程提交,报错,无法提交,因为该分支的内容没有和远程服务器上的分支进行跟踪,即不知道往哪提交

 D. 按照上述描述,运行指令 【 git push --set-upstream origin feature】,分支提交成功了,同时最新的内容也提交上去了,也建立起了跟踪关系了。

    【git push --set-upstream origin feature】等价于以下两句话:推送分支并且建立跟踪

    【git push origin feature】  推送了分支并且将分支对应的最新内容也提交上去了

    git branch --set-upstream-to=origin/feature  将当前分支远远程的origin/feature2分支建立跟踪关系,方便后期直接进行 【git push】提交即可。

 

(3). 如何新建本地分支跟踪远程分支呢?

   (这里指的是远程服务器有分支,想建立一个同名的本地分支与起关联跟踪) 

   【git checkout --track <remoteName>/<branchName>】 简写为  【git checkout branchName】

PS:  尽量不要 本地分支名称 和远程分支的名称不相同,会产生一些额外的配置!!!!!!!!

3.  分支使用场景 【重点】

  开发某个项目,在默认分支master上进行开发, 实现项目的功能需求,不断提交;333的时候打上标签 tag v1.0.0,表示这是一个正式版本,已经发布了; 然后继续开发 444←555.

  正在此时,你突然接到一个电话说有个很严重的问题需要紧急修补, 你将按照如下方式来处理: 切换到tag v1.0.0的版本,并且创建一个分支hotfix;进行修改bug,并进行两次提交,最后那次提交表示bug修改完成,打上标签 tag v1.0.1

  然后切换到主分支上,合并hotfix分支,此时会有冲突,需要解决一下,解决完成,合并成功。 


(1).  编辑test1.txt文件,每行的内容依次是 111 、222、333、444、555 。其中 333 的使用,需要加一个 tag v1.0.0 标签。

     【git commit -a - m "111"】【git push】

     【git commit -a - m "222"】【git push】

     【git commit -a - m "333"】【git push】  【git tag -a v1.0.0 -m "v1.0.0正式版本"】 【git push origin v1.0.0】

     【git commit -a - m "444"】【git push】

     【git commit -a - m "555"】【git push】

 

(2).  切换到 tag v1.0.0版本,并创建标签 hotfix

   【git checkout -b hotfix v1.0.0】

 

(3). 修改test1.txt内容,修改两次, 第一次在 333的基础上 加 “aaa”,提交; 第二次加上 “bbb”提交,然后打上标签,v1.0.1 ,表示修复了bug

    【git commit -a -m "fix_01"】

    【git commit -a -m "fix_02"】

   【git tag -a v1.0.1 -m "v1.0.1修复bug版本"】

 

(4). 将hotfix分支上的内容推送要远程,然后再把标签也推送到远程服务器。

   【git push --set-upstream origin hotfix】

   【git push origin v1.0.1】

 

(5). 切换到master分支上,合并hotfix分支,并借助客户端  ToritoiseGit 解决冲突。

    【git checkout master】

    【git merge hotfix】

(6). 提交合并后的版本到远程服务,大功告成,收工。

  【git commit -a -m "合并了hotfix的版本完善"】【git push】

 

 

四. 标签的使用

1. tag标签常见场景

场景1: (不建新分支的情况下,通过校验值回退到某个tag上)

  (1). 可以直接根据标签上的校验码进行版本回退,【git reset --hard 8b4dff9】, 此时还是在master分支上,并不是空分支

  (2). 这个时候,修改代码,然后进行 【git commit -a -m "xxxxx"】,进行本地提交;  然后进行远程推送 【git push】

   这时候会报错,原因是由于你回退到之前的一个版本了,当前的版本落后于远程仓库的版本,所以不允许提交

  (3). 运行 【git pull】拉取并合并代码,可能会有冲突,可以借助客户端进行解决

  (4).  提交本地仓库并且推送远程仓库

  【git commit -a -m "xxxx"】【git push】

 

场景2: (迁移到某个tag,但是不加分支)

【git checkout <tagName>】迁出到该tag上,然后修改代码,最后git push,会报错,因为当前没有分支 

 

场景3: (迁移到某个tag,并创建分支)

【git checkout -b <branchName> <tagName>】回退到这个tag版本上,并且新建一个分支

 详见上面最后那个分支的使用场景

 

3. tag原理

    tag实际上就是一个标记,重大的版本我们常常会打上一个标签,以表示它的重要性。 我们可以把它理解成是一个固定的指针,通过这个指针可以快速回退到某一个版本,但通常回退到某个tag的时候,需要建立一个新的分支,否则无法直接提交代码,因为位于空分支。

 

五. rebase原理及使用

1. rebase含义

  核心指令【git  rebase <branchName1>】, 表示将当前分支上   变基到   <branchName1>分支上。 (参考:https://blog.csdn.net/weixin_42310154/article/details/119004977 )

  比如在 feature 分支上执行 【git rebase master】,  则:表示把 feature分支 变基到 master分支上。

    ①. feature:待变基分支、当前分支

    ②. master:基分支、目标分支

rebase有一条黄金法则:永远不要在主分支上使用rebase, 如果在主分支上面使用rebase,会造成大量的提交历史在main分支中不同;

 

2. rebase原理

(1).  下面是原始图,表示在 bbb 的基础上新建了一个 feature分支,并提交两次记录,分别是 f01、f02。

(2). 下面是变基图,表示在feature分支上执行指令 【git rebase master】,变基到 master分支上,生成的快照 f01' 、f02'。 

特别注意:这里的 f01' 、f02' 和之前 f01、f02并不相同,这里的f01’表示是f01和ccc节点合并后的内容,这里的f02’表示是f02和ccc节点合并后的内容,可能会存在冲突,需要我们手动处理。

补充merge的图,用于和上述rebase的图进行比较,下图表示在master分支上执行 【git merge feature】

(3). 在上图的基础上切换到master分支,然后执行【 git merge feature】,这里的 master指向的 f02' 的内容 实际上与合并后的 ddd内容是相同。

补充 merge 和 rebase的区别:

  A. merge 会多出一次 merge commit,rebase不会。

  B. .merge 的提交树是非线性的,rebase 的提交树是线性的,可以通过指令 【git log --pretty=oneline --graph】来查看。

 

3. rebase实操

(1).  有个test1.txt 文件,在master分支上,内容分别为 aaa、bbb、并且push到远程仓库。

      【git commit -a -m "aaa"】【git push】

      【git commit -a -m "bbb"】【git push】  

(2).   新建一个分支 feature;然后两次修改test1.txt文件,内容分别为  aaa+f01、 bbb+f02

       【git checkout -b feature】

      【git commit -a -m "f01"】【git push --set-upstream origin feature】

      【git commit -a -m "f02"】【git push】

(3). 回到master分支,修改内容 ccc,并且push到远程仓库

 【git checkout master】

 【git commit -a -m "ccc"】【git push】

 

(4). 在feature分支执行rebase操作。 

   【git checkout feature】

   【git rebase master】

编辑后,会有冲突,报错。

通过客户端解决冲突后,继续执行【git rebase --continue】

(4). 切换到master分支上,执行合并操作

  【git checkout master】

  【git merge feature】

 

 

 

 

 

 

 

!

  • 作       者 : Yaopengfei(姚鹏飞)
  • 博客地址 : http://www.cnblogs.com/yaopengfei/
  • 声     明1 : 如有错误,欢迎讨论,请勿谩骂^_^。
  • 声     明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
 
posted @ 2023-03-14 14:10  Yaopengfei  阅读(225)  评论(1编辑  收藏  举报