Git从入门到熟练使用

96
__silhouette
2018.03.09 22:14* 字数 14623

Git 基础

基本原理

  • 客户端并不是只提取最新版本的文件快照,而是把代码仓库完整的镜像下来。这样一来,任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜像出来的本地仓库恢复。每一次的克隆操作,实际上都是一次对代码仓库的完整备份。

Git的优势

直接记录快照

  • Git 更像是把数据看作是对小型文件系统的一组快照。 每次你提交更新,或在 Git 中保存项目状态时,它主要对当时的全部文件制作一个快照并保存这个快照的索引。 为了高效,如果文件没有修改,Git 不再重新存储该文件,而是只保留一个链接指向之前存储的文件。 Git 对待数据更像是一个 快照流

  • 如图,在version2中的 B 即是因为 File B 没有改变,所以直接存储了一个指向 FileB 的链接。只有修改了的文件才会产生一个新的文件,覆盖原来的文件。

git存储项目虽时间改变的快照.png

几乎所有操作都在本地执行

  • 在 Git 中的绝大多数操作都只需要访问本地文件和资源,一般不需要来自网络上其它计算机的信息。因为你在本地磁盘上就有项目的完整历史,所以大部分操作看起来瞬间完成。

Git保证完整性

  • Git 中所有数据在存储前都计算校验和,然后以校验和来引用。Git 用以计算校验和的机制叫做 SHA-1 散列(hash,哈希)。Git 数据库中保存的信息都是以文件内容的哈希值来确定的,而不是文件名。
  • 这意味着不可能在 Git 不知情时更改任何文件内容或目录内容。 这个功能建构在 Git 底层,是构成 Git 哲学不可或缺的部分。 若你在传送过程中丢失信息或损坏文件,Git 就能发现。

Git一般只添加数据

  • 你执行的 Git 操作,几乎只往 Git 数据库中增加数据。 很难让 Git 执行任何不可逆操作,或者让它以任何方式清除数据。 同别的 VCS 一样,未提交更新时有可能丢失或弄乱修改的内容;但是一旦你提交快照到 Git 中,就难以再丢失数据,特别是如果你定期的推送数据库到其它仓库的话。这个特性使得我们可以尽情的尝试对Git进行操作而不用害怕把它改坏了,只需要回滚即可。

需要注意的重点

三种状态

  • 已提交 committed :数据已经保存在本地 Git 仓库

  • 已修改 modified : 修改了文件,但是还没保存在仓库中

  • 已暂存 staged : 对一个已修改的文件的当前版本做了标记

工作目录,暂存区域及Git仓库.png

三个区域

  • 工作目录 Working Directory :对项目的某个版本独立提取出来的内容,这些从Git仓库的压缩数据库提取出来的文件,放在磁盘上供你使用或修改。
  • 暂存区域 Staging Area :是一个文件保存了下次将提交的文件列表,是待提交文件的暂存区域。一般在Git仓库的目录中,有时也被称为索引。
  • Git仓库:用来保存项目的元数据和对象数据库的地方。是Git中最重要的部分,从其他计算机克隆仓库时拷贝的就是这里的数据

基本的Git工作流程

  • 在工作目录中修改文件
  • 暂存文件,将文件的快照存储在暂存区域
  • 提交更新,找到暂存区域的位置,将快照永久性存储到Git仓库目录
    • 提交状态:如果Git目录中保存着特定版本的文件,就属于已提交状态。
    • 暂存状态:如果做了修改并且已经放入暂存区域,就属于暂存状态。
    • 已修改状态:如果自上次取出后,做了修改但是还没有存在暂存区域,就是已修改状态。

基本的Git操作流程

基础设置

  • 首先最基础的是需要配置用户信息

    $ git config --global user.name "lanya"
    $ git config --global user.email shenglanya@corp.netease.com
    

    关于 config 的种类

    Config file location
    # global 表示配置全局信息,配置之后无论你在该系统上做任何事情,Git都会使用这些信息。
        --global              use global config file
        --system              use system config file
        --local               use repository config file
        -f, --file <file>     use given config file
        --blob <blob-id>      read config from given blob object
    
  • 接着需要检查你的配置信息,使用 $ git config --list 指令检查全部配置信息,结果如下:

    core.excludesfile=~/.gitignore
    core.legacyheaders=false
    core.quotepath=false
    mergetool.keepbackup=true
    push.default=simple
    color.ui=auto
    color.interactive=auto
    repack.usedeltabaseoffset=true
    alias.s=status
    alias.a=!git add . && git status
    alias.au=!git add -u . && git status
    alias.aa=!git add . && git add -u . && git status
    alias.c=commit
    alias.cm=commit -m
    alias.ca=commit --amend
    alias.ac=!git add . && git commit
    alias.acm=!git add . && git commit -m
    alias.l=log --graph --all --pretty=format:'%C(yellow)%h%C(cyan)%d%Creset %s %C(white)- %an, %ar%Creset'
    alias.ll=log --stat --abbrev-commit
    alias.lg=log --color --graph --pretty=format:'%C(bold white)%h%Creset -%C(bold green)%d%Creset %s %C(bold green)(%cr)%Creset %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative
    alias.llg=log --color --graph --pretty=format:'%C(bold white)%H %d%Creset%n%s%n%+b%C(bold blue)%an <%ae>%Creset %C(bold green)%cr (%ci)' --abbrev-commit
    alias.d=diff
    alias.master=checkout master
    alias.spull=svn rebase
    alias.spush=svn dcommit
    alias.alias=!git config --list | grep 'alias\.' | sed 's/alias\.\([^=]*\)=\(.*\)/\1\   => \2/' | sort
    include.path=~/.gitcinclude
    include.path=.githubconfig
    include.path=.gitcredential
    diff.exif.textconv=exif
    credential.helper=osxkeychain
    core.excludesfile=/Users/shenglanya/.gitignore_global
    difftool.sourcetree.cmd=opendiff "$LOCAL" "$REMOTE"
    difftool.sourcetree.path=
    mergetool.sourcetree.cmd=/Applications/Sourcetree.app/Contents/Resources/opendiff-w.sh "$LOCAL" "$REMOTE" -ancestor "$BASE" -merge "$MERGED"
    mergetool.sourcetree.trustexitcode=true
    user.name=shenglanya
    user.email=shenglanya@corp.netease.com
    commit.template=/Users/shenglanya/.stCommitMsg
    core.repositoryformatversion=0
    core.filemode=true
    core.bare=false
    core.logallrefupdates=true
    core.ignorecase=true
    core.precomposeunicode=true
    remote.origin.url=https://git.ms.netease.com/netease-precious-metals-client/ios-client.git
    remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
    branch.essential.remote=origin
    branch.essential.merge=refs/heads/essential
    branch.r_4.4.remote=origin
    branch.r_4.4.merge=refs/heads/r_4.4
    
  • 使用 $ git config <key> 来检查某一项配置信息

    $ git config user.name
    shenglanya
    

查阅帮助手册方法

  • 以下方法均可找到 Git 命令手册

    $ git help <verb>
    $ git <verb> --help
    $ man git-<verb>
    

获取Git仓库

方法一:在现有目录中初始化仓库(创建一个新的自己的仓库)
  • git init 该命令将创建一个名为 .git 的子目录,这个子目录含有你在初始化的Git仓库中所有的必须文件,这些文件是Git仓库的骨干。但是,在这个时候,我们仅仅是做了一个初始化的操作,你的项目里的文件还没有被跟踪。

  • 如果你是在一个已经存在文件的文件夹(而不是空文件夹)中初始化 Git 仓库来进行版本控制的话,你应该开始跟踪这些文件并提交。 你可通过 git add 命令来实现对指定文件的跟踪,然后执行 git commit提交:

    $ git add *.c
    $ git add LICENSE
    $ git commit -m 'initial project version'
    
  • 具体操作流程

    # 首先
    $ git init
    Initialized empty Git repository in /Users/shenglanya/Desktop/.git/
    
    #然后使用 ls -a 可查看隐藏文件,发现存在名为 .git 的子目录
    $ ls -a
    .     .DS_Store   .localized
    ..        .git        pic
    
    # 接着进入子目录,发现此目录中包含你初始化仓库中所有的必须文件,这些文件是 Git 仓库的骨干
    $ cd .git
    $ ls
    HEAD      config      hooks       objects
    branches  description info        refs
    
    # 接着需要跟踪项目里的文件,需要注意的是,当创建一个新的项目里的文件时,它默认是未被跟踪的,所以此时我们需要手动的将它添加到版本控制中,也就是被跟踪
    
方法二:克隆现有仓库(clone别人的)
  • 如果你想获得一份已经存在了的 Git 仓库的拷贝,比如说,你想为某个开源项目贡献自己的一份力,这时就要用到 git clone 命令。Git 克隆的是该 Git 仓库服务器上的几乎所有数据,而不是仅仅复制完成你的工作所需要文件。 当你执行 git clone 命令的时候,默认配置下远程 Git 仓库中的每一个文件的每一个版本都将被拉取下来。

    $ git clone https://github.com/libgit2/libgit2
    

    Git 支持多种数据传输协议。 上面的例子使用的是 https:// 协议,不过你也可以使用 git:// 协议或者使用 SSH 传输协议,比如 user@server:path/to/repo.git

记录每次更新到仓库

  • 你工作目录下的每一个文件都不外乎这两种状态:已跟踪或未跟踪。 已跟踪的文件是指那些被纳入了版本控制的文件,在上一次快照中有它们的记录,在工作一段时间后,它们的状态可能处于未修改,已修改或已放入暂存区。 工作目录中除已跟踪文件以外的所有其它文件都属于未跟踪文件,它们既不存在于上次快照的记录中,也没有放入暂存区。 初次克隆某个仓库的时候,工作目录中的所有文件都属于已跟踪文件,并处于未修改状态。

检查当前文件状态

  • 要查看哪些文件处于什么状态,可以用 git status 命令。 如果在克隆仓库后立即使用此命令,会看到类似这样的输出:

    $ git status
    On branch master
    nothing to commit, working directory clean
    

    这说明你现在的工作目录相当干净。表示所有已跟踪文件在上次提交后都未被更改过。 此外,上面的信息还表明,当前目录下没有出现任何处于未跟踪状态的新文件,否则 Git 会在这里列出来。 最后,该命令还显示了当前所在分支,并告诉你这个分支同远程服务器上对应的分支没有偏离。 现在,分支名是 “master”,这是默认的分支名。

  • 如果你在当前已经有仓库管理的项目中添加了一个文件,名字叫做 README 。然后使用 git status 命令,你会发现会出现:

    $ echo 'My Project' > README
    $ git status
    On branch master
    Untracked files:
      (use "git add <file>..." to include in what will be committed)
    
        README
    
    nothing added to commit but untracked files present (use "git add" to track)
    

    表示 README 还未被跟踪,表示 Git 之前的提交中没有这些文件。Git也不会自动跟踪它,这使得你不必担心将生成的二进制文件或者其他不想被包含的文件包含进来。若你想跟踪它,则需要明明白白的告诉它你想跟踪这个文件,使用 git add 指令。

跟踪新文件

  • 使用 git add 可以跟踪新文件。所以可以使用 git add README , 然后再运行 git status 会看到

    $ git status
    On branch master
    
    No commits yet
    
    Changes to be committed:
      (use "git rm --cached <file>..." to unstage)
    
      new file:   pic/git存储项目虽时间改变的快照.png
      new file:   pic/lifecycle.png
      new file:   pic/工作目录,暂存区域及Git仓库.png
    
    Untracked files:
      (use "git add <file>..." to include in what will be committed)
    
      pic/实习学习笔记.md
    
    # 使用 git add 后
    $ git add pic/实习学习笔记.md
    $ git status
    On branch master
    
    No commits yet
    
    Changes to be committed:
      (use "git rm --cached <file>..." to unstage)
    
      new file:   pic/git存储项目虽时间改变的快照.png
      new file:   pic/lifecycle.png
      new file:   pic/实习学习笔记.md
      new file:   pic/工作目录,暂存区域及Git仓库.png
    

    只要在 Changes to be committed 这行下面的,就说明是已暂存状态。 如果此时提交,那么该文件此时此刻的版本将被留存在历史记录中。 你可能会想起之前我们使用 git init 后就运行了 git add (files) 命令,开始跟踪当前目录下的文件。 git add 命令使用文件或目录的路径作为参数;如果参数是目录的路径,该命令将递归地跟踪该目录下的所有文件。

  • 关于 git add 指令还有别的作用:

    • 用于追踪新文件
    • 用于将已跟踪的文件放入暂存区
    • 用于合并时把有冲突的文件标记为已解决

暂存已修改文件

  • 修改已被跟踪的文件。比如说修改了一个名为 实习学习笔记.md 的文件,然后运行 git status

    $ git status
    On branch master
    
    No commits yet
    
    Changes to be committed:
      (use "git rm --cached <file>..." to unstage)
    
      new file:   pic/git存储项目虽时间改变的快照.png
      new file:   pic/lifecycle.png
      new file:   pic/实习学习笔记.md
      new file:   pic/工作目录,暂存区域及Git仓库.png
    
    # 说明已跟踪文件内容发生了变化,但是还未放入暂存区。如果想暂存这次更新,需要使用 git add 指令。 git add 指令是一个多功能命令:可以用它来跟踪新文件,或者把已经跟踪的文件放到暂存区中,还能用于合并时把有冲突的文件标记为已解决状态等。
    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:   pic/实习学习笔记.md
      
      
    # 使用 git add 指令将其添加到暂存区
    $ git add pic/实习学习笔记.md
    $ git status
    On branch master
    
    No commits yet
    
    Changes to be committed:
      (use "git rm --cached <file>..." to unstage)
    
      new file:   pic/git存储项目虽时间改变的快照.png
      new file:   pic/lifecycle.png
      new file:   pic/实习学习笔记.md
      new file:   pic/工作目录,暂存区域及Git仓库.png
    
  • 需要注意的是,当已经使用了 git add 指令暂存的版本又经过修改之后,需在再重新使用 git add 指令将最新的修改放入暂存区,否则此时暂存区里只有上一次修改的内容。

提交文件到仓库

  • 使用 git commit 指令可以使得暂存在暂存区的文件被提交到仓库中去。

    $ git commit
    [master (root-commit) 2713657] 第一次的修改提交
     4 files changed, 22 insertions(+)
     create mode 100644 pic/git存储项目虽时间改变的快照.png
     create mode 100644 pic/lifecycle.png
     create mode 100644 pic/实习学习笔记.md
     create mode 100644 pic/工作目录,暂存区域及Git仓库.png
    

基本的 Git 操作指令

git status 命令概述

  • 使用 git status 时,实际上可以使用更为方便的指令来达到更为紧凑的格式输出。比如使用 git status -s

    $ git status -s
    
    #  M 靠右的 M 表示修改过的文件并且还未被放入暂存区
     M README
     
    # MM 靠左的 M 表示该文件被修改后放入了暂存区,靠右的表示修改过的文件并且还未被放入暂存区,所以 Rakefile 文件被修改过后放入了暂存区,但是之后又进行了修改,还未将最后一次修改放入暂存区
    MM Rakefile
    
    # A 表示新添加到暂存区的文件
    A  lib/git.rb
    
    # M 靠左的 M 表示该文件被修改后放入了暂存区
    M  lib/simplegit.rb
    
    # ?? 表示还未被跟踪
    ?? LICENSE.txt  
    
    # 所以此时暂存区中的文件有 Rakefile, lib/git.rb, lib/simplegit.rb
    

git diff 命令概述

  • git diff 可以说是 git status 的具体版本,git status 只能查看修改了哪些文件,而 git diff 能够具体到该文件的某一部分。通常有以下两个用法

    • 当前做的更新哪些还没有暂存?

      首先修改 pic/实习学习笔记.md 文件,然后使用 git status 指令

      $ git status
      On branch 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:   pic/实习学习笔记.md
          
      # 表示该文件修改后还没有暂存
      

      此时使用 git diff 可以查看当前未暂存文件更新了哪些部分

      $ git diff
      diff --git a/pic/实习学习笔记.md b/pic/实习学习笔记.md
      index 2b4e07b..a50f1a2 100644
      --- a/pic/实习学习笔记.md
      +++ b/pic/实习学习笔记.md
      @@ -14,7 +14,7 @@
      -* 有额外时间的话,需要将之前没读完的书继续读下去。
      +* 有额外时间的话,需要将之前没读完的书继续读下去。呵呵呵
      

      此时就可以查看未暂存文件修改的部分了。

      • 有哪些更新已经暂存起来了准备好了下次提交?

        可以使用 git diff --staged 指令查看,首先需要使用 git add 指令将刚刚修改的文件加入暂存区

        $ git add pic/实习学习笔记.md
        shenglanyadeMacBook-Pro:desktop shenglanya$ git diff --staged
        diff --git a/pic/实习学习笔记.md b/pic/实习学习笔记.md
        index 2b4e07b..a50f1a2 100644
        --- a/pic/实习学习笔记.md
        +++ b/pic/实习学习笔记.md
        @@ -14,7 +14,7 @@
        -* 有额外时间的话,需要将之前没读完的书继续读下去。
        +* 有额外时间的话,需要将之前没读完的书继续读下去。呵呵呵
        
  • 当我们将文件暂存后继续编辑时,使用 git status 指令查看如下:

    $ git status
    On branch master
    Changes to be committed:
      (use "git reset HEAD <file>..." to unstage)
    
      modified:   pic/实习学习笔记.md
    
    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:   pic/实习学习笔记.md
    
    # 该文件同时出现在了暂存区和修改部分。
    
  • 现在运行 git diff 查看暂存前后的变化

    git diff
    diff --git a/pic/实习学习笔记.md b/pic/实习学习笔记.md
    index a50f1a2..2b4e07b 100644
    --- a/pic/实习学习笔记.md
    +++ b/pic/实习学习笔记.md
    @@ -14,7 +14,7 @@
    -* 有额外时间的话,需要将之前没读完的书继续读下去。呵呵呵
    +* 有额外时间的话,需要将之前没读完的书继续读下去。
    
  • 再使用 git diff --staged 查看变化

    $ git diff --staged
    diff --git a/pic/实习学习笔记.md b/pic/实习学习笔记.md
    index 2b4e07b..a50f1a2 100644
    --- a/pic/实习学习笔记.md
    +++ b/pic/实习学习笔记.md
    @@ -14,7 +14,7 @@
    -* 有额外时间的话,需要将之前没读完的书继续读下去。
    +* 有额外时间的话,需要将之前没读完的书继续读下去。呵呵呵
    

    表示这个指令查看的是暂存区中文件的修改。

git commit 命令概述

  • 当使用 git commit 命令提交暂存区域的文件时,一定要确认是否还有什么修改过或新建的文件还未放入暂存区,否则一旦提交,这些文件或修改都会只留在本地磁盘,不会加入版本控制中。所以每次提交前都需要执行 git status 命令来查看是否都暂存起来了

  • 可以在 commit 命令后添加 -m 选项,将提交信息与命令放在同一行

    $ git commit -m "Story 182: Fix benchmarks for speed"
    
    # 表示当前在 master 分支上提交的,本次提交的完整 SHA-1 校验和是 463dc4f
    [master 463dc4f] Story 182: Fix benchmarks for speed
    
     2 files changed, 2 insertions(+)
     create mode 100644 README
    
  • 注意:提交的是放在暂存区的快照,任何还未暂存的仍然保持已修改状态,可以在下次提交时再纳入版本管理。每一次提交都是对项目的一次快照,以后可以回到这个状态或进行比较。

  • 使用 git commit -a 可以跳过暂存这一步骤,git 会自动把所有已经跟踪过的文件暂存起来并且提交,即跳过 git add 步骤。

git rm 命令概述

  • 要从 Git 中移除某个文件,就必须从已经跟踪的文件清单中删除,然后提交。

  • 删除有两种方式

    • 第一种是简单的从暂存区中删除。但是文件还在被跟踪着。
    • 第二种是直接在未暂存区域中移除文件,表示直接将文件移除版本控制中。不再跟踪。
  • 下面来演示一下,首先对工作区域中的文件删除,使用 rm pic/实习学习笔记.md

    $ rm pic/实习学习笔记.md
    $ git status
    On branch 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:    pic/实习学习笔记.md
    
    no changes added to commit (use "git add" and/or "git commit -a")
    
    # 此时将文件从暂存区域中删除,但是文件还在被追踪
    
  • 然后再将文件从跟踪中删除,这里两种指令 $ git rm pic/实习学习笔记.md$ git add pic/实习学习笔记.md 都能达到同样效果。

    $ git add pic/实习学习笔记.md
    $ git status
    On branch master
    Changes to be committed:
      (use "git reset HEAD <file>..." to unstage)
    
      deleted:    pic/实习学习笔记.md
    
    
  • 需要注意的是,如果删除文件之前文件修改过并且已经放入了暂存区域,则必须使用强制删除选项-f 才能将其删除。主要是为了防止误删。

  • 当我们想要将文件从 Git 仓库中删除但是却想让他仍在我们的工作区域中时,(即保存在本地磁盘并且不被 Git 跟踪),为了达到这一目的,使用 --cached 选项。

    $ git rm --cached pic/git存储项目虽时间改变的快照.png
    rm 'pic/git存储项目虽时间改变的快照.png'
    
    # 执行完此命令后,pic/git存储项目虽时间改变的快照.png 文件还在本地磁盘上,并没有被删除。
    

git mv 命令概述

  • Git 并不显式的跟踪文件移动操作。所以如果 Git 重命名某个文件,仓库中存储的元数据并不会体现出这是一次改名操作。

  • 当我们想在 Git 中对文件进行改名可以使用 git mv a b 方式来操作

    $ git mv pic/实习学习笔记.md pic/note.md
    $ git diff --staged
    diff --git a/pic/实习学习笔记.md b/pic/note.md
    similarity index 100%
    rename from pic/实习学习笔记.md
    rename to pic/note.md
    
  • git mv 等价于

    $ mv pic/实习学习笔记.md pic/note.md
    $ git rm pic/实习学习笔记.md
    $ git add pic/note.md
    

忽略文件

  • 我们有时会有些文件不需要 Git 来进行管理,也不希望他们总是出现在未跟踪列表中,所以此时,我们可以创建一个名为 .gitignore 的文件,并在其中列出要忽略掉文件模式。

    # 先创建此忽略文件并向其中添加需要忽略的文件
    $ vi .gitignore
    
    # 查看此文件
    $ cat .gitignore
    .localized
    
    # 表示忽略所有以 .o 或 .a 结尾的文件
    *.[oa]
    
    # 表示忽略所有以波浪符(~)结尾的文件
    *~
    
  • 一些规范如下

    • 所有空行或者以 开头的行都会被 Git 忽略。
    • 可以使用标准的 glob 模式匹配。glob 即是指 shell 简化了的正则表达式。
      • 其中 * 可以匹配 0 ~ n 个字符
      • ? 只能匹配一个字符
      • [0-9]表示匹配所有 0 到 9 的数字
      • ** 表示匹配任意中间目录 比如 a/**/z 可以匹配 a/z, a/b/z, a/b/c/z 等
    • 匹配模式可以以(/)开头防止递归。
    • 匹配模式可以以(/)结尾指定目录。
    • 要忽略指定模式以外的文件或目录,可以在模式前加上惊叹号(!)取反。

git stash 命令概述

  • 当我们已经在一个分支上修改文件后,如果必须要切换到其他分支展开其他的工作,而当前分支的工作还没有完成,此时我们需要使用 $ git stash$ git stash save 命令将当前分支上的工作暂存到栈上,这时你的工作目录就干净了,就可以切换到其他分支工作,等工作完成后,再切换回原来的分支,可以使用 $ git stash apply 将你刚刚的储藏重新应用。如果想查看你当前一共有多少个储藏,可以使用 $ git stash list 来查看。如果你并不想应用最新的分支,而是想应用某一个早些时间的分支,你可以使用 $ git stash apply stash@{1} ,其中最后一个括号内的数字为你某一次提交到工作栈上的暂存记录。如果你不指定 apply 的参数,git 将认为你想要应用最近一次的储藏。

  • 当我们返回原本的分支后,使用 $ git stash apply 指令恢复了工作栈中暂存的数据,但是如果当你提交这个分支之前,已经在暂存区缓存了一部分工作内容,并且使用 stash 保存了工作状态,此时当你恢复工作栈中的数据后,实际上暂存区中的内容将会被移出暂存区,而被放在了工作目录中修改的部分,你需要手动将它再放回暂存区,否则可以使用 $ git stash apply --index 来尝试重新将暂存区的文件恢复到暂存区中。当你把这个修改放入暂存区后,实际上堆栈上还有这个修改的记录,此时你可以使用 $ git stash drop stash@{1} 来从栈中移除它,或者直接使用 $ git stash pop 来应用储藏栈这样它就会自动从储藏栈上消失了。

  • $ git stash --keep-index 指令的作用在于告诉 Git 不要储藏任何你通过 git add 命令已经暂存的东西,也就是说比如你现在已经修改了一部分工作目录中的内容,并且还有一部分已经被你暂存了下来。此时你暂时不想继续改工作目录中的内容了,可是你也不想将它暂存到暂存区,此时可以使用这个指令将它暂存到工作栈上。

    $ git status -s
    M  index.html
     M lib/simplegit.rb
    
    $ git stash --keep-index
    Saved working directory and index state WIP on master: 1b65b17 added the index file
    HEAD is now at 1b65b17 added the index file
    
    $ git status -s
    M  index.html
    
  • $ git stash -u 可以储藏还未跟踪的文件到工作栈

  • $ git stash branch 如果使用 stash 储藏了一些工作,然后继续在储藏的分支上工作,在重新应用 stash 储藏的文件工作时可能会有问题。 如果应用尝试修改刚刚储藏的修改的文件,也就是两次同时修改了一个文件,你会得到一个合并冲突并不得不解决它。 如果想要一个轻松的方式来再次测试储藏的改动,可以运行 git stash branch 创建一个新分支,检出储藏工作时所在的提交,重新在那应用工作,然后在应用成功后扔掉储藏

    $ git stash branch testchanges
    Switched to a new branch "testchanges"
    # On branch testchanges
    # Changes to be committed:
    #   (use "git reset HEAD <file>..." to unstage)
    #
    #      modified:   index.html
    #
    # Changed but not updated:
    #   (use "git add <file>..." to update what will be committed)
    #
    #      modified:   lib/simplegit.rb
    #
    Dropped refs/stash@{0} (f0dfc4d5dc332d1cee34a634182e168c4efc3359)
    
  • $ git stash -all 可以移除工作目录中所有未跟踪的文件并且存储在工作栈上,相应的一个不怎么安全的方法是 $ git clean 直接清除了内容,无法追溯回。不过可以使用 git clean 命令去除冗余文件或者清理工作目录。 使用git clean -f -d命令来移除工作目录中所有未追踪的文件以及空的子目录。 -f 意味着 强制 或 “确定移除”。在使用 $ git clean 之前,我们可以先使用 $ git clean -d -n 来看一下这样做的后果是什么,也就是有什么文件会被移除。

git log 命令概述

  • 在提交了若干更新,又或者克隆了某个项目之后,你也许想回顾下提交历史。 此时便需要 git log 命令。默认不加其他参数时, git log 惠安提交时间列出所有更新。

    $ git log
    commit fb40f7a259de8ec2f2edbada6f85aa855f4a6585 (HEAD -> master)
    Author: shenglanya <shenglanya@corp.netease.com>
    Date:   Wed Mar 7 11:34:54 2018 +0800
    
        add pic
    
    commit ec50914561593b769a98ff468de6697a6d964cbd
    Author: shenglanya <shenglanya@corp.netease.com>
    Date:   Wed Mar 7 11:33:36 2018 +0800
    
        xiugai
    
    commit a7372097ab8f063e17beca6fa8f82a15bb11c5e3
    Author: shenglanya <shenglanya@corp.netease.com>
    Date:   Wed Mar 7 11:20:05 2018 +0800
    
        提交
    
  • 常用选项 -p ,用来显示每次提交的内容差异,可以加上 -2 来仅仅显示最近两次提交

    $ git log -p
    commit fb40f7a259de8ec2f2edbada6f85aa855f4a6585 (HEAD -> master)
    Author: shenglanya <shenglanya@corp.netease.com>
    Date:   Wed Mar 7 11:34:54 2018 +0800
    
        add pic
    
    diff --git a/pic/git存储项目虽时间改变的快照.png b/pic/git存储项目虽时间改变的快照.png
    new file mode 100644
    index 0000000..1036a42
    Binary files /dev/null and b/pic/git存储项目虽时间改变的快照.png differ
    
    commit ec50914561593b769a98ff468de6697a6d964cbd
    Author: shenglanya <shenglanya@corp.netease.com>
    Date:   Wed Mar 7 11:33:36 2018 +0800
    
        xiugai
    
    diff --git a/pic/git存储项目虽时间改变的快照.png b/pic/git存储项目虽时间改变的快照.png
    deleted file mode 100644
    index 1036a42..0000000
    Binary files a/pic/git存储项目虽时间改变的快照.png and /dev/null differ
    
  • --stat 选项可以看到每次提交的简略统计信息

    $ git log --stat
    commit fb40f7a259de8ec2f2edbada6f85aa855f4a6585 (HEAD -> master)
    Author: shenglanya <shenglanya@corp.netease.com>
    Date:   Wed Mar 7 11:34:54 2018 +0800
    
        add pic
    
     pic/git存储项目虽时间改变的快照.png | Bin 0 -> 20722 bytes
     1 file changed, 0 insertions(+), 0 deletions(-)
    
    commit ec50914561593b769a98ff468de6697a6d964cbd
    Author: shenglanya <shenglanya@corp.netease.com>
    Date:   Wed Mar 7 11:33:36 2018 +0800
    
        xiugai
    
     pic/git存储项目虽时间改变的快照.png | Bin 20722 -> 0 bytes
     pic/实习学习笔记.md                       |  22 ++++++++++++++++++++++
     2 files changed, 22 insertions(+)
    
    commit a7372097ab8f063e17beca6fa8f82a15bb11c5e3
    Author: shenglanya <shenglanya@corp.netease.com>
    Date:   Wed Mar 7 11:20:05 2018 +0800
    
    
  • 常用选项 --pretty 可以指定使用不同于默认格式的方式展示提交信息。比如 oneline 将每个提交放在一行显示,查看到提交数很大时非常有用。另外还有 short full 等。

    $ git log --pretty=oneline
    fb40f7a259de8ec2f2edbada6f85aa855f4a6585 (HEAD -> master) add pic
    ec50914561593b769a98ff468de6697a6d964cbd xiugai
    a7372097ab8f063e17beca6fa8f82a15bb11c5e3 提交
    2713657f264a3a019580dc3a489d303fade5dc5c 第一次的修改提交
    
  • format 选项可以定制要显示的记录格式。这样的输出对后期提取分析格外有用。

    $git log --pretty=format:"%h - %an, %ar : s"
    fb40f7a - shenglanya, 60 minutes ago : add pic
    ec50914 - shenglanya, 61 minutes ago : xiugai
    a737209 - shenglanya, 74 minutes ago : 提交
    2713657 - shenglanya, 3 hours ago : 第一次的修改提交
    

    常用选项以及其代表意义

    选项        说明
    %H    提交对象(commit)的完整哈希字串
    %h        提交对象的简短哈希字串
    %T        树对象(tree)的完整哈希字串
    %t        树对象的简短哈希字串
    %P        父对象(parent)的完整哈希字串
    %p        父对象的简短哈希字串
    %an       作者(author)的名字
    %ae       作者的电子邮件地址
    %ad       作者修订日期(可以用 --date= 选项定制格式)
    %ar       作者修订日期,按多久以前的方式显示
    %cn       提交者(committer)的名字
    %ce       提交者的电子邮件地址
    %cd       提交日期
    %cr       提交日期,按多久以前的方式显示
    %s        提交说明
    
  • 选项 --graph 可以形象的展示分支,合并历史

    $ git log --pretty --graph
    * commit fb40f7a259de8ec2f2edbada6f85aa855f4a6585 (HEAD -> master)
    | Author: shenglanya <shenglanya@corp.netease.com>
    | Date:   Wed Mar 7 11:34:54 2018 +0800
    | 
    |     add pic
    | 
    * commit ec50914561593b769a98ff468de6697a6d964cbd
    | Author: shenglanya <shenglanya@corp.netease.com>
    | Date:   Wed Mar 7 11:33:36 2018 +0800
    | 
    |     xiugai
    | 
    * commit a7372097ab8f063e17beca6fa8f82a15bb11c5e3
    | Author: shenglanya <shenglanya@corp.netease.com>
    | Date:   Wed Mar 7 11:20:05 2018 +0800
    | 
    |     提交
    
  • git log 的常用选项

    选项                说明
    -p                按补丁格式显示每个更新之间的差异。
    --stat            显示每次更新的文件修改统计信息。
    --shortstat       只显示 --stat 中最后的行数修改添加移除统计。
    --name-only       仅在提交信息后显示已修改的文件清单。
    --name-status 显示新增、修改、删除的文件清单。
    --abbrev-commit   仅显示 SHA-1 的前几个字符,而非所有的 40 个字符。
    --relative-date   使用较短的相对时间显示(比如,“2 weeks ago”)。
    --graph           显示 ASCII 图形表示的分支合并历史。
    --pretty      使用其他格式显示历史提交信息。可用的选项包括 oneline,short,full,fuller 和 format(后跟指定格式)。
    
    
  • 限制 git log 输出的选项

    选项                说明
    -(n)          仅显示最近的 n 条提交
    --since, --after仅显示指定时间之后的提交。
    --until, --before仅显示指定时间之前的提交。
    --author      仅显示指定作者相关的提交。
    --committer       仅显示指定提交者相关的提交。
    --grep            仅显示含指定关键字的提交
    -S                仅显示添加或移除了某个关键字的提交
    

撤销操作指令

  • 重新提交:有时候我们提交完了才发现漏掉了几个文件没有添加,或者提交信息写错了。 此时,可以运行带有 --amend 选项的提交命令尝试重新提交:$ git commit --amend 这个命令将暂存区中的文件提交,如果自从上次提交以来还未做任何修改,则快照保持不变,你修改的只有提交信息。例如你提交后发现忘记了暂存某些需要的修改,可以像下面这样操作:

    $ git commit -m 'initial commit'
    $ git add forgotten_file
    $ git commit --amend
    
    # 最终只会有一个提交,第二次提交将代替第一次提交的结果
    
  • 取消暂存的文件:可以使用 git reset HEAD yourfile 来进行取消暂存区域内文件的暂存操作。

  • 撤销对文件的修改:如果你不想保存对文件的修改,如何方便的将其还原成上次提交的样子?使用 $ gitcheckout -- pic/实习学习笔记.md 撤销之前所做的修改。

Git 远程仓库的使用

  • 查看远程仓库 : 使用 git remote 命令可以列出你指定的每个远程服务器的简写。如果已经克隆了自己的仓库,那么至少能看到 origin

    $ cd ios-client
    $ git remote
    origin
    

    可以指定参数 -v 可以查看你的读写权限

    $ git remote -v
    origin    https://git.ms.netease.com/netease-precious-metals-client/ios-client.git (fetch)
    origin    https://git.ms.netease.com/netease-precious-metals-client/ios-client.git (push)
    
  • 添加远程仓库: 运行 git remote add <shortname> <url> 添加一个新的远程 Git 仓库

    $ git remote
    origin
    $ git remote add test https://github.com/lanyasheng/NTAlgorithm.git
    $ git remote -v
    origin    https://git.ms.netease.com/netease-precious-metals-client/ios-client.git (fetch)
    origin    https://git.ms.netease.com/netease-precious-metals-client/ios-client.git (push)
    test  https://github.com/lanyasheng/NTAlgorithm.git (fetch)
    test  https://github.com/lanyasheng/NTAlgorithm.git (push)
    

    现在就可以使用 test 来代替整个 URL ,例如使用 git fetch test 来拉取远端 Git 仓库中有但你没有的信息。

    $ git fetch test
    warning: no common commits
    remote: Counting objects: 84, done.
    remote: Total 84 (delta 0), reused 0 (delta 0), pack-reused 83
    Unpacking objects: 100% (84/84), done.
    From https://github.com/lanyasheng/NTAlgorithm
     * [new branch]          develop    -> test/develop
     * [new branch]          master     -> test/master
    

    现在可以在本地访问 test/master 分支了,实际上对应远端的 master 分支。

  • 从仓库中抓取: git fetch 会访问远端仓库,从中拉取所有你没有的信息。执行完后,你会拥有该仓库的所有分支引用可以用来随时合并和查看。当使用了 git clone 命令克隆一个远端仓库时,命令会自动将其添加为远程仓库并默认以 “origin” 为简写。git fetch origin 会抓取克隆(或上一次抓取)后新推送的所有工作。 必须注意 git fetch 命令会将数据拉取到你的本地仓库 - 它并不会自动合并或修改你当前的工作。 当准备好时你必须手动将其合并入你的工作。

  • 从仓库上拉取: git pull 可以用来自动的抓取然后合并远程分支到当前分支,前提是你有一个分支设置为跟踪一个远程的分支。所以 git pull == git fetch + git merge。默认情况下, git clone 会自动设置本地的 master 分支跟踪远程仓库的 master 分支,运行 git pull 通常会从最初克隆的服务器上抓取数据并自动尝试合并到当前所在的分支。

  • 推送到远程分支git push [remote-name][branch-name] 指令可以将你的项目推送到服务器。例如当你想将 master 推到 origin 时,可以使用 $ git push origin master 只有当你有所克隆服务器的写入权限,并且之前没有人推送过时,这条命令才能生效。 当你和其他人在同一时间克隆,他们先推送到上游然后你再推送到上游,你的推送就会毫无疑问地被拒绝。 你必须先将他们的工作拉取下来并将其合并进你的工作后才能推送

  • 查看远程仓库: 如果想查看一个远程仓库的更多信息,可以使用 $ git remote show test

    $ git remote show test
    * remote test
      Fetch URL: https://github.com/lanyasheng/NTAlgorithm.git
      Push  URL: https://github.com/lanyasheng/NTAlgorithm.git
      HEAD branch: master
      Remote branches:
        develop tracked
        master  tracked
        
      Local branches configured for 'git pull':
        develop merges with remote develop
        master  merges with remote master
      Local refs configured for 'git push':
        develop pushes to develop (local out of date)
        master  pushes to master  (local out of date)
    

    这个命令列出了当你在特定的分支上执行 git push 会自动地推送到哪一个远程分支。 它也同样地列出了哪些远程分支不在你的本地,哪些远程分支已经从服务器上移除了,还有当你执行 git pull 时哪些分支会自动合并

  • 远程仓库的移除与命名:运行 git remote rename <shortname> <url> 重命名远程仓库

    $ git remote rename test testNea
    $ git remote
    origin
    testNea
    
  • 移除远程仓库:

    $ git remote rm testNea
    $ git remote
    origin
    

Git 标签

创建标签

  • 轻量标签 — 就像一个不会改变的分支,只是一个特定提交的引用,创建轻量标签只需要提供版本号即可。git tag v1.4-1w

    $ git tag v1.4-1w
    $ git show
    commit fb40f7a259de8ec2f2edbada6f85aa855f4a6585 (HEAD -> master, tag: v1.4-1w, tag: v1.3)
    Author: shenglanya <shenglanya@corp.netease.com>
    Date:   Wed Mar 7 11:34:54 2018 +0800
    
        add pic
    
    diff --git a/pic/git存储项目虽时间改变的快照.png b/pic/git存储项目虽时间改变的快照.png
    new file mode 100644
    index 0000000..1036a42
    Binary files /dev/null and b/pic/git存储项目虽时间改变的快照.png differ
    
  • 附注标签 — 一个存储在 Git 数据库中的一个完整对象,他们可以被校验。其中包含打标签者的名字,电子邮件地址、日期时间,标签信息。并且可以使用 GNU Privacy Guard (GPG)签名与验证。可以使用$ git tag -a v1.3 这样就给当前版本打上了 v1.3 标签。也可以使用 $ git tag -a v1.3 -m 'my version 1.3' 这样就直接标备注了。 git show 可以查看标签信息与对应的提交信息

    $ git tag -a v1.3
    $ git show
    commit fb40f7a259de8ec2f2edbada6f85aa855f4a6585 (HEAD -> master, tag: v1.3)
    Author: shenglanya <shenglanya@corp.netease.com>
    Date:   Wed Mar 7 11:34:54 2018 +0800
    
        add pic
    
    diff --git a/pic/git存储项目虽时间改变的快照.png b/pic/git存储项目虽时间改变的快照.png
    new file mode 100644
    index 0000000..1036a42
    Binary files /dev/null and b/pic/git存储项目虽时间改变的快照.png differ
    

后期打标签

  • 也可以对过去提交打标签。例如提交历史如下

    $ git log --pretty=oneline
    fb40f7a259de8ec2f2edbada6f85aa855f4a6585 (HEAD -> master, tag: v1.4-1w, tag: v1.3) add pic
    ec50914561593b769a98ff468de6697a6d964cbd xiugai
    a7372097ab8f063e17beca6fa8f82a15bb11c5e3 提交
    20c944dba3f056aef30aada88d0a452e8faffcbc hehe
    2713657f264a3a019580dc3a489d303fade5dc5c 第一次的修改提交
    

    可以使用 $ git tag -a v1.2 2713657 表示对该校验和的版本打上标签。

    $ git tag
    v1.2
    v1.3
    v1.4-1w
    $ git show v1.2
    tag v1.2
    Tagger: shenglanya <shenglanya@corp.netease.com>
    Date:   Wed Mar 7 15:00:31 2018 +0800
    
    对之前的打标签`
    
    commit 2713657f264a3a019580dc3a489d303fade5dc5c (tag: v1.2)
    Author: shenglanya <shenglanya@corp.netease.com>
    Date:   Wed Mar 7 09:41:21 2018 +0800
    
        第一次的修改提交
    
    diff --git a/pic/git存储项目虽时间改变的快照.png b/pic/git存储项目虽时间改变的快照.png
    new file mode 100644
    index 0000000..1036a42
    Binary files /dev/null and b/pic/git存储项目虽时间改变的快照.png differ
    diff --git a/pic/lifecycle.png b/pic/lifecycle.png
    new file mode 100644
    index 0000000..922b02c
    Binary files /dev/null and b/pic/lifecycle.png differ
    diff --git a/pic/实习学习笔记.md b/pic/实习学习笔记.md
    new file mode 100644
    

Git 分支

分支简介

简介

  • Git 保存到不是文件的变化或差异,而是一系列不同时刻的文件快照。当提交时,Git 会保存一个提交的对象。该提交对象会包含一个指向暂存内容快照的指针,还会包含作者姓名和邮箱,提交时输入的信息以及指向他的父对象的指针。首次提交产生的提交对象没有父对象,普通提交操作产生的提交对象有一个父对象,而由多个分支合并产生的提交对象有多个父对象。

  • 我们假设现在有一个工作目录,里面包含了三个将要被暂存和提交的文件。 暂存操作会为每一个文件计算校验和然后会把当前版本的文件快照保存到 Git 仓库中,最终将校验和加入到暂存区域等待提交:

创建分支

  • Git 创建新分支的本质就是创建一个可以移动的新的指针。比如创建一个 testing 分支。$ git branch testing 这会在当前所提交的对象上创建一个指针,此时如图:
two-branches.png
  • 如何判断 Git 当前在哪一个分支?此时就要依靠 HEAD 指针。该指针指向当前所在的本地分支。如图
    head-to-master.png

此时 HEAD 指针指向 master 指针,也就是实际上 HEAD 指针指向的时当前所在的本地分支。在本例中,我们仍在 master 分支上,因为 git branch 命令仅仅是创建了一个新分支,并没有切换到它上面。可以使用以下命令来查看各个分支当前所指的对象

$ git log --oneline --decorate
5a5f9fe (HEAD -> master) rename
fb40f7a (tag: v1.4-1w, tag: v1.3, testing) add pic
ec50914 xiugai
a737209 提交
2713657 (tag: v1.2) 第一次的修改提交

可以看到,当前 HEAD 和 master 分支均指向 5a5f9fe 开头的对象

分支切换

  • 使用 git checkout 命令可以切换分支

    $ git checkout testing
    Switched to branch 'testing'
    $ git log --oneline --decorate
    fb40f7a (HEAD -> testing, tag: v1.4-1w, tag: v1.3) add pic
    ec50914 xiugai
    a737209 提交
    2713657 (tag: v1.2) 第一次的修改提交
    

    可以看到,此时 HEAD 指针指向了 testing 指针,表示当前的本地分支切换为 testing 分支。然后在 testing 分支上进行一些操作

    $ git commit -a -m 'made a change on tesing'
    [testing 844332b] made a change on tesing
     3 files changed, 1 insertion(+)
     create mode 100644 pic/head-to-master.png
     create mode 100644 pic/test.md
     create mode 100644 pic/two-branches.png
    $ git log --oneline --decorate
    844332b (HEAD -> testing) made a change on tesing
    fb40f7a (tag: v1.4-1w, tag: v1.3) add pic
    ec50914 xiugai
    a737209 提交
    20c944d hehe
    2713657 (tag: v1.2) 第一次的修改提交
    

    此时可以发现 HEAD 指针指向 testing 指针指向了新提交的文件。[图片上传失败...(image-dde0a4-1520604809580)]

    此时再切换到 master 分支看一下

    $ git checkout master
    Switched to branch 'master'
    $ git log --oneline --decorate
    5a5f9fe (HEAD -> master) rename
    fb40f7a (tag: v1.4-1w, tag: v1.3) add pic
    ec50914 xiugai
    a737209 提交
    2713657 (tag: v1.2) 第一次的修改提交
    

    可以发现此时 master 分支还指向刚刚它指向的位置,也就是[图片上传失败...(image-85e5da-1520604809580)]

  • git checkout master 一共做了两件事:

    • 使 HEAD 指向 master 分支
    • 将工作目录恢复成 master 分支所指向的快照内容,也就是忽略 testing 分支所做的修改。
  • 若我们此时再对 master 分支上的文件上进行修改,就会产生分叉。因为你刚创建了一个新分支,并且切换过去进行了一些工作,然后后切换回了 master 分支进行了一些额外的工作。上述改动针对的是不同分支,你可以在不同分支之间来回切换并在某一时刻将他们合并。

项目分叉历史

  • 可以使用 git log 命令查看分叉历史。运行 git log --oneline --decorate --graph —all,他会输出你的提交历史各个分支的指向以及项目的分支分叉情况。

    $ git log --oneline --decorate --graph --all
    * b551643 (HEAD -> master) made a change on master
    * 5a5f9fe rename
    | * 844332b (testing) made a change on tesing
    |/  
    * fb40f7a (tag: v1.4-1w, tag: v1.3) add pic
    * ec50914 xiugai
    * a737209 提交
    * 20c944d hehe
    * 2713657 (tag: v1.2) 第一次的修改提交
    

    由于 Git 的分支实际上只是包含所指对象的校验和,创建一个新分支仅仅相当于往一个文件中写入 41 个字节。

分支操作

分支的新建与合并

  • 具体实例总结在此文章中 分支的新建与合并
  • 需要注意的地方:
    • 首先当你想直接从当前分支创建并切换到新分支时,可以使用 $ git checkout -b yourname 来进行操作,这个命令等价于 $ git branch yourname + $ git checkout yourname
    • 当你在新分支上工作时,突然需要切换到之前开始分叉的 master 分支并且需要在 master 分支上开一个新的分支进行工作,则首先需要暂存你在 yourname 分支上还未进行暂存的修改,然后将其提交到仓库。否则可能会跟你即将检出的分支产生冲突。
    • 当你在 master 分支上开了一个新分支并且已经解决完问题后,可以将 master 和 hotfix 进行合并,使用 $ git checkout master, $ git merge hotfix 进行合并。
      • 快进 (Fast forward):在合并时,如果当前的 master 分支是你要合并分支的直接上游,则 Git 会直接将 master 指针向前推进到 hotfix 上面。然后就可以将 hotfix 进行删除。 使用 $ git branch -d hotfix
      • 合并提交:而如果 master 不是你要合并分支的直接上游,比如此时 master 分支已经指向了原本 hotfix 指向的位置,则将它与 yourname 分支合并起来会比较麻烦。由于此时 master 分支已经更新了,如果我们需要它新的内容可以将 master 合并到 yourname 上,如果不需要可以直接等 yourname 分支任务完成后,将其合并到 master 上面。如果我们想将 yourname 合并到 master 上,首先会记录他们两个指针所指向的最后一个快照,然后记录他们共同的祖先快照,最后将三方合并的结果做一个新的快照并且自动创建一个新的提交指向它。合并后可以删除 yourname 分支。
  • 遇到冲突的分之合并:可以直接使用 git status 状态来查看具体是哪个文件产生了冲突,然后直接打开该文件删除乱码部分和不需要的部分。

分支管理(git branch 命令)

  • $ git branch 命令不仅可以创建或删除分支,当不加参数时,其作用为可以查看当前分支

    $ git branch
    * master
      testing
    

    其中 * 表示当前分支

  • $ git branch -v 可以查看每个分支的最后一次提交

    $ git branch -v
    * master  b551643 made a change on master
      testing 844332b made a change on tesing
    
  • $ git branch --merged 可以查看哪些分支已经合并到当前分支上,同理 $ git branch --no-merged

    $ git branch --merged
    * master
    $ git branch --no-merged
      testing
    
  • $ git branch -d yourname 可以用来删除已经合并的分支,如果是未合并的分支则会报错。

分支开发工作流程

  • 长期分支(最常用)
    • 如只在 master 上保留稳定的代码,有可能仅仅是已经发布的代码。还有一些其他的分支如 develop 和 next 平行分支用来进行后续开发,一旦在在这些分支上达到了稳定,再将他们合并到 master 分支上。这样在确保这些已完成的特性分支能够通过所有的测试,并且不会引入 bug 后再将他们合并到 master 上等待下一次发布。
  • 特性分支
    • 特性分支被用来实现单一特性或相关工作,一旦工作完成它就会被删除。这项技术可以使你快速的进行上下文切换。当你做这么多操作时,这些分支要确保存于本地,而不会与服务器进行交互。

远程分支

  • 远程引用是指对远程仓库的引用,包括分支标签等。他们是你不能移动的本地引用,当你做任何网络通信操作时,他们会自动移动。远程跟踪分支像是你上次连接到远程仓库时,那些分支所处状态的书签。他们的命名格式为 (remote)/(branch) 。如果你想要看你最后一次与远程 origin 分支通信时 master 分支的状态,则可以查看 origin / master 分支。你与同事合作解决一个问题并且他们推送了一个 iss53 分支,你可能有自己的本地 iss53 分支;但是在服务器上的分支会指向 origin/iss53 的提交。
  • 当与远端仓库共同工作时,如果你不抓取fetch远端 orgin/master ,则它将会一直指向在你上次 fetch 的那个文件。此时即使你本地的 master 已经指向很远的地方了,远端的 orgin/master 还依旧指向你上次 fetch 的那个位置。直到你下一次 fetch。

需要注意的问题

  • 当我们使用分支合并时,要确定是谁合并到谁:当我们需要使用其他分支的内容时,可以把其他分支合并到我们的分支上。但是当我们在开发时,有时可能是从 master 或 develop 分支上拉取的工作分支,此时如果 master 或 develop 分支有更新并且我们需要用到,可以将 master 或 develop 分支拉取到我们的分支。否则,则应该等开发完毕后,将我们的分支合并到 master 或 develop 分支上。当开发完毕后,首先需要检出 master 分支,然后将工作分支合并到 master 上即可。 $ git checkout master $ git merge workBranch 。合并完成后,可以将工作分支删除。$ git branch -d workBranch,需要注意的是,当我们删除的分支还包含未提交的内容,分支删除会失效。强制删除可以使用 -D

  • 当 merge 出现冲突时,我们可以先 $ git status 来查看是哪里出现了问题,然后 cd 进入该文件,直接将冲突部分删除即可解决问题。合并完成后再次执行 $ git status 来查看问题是否解决。若问题解决,即可提交。

  • 当已经使用了 git add 指令暂存的版本又经过修改之后,需在再重新使用 git add 指令将最新的修改放入暂存区,否则此时暂存区里只有上一次修改的内容

  • $ git commit 指令仅仅是将暂存区内的文件快照提交到本地仓库中,想要推送到远程仓库则还需要 push 操作,在 push 操作之前我们需要先 $ git fetch 操作将远程仓库的需要合并的文件抓取到本地,然后进行合并,合并完成后使用 $ git status 指令进行查看,没问题后再推送到远端。这里其实也可以使用 $ git pull 来拉取远端分支的快照,但是这容易产生冲突,若产生冲突则可以找到产生冲突的文件,修改冲突部分再重新提交。提交完成后若想删掉远端工作分支,则可以使用 $ git push origin --delete 指令。

  • 当我们想删除本地暂存区中的内容,可以使用$ git rm --cache 文件名 指令,当我们想删除工作区的某个文件可以使用 $ git rm -f

  • 当我们想要删除错误提交到本地仓库的 commit

    • $ git reset --soft 版本库ID 仅仅撤销已经提交的版本库,不会修改暂存区和工作区
    • $ git reset --mixed 版本库ID 仅仅撤销提交到版本库和暂存区的内容,不会修改工作区的内容
    • $ git reset --hard 版本库ID 将工作区,暂存区,和版本库记录恢复到指定版本。
  • $ git stash branch 如果使用 stash 储藏了一些工作,然后继续在储藏的分支上工作,在重新应用 stash 储藏的文件工作时可能会有问题。 如果应用尝试修改刚刚储藏的修改的文件,也就是两次同时修改了一个文件,你会得到一个合并冲突并不得不解决它。 如果想要一个轻松的方式来再次测试储藏的改动,可以运行 git stash branch 创建一个新分支,检出储藏工作时所在的提交,重新在那应用工作,然后在应用成功后自动扔掉储藏。

  • 可以使用 $ git stash -all 来清除工作目录中所有冗余的未被跟踪的文件,并且他们会被存储在工作栈上,当你想要恢复时也可以使用 $ git stash apply 恢复使用。

  • 当在本地新创建一个分支时,需要先 push 到远端仓库,远端仓库才会有这个分支,否则会报错

    error: the requested upstream branch 'origin/f_tradeReverse' does not exist
    hint:
    hint: If you are planning on basing your work on an upstream
    hint: branch that already exists at the remote, you may need to
    hint: run "git fetch" to retrieve it.
    hint:
    hint: If you are planning to push out a new local branch that
    hint: will track its remote counterpart, you may want to use
    hint: "git push -u" to set the upstream config as you push.
    $ git fetch
    $ git status
    On branch f_tradeReverse
    nothing to commit, working tree clean
    $ git push
    fatal: The current branch f_tradeReverse has no upstream branch.
    To push the current branch and set the remote as upstream, use
    
        git push --set-upstream origin f_tradeReverse
    
    $  git push --set-upstream origin f_tradeReverse
    Username for 'https://git.ms.netease.com': shenglanya
    Password for 'https://shenglanya@git.ms.netease.com':
    Total 0 (delta 0), reused 0 (delta 0)
    remote:
    remote: Create merge request for f_tradeReverse:
    remote:   https://git.ms.netease.com/preciousmetals/LDPMTrade/merge_requests/new?merge_request%5Bsource_branch%5D=f_tradeReverse
    remote:
    To https://git.ms.netease.com/preciousmetals/LDPMTrade.git
     * [new branch]        f_tradeReverse -> f_tradeReverse
    Branch 'f_tradeReverse' set up to track remote branch 'f_tradeReverse' from 'origin'.
    
  • git 拉取远程分支并且创建本地分支 $ git checkout -b 本地分支名x origin/远程分支名x

  • 如果写错名字,重命名远程为dev1。思路:删除远程分支、重命名本地分支、重新提交一个远程分支

    1、git push --delete origin dev——删除远程分支

    2、git branch -m dev dev1——重命名本地分支为dev1

    3、git push origin dev1——重新推送远端仓库分支名称为dev1

  • 如何删除本地的文件的修改?

    • 如果是删除已经暂存的文件,则直接使用 $ git reset HEAD 文件名
    • 如果是要删除未暂存的文件,使用 $ git checkout --文件名 这样会使得这个文件去掉所有还未暂存的修改
    • 如果删除未跟踪的文件,使用 $ git clean -df
    • 删除不想要的修改 $ git stash && $ git stash clear
    • 删除本地分支 $ git branch -D BranchName
  • 删除远端分支

    • 删除本地的远端分支 $ git branch -r -D origin/BranchName
    • 删除远端服务器的分支 $ git push origin -d BranchName
  • 打 tag

    • 在本地打 tag :$ git tag 4.20.1
    • 将 tag 推送到远端 : $ git push origin :4.20.1
  • 查看远端分支 $ git branch -r

  • 从远端拉取分支 $ git checkout -b x origin/x

总结

  • 本次 Git 基础学习总结到现在就告一段落,文章由于时间,精力和自己本身能力原因并未能够完整的写完,留到日后的学习工作中当有时间和精力,以及对 Git 的使用更加了解后,将继续完善。

参考资料

日记本
Gupao