从零出发

中义传家美,永保万年春

0%

Git使用分享

Git使用分享

一、Git概述

1.1 Git历史

Git 诞生于一个极富纷争大举创新的年代。Linux 内核开源项目有着为数众多的参与者。 绝大多数的 Linux 内核维护工作都花在了提交补丁和保存归档的繁琐事务上(1991-2002年间)。 到 2002 年,整个项目组开始启用一个专有的分布式版本控制系统 BitKeeper 来管理和维护代码。
到了 2005 年,开发 BitKeeper 的商业公司同 Linux 内核开源社区的合作关系结束,他们收回了 Linux 内核社区免费使用 BitKeeper 的权力。 这就迫使 Linux 开源社区(特别是 Linux 的缔造者 Linus Torvalds)基于使用 BitKeeper 时的经验教训,开发出自己的版本控制系统。
他们对新的系统制订了若干目标:

  • 速度
  • 简单的设计
  • 对非线性开发模式的强力支持(允许成千上万个并行开发的分支)
  • 完全分布式
  • 有能力高效管理类似 Linux 内核一样的超大规模项目(速度和数据量)

    1.2 Git与SVN对比

    SVN是集中式版本控制系统,版本库是集中放在中央服务器的,而开发人员工作的时候,用的都是自己的电脑,所以首先要从中央服务器下载最新的版本,然后开发,开发完后,需要把自己开发的代码提交到中央服务器。
    Git 与 SVN 区别点:
  • 1、Git 是分布式的,SVN 不是:这是 Git 和其它非分布式的版本控制系统,例如 SVN,CVS 等,最核心的区别。
  • 2、Git 把内容按元数据方式存储,而 SVN 是按文件:所有的资源控制系统都是把文件的元信息隐藏在一个类似 .svn、.cvs 等的文件夹里。
  • 3、Git 分支和 SVN 的分支不同:分支在 SVN 中一点都不特别,其实它就是版本库中的另外一个目录。
  • 4、Git 没有一个全局的版本号,而 SVN 有:目前为止这是跟 SVN 相比 Git 缺少的最大的一个特征。
  • 5、Git 的内容完整性要优于 SVN:Git 的内容存储使用的是 SHA-1 哈希算法。这能确保代码内容的完整性,确保在遇到磁盘故障和网络问题时降低对版本库的破坏。

集中式版本控制工具缺点:

  • 服务器单点故障
  • 容错性差
    Git是分布式版本控制系统(Distributed Version Control System,简称 DVCS) ,分为两种类型的仓库:
  • 本地仓库:是在开发人员自己电脑上的Git仓库
  • 远程仓库:是在远程服务器上的Git仓库
    svn.vs.git

    1.3 Git工作流程

    工作流程如下:
    1.从远程仓库中克隆代码到本地仓库
    2.从本地仓库中checkout代码然后进行代码修改
    3.在提交前先将代码提交到暂存区
    4.提交到本地仓库。本地仓库中保存修改的各个历史版本
    5.修改完成后,需要和团队成员共享代码时,将代码push到远程仓库
    git-workflow

    1.4 Git下载与安装

    下载地址: https://git-scm.com/download
    git-dowmload
    下载完成后可以得到如下安装文件:
    git.exe
    这里默认下载的是64位的软件
    双击下载的安装文件来安装Git。
    一直下一步直到安装完成即可
    安装完成后在电脑桌面(也可以是其他目录)点击右键,如果能够看到如下两个菜单则说明Git安装成功。
    git-bash
    Git GUI:Git提供的图形界面工具
    Git Bash:Git提供的命令行工具

    二、Git代码托管服务

    2.1 常用的Git代码托管服务

    前面我们已经知道了Git中存在两种类型的仓库,即本地仓库和远程仓库。那么我们如何搭建Git远程仓库呢?我们可以借助互联网上提供的一些代码托管服务来实现,其中比较常用的有GitHub、码云、GitLab等。
  • gitHub( 地址:https://github.com/ )是一个面向开源及私有软件项目的托管平台,因为只支持Git 作为唯一的版本库格式进行托管,故名gitHub
  • 码云(地址: https://gitee.com/ )是国内的一个代码托管平台,由于服务器在国内,所以相比于GitHub,码云速度会更快
  • GitLab (地址: https://about.gitlab.com/ )是一个用于仓库管理系统的开源项目,使用Git作为代码管理工具,并在此基础上搭建起来的web服务

本次使用码云作为演示,码云在国内用起来网速比GitHub快

2.2 在码云注册账号

要想使用码云的相关服务,需要注册账号(地址: https://gitee.com/signup
gitee-register

2.3 登录码云并创建Git远程仓库

注册完成后就可以使用刚刚注册的邮箱进行登录(地址: https://gitee.com/login
gitee-login
登录成功后就可以创建Git远程仓库
git-init
创建完成后可以查看仓库信息
git-init
每个Git远程仓库都会对应一个网络地址,可以点击克隆/下载按钮弹出窗口并点击复制按钮获得这个网络地址
git-test

2.4 邀请其他用户成为仓库成员

前面已经在码云上创建了自己的远程仓库,目前仓库成员只有自己一个人(身份为管理员)。在企业实际开发中,一个项目往往是由多个人共同开发完成的,为了使多个参与者都有权限操作远程仓库,就需要邀请其他项目参与者成为当前仓库的成员。
gitee-members

三、Git常用命令

先学习如下一些命令和概念:

  • 环境配置
  • 获取Git仓库
  • 工作目录、暂存区以及版本库概念
  • Git工作目录下文件的两种状态
  • 本地仓库操作
  • 远程仓库的使用
  • 分支
  • 标签

    3.1 环境配置

    当安装Git后首先要做的事情是设置用户名称和email地址。这是非常重要的,因为每次Git提交都会使用该用户信息
    设置用户信息
    git config --global user.name “your name”
    git config --global user.email “your name@gmail.com”
    查看配置信息
    git config --list
    git config user.name
    通过上面的命令设置的信息会保存在~/.gitconfig文件中

3.2 获取Git仓库

要使用Git对我们的代码进行版本控制,首先需要获得Git仓库
获取Git仓库通常有两种方式:

  • 在本地初始化一个Git仓库
  • 从远程仓库克隆

    3.2.1 在本地初始化一个Git仓库

    执行步骤如下:
  1. 在电脑的任意位置创建一个空目录(例如testGit)作为我们的本地Git仓库
  2. 进入这个目录中,点击右键打开Git bash窗口
  3. 执行命令git init
  4. 如果在当前目录中看到.git文件夹(此文件夹为隐藏文件夹)则说明Git仓库创建成功
    git-folder

    3.2.2 从远程仓库克隆

    可以通过Git提供的命令从远程仓库进行克隆,将远程仓库克隆到本地
    命令形式为:git clone 远程Git仓库地址
    git-clone

执行如下命令以创建一个本地仓库的克隆版本:
git clone /path/to/repository
如果是远端服务器上的仓库,你的命令会是这个样子:
git clone username@host:/path/to/repository

3.3 工作目录、暂存区以及版本库概念

为了更好的学习Git,我们需要了解Git相关的一些概念,这些概念在后面的学习中会经常提到

  • 版本库:前面看到的.git隐藏文件夹就是版本库,版本库中存储了很多配置信息、日志信息和文件版本信息等

  • 工作目录(工作区):包含.git文件夹的目录就是工作目录,主要用于存放开发的代码

  • 暂存区:.git文件夹中有很多文件,其中有一个index文件就是暂存区,也可以叫做stage。暂存区是一个临时保存修改文件的地方

  • HEAD:指向你最近一次提交后的结果
    参考外图
    下面这个图展示了工作区、版本库中的暂存区和版本库之间的关系
    参考外图

  • 图中左侧为工作区,右侧为版本库。在版本库中标记为 “index” 的区域是暂存区(stage/index),标记为 “master” 的是 master 分支所代表的目录树。

  • 图中我们可以看出此时 “HEAD” 实际是指向 master 分支的一个”游标”。所以图示的命令中出现 HEAD 的地方可以用 master 来替换。

  • 图中的 objects 标识的区域为 Git 的对象库,实际位于 “.git/objects” 目录下,里面包含了创建的各种对象及内容。

  • 当对工作区修改(或新增)的文件执行 git add 命令时,暂存区的目录树被更新,同时工作区修改(或新增)的文件内容被写入到对象库中的一个新的对象中,而该对象的ID被记录在暂存区的文件索引中。

  • 当执行提交操作(git commit)时,暂存区的目录树写到版本库(对象库)中,master 分支会做相应的更新。即 master 指向的目录树就是提交时暂存区的目录树。

  • 当执行 git reset HEAD 命令时,暂存区的目录树会被重写,被 master 分支指向的目录树所替换,但是工作区不受影响。

  • 当执行 git rm --cached <file> 命令时,会直接从暂存区删除文件,工作区则不做出改变。

  • 当执行 git checkout . 或者 git checkout-- <file>命令时,会用暂存区全部或指定的文件替换工作区的文件。这个操作很危险,会清除工作区中未添加到暂存区的改动。

  • 当执行 git checkout HEAD . 或者 git checkout HEAD <file> 命令时,会用 HEAD 指向的 master 分支中的全部或者部分文件替换暂存区和以及工作区中的文件。这个命令也是极具危险性的,因为不但会清除工作区中未提交的改动,也会清除暂存区中未提交的改动。

    3.4 Git工作目录下文件的五种状态

    Git工作目录下的文件存在五种状态:

  • untracked 未跟踪(未被纳入版本控制)

  • tracked 已跟踪(被纳入版本控制)

  • unmodified 未修改状态

  • modified 已修改状态

  • staged 已暂存状态
    这些文件的状态会随着我们执行Git的命令发生变化

    3.5 本地仓库操作

  • git status 查看文件状态,也可以使用git status –s 使输出信息更加简洁

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    PS D:\test> 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: README.md

    no changes added to commit (use "git add" and/or "git commit -a")
    PS D:\test> git status -s
    M README.md
    PS D:\test>
  • git add 将未跟踪的文件加入暂存区
    将新创建的文件加入暂存区后查看文件状态

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    PS D:\test> git add .\README.md
    PS D:\test> 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: README.md

    PS D:\test>
  • git reset 将暂存区的文件取消暂存
    将文件取消暂存后查看文件状态

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    PS D:\test> git reset .\README.md   
    Unstaged changes after reset:
    M README.md
    PS D:\test> 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: README.md

    no changes added to commit (use "git add" and/or "git commit -a")
    PS D:\test>
  • git commit 将暂存区的文件修改提交到本地仓库

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    PS D:\test> git add .\README.md
    PS D:\test> git commit -m "update Readme" .\README.md
    [master 7ac056e] update Readme
    1 file changed, 4 insertions(+)
    PS D:\test> git status
    On branch master
    Your branch is ahead of 'origin/master' by 1 commit.
    (use "git push" to publish your local commits)

    nothing to commit, working tree clean
    PS D:\test>
  • git rm 删除文件
    删除文件后查看文件状态

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    PS D:\test> git rm .\README.md   
    rm 'README.md'
    PS D:\test> git status
    On branch master
    Your branch is ahead of 'origin/master' by 1 commit.
    (use "git push" to publish your local commits)

    Changes to be committed:
    (use "git reset HEAD <file>..." to unstage)

    deleted: README.md

    PS D:\test>

    上面删除的只是工作区的文件,需要提交到本地仓库

  • 将文件添加至忽略列表
    一般我们总会有些文件无需纳入Git 的管理,也不希望它们总出现在未跟踪文件列表。 通常都是些自动生成的文件,比如日志文件,或者编译过程中创建的临时文件等。 在这种情况下,我们可以在工作目录中创建一个名为 .gitignore 的文件(文件名称固定),列出要忽略的文件模式。下面是一个示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    # no .a files
    *.a
    # but do track lib.a, even though you're ignoring .a files above
    !lib.a
    # only ignore the TODO file in the current directory, not subdir/TODO
    /TODO
    # ignore all files in the build/ directory
    build/
    # ignore doc/notes.txt, but not doc/server/arch.txt
    doc/*.txt
    # ignore all .pdf files in the doc/ directory
    doc/**/*.pdf

    3.6 远程仓库操作

    前面执行的命令操作都是针对的本地仓库,本章节我们会学习关于远程仓库的一些操作,具体包括:

  • 查看远程仓库
    如果想查看已经配置的远程仓库服务器,可以运行 git remote 命令。 它会列出指定的每一个远程服务器的简写。 如果已经克隆了远程仓库,那么至少应该能看到 origin ,这是 Git 克隆的仓库服务器的默认名字

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    PS D:\test> git remote
    origin
    PS D:\test> git remote -v
    origin https://gitee.com/fusionshen/test.git (fetch)
    origin https://gitee.com/fusionshen/test.git (push)
    PS D:\test> git remote show origin
    * remote origin
    Fetch URL: https://gitee.com/fusionshen/test.git
    Push URL: https://gitee.com/fusionshen/test.git
    HEAD branch: master
    Remote branch:
    master tracked
    Local branch configured for 'git pull':
    master merges with remote master
    Local ref configured for 'git push':
    master pushes to master (up to date)
    PS D:\test>
  • 添加远程仓库
    运行 git remote add < shortname> < url> 添加一个新的远程 Git 仓库,同时指定一个可以引用的简写

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    PS D:\minhang\testGit> git status
    On branch master

    No commits yet

    nothing to commit (create/copy files and use "git add" to track)
    PS D:\minhang\testGit> git remote add origin https://gitee.com/fusionshen/test.git
    PS D:\minhang\testGit> git remote -v
    origin https://gitee.com/fusionshen/test.git (fetch)
    origin https://gitee.com/fusionshen/test.git (push)
    PS D:\minhang\testGit>
  • 从远程仓库克隆
    如果你想获得一份已经存在了的 Git 仓库的拷贝,这时就要用到 git clone 命令。 Git 克隆的是该 Git 仓库服务器上的几乎所有数据(包括日志信息、历史记录等),而不仅仅是复制工作所需要的文件。 当你执行 git clone 命令的时候,默认配置下远程 Git 仓库中的每一个文件的每一个版本都将被拉取下来。
    克隆仓库的命令格式是 git clone [url]

  • 移除无效的远程仓库
    如果因为一些原因想要移除一个远程仓库 ,可以使用 git remote rm

    1
    2
    3
    4
    5
    PS D:\minhang\testGit> git remote 
    origin
    PS D:\minhang\testGit> git remote rm origin
    PS D:\minhang\testGit> git remote
    PS D:\minhang\testGit>

    注意:此命令只是从本地移除远程仓库的记录,并不会真正影响到远程仓库

  • 从远程仓库中抓取与拉取
    git fetch 是从远程仓库获取最新版本到本地仓库,不会自动merge
    git pull 是从远程仓库获取最新版本并merge到本地仓库,即git fetch + git merge
    fetch&merge

    注意:如果当前本地仓库不是从远程仓库克隆,而是本地创建的仓库,并且仓库中存在文件,此时再从远程仓库拉取文件的时候会报错(fatal: refusing to merge unrelated histories ),解决此问题可以在git pull命令后加入参数–allow-unrelated-histories
    当执行git中的“git pull origin master –allow-unrelated-histories”命令时,会出现“ couldn’t find remote ref –allow-unrelated-histories”的错误,
    输入如下命令即可解决:
    git pull –rebase origin master

  • 将本地分支与远程分支关联:
    git branch --set-upstream-to origin/master master

  • 推送到远程仓库
    当你想分享你的代码时,可以将其推送到远程仓库。 命令形式:git push [remote-name] [branch-name]
    git-push

    3.7 Git分支

    几乎所有的版本控制系统都以某种形式支持分支。 使用分支意味着你可以把你的工作从开发主线上分离开来,以免影响开发主线。Git 的master分支并不是一个特殊分支。 它跟其它分支没有区别。 有人把 Git 的分支模型称为必杀技特性,而正是因为它,将 Git 从版本控制系统家族里区分出来,也就是所谓“杀手”级应用。之所以几乎每一个仓库都有 master 分支,是因为git init 命令默认创建它,并且大多数人都懒得去改动它。
    在本章节我们会学习到关于分支的相关命令,具体如下:

  • 查看分支

    • 列出所有本地分支
      git branch
    • 列出所有远程分支
      git branch -r
    • 列出所有本地分支和远程分支
      git branch -a
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      PS D:\minhang\testGit> git banch -r
      git: 'banch' is not a git command. See 'git --help'.

      The most similar command is
      branch
      PS D:\minhang\testGit> git branch -r
      origin/master
      PS D:\minhang\testGit> git branch -a
      dev
      master
      * stage
      remotes/origin/master
      PS D:\minhang\testGit>
  • 创建分支

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    PS D:\minhang\testGit> git branch
    * master
    PS D:\minhang\testGit> git branch dev
    PS D:\minhang\testGit> git branch
    dev
    * master
    PS D:\minhang\testGit> git checkout -b stage
    Switched to a new branch 'stage'
    PS D:\minhang\testGit> git branch
    dev
    master
    * stage
  • 切换分支

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    PS D:\minhang\testGit> git branch -a
    dev
    master
    * stage
    remotes/origin/master
    PS D:\minhang\testGit> git checkout master
    Switched to branch 'master'
    Your branch is up to date with 'origin/master'.
    PS D:\minhang\testGit> git branch
    dev
    * master
    stage
    PS D:\minhang\testGit>
  • 推送至远程仓库分支

    1
    2
    3
    4
    5
    6
    7
    8
    PS D:\minhang\testGit> git push origin dev
    Total 0 (delta 0), reused 0 (delta 0)
    remote: Powered by GITEE.COM [GNK-5.0]
    remote: Create a pull request for 'dev' on Gitee by visiting:
    remote: https://gitee.com/fusionshen/test/pull/new/fusionshen:dev...fusionshen:master
    To https://gitee.com/fusionshen/test.git
    * [new branch] dev -> dev
    PS D:\minhang\testGit>
  • 合并分支

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    PS D:\minhang\testGit> git status
    On branch dev
    (use "git add <file>..." to update what will be committed)
    (use "git checkout -- <file>..." to discard changes in working directory)

    modified: README.md
    no changes added to commit (use "git add" and/or "git commit -a")
    PS D:\minhang\testGit> git add .
    PS D:\minhang\testGit> git commit -m "测试分支合并"
    [dev acff4ab] 测试分支合并
    1 file changed, 2 insertions(+), 1 deletion(-)
    PS D:\minhang\testGit> git push origin dev
    Counting objects: 3, done.
    Delta compression using up to 4 threads.
    Compressing objects: 100% (3/3), done.
    Writing objects: 100% (3/3), 320 bytes | 320.00 KiB/s, done.
    Total 3 (delta 2), reused 0 (delta 0)
    remote: Powered by GITEE.COM [GNK-5.0]
    To https://gitee.com/fusionshen/test.git
    f5d3192..acff4ab dev -> dev
    PS D:\minhang\testGit> git checkout master
    Switched to branch 'master'
    Your branch is up to date with 'origin/master'.
    PS D:\minhang\testGit> git merge dev
    Updating f5d3192..acff4ab
    Fast-forward
    README.md | 3 ++-
    1 file changed, 2 insertions(+), 1 deletion(-)
    PS D:\minhang\testGit> git status
    On branch master
    Your branch is ahead of 'origin/master' by 1 commit.
    (use "git push" to publish your local commits)

    nothing to commit, working tree clean
    PS D:\minhang\testGit>

    有时候合并操作不会如此顺利。 如果你在两个不同的分支中,对同一个文件的同一个部分进行了不同的修改,Git 就没办法合并它们,同时会提示文件冲突。此时需要我们打开冲突的文件并修复冲突内容,最后执行git add命令来标识冲突已解决

  • 删除分支

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    PS D:\minhang\testGit> git branch
    * dev
    master
    stage
    PS D:\minhang\testGit> git checkout stage
    Switched to branch 'stage'
    PS D:\minhang\testGit> git branch -d stage
    error: Cannot delete branch 'stage' checked out at 'D:/minhang/testGit'
    PS D:\minhang\testGit> git checkout master
    Switched to branch 'master'
    Your branch is ahead of 'origin/master' by 1 commit.
    (use "git push" to publish your local commits)
    PS D:\minhang\testGit> git branch -d stage
    Deleted branch stage (was f5d3192).
    PS D:\minhang\testGit>

    如果要删除的分支中进行了一些开发动作,此时执行上面的删除命令并不会删除分支,如果坚持要删除此分支,可以将命令中的-d参数改为-D

    3.8 Git标签

    像其他版本控制系统(VCS)一样,Git 可以给历史中的某一个提交打上标签,以示重要。 比较有代表性的是人们会使用这个功能来标记发布结点(v1.0 、v1.2等)。标签指的是某个分支某个特定时间点的状态。通过标签,可以很方便的切换到标记时的状态。
    下面将学习:

  • 列出已有的标签

    1
    2
    3
    4
    # 列出所有tag
    $ git tag
    # 查看tag信息
    $ git show [tag]
  • 创建新标签

    1
    2
    # 新建一个tag
    $ git tag [tagName]
  • 将标签推送至远程仓库

    1
    2
    # 提交指定tag
    $ git push [remote] [tag]
  • 检出标签

    1
    2
    # 新建一个分支,指向某个tag
    $ git checkout -b [branch] [tag]
  • 删除标签

    1
    2
    3
    4
    # 删除本地tag
    $ git tag -d [tag]
    # 删除远程tag
    $ git push origin :refs/tags/[tag]

    四、在IDEA中使用Git

    4.1 在IDEA中配置Git

    安装好IntelliJ IDEA后,如果Git安装在默认路径下,那么idea会自动找到git的位置,如果更改了Git的安装位置则需要手动配置下Git的路径。
    选择File→Settings打开设置窗口,找到Version Control下的git选项:
    idea-config-git
    选择git的安装目录后可以点击“Test”按钮测试是否正确配置

    4.2 在IDEA中使用Git

    本章节我们会学习在IDEA中使用Git进行版本管理,具体包括:

  • 在IDEA中创建工程并将工程添加至Git
    idea-clone
    将项目添加至Git管理后,可以从IDEA的工具栏上看到Git操作的按钮
    当然更多的情况是用IDEA打开远程仓库
    idea-cloneimage-20210315211623301

  • 将文件添加到暂存区
    git-add-dot

  • 提交文件
    git-commit

  • 将代码推送到远程仓库
    git-pushimage-20210315213016819git-push-3

  • 从远程仓库克隆工程到本地

  • 从远程拉取代码
    git-pull-1git-pull-2

  • 版本对比
    git-diffgit-diff-2git-diff-3

  • 创建分支
    git-b-branch

  • 切换分支
    git-checkout

  • 分支合并
    git-merge
    git-merge-2

    五、命令行更好用

    5.1 查看提交历史

  • git log -查看历史提交记录
    在使用 Git 提交了若干更新之后,又或者克隆了某个项目,想回顾下提交历史,我们可以使用 git log 命令查看。

    • 我们可以用 –oneline 选项来查看历史记录的简洁的版本。git log --oneline
      1
      2
      3
      4
      5
      6
      7
      8
      9
      PS D:\minhang\testGit> git log --oneline
      1f98086 (HEAD -> master, origin/master) fix conflicts
      69302e7 idea
      2d5d070 (origin/dev, dev) 测试idea合并分支
      b394ef7 测试IDEA提交服务器
      acff4ab 测试分支合并
      f5d3192 提交
      7399e20 Initial commit
      PS D:\minhang\testGit>
    • 我们还可以用 –graph 选项,查看历史中什么时候出现了分支、合并,开启了拓扑图选项。git log --graph
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      PS D:\minhang\testGit> git log --graph --oneline
      * 1f98086 (HEAD -> master, origin/master) fix conflicts
      |\
      | * 2d5d070 (origin/dev, dev) 测试idea合并分支
      * | 69302e7 idea
      * | b394ef7 测试IDEA提交服务器
      |/
      * acff4ab 测试分支合并
      * f5d3192 提交
      * 7399e20 Initial commit
      PS D:\minhang\testGit>
    • 我们也可以用 –reverse 参数来逆向显示所有日志。git log --reverse --online
    • 如果只想查找指定用户的提交日志可以使用命令:git log –author , 例如,比方说我们要找 Git 源码中 Linus 提交的部分。
      git log --author=Linus --oneline -5
  • 如果你要指定日期,可以执行几个选项:–since 和 –before,但是你也可以用 –until 和 –after。例如,如果我要看 Git 项目中三周前且在四月十八日之后的所有提交,我可以执行这个(我还用了 –no-merges 选项以隐藏合并提交) 。
    git log --oneline --before={3.weeks.ago} --after={2010-04-18} --no-merges

  • git blame -如果要查看指定文件的修改记录

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    PS D:\minhang\testGit> git blame .\README.md   
    ^7399e20 (fusionshen 2021-03-15 16:55:24 +0800 1) # test
    ^7399e20 (fusionshen 2021-03-15 16:55:24 +0800 2)
    ^7399e20 (fusionshen 2021-03-15 16:55:24 +0800 3) #### 介绍
    ^7399e20 (fusionshen 2021-03-15 16:55:24 +0800 4) 测试
    ^7399e20 (fusionshen 2021-03-15 16:55:24 +0800 5)
    ^7399e20 (fusionshen 2021-03-15 16:55:24 +0800 6) #### 软件架构
    ^7399e20 (fusionshen 2021-03-15 16:55:24 +0800 7) 软件架构说明
    ^7399e20 (fusionshen 2021-03-15 16:55:24 +0800 8)
    ^7399e20 (fusionshen 2021-03-15 16:55:24 +0800 9)
    ^7399e20 (fusionshen 2021-03-15 16:55:24 +0800 10) #### 安装教程
    ^7399e20 (fusionshen 2021-03-15 16:55:24 +0800 11)
    ^7399e20 (fusionshen 2021-03-15 16:55:24 +0800 12) 1. xxxx
    ^7399e20 (fusionshen 2021-03-15 16:55:24 +0800 13) 2. xxxx
    ^7399e20 (fusionshen 2021-03-15 16:55:24 +0800 14) 3. xxxx
    ^7399e20 (fusionshen 2021-03-15 16:55:24 +0800 15)
    ^7399e20 (fusionshen 2021-03-15 16:55:24 +0800 16) #### 使用说明
    ^7399e20 (fusionshen 2021-03-15 16:55:24 +0800 17)
    ^7399e20 (fusionshen 2021-03-15 16:55:24 +0800 18) 1. xxxx
    ^7399e20 (fusionshen 2021-03-15 16:55:24 +0800 19) 2. xxxx
    ^7399e20 (fusionshen 2021-03-15 16:55:24 +0800 20) 3. xxxx
    ^7399e20 (fusionshen 2021-03-15 16:55:24 +0800 21)
    ^7399e20 (fusionshen 2021-03-15 16:55:24 +0800 22) #### 参与贡献
    ^7399e20 (fusionshen 2021-03-15 16:55:24 +0800 23)
    ^7399e20 (fusionshen 2021-03-15 16:55:24 +0800 24) 1. Fork 本仓库
    ^7399e20 (fusionshen 2021-03-15 16:55:24 +0800 25) 2. 新建 Feat_xxx 分支
    ^7399e20 (fusionshen 2021-03-15 16:55:24 +0800 26) 3. 提交代码
    ^7399e20 (fusionshen 2021-03-15 16:55:24 +0800 27) 4. 新建 Pull Request
    ^7399e20 (fusionshen 2021-03-15 16:55:24 +0800 28)
    ^7399e20 (fusionshen 2021-03-15 16:55:24 +0800 29)
    ^7399e20 (fusionshen 2021-03-15 16:55:24 +0800 30) #### 特技
    ^7399e20 (fusionshen 2021-03-15 16:55:24 +0800 31)
    ^7399e20 (fusionshen 2021-03-15 16:55:24 +0800 32) 1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
    ^7399e20 (fusionshen 2021-03-15 16:55:24 +0800 33) 2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com)
    ^7399e20 (fusionshen 2021-03-15 16:55:24 +0800 34) 3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目
    ^7399e20 (fusionshen 2021-03-15 16:55:24 +0800 35) 4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
    ^7399e20 (fusionshen 2021-03-15 16:55:24 +0800 36) 5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
    ^7399e20 (fusionshen 2021-03-15 16:55:24 +0800 37) 6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
    f5d3192c (fusionshen 2021-03-15 17:56:33 +0800 38)
    f5d3192c (fusionshen 2021-03-15 17:56:33 +0800 39) #### 测试2
    acff4ab3 (fusionshen 2021-03-15 20:49:17 +0800 40) 就是个测试
    b394ef7c (fusionshen 2021-03-15 21:29:36 +0800 41) 测试分支合并
    b394ef7c (fusionshen 2021-03-15 21:29:36 +0800 42) 测试idea将文件添加至暂存区
    PS D:\minhang\testGit>

    5.2 版本回退

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    PS D:\minhang\testGit> git log --graph --oneline
    * 1f98086 (HEAD -> master, origin/master) fix conflicts
    |\
    | * 2d5d070 (origin/dev, dev) 测试idea合并分支
    * | 69302e7 idea
    * | b394ef7 测试IDEA提交服务器
    |/
    * acff4ab 测试分支合并
    * f5d3192 提交
    * 7399e20 Initial commit
    PS D:\minhang\testGit>

    首先,Git必须知道当前版本是哪个版本,在Git中,用HEAD表示当前版本,也就是最新的提交1f98086...,上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100

  • HEAD指向的版本就是当前版本,因此,Git允许我们在版本的历史之间穿梭,使用命令git reset --hard commit_id
  • 穿梭前,用git log可以查看提交历史,以便确定要回退到哪个版本。
  • 要重返未来,用git reflog查看命令历史,以便确定要回到未来的哪个版本。

    5.3 惯用分支,大胆commit,谨慎push(引用廖雪峰git教程)

    软件开发中,经常要开发耗时很长的模块或者功能,通常有两种做法:
  • 功能分解成小任务小模块,本地开发完成并验证通过后依次push到远程分支。以便于发现bug后本地回滚

  • 本地开发完全并全部验证通过后统一push到远程分支。
    有同时满足以上要求的吗?有!

  • 本地新增一个分支,依次开发,小任务小模块commit。

  • 全部开发完成并本地验证通过后merge到自己主分支,优先pull。

  • git reset –soft

  • git add . & git commit -m “xxxxx” & git push origin master。

  • 远程分支验证通过后,删除本地新增分支或者不删除,留作纪念。
    还有没有更简单的方法?有!

    1
    2
    $ git checkout master
    $ git merge --no-ff feature

    ​ A—B—C feature(master)

    ​ / \

    D—E—F———–G master (–no-ff)
    --no-ff 会让 Git 生成一个新的提交对象。为什么要这样?通常我们把 master 作为主分支,上面存放的都是比较稳定的代码,提交频率也很低,而 feature 是用来开发特性的,上面会存在许多零碎的提交,快进式合并会把 feature 的提交历史混入到 master 中,搅乱 master 的提交历史。所以如果你根本不在意提交历史,也不爱管 master 干不干净,那么 --no-ff 其实没什么用。不过,如果某一次 master 出现了问题,你需要回退到上个版本的时候,比如上例,你就会发现退一个版本到了 B,而不是想要的 F,因为 feature 的历史合并进了 master 里。
    软件开发中,bug就像家常便饭一样。有了bug就需要修复,在Git中,由于分支是如此的强大,所以,每个bug都可以通过一个新的临时分支来修复,修复后,合并分支,然后将临时分支删除。
    当你接到一个修复一个代号101的bug的任务时,很自然地,你想创建一个分支issue-101来修复它,但是,等等,当前正在dev上进行的工作还没有提交。
    并不是你不想提交,而是工作只进行到一半,还没法提交,预计完成还需1天时间。但是,必须在两个小时内修复该bug,怎么办?
    幸好,Git还提供了一个stash功能,可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作:

    1
    2
    $ git stash
    Saved working directory and index state WIP on dev: f52c633 add merge

    现在,用git status查看工作区,就是干净的(除非有没有被Git管理的文件),因此可以放心地创建分支来修复bug。
    首先确定要在哪个分支上修复bug,假定需要在master分支上修复,就从master创建临时分支:

    1
    2
    3
    4
    5
    6
    7
    $ git checkout master
    Switched to branch 'master'
    Your branch is ahead of 'origin/master' by 6 commits.
    (use "git push" to publish your local commits)

    $ git checkout -b issue-101
    Switched to a new branch 'issue-101'

    现在修复bug,需要把“Git is free software …”改为“Git is a free software …”,然后提交:

    1
    2
    3
    4
    $ git add readme.txt 
    $ git commit -m "fix bug 101"
    [issue-101 4c805e2] fix bug 101
    1 file changed, 1 insertion(+), 1 deletion(-)

    修复完成后,切换到master分支,并完成合并,最后删除issue-101分支:

    1
    2
    3
    4
    5
    6
    7
    8
    $ git switch master
    Switched to branch 'master'
    Your branch is ahead of 'origin/master' by 6 commits.
    (use "git push" to publish your local commits)
    $ git merge --no-ff -m "merged bug fix 101" issue-101
    Merge made by the 'recursive' strategy.
    readme.txt | 2 +-
    1 file changed, 1 insertion(+), 1 deletion(-)

    现在,是时候接着回到dev分支干活了!

    1
    2
    3
    4
    5
    6
    $ git switch dev
    Switched to branch 'dev'

    $ git status
    On branch dev
    nothing to commit, working tree clean

    工作区是干净的,刚才的工作现场存到哪去了?用git stash list命令看看:

    1
    2
    $ git stash list
    stash@{0}: WIP on dev: f52c633 add merge

    工作现场还在,Git把stash内容存在某个地方了,但是需要恢复一下,有两个办法:
    一是用git stash apply恢复,但是恢复后,stash内容并不删除,你需要用git stash drop来删除;
    另一种方式是用git stash pop,恢复的同时把stash内容也删了:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    $ git stash pop
    On branch dev
    Changes to be committed:
    (use "git reset HEAD <file>..." to unstage)

    new file: hello.py

    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: readme.txt

    Dropped refs/stash@{0} (5d677e2ee266f39ea296182fb2354265b91b3b2a)

    再用git stash list查看,就看不到任何stash内容了:

    1
    $ git stash list

    你可以多次stash,恢复的时候,先用git stash list查看,然后恢复指定的stash,用命令:

    1
    $ git stash apply stash@{0}

    在master分支上修复了bug后,我们要想一想,dev分支是早期从master分支分出来的,所以,这个bug其实在当前dev分支上也存在。
    那怎么在dev分支上修复同样的bug?重复操作一次,提交不就行了?
    有没有更简单的方法?
    有!
    同样的bug,要在dev上修复,我们只需要把4c805e2 fix bug 101这个提交所做的修改“复制”到dev分支。

    注意:我们只想复制4c805e2 fix bug 101这个提交所做的修改,并不是把整个master分支merge过来。
    为了方便操作,Git专门提供了一个cherry-pick命令,让我们能复制一个特定的提交到当前分支:

    1
    2
    3
    4
    5
    6
    $ git branch
    * dev
    master
    $ git cherry-pick 4c805e2
    [master 1d4b803] fix bug 101
    1 file changed, 1 insertion(+), 1 deletion(-)

    Git自动给dev分支做了一次提交,注意这次提交的commit是1d4b803,它并不同于master的4c805e2,因为这两个commit只是改动相同,但确实是两个不同的commit。用git cherry-pick,我们就不需要在dev分支上手动再把修bug的过程重复一遍。
    既然可以在master分支上修复bug后,在dev分支上可以“重放”这个修复过程,那么直接在dev分支上修复bug,然后在master分支上“重放”行不行?当然可以,不过你仍然需要git stash命令保存现场,才能从dev分支切换到master分支。

    六、贴士

  • 全命令https://git-scm.com/docs

  • Google现场教学视频https://v.qq.com/x/page/o0772kqh5iv.html?n_version=2021

  • Git 不仅仅是个版本控制系统,它也是个内容管理系统(CMS),工作管理系统等,但是不适合管理二进制文件。

  • Git push -f 慎用
    git-push-f

  • 优先pull,冲突只能在本地分支解决。

  • git rebase或者git pull –rebase可以让提交时间线整齐划一

  • git flow
    A successful Git branching model » nvie.com

  • RP和代码审查

  • git服务器搭建

  • 《ProGit》进阶

至少你看了我一眼,我们彼此分享了笑容:)

欢迎关注我的其它发布渠道