Git使用总结

Git

1 Git简介

1.1 关于版本控制

版本控制系统有rcs,cvs,svn,git,Mercurial,Bazzar等。其中rcs属于本地版本控制系统,cvs、svn属于集中化版本控制系统,git、Mercurial、Bazzar属于分布式版本控制系统。

分布式版本控制系统,客户端并不只提取最新版本的文件快照,而是把代码仓库完整地镜像下来。任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜像出来的本地仓库恢复。

1.2 git的特征

  • Git 可以保存任何文件,最善于保存文本文档,提供了许多有助于文本分析的工具。对于非文本文档,Git 只是简单地为其进行备份并实施版本管理。

  • 直接记录快照,而非差异比较。Git和其他版本控制系统(svn和近似工具)的主要区别在于Git对待数据的方法。概念上来区分,其他大部分系统以文件变更列表的方式存储信息。这类系统(cvs、svn、perforce、bazaar等)将它们保存的信息看作是一组基本文件和每个文件随时间逐步累计的差异。Git像是把数据看作是对小型文件系统的一组快照。为了高效,如果文件没有修改,Git不再重新存储该文件,而是只保留一个链接指向之前存储的文件。Git对待数据更像是一个快照流。

  • 近乎所有操作都是本地执行。在Git中的绝大多数操作都只需要访问本地文件和资源,在本地磁盘上就有项目的完整历史。

  • Git保证完整性。Git中所有数据在存储前都计算校验和,然后以校验和来应用。其用以计算校验和的机制叫做SHA-1哈希。这意味着在传输过程中丢失信息或损坏文件,Git就能发现。

  • Git一般只添加数据。执行Git操作时,几乎只往Git数据库中增加数据。未提交更新时有可能丢失或弄乱修改的内容,一旦提交快照到Git中,并且定期推送数据库到其他仓库的话,就很难再丢失数据。

1.3 git的三种状态

git有三种状态,你的文件可能处于其中之一:已修改(modified)、已暂存(staged)、已提交(committed)。已修改表示修改了文件,但还没有保存到数据库中。已暂存表示对一个已修改文件的当前版本做了标记,使之包含在下次提交中。已提交表示数据已经安全的保存在本地仓库中。由此引入git项目的三个工作区域的概念:工作目录、暂存区域、git仓库。

图 0

HEAD:一个指针,指向当前所在的本地分支(将 HEAD 想象为当前分支的别名)
INDEX:指暂存区

2 Git安装配置

2.1 安装git

  • 在 Linux 上安装

    如果你想在 Linux 上用二进制安装程序来安装 Git,可以使用发行版包含的基础软件包管理工具来安装。 如果以 Fedora 上为例,你可以使用 yum:

    sudo yum install git
    

    如果你在基于 Debian 的发行版上,请尝试用 apt-get:

    sudo apt-get install git
    

    要了解更多选择,Git 官方网站上有在各种 Unix 风格的系统上安装步骤,网址为 http://git-scm.com/download/linux。

  • 在 Mac 上安装

    在 Mac 上安装 Git 有多种方式。 最简单的方法是安装 Xcode Command Line Tools。 Mavericks (10.9) 或更高版本的系统中,在 Terminal 里尝试首次运行 git 命令即可。 如果没有安装过命令行开发者工具,将会提示你安装。
    如果你想安装更新的版本,可以使用二进制安装程序。 官方维护的 OSX Git 安装程序可以在 Git 官方网站下载,网址为 http://git-scm.com/download/mac。
    你也可以将它作为 GitHub for Mac 的一部分来安装。 它们的图形化 Git 工具有一个安装命令行工具的选项。 你可以从 GitHub for Mac 网站下载该工具,网址为 http://mac.github.com.

  • 在 Windows 上安装

    在 Windows 上安装 Git 也有几种安装方法。 官方版本可以在 Git 官方网站下载。 打开 http://git-scm.com/download/win,下载会自动开始。 要注意这是一个名为 Git for Windows的项目(也叫做 msysGit),和 Git是分别独立的项目;更多信息请访问 http://msysgit.github.io/。
    另一个简单的方法是安装 GitHub for Windows。 该安装程序包含图形化和命令行版本的 Git。 它也能支持Powershell,提供了稳定的凭证缓存和健全的 CRLF 设置。 稍后我们会对这方面有更多了解,现在只要一句话就够了,这些都是你所需要的。 你可以在 GitHub for Windows 网站下载,网址为http://windows.github.com.

  • 从源代码安装

    有人觉得从源码安装 Git 更实用,因为你能得到最新的版本。
    如果想从源码安装 Git,需要安装 Git 依赖的库:curl、zlib、openssl、expat,还有libiconv。 如果你的系统上有 yum (如 Fedora)或者 apt-get(如基于 Debian 的系统),可以使用以下命令之一来安装最小化的依赖包来编译和安装 Git 的二进制版:

    $ sudo yum install curl-devel expat-devel gettext-devel 
    openssl-devel zlib-devel
    $ sudo apt-get install libcurl4-gnutls-dev libexpat1-dev gettext 
    libz-dev libssl-dev
    

    为了能够添加更多格式的文档(如 doc, html, info),你需要安装以下的依赖包:

    sudo yum install asciidoc xmlto docbook2x
    sudo apt-get install asciidoc xmlto docbook2x
    

    当你安装好所有的必要依赖,你可以继续从几个地方来取得最新发布版本的 tar 包。 你可以从 Kernel.org 网站获取,网址为 https://www.kernel.org/pub/software/scm/git,或从 GitHub 网站上的镜像来获得,网址为https://github.com/git/git/releases。 通常在 GitHub 上的是最新版本,但 kernel.org 上包含有文件下载签名,如果你想验证下载正确性的话会用到。 接着,编译并安装:

    tar -zxf git-2.0.0.tar.gz
    cd git-2.0.0
    make configure
    ./configure --prefix=/usr
    make all doc info
    sudo make install install-doc install-html install-info
    

    完成后,你可以使用 Git 来获取 Git 的升级:

    git clone git://git.kernel.org/pub/scm/git/git.git
    

2.2 初次运行git前的配置

Git 自带一个 git config 的工具来帮助设置控制 Git 外观和行为的配置变量。 这些变量存储在三个不同的位置:

  • /etc/gitconfig 文件: 包含系统上每一个用户及他们仓库的通用配置。 如果使用带有 --system 选项的git config 时,它会从此文件读写配置变量。

  • ~/.gitconfig 或 ~/.config/git/config 文件:只针对当前用户。 可以传递 --global 选项让 Git 读写此文件。

  • 当前使用仓库的 Git 目录中的 config 文件(就是 .git/config):针对该仓库。

每一个级别覆盖上一级别的配置,所以 .git/config 的配置变量会覆盖 /etc/gitconfig 中的配置变量。
在 Windows 系统中,Git 会查找 $HOME 目录下(一般情况下是 C:\Users$USER)的 .gitconfig 文件。Git 同样也会寻找 /etc/gitconfig 文件,但只限于 MSys 的根目录下,即安装 Git 时所选的目标位置。

  • 用户信息

    当安装完 Git 应该做的第一件事就是设置你的用户名称与邮件地址。 这样做很重要,因为每一个 Git 的提交都会使用这些信息,并且它会写入到你的每一次提交中,不可更改:

    git config --global user.name "John Doe"
    git config --global user.email johndoe@example.com
    

    再次强调,如果使用了 --global 选项,那么该命令只需要运行一次,因为之后无论你在该系统上做任何事情, Git 都会使用那些信息。 当你想针对特定项目使用不同的用户名称与邮件地址时,可以在那个项目目录下运行没有 --global 选项的命令来配置。
    很多 GUI 工具都会在第一次运行时帮助你配置这些信息。

  • Git别名

    可以为常用操作设置alias,如:

    git config --global alias.co checkout
    git config --global alias.br branch
    git config --global alias.ci commit
    git config --global alias.st status
    git config --global alias.unstage 'reset HEAD --'
    git config --global alias.last 'log -1 HEAD'
    git config --global alias.visual '!gitk'
    
  • 文本编辑器

    既然用户信息已经设置完毕,你可以配置默认文本编辑器了,当 Git 需要你输入信息时会调用它。 如果未配置,Git 会使用操作系统默认的文本编辑器,通常是 Vim。 如果你想使用不同的文本编辑器,例如 Emacs,可以这样做:

    git config --global core.editor emacs
    
  • 检查配置信息

    如果想要检查你的配置,可以使用 git config --list 命令来列出所有 Git 当时能找到的配置。

    $ git config --list
    user.name=John Doe
    user.email=johndoe@example.com
    color.status=auto
    color.branch=auto
    color.interactive=auto
    color.diff=auto
    ...
    

    你可能会看到重复的变量名,因为 Git 会从不同的文件中读取同一个配置(例如:/etc/gitconfig 与~/.gitconfig)。 这种情况下,Git 会使用它找到的每一个变量的最后一个配置。
    你可以通过输入 git config <key>: 来检查 Git 的某一项配置

    $ git config user.name
    John Doe
    

2.3 gitignore文件

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

文件 .gitignore 的格式规范如下:

  • 所有空行或者以 # 开头的行都会被 Git 忽略。
  • 可以使用标准的 glob 模式匹配。 所谓的 glob 模式是指 shell 所使用的简化了的正则表达式。
  • 匹配模式可以以(/)开头防止递归。
  • 匹配模式可以以(/)结尾指定目录。
  • 要忽略指定模式以外的文件或目录,可以在模式前加上惊叹号(!)取反。
  • 星号(*)匹配零个或多个任意字符;
  • [abc] 匹配任何一个列在方括号中的字符;如果在方括号中使用短划线分隔两个字符,表示所有在这两个字符范围内的都可以匹配(比如 [0-9] 表示匹配所有 0 到 9 的数字)。
  • 问号(?)只匹配一个任意字符;
  • 使用两个星号(*) 表示匹配任意中间目录,比如a/**/z 可以匹配 a/z, a/b/z 或 a/b/c/z等。

3 Git基础与命令工具

3.1 获取 Git 仓库

  • 在现有目录中初始化仓库:

    git init 在当前目录新建一个仓库
    git init [project-name] 在当前目录下新建本地仓库
    
  • 克隆现有的仓库:

    git clone [url] 克隆一个远程仓库
    git clone [url] [project-name] 克隆一个远程仓库,自定义本地仓库的名字
    

    git clone 实际上是一个封装了其他几个命令的命令。 它创建了一个新目录,切换到新的目录,然后 git init 来初始化一个空的 Git 仓库, 然后为你指定的 URL 添加一个(默认名称为 origin 的)远程仓库(git remote add),再针对远程仓库执行 git fetch,最后通过 git checkout 将远程仓库的最新提交检出到本地的工作目录。

3.2 记录每次更新到仓库

使用 Git 时文件的生命周期如下:

图 1

  • 将工作区文件添加到暂存区:

    git add [file-name1] [file-name2] ... 从工作区添加指定文件到暂存区
    git add . 将工作区的被修改的文件和新增的文件提交到暂存区,不包括被删除的文件
    git add -u . u指update,将工作区的被修改的文件和被删除的文件提交到暂存区,不包括新增的文件
    git add -A . A指all,将工作区被修改、被删除、新增的文件都提交到暂存区
    
  • 提交更新

    git commit [file-name-1] [file-name-2] -m [massage] 将暂存区指定文件添加到本地仓库,不输入[file-name]即将暂存区所有文件添加到本地仓库
    git commit -am [massage] 将工作区的内容直接加入本地仓库
    git commit --amend 快速将当前文件修改合并到最新的commit,不会产生新的commit。在提交commit后发现还有部分文件修改忘记提交了可以是用该命令
    
  • 移除文件

    git rm --cached [file-name] 文件从 Git 仓库中删除(亦即从暂存区域移除),但仍然希望保留在当前工作目录中
    git rm -rf .  不但删除所有暂存区的文件,还删除所有工作区的物理文件
    
  • 移动文件

    git mv [file_from] [file_to]  重命名或者移动文件
    
  • 查看文件状态

    git status [file-name] 查看指定文件状态,不输入[file-name]即为查看所有文件状态
    git status -s  得到一种更为紧凑的格式输出
    
  • 查看已暂存和未暂存的修改

    当需要查看任意两棵树的差异时你可以使用 git diff 命令。 此命令可以查看你工作环境与你的暂存区的差异(git diff 默认的做法),你暂存区域与你最后提交之间的差异(git diff --staged),或者比较两个提交记录的差异(git diff master branchB)。

    git diff [version1] [version2] [file-name]  查看指定两个版本中指定文件的区别,指定版本可以为commit-id/branch-name/git树
                [version1]默认为最新本地版本库,[version2]默认为工作区文件,不输入[file-name]即为查看所有文件的区别
    git diff [local branch] origin/[remote branch] 比较本地分支和远程分支的区别
    git diff --staged  暂存区域与最后提交之间的差异
    
  • 撤销操作

    git reset HEAD [file-name] 取消暂存的文件
    git checkout -- [file-name] 用暂存区的文件覆盖掉工作区的文件,如果暂存区没有可更新的就会用commit的文件更新工作区的文件
    

3.3 远程仓库的使用

  • 查看远程仓库

    git remote 列出你指定的每一个远程服务器的简写,克隆的仓库服务器的默认名字:origin
    git remote -v 显示需要读写远程仓库使用的 Git 保存的简写与其对应的 URL
    git remote show [remote-name] 查看某一个远程仓库的更多信息
    
  • 添加远程仓库

    git remote add [remote-name] <url>  添加一个新的远程 Git 仓库,同时指定一个你可以轻松引用的简写
    
  • 远程仓库的移除与重命名

    git remote rename [old-remote-name] [new-remote-name]  修改一个远程仓库的简写名
    git remote remove [remote-name]  删除本地指定的远程地址
    
  • 从远程仓库抓取与拉取

    git fetch [remote-name] 从远程仓库中获得数据,它并不会自动合并或修改你当前的工作。 当准备好时必须手动将其合并入你的工作
    git pull  从最初克隆的服务器上抓取数据并自动尝试合并到当前所在的分支。
    
  • 推送到远程仓库

    git push [remote-name] [branchname] 推送当前本地分支到指定远程分支
    git push -f 强制提交,当我们本地reset到旧的版本时,然后普通push会被拦截,因为此时本地HEAD指向比远程库还要旧
    

3.4 查看提交历史

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(后跟指定格式)
-(n)仅显示最近的 n 条提交
–since, --after仅显示指定时间之后的提交
–until, --before仅显示指定时间之前的提交
–author仅显示指定作者相关的提交
–committer仅显示指定提交者相关的提交
–grep仅显示含指定关键字的提交
-S仅显示添加或移除了某个关键字的提交
[path]只关心某些文件或者目录的历史提交
–all-match如果要得到同时满足这两个选项搜索条件的提交,就必须用 --all-match 选项。否则,满足任意一个条件的提交都会被匹配出来
–decorate查看各个分支当前所指的对象(commit id)

一些例子:

git log [filename] 查看某文件的提交记录
git log --pretty=oneline 将日志缩写为单行显示
git log --graph --pretty=oneline --abbrev-commit 查看分支合并情况
git log --pretty=format:"%h - %an, %ar : %s" 定制要显示的记录格式
git log --oneline --decorate --graph --all 查看分叉历史,包括:提交历史、各个分支的指向以及项目的分支分叉情况。
git log -p -3 显示最新3条commit日志及每次提交的内容差异
git log --since=2.weeks 列出所有最近两周
内的提交
git log -Sfunction_name 找出添加或移
除了某一个特定函数的引用的提交
git reflog 显示操作本地版本库的命令,包括commit和reset等,在回退版本以后又后悔找不到commit id了可以使用此命令查看历史
git show [commit-id] [filename]  查看某文件提交的详细信息
git show --stat [commit-id] 查看某次提交的简略信息

3.5 打标签

Git 使用两种主要类型的标签:轻量标签(lightweight)与附注标签(annotated),轻量标签只是一个特定提交的引用,附注标签是存储在 Git 数据库中的一个完整对象,其中包含打标签者的名字、电子邮件地址、日期时间、标签信息。

  • 查看标签

    git tag 查看所有标签
    git tag -l [tagname]  筛选标签
    git show [tagname]   查看标签信息与对应的提交信息
    
  • 创建标签

    git tag [tagname] [commit-id] 轻量标签,给指定的commit-id打上标签
    git tag -a [tagname] -m [massage] 附注标签,给指定的commit-id打上标签并附上说明文字
    git tag -a [tagname] [commit-id]
    
  • 删除标签

    git tag -d [tagname] 删除标签
    
  • 将标签推送到远程

    git push origin [tagname] 创建完标签后需显式地推送标签到共享服务器
    git push origin --tags 把所有不在远程仓库服务器上的标签全部传送
    
  • 检出标签

    在Git中并不能真的检出一个标签,因为它们并不能像分支一样来回移动,因此需在特定的标签上创建一个新分支

    git checkout -b [branchname] [tagname] 在特定的标签上创建一个新分支
    

3.6 分支

Git 的分支,其实本质上仅仅是指向提交对象的可变指针。 Git 的默认分支名字是 master。 在多次提交操作之后,你其实已经有一个指向最后那个提交对象的 master 分支。 它会在每次的提交操作中自动向前移动。
那么,Git 又是怎么知道当前在哪一个分支上呢? 也很简单,它有一个名为 HEAD 的特殊指针。请注意它和许多其它版本控制系统(如 Subversion 或 CVS)里的 HEAD 概念完全不同。 在 Git 中,它是一个指针,指向当前所在的本地分支(将 HEAD 想象为当前分支的别名)。

  • 查看分支

    git branch 查看当前分支
    git branch -v  查看每一个分支的最后一次提
    交
    git branch -vv 查看设置的所有跟踪分支
    git branch -a 查看本地和远程的所有分支
    git branch -r 查看远程所有分支
    git remote show [remotename] 获得远程分支的更多信息
    git ls-remote [remotename]  显式地获得远程引用的完整列表
    
  • 新建与推送分支

    git branch [branch-name] 创建分支
    git checkout -b [newbranchname] 创建并切换分支
    git switch -c [branch-name] 创建新分支并切换到该分支
    git push [remotename] [branchname] 将本地分支推送到远程仓库
    
  • 本地与远程分支连接

    git checkout -b [branch] [remotename]/[branch] 从一个远程跟踪分支检出一个本地分支会自动创建一个 “跟踪分支”
    git checkout --track [remotename]/[branch] 上述命令的快捷操作
    git branch --set-upstream-to=origin/[branchname] [branchname] 把本地分支和远程分支进行连接
    git branch -u origin/[branchname]  上述命令的快捷操作
    
  • 切换分支

    git checkout [branchname] 切换分支
    git switch [branch-name] 切换到已有分支
    
  • 删除分支

    git branch -d [branchname] 删除一个分支
    git branch -D [branchname] 强制删除一个没有合并的分支
    git push origin --delete [branchname]  删除远程分支
    
  • 分支的合并与变基

    不像其他的版本控制系统,Git 并不会尝试过于聪明的合并冲突解决方案。 Git 的哲学是聪明地决定无歧义的合并方案,但是如果有冲突,它不会尝试智能地自动解决它。
    在 Git 中整合来自不同分支的修改主要有两种方法:merge 以及 rebase,无论是通过变基还是通过三方合并,整合的最终结果所指向的快照始终是一样的,只不过提交历史不同罢了。 变基是将一系列提交按照原有次序依次应用到另一分支上,而合并是把最终结果合在一起。

    • 合并:

      图 2

      整合分支最容易的方法是 merge 命令。 它会把两个分支的最新快照(C3 和 C4)以及二者最近的共同祖先(C2)进行三方合并,合并的结果是生成一个新的快照(并提交),当 git fetch 命令从服务器上抓取本地没有的数据时,它并不会修改工作目录中的内容。 它只会获取数据然后让你自己合并。 然而,有一个命令叫作 git pull 在大多数情况下它的含义是一个 git fetch 紧接着一个git merge 命令。 如果有一个像之前章节中演示的设置好的跟踪分支,不管它是显式地设置还是通过 clone或 checkout 命令为你创建的,git pull 都会查找当前分支所跟踪的服务器与分支,从服务器上抓取数据然后尝试合并入那个远程分支。
      git merge合并的方式:
      (1)fast-forward方式:当条件允许的时候,git直接把HEAD指针指向合并分支的头,完成合并。属于“快进方式”,不过这种情况如果删除分支,则会丢失分支信息。因为在这个过程中没有创建commit
      (2)squash:用来把一些不必要commit进行压缩,比如说,你的feature在开发的时候写的commit很乱,那么我们合并的时候不希望把这些历史commit带过来,于是使用–squash进行合并,此时文件已经同合并后一样了,但不移动HEAD,不提交。需要进行一次额外的commit来“总结”一下,然后完成最终的合并
      (3)–no-ff:强行关闭fast-forward方式,这样会创建新的commit

      git merge 合并本地origin/[branch-name]和HEAD->[branch-name]的代码,并同步到工作空间
      git merge [branch-name] 用于合并指定分支到当前分支
      git merge --quit 退出当前分支合并,当合并后冲突很多,要撤回合并分支就可以用这个命令
      git merge --no-ff -m [massage] [branch-name] 不使用Fast forward合并分支
      
    • 变基:

      图 3

      使用 rebase 命令将提交到某一分支上的所有修改都移至另一分支上,提取在 C4 中引入的补丁和修改,然后在 C3 的基础上应用一次,就好像“重新播放”一样。git rebase 命令基本是一个自动化的 cherry-pick 命令。 它计算出一系列的提交,然后再以它们在其他地方以同样的顺序一个一个的 cherry-picks 出它们。
      不要对在你的仓库外有副本的分支执行变基。

      git rebase [branch-name] 将当前分支的提交内容变基到指定分支
      git pull --rebase 相当于git fetch + git rebase
      git cherry-pick [commit-id] 这个是复制一次commit提交,然后在当前分支上重新提交一遍;也就是将指定commit的合并到当前分支;
      

3.7 选择版本

  • 提交commit-id

    可以通过 Git 给出的 SHA-1 值(- commit-id)来获取一次提交,也可以通过简短的 SHA-1 值(SHA-1 的前几个字符,不得少于 4 个且没有歧义)。
    通常 8 到 10 个字符就已经足够在一个项目中避免 SHA-1 的歧义。比如 Linux 内核这个相当大的 Git 项目,目前有超过 45 万个提交,包含 360 万个对象,也只需要前 11 个字符就能保证唯一性。

  • 使用分支名

    指明一次提交最直接的方法是有一个指向它的分支引用。 这样你就可以在任意一个 Git 命令中使用这个分支名来代替对应的提交对象或者 SHA-1 值。 例如,你想要查看一个分支的最后一次提交的对象,假设 topic1 分支指向 ca82a6d ,那么以下的命令是等价的:

    git show ca82a6d
    git show topic1
    
  • 日志引用

    你可以使用 git reflog 来查看引用日志

    $ git reflog
    734713b HEAD@{0}: commit: fixed refs handling, added gc auto, updated
    d921970 HEAD@{1}: merge phedders/rdocs: Merge made by recursive.
    1c002dd HEAD@{2}: commit: added some blame and merge stuff
    1c36188 HEAD@{3}: rebase -i (squash): updating HEAD
    95df984 HEAD@{4}: commit: # This is a combination of two commits.
    1c36188 HEAD@{5}: rebase -i (squash): updating HEAD
    7e05da5 HEAD@{6}: rebase -i (pick): updating HEAD
    

    可以使用@{n} 来引用 reflog 中输出的提交记录

    git show HEAD@{5}
    

    也可以使用这个语法来查看某个分支在一定时间前的位置

    git show master@{yesterday}  查看 master 分支在昨天的时候指向了哪个提交
    git show HEAD@{2.months.ago} 查看当前分支在两个月前指向了哪个提交
    
  • 祖先引用

    你可以使用 ^ 或~来查看祖先提交,

    git show HEAD^ 或 git show HEAD~  查看当前分支的父提交
    git show d921970^ 或 git show d921970~  查看d921970的父提交
    git show HEAD^2  查看当前分支的第二父提交,这个语法只适用于合并(merge)的提交,因为合并提交会有多个父提交,第一父提交是你合并时所在分支,而第二父提交是你所合并的分支
    git show HEAD^^ 或 git show HEAD~2  查看第一父提交的第一父提交
    git show HEAD~3^2  查看当前分支第一父提交的第一父提交的第一父提交的第二父提交
    
  • 提交区间

    git log refA refB --not refC   与上述命令等价
    git log master...experiment   master 或者 experiment 中包含的但不是两者共有的提交
    

3.8 储藏

储藏会处理工作目录的脏的状态( 即,修改的跟踪文件与暂存改动 ) 然后将未完成的修改保存到一个栈上,而你可以在任何时候重新应用这些改动。

  • 储藏工作

    git stash 储藏当前工作的修改,如果不储藏自己修改的半成品代码,就会发生切换到别的分支后,将然后自己的半成品代码带入其他分支,这样就发生很多不必要的麻烦。
    git stash save message 执行储藏时,添加备注,方便查找,只有git stash 也要可以的,但查找时不方便识别。
    git stash --keep-index 不要储藏任何你通过 git add 命令已暂存的东西
    git stash -u 储藏内容包含任何创建的未跟踪文件。
    git stash --patch 交互式地提示哪些改动想要储藏、哪些改动需要保存在工作目录中
    
  • 查看储藏

    git stash list 查看储藏的工作信息列表
    
  • 应用储藏

    git stash pop 恢复储藏的工作信息,同时删除储藏的工作信息
    git stash apply stash@{0} 恢复指定的储藏工作信息,但是不会删除储藏的工作信息
    git stash branch [branchname] 创建一个新分支,检出储藏工作时所在的提交,重新在那应用工作,然后在应用成功后扔掉储藏
    
  • 删除储藏

    git stash drop 删除储藏的工作信息
    
  • 清理

    git clean -d -n 加-d是指包含目录,加-f是指强制,移除由合并或外部工具生成的东西,
    git stash --all 更安全地移除每一样东西并存放在栈中
    

3.9 重置

Git 作为一个系统,是以它的一般操作来管理并操纵这三棵树的:
HEAD当前分支引用的指针,它总是指向该分支上的最后一次提交。上一次提交的快照,下一次提交的父结点IndexGit 的 “暂存区域”,预期的下一次提交的快照Working Directory另外两棵树以一种高效但并不直观的方式,将它们的内容存储在 .git 文件夹中。 工作目录会将它们解包为实际的文件以便编辑。

  • 使用reset重置

    reset 命令会以特定的顺序重写这三棵树,在你指定以下选项时停止:
    (1)移动 HEAD 分支的指向 (若指定了 --soft,则到此停止)
    (2)使索引看起来像 HEAD (若未指定 --hard,则到此停止)
    (3)使工作目录看起来像索引
    若指定了一个路径,reset 将会跳过第 1 步,并且将它的作用范围限定为指定的文件或文件集合。这样做自然有它的道理,因为 HEAD 只是一个指针,你无法让它同时指向两个提交中各自的一部分。 不过索引和工作目录 可以部分更新,所以重置会继续进行第 2、3 步。
    必须注意,–hard 标记是 reset 命令唯一的危险用法,它也是 Git 会真正地销毁数据的仅有的几个操作之一。其他任何形式的 reset 调用都可以轻松撤消,但是 --hard 选项不能,因为它强制覆盖了工作目录中的文件。如果 Git 数据库中的一个提交内还留有覆盖掉的文件,我们可以通过 reflog 来找回它。但是若该文件还未提交,Git 仍会覆盖它从而导致无法恢复。

    git reset --[soft|(mixed)|hard] HEAD
        --soft 其中可选参数soft表示单纯的切换HEAD指向的commit-id
        --mixed 默认值mixed参数表示先执行上面一步,然后再将commit-id里面的内容更新到暂存区
        --hard hard表示先执行上面两步,然后再将暂存区内容同步到工作区
    git reset [commit-id] [file-name] 将指定commit-id中的文件替换掉暂存区的文件
    
  • checkout 和 reset 之间的区别:

    (1)git checkout [branch] 与 git reset --hard [branch],首先不checkout 对工作目录是安全的,它会通过检查来确保不会将已更改的文件弄
    丢。 其实它会在工作目录中先试着简单合并一下,这样所有“还未修改过的”文件都会被更
    新。 而 reset --hard 则会不做检查就全面地替换所有东西。第二个重要的区别是如何更新 HEAD。 reset 会移动 HEAD 分支的指向,而 checkout 只会移动 HEAD 自身来指向另一个分支。
    (2)运行 checkout 的另一种方式就是指定一个文件路径,这会像 reset 一样不会移动 HEAD。 它就像 git reset [branch] file 用该次提交中的那个文件来更新索引,但是它也会覆盖工作目录中对应的文件。它就像是 git reset --hard [branch] file(如果 reset 允许你这样运行的话,这样对工作目录并不安全,它也不会移动 HEAD)

  • revert 和 reset 之间的区别:

    • reset 切换版本是会删除丢弃最新的版本的,HEAD会直接跳到指定版本,但是还是可以通过reflog找回。

    • revert 会将指定的bug版本视为bug版,会将当前版本中的bug版的代码删除,生成新的commit覆盖掉当前commit,但是commit-id是不会变的。

      git revert 命令本质上就是一个逆向的 git cherry-pick 操作。 它将你提交中的变更的以完全相反的方式的应用到一个新创建的提交中,本质上就是撤销或者倒转。
      git revert -n [commit-id]
      git revert -n HEAD^^
      

3.10 其他不常用

  • 搜索

    查找字符串
    Git 提供了一个 grep 命令,你可以很方便地从提交历史或者工作目录中查找一个字符串或者正则表达式。

    git grep -n [search-str]  查找一个字符串,-n 参数来输出 Git 所找到的匹配行行号
    git grep --count [search-str]  输出概述的信息,包括哪些文件包含匹配以及每个文件包含了多少个匹配
    git grep -p [search-str] *.c  匹配的行是属于哪一个方法或者函数
    
  • 查找日志

    git log 命令有许多强大的工具可以通过提交信息甚至是 diff 的内容来找到某个特定的提交。
    git log -SZLIB_BUF_MAX --oneline 找到 ZLIB_BUF_MAX 常量是什么时候引入的
    git log -L :git_deflate_bound:zlib.c  想查看 zlib.c 文件中git_deflate_bound 函数的每一次变更
    
  • 重写历史

    • 使用git rebase -i 重写历史:
      (1)git rebase -i ,可以指定所要修改的历史的范围,比如HEAD~3,表示在 HEAD~3…HEAD 范围内
      (2)在文本编辑器中将要修改的commiid前的pick改为edit
      (3)保存退出文本编辑器之后,就可以回到要修改的commitid处,此时可进行修改,修改完成之后git commit --amend。若要拆分此提交,可使用类似如下步骤:

      git reset HEAD^
      git add README
      git commit -m 'updated README formatting'
      git add lib/simplegit.rb
      git commit -m 'added blame'
      

      (4)最后使用git rebase --continue,将原本此commitid之后的提交变基到最新的提交历史上记住这是一个变基命令,在 HEAD~3…HEAD 范围内的每一个提交都会被重写,无论你是否修改信息。 不要涉及任何已经推送到中央服务器的提交,这样做会产生一次变更的两个版本。

      使用git rebase -i 还可以重新排序提交、删除提交、合并提交(pick改为squash)、修改commit message(pick改为reword)

    • 核武器级选项:filter-branch

      如果想要通过脚本的方式改写大量提交的话可以使用它 - 例如,全局修改你的邮箱地址或从每一个提交中移除一个文件。除非你的项目还没有公开并且其他人没有基于要改写的工作的提交做的工作,你不应当使用它。

      git filter-branch --tree-filter 'rm -f passwords.txt' HEAD  从整个提交历史中移除一个叫做 passwords.txt 的文件
      git filter-branch --subdirectory-filter trunk HEAD  让trunk 子目录作为每一个提交的新的项目根目录
      git filter-branch --commit-filter '
          if [ "$GIT_AUTHOR_EMAIL" = "schacon@localhost" ];
          then
              GIT_AUTHOR_NAME="Scott Chacon";
              GIT_AUTHOR_EMAIL="schacon@example.com";
              git commit-tree "$@";
          else
              git commit-tree "$@";
          fi' HEAD  一次性修改多个提交中的邮箱地址。 需要小心的是只修改你自己的邮箱地址,所以你使用 --commit-filter
      
  • rerere

    git rerere 功能是一个隐藏的功能。 正如它的名字 “reuse recorded resolution” 所指,它允许你让 Git 记住解决一个块冲突的方法,这样在下一次看到相同冲突时,Git 可以为你自动地解决它。

  • 文件标注

    如果你在追踪代码中的一个 bug,并且想知道是什么时候以及为何会引入,文件标注通常是最好用的工具。 它展示了文件中每一行最后一次修改的提交。

    git blame -L [row1,row2] [filename]   展示了文件中row1至row2行最后一次修改的提交。
    git blame -C -L [row1,row2] [filename]  后面加上一个 -C,Git 会分析你正在标注的文件,并且尝试找出文件中从别的地方复制过来的代码片段的原始出处。
    
  • 二分查找

    如果你不知道哪里出了问题,并且自从上次可以正常运行到现在已经有数十个或者上百个提交,这个时候你可以使用 git bisect 来帮助查找。

    git bisect start   启动bisect
    git bisect bad    告诉bisect当前你所在的提交是有问题的
    git bisect good [good_commit]   告诉 bisect 已知的最后一次正常状态是哪次提交
    git bisect good  告诉 bisect当前检出的那个提交是没问题的
    git bisect bad  告诉 bisect当前检出的那个提交是有问题的
    git bisect reset  查找到有问题的提交之后,重置你的 HEAD 指针到最开始的位置
    

    如果你有一个脚本在项目是正常的情况下返回 0,在不正常的情况下返回非 0,你可以使 git bisect 自动化这些操作。

  • 子模块

    某个工作中的项目需要包含并使用另一个项目。 也许是第三方库,或者你独立开发的,用于多个父项目的库。Git子模块允许你将一个 Git 仓库作为另一个 Git 仓库的子目录。 它能让你将另一个仓库克隆到自己的项目中,同时还保持提交的独立。

    git submodule add [URL] 将一个已存在的 Git 仓库添加为正在工作的仓库的子模块,添加完成之后产生新的.gitmodules 文件,保存了项目 URL 与已经拉取的本地目录之间的映射
    git submodule init  克隆含有子模块的项目后用来初始化本地配置文件
    git submodule update --remote --merge   来从上游拉取新工作。 并将它们合并到你的本地工作中
    git clone --recursive  [URL] 克隆仓库时自动初始化并更新仓库中的每一个子模块
    git diff --cached --submodule  查看改动
    git push --recurse-submodules=check   让 Git 在推送到主项目前检查所有子模块是否已推送
    
  • 打包

    Git 可以将它的数据 “打包” 到一个文件中。 这在许多场景中都很有用。 有可能你的网络中断了,但你又希望将你的提交传给你的合作者们。 可能你不在办公网中并且出于安全考虑没有给你接入内网的权限。 可能你的无线、有线网卡坏掉了。 可能你现在没有共享服务器的权限,你又希望通过邮件将更新发送给别人,却不希望通过 format-patch 的方式传输 40 个提交。
    这些情况下 git bundle 就会很有用。 bundle 命令会将 git push 命令所传输的所有内容打包成一个二进制文件,你可以将这个文件通过邮件或者闪存传给其他人,然后解包到其他的仓库中。

    git bundle create repo.bundle HEAD master  打包成名为 repo.bundle 的文件,该文件包含了所有重建该仓库 master 分支所需的数据
    git bundle create commits.bundle master ^9a466c5  打包时加上要打包的提交区间
    git clone repo.bundle repo   从这个文件中克隆出一个目录。
    git clone repo.bundle repo -b [branchname] 如果你在打包时没有包含 HEAD 引用,你还需要在命令后指定一个被引入的分支,否则Git 不知道应该检出哪一个分支。
    git bundle verify repo.bundle 检查这个文件是否是一个合法的 Git 包,是否拥有共同的祖先来导入
    
  • 替换

    Git 对象是不可改变的,但它提供一种有趣的方式来用其他对象假装替换数据库中的 Git 对象。
    replace 命令可以让你在 Git 中指定一个对象并可以声称“每次你遇到这个 Git 对象时,假装它是其他的东
    西”。 在你用一个不同的提交替换历史中的一个提交时,这会非常有用。

  • 获取帮助

    若你使用 Git 时需要获取帮助,有三种方法可以找到 Git 命令的使用手册:

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

    例如,要想获得 config 命令的手册,执行

    git help config
    

    这些命令很棒,因为你随时随地可以使用而无需联网。 如果你觉得手册或者本书的内容还不够用,你可以尝试在 Freenode IRC 服务器( irc.freenode.net )的 #git 或 #github 频道寻求帮助。 这些频道经常有上百人在线,他们都精通 Git 并且乐于助人。

4 分布式Git

4.1 git flow的种类

4.1.1 Centralized Workflow

图 4

(1)从远程仓库(central repository)克隆工程到本地仓库(local repository)-- git clone
(2)在本地仓库编辑文件和提交更新 – git add 和 git commit
(3)fetch远程仓库已更新的commit到本地仓库和rebase到已更新的commit的上面 – git fetch 和 git rebase(或直接使用git pull --rebase)
(4)push本地主分支(master branch)到远程仓库 – git push
何时发生冲突:在开发者发布它们功能之前,他们需要fetch远程仓库已更新的commit到本地仓库和rebase到已更新的commit上面。有时,本地提交与远程提交会发生冲突,git会暂停rebase过程来让你手动解决冲突。
如何解决冲突:可以使用git status和git add来手动解决合并时冲突
这种方式是一种svn的替代方式,并没有利用git分布式代码管理的优势。缺点:
(1)无法追溯版本
(2)不能很好的支持并行项目开发

4.1.2 Feature Branch Workflow

图 5

Feature Branch Workflow的主要思想就是在开发每个功能时都创建一个独立的分支而不只是使用主分支。由于每个分支是独立且互不影响,这就意味着主分支不会包含broken code,对持续集成环境是很有帮助的。
(1)仍然使用远程仓库(central repository)和主分支(master branch)记录官方工程的历史。
(2)开发者每次开发新功能时都创建一个新分支 – git checkout -b feature\new
(3)Feature branches应该推送到远程仓库(central repository) – git push
(4)发送pull request来请求管理员能否合并到主分支(master branch)
(5)发布新功能到远程仓库(central repository)

4.1.3 Gitflow Workflow

图 6

Gitflow Workflow在Feature Branch Workflow的基础上,使用独立的分支来准备发布(preparing)、维护(maintaining)、记录版本(recording releases)

  • Historical Branch (master branch)

    图 7

    master分支保存官方发布历史,develop分支衍生出各个feature分支

  • Feature Branches

    图 8

    • feature分支使用develop分支作为它们的父类分支
    • 当其中一个feature分支完成后,它会合并到develop分支
    • feature分支应该从不与master分支直接交互
  • Release Branches

    图 9

    Release分支主要用来清理释放、测试和更新文档。
    一旦develop分支获得足够的功能来发布时,你可以从develop衍生出一个release分支,一旦准备好上线,release合并到master分支并且标记一个版本号,另外,还需要合并回develop分支

  • Maintenance Branches(hotfix)

    图 10

    maintenance分支用来快速给已发布产品修复bug或微调功能,它从master分支直接衍生出来,一旦完成修复bug,它应该合并回master分支和develop分支,master应该被标记一个新的版本号。-- git tag -a 0.1 -m “Initial public release” master 和 git push origin master --tags

4.2 实际业务场景

4.2.1 整体工作流程

图 11

  • 长期存在的分支

    • master:主分支,负责记录上线版本的迭代,该分支代码与线上代码是完全一致的。
    • develop:开发分支,该分支记录相对稳定的版本,所有的feature分支和bugfix分支都从该分支创建。
  • 短期分支,其完成功能开发之后需要删除

    • feature/*:特性(功能)分支,用于开发新的功能,不同功能创建不同的功能分支,功能分支开发完成并自测通过后,需要合并到develop分支,之后删除该分支。
    • release/*:发布分支,用于代码上线准备,该分支从develop分支创建,创建之后由测试同学发布到测试环境进行测试,测试过程中发现bug需要开发人员在该release分支上进行bug修复,所有bug修复完之后,在上线前,需要合并该release分支到master分支和develop分支。
    • hotfix/*:紧急bug修复分支,该分支只有在紧急情况下使用,从master分支创建,用于紧急修复线上bug,修复完成后,需要合并该分支到master分支以便上线,同时需要再合并到develop分支,并打上tag。
4.2.2 项目并行开发流程

图 12

5 内部原理

当在一个新目录或已有目录执行 git init 时,Git 会创建一个 .git 目录。 这个目录包含了几乎所有 Git 存储 和操作的对象。 如若想备份或复制一个版本库,只需把这个目录拷贝至另一处即可。

目录名称保存信息
HEAD指示目前被检出的分支
index保存暂存区信息
objects/存储所有数据内容,一个文件对应一条内容,以该内容加上特定头部信息一起的 SHA-1 校验和为文件命名。 校验和的前两个字符用于命名子目录,余下的 38 个字符则用作文件名。
refs/存储指向数据(分支)的提交对象的指针
description仅供 GitWeb 程序使用,我们无需关心
config包含项目特有的配置选项
info/包含一个全局性排除(global exclude)文件,用以放置那些不希望被记录在 .gitignore 文件中的忽略模式(ignored patterns)
hooks/包含客户端或服务端的钩子脚本(hook scripts)
  • Git对象

    Git 的核心部分是一个简单的键值对数据库(key-value data store)。 你可以向该数据库插入任意类型的内容,它会返回一个键值,通过该键值可以在任意时刻再次检索(retrieve)该内容。这样的文件被称为“对象(object)”,你可以在 .git/object 目录下找到这类含有 SHA-1 值的文件。
    Git 以一种类似于 UNIX 文件系统的方式存储内容,但作了些许简化。 所有内容均以树对象和数据对象的形式存储,其中树对象对应了 UNIX 中的目录项,数据对象则大致上对应了 inodes 或文件内容。

  • 数据对象

    文件内容的存储对象。

  • 树对象

    它能解决文件名保存的问题,也允许我们将多个文件组织到一起。一个树对象包含了一条或多条树对象记录(tree entry),每条记录含有一个指向数据对象或者子树对象的 SHA-1 指针,以及相应的模式、类型、文件名信息。

  • 提交对象

    指明了顶层树对象和父提交

  • Git引用

    我们可以借助类似于 git log 1a410e 这样的命令来浏览完整的提交历史,但为了能遍历那段历史从而找到所有相关对象,你仍须记住 1a410e 是最后一个提交。 我们需要一个文件来保存 SHA-1 值,并给文件起一个简单的名字,然后用这个名字指针来替代原始的 SHA-1 值。
    在 Git 里,这样的文件被称为“引用(references,或缩写为 refs)”,你可以在 .git/refs 目录下找到这类含有 SHA-1 值的文件。

  • HEAD 引用

    HEAD 文件是一个符号引用(symbolic reference),指向目前所在的分支。所谓符号引用,意味着它并不像普通引用那样包含一个 SHA-1 值——它是一个指向其他引用的指针。

  • 标签引用

    标签对象(tag object)非常类似于一个提交对象——它包含一个标签创建者信息、一个日期、一段注释信息,以及一个指针。 主要的区别在于,标签对象通常指向一个提交对象,而不是一个树对象。 它像是一个永不移动的分支引用——永远指向同一个提交对象,只不过给这个提交对象加上一个更友好的名字罢了。

  • 远程引用

    如果你添加了一个远程版本库并对其执行过推送操作,Git 会记录下最近一次推送操作时每一个分支所对应的值,并保存在 refs/remotes 目录。远程引用和分支(位于 refs/heads 目录下的引用)之间最主要的区别在于,远程引用是只读的。 虽然可以git checkout 到某个远程引用,但是 Git 并不会将 HEAD 引用指向该远程引用。因此,你永远不能通过 commit 命令来更新远程引用。 Git 将这些远程引用作为记录远程服务器上各分支最后已知位置状态的书签来管理。

  • 引用规格

    • 拉取引用规格

      使用git remote add origin [url]后会在 .git/config 文件中添加一个小节,并在其中指定远程版本库的名称(origin)、URL 和一个用于获取操作的引用规格(refspec)

      
      [remote "origin"]
          url = <https://github.com/schacon/simplegit-progit>
          fetch = +refs/heads/:refs/remotes/origin/
      

      引用规格的格式由一个可选的 + 号和紧随其后的 <src>:<dst> 组成,其中 <src> 是一个模式(pattern),代表远程版本库中的引用;<dst> 是那些远程引用在本地所对应的位置。 + 号告诉 Git 即使在不能快进的情况下也要(强制)更新引用。
      默认情况下,引用规格由 git remote add 命令自动生成, Git 获取服务器中 refs/heads/ 下面的所有引用,并将它写入到本地的 refs/remotes/origin/ 中。
      这是针对该远程版本库的 git fetch 操作的默认引用规格。 如果有只希望被执行一次的操作,我们也可以在命令行指定引用规格。

      git fetch origin master:refs/remotes/origin/mymaster
      

      如果服务器上有一个 master 分支,我们可以在本地通过下面这种方式来访问该分支上的提交记录,下面的三个命令作用相同,因为 Git 会把它们都扩展成 refs/remotes/origin/master:

      git log origin/master
      git log remotes/origin/master
      git log refs/remotes/origin/master
      
    • 推送的引用规格

      可以在他们的配置文件中添加一条 push值:

      [remote "origin"]
          url = <https://github.com/schacon/simplegit-progit>
          fetch = +refs/heads/:refs/remotes/origin/
          push = refs/heads/master:refs/heads/qa/master
      

      如果有只希望被执行一次的操作,我们也可以在命令行指定引用规格。

      git push origin master:refs/heads/qa/master
      
    • 删除引用

      因为引用规格(的格式)是 <src>:<dst>,所以把 <src> 留空,意味着把远程版本库的 topic 分支
      定义为空值,也就是删除它。借助类似下面的命令通过引用规格从远程服务器上删除引用:

      git push origin :topic
      git push origin --delete topic 在Git v1.7.0以后可用的更新的语法
      
  • 维护与数据恢复

    • 包文件

      Git 向磁盘中存储对象时所使用的格式被称为“松散(loose)”对象格式,即文件的每次改动都会用一个全新的对象来存储新的文件内容。但 是,Git 会时不时地将多个这些对象打包成一个称为“包文件(packfile)”的二进制文件,以节省空间和提高效率。 当版本库中有太多的松散对象,或者你手动执行 git gc 命令,或者你向远程服务器执行推送时,Git 都会这样做。
      执行 git gc 命令让 Git 对对象进行打包之后,会将打包的对象删除,并在.git/objects/pack/中生成一个包文件和一个索引,包文件包含了刚才从文件系统中移除的所有对象的内容。 索引文件包含了包文件的偏移信息,我们通过索引文件就可以快速定位任意一个指定对象。
      Git 打包对象时,会查找命名及大小相近的文件,并只保存文件不同版本之间的差异内 容。 你可以查看包文件,观察它是如何节省空间的。 git verify-pack 这个底层命令可以让你查看已打包的 内容。

    • 数据恢复

    • 移除对象

  • 传输协议

    • 使用git协议搭建的服务器,git协议是专门为搭建git服务器所创建的一个协议,它也是最快的传输协议,不过它的问题就是授权机制过于简单,要么所有人都有推送权限,要么所有人都没有推送权限。通常使用git://访问。

    • 使用http协议或者https协议来架设,这主要是因为http协议太常用了,而且架设太简单了,它的传输效率就没有那么高了。http协议为哑协议,用于只读的版本库。

    • 使用ssh协议来架设,而且绝大多数环境都支持通过ssh对服务器进行访问,而且ssh也是唯一一个同时对于读和写操作都很方便的网络协议,而http协议或者git协议通常都是只读的。而且ssh的安全性也相对较高,一般使用ssh://来访问。通常git都是默认使用ssh协议的。

  • 环境变量

    Git 总是在一个 bash shell 中运行,并借助一些 shell 环境变量来决定它的运行方式。

  • 部分底层命令

    • hash-object:可将任意数据保存于 .git 目录。-w 选项指示 hash-object 命令存储数据对象;若不指定此选项,则该命令仅返回对应的键值。 --stdin 选 项则指示该命令从标准输入读取内容;若不指定此选项,则须在命令尾部给出待存储文件的路径。 该命令输出 一个长度为 40 个字符的校验和(SHA-1 哈希值)。
    • cat-file:从 Git 那里取回数据。-p 选项可指示该命令自动判断内容的类型,并为我们显示格式友好的内容。-t 选项可以让 Git 告诉我们其内部存储的任何对象类型,只要给定该对象的SHA-1 值。
    • update-index:为一个单独文件创建一个暂存区
    • write-tree:将暂存区内容写入一个树对象
    • read-tree:把树对象读入暂存区
    • commit-tree:创建一个提交对象
    • update-ref:更新某个引用
    • symbolic-ref:设置 HEAD 引用的值,不能把符号引用设置为一个不符合引用格式的值
    • git verify-pack:查看通过git gc已打包的内容
    • git count-objects:快速的查看占用空间大小
    • git rev-list:会列出所有提交的 SHA-1、数据对象的 SHA-1 和与它们相关联的文件路径

参考链接

git命令大全
Git在团队中的最佳实践–如何正确使用Git Flow
git-flow备忘清单
研发团队GIT开发流程新人学习指南
tutoriaatlassian git
pro git

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嵌梦之旅:小城开发者的笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值