Git 基础(分布式版本控制系统)

时间:2021-07-29 06:43:53

1、Git 简史

  • 自诞生于 2005 年以来,Git 日臻成熟完善,在高度易用的同时,仍然保留着初期设定的目标。它的速度飞快,极其适合管理大项目,有着令人难以置信的非线性分支管理系统。

2、Git 基础

  • 1)直接记录快照,而非差异比较

    • Git 和其它版本控制系统(包括 Subversion 和近似工具)的主要差别在于 Git 对待数据的方法。概念上来区分,其它大部分系统以文件变更列表的方式存储信息。这类系统(CVS、Subversion、Perforce、Bazaar 等等)将它们保存的信息看作是一组基本文件和每个文件随时间逐步累积的差异。

      Git 基础(分布式版本控制系统)

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

      Git 基础(分布式版本控制系统)

  • 2)近乎所有操作都是本地执行

    • 在 Git 中的绝大多数操作都只需要访问本地文件和资源,一般不需要来自网络上其它计算机的信息。如果你习惯 于所有操作都有网络延时开销的集中式版本控制系统,Git 在这方面会让你感到速度之神赐给了 Git 超凡的能 量。因为你在本地磁盘上就有项目的完整历史,所以大部分操作看起来瞬间完成。这也意味着你离线或者没有 VPN 时,几乎可以进行任何操作。
  • 3)Git 保证完整性

    • Git 中所有数据在存储前都计算校验和,然后以校验和来引用。这意味着不可能在 Git 不知情时更改任何文件内容或目录内容。这个功能建构在 Git 底层,是构成 Git 哲学不可或缺的部分。若你在传送过程中丢失信息或损坏 文件,Git 就能发现。

    • Git 用以计算校验和的机制叫做 SHA-1 散列(hash,哈希)。这是一个由 40 个十六进制字符(0-9 和 a-f)组成字符串,基于 Git 中文件的内容或目录结构计算出来。SHA-1 哈希看起来是这样:

      24b9da6552252987aa493b52f8696cd6d3b00373
    • Git 中使用这种哈希值的情况很多,你将经常看到这种哈希值。实际上,Git 数据库中保存的信息都是以文件内容的哈希值来索引,而不是文件名。

  • 4)Git 一般只添加数据

    • 你执行的 Git 操作,几乎只往 Git 数据库中增加数据。很难让 Git 执行任何不可逆操作,或者让它以任何方式清除数据。同别的 VCS 一样,未提交更新时有可能丢失或弄乱修改的内容;但是一旦你提交快照到 Git 中,就难以再丢失数据,特别是如果你定期的推送数据库到其它仓库的话。

3、Git 状态

3.1 Git 三种状态

  • 已提交(committed)、已修改(modified)和已暂存(staged)。已提交表示数据已经安全的保存在本地数据库中。已修改表示修改了文件,但还没保存到数据库中。已暂存表示对一个已修改文件的当前版本做了标记,使之包含在下次提交的快照中。

  • 如果 Git 目录中保存着的特定版本文件,就属于已提交状态。如果作了修改并已放入暂存区域,就属于已暂存状态。如果自上次取出后,作了修改但还没有放到暂存区域,就是已修改状态。

3.2 Git 项目的三个工作区域

  • 由此引入 Git 项目的三个工作区域的概念:Git 仓库、工作目录以及暂存区域。

    Git 基础(分布式版本控制系统)

  • Git 仓库目录是 Git 用来保存项目的元数据和对象数据库的地方。这是 Git 中最重要的部分,从其它计算机克隆仓库时,拷贝的就是这里的数据。

  • 工作目录是对项目的某个版本独立提取出来的内容。这些从 Git 仓库的压缩数据库中提取出来的文件,放在磁盘上供你使用或修改。

  • 暂存区域是一个文件,保存了下次将提交的文件列表信息,一般在 Git 仓库目录中。有时候也被称作“索引”,不过一般说法还是叫暂存区域。

4、基本的 Git 工作流程

  • 1)在工作目录中修改文件。

  • 2)暂存文件,将文件的快照放入暂存区域。

  • 3)提交更新,找到暂存区域的文件,将快照永久性存储到 Git 仓库目录。

5、Git 常用命令

  • 1)Git 配置

    # 告诉 git 你是谁
    # git config --global user.name [用户名]
    $ git config --global user.name "Qian Chia" # 告诉 git 怎么联系你
    # git config --global user.email [用户邮箱]
    $ git config --global user.email "qianchiae@icloud.com" # 查看所有配置信息
    $ git config -l
    $ git config --list # 查看部分配置信息
    $ git config user.name
    $ git config user.email
  • 2)Git 帮助

    # 获取 Git 命令的使用手册
    
    # git help [verb]
    $ git help config # git [verb] --help
    $ git config --help # man git-[verb]
    $ man git-config
  • 3)获取 Git 仓库

    # 初始化仓库
    $ git init # 从远程仓库克隆到本地
    # git clone [仓库的 url 地址]
    $ git clone https://github.com/libgit2/libgit2 # 从远程仓库克隆到本地,自定义本地仓库的名字
    # git clone [仓库的 url 地址] [本地仓库名称]
    $ git clone https://github.com/libgit2/libgit2 mylibgit
  • 4)检查当前文件状态

    # 查看所有文件状态
    $ git status # 查看部分文件状态
    $ git status -s
    $ git status --short # 查看指定文件的状态
    $ git status [文件名]
    $ git status README.md # 查看修改之后还没有暂存起来的变化内容
    $ git diff # 查看已暂存的将要添加到下次提交里的内容
    $ git diff --staged
    $ git diff --cached # 查看分支引用记录,能够查阅所有的版本号
    $ git reflog
  • 5)提交更新到仓库

    # 添加文件,跟踪新文件,暂存已修改文件
    # git add [文件名]
    $ git add *.c # 提交文件到本地仓库,提交暂存区域的文件
    # git commit -m [提交内容说明]
    $ git commit -m "initial project version" # 提交文件到本地仓库,跳过使用暂存区域直接提交
    # git commit -a -m [提交内容说明]
    $ git commit -a -m 'added new benchmarks' # 覆盖提交,修改最后一次提交的注释
    # git commit --amend -m [提交内容说明]
    $ git commit --amend -m "Amend commit dsc"
  • 6)查看提交历史

    # 查看提交历史,按提交时间列出所有的更新
    $ git log # 显示每次提交的内容差异
    $ git log -p # 显示提交的简略的统计信息
    $ git log --stat # 将每个提交放在一行显示
    $ git log --pretty=oneline # 定制要显示的记录格式
    $ git log --pretty=format:"%h - %an, %ar : %s" # 形象地展示你的分支、合并历史
    $ git log --pretty=format:"%h %s" --graph
  • 7)版本回撤

    # 移除文件,彻底删除文件
    # git rm [文件名]
    $ git rm PROJECTS.md # 移除文件,从 Git 仓库中移除文件,不删除文件
    # git rm --cached [文件名]
    $ git rm --cached README # 重命名文件
    # git mv [文件名] [新文件名]
    $ git mv README.md README # 取消暂存的文件
    # git reset HEAD [文件名]
    $ git reset HEAD CONTRIBUTING.md # 撤消对文件的修改
    # git checkout -- [文件名]
    $ git checkout -- CONTRIBUTING.md # 回撤到上一个版本
    $ git reset --hard HEAD^ # 回撤到上上一个版本
    $ git reset --hard HEAD^^ # 切换到任意版本
    $ git reset --hard 版本号(前6位)
    $ git reset --hard 2dce7h
  • 8)远程仓库

    # 查看远程仓库
    $ git remote # 查看远程仓库,显示需要读写远程仓库使用的 Git 保存的简写与其对应的 URL
    $ git remote -v # 查看指定的远程仓库
    # git remote show [remote-name]
    $ git remote show origin # 添加远程仓库
    # git remote add [shortname] [url]
    $ git remote add pb https://github.com/paulboone/ticgit # 移除远程仓库
    # git remote rm [shortname]
    $ git remote rm paul # 重命名远程仓库
    # git remote rename [old-shortname] [new-shortname]
    $ git remote rename pb paul # 从远程仓库克隆到本地
    # git clone [仓库的 url 地址]
    $ git clone https://github.com/libgit2/libgit2 # 从远程仓库克隆到本地,自定义本地仓库的名字
    # git clone [仓库的 url 地址] [本地仓库名称]
    $ git clone https://github.com/libgit2/libgit2 mylibgit # 从远程仓库中抓取,不会自动合并或修改你当前的工作
    # git fetch [remote-name]
    $ git fetch origin # 从远程仓库中拉取,会自动尝试合并到当前所在的分支
    $ git pull # 推送到远程仓库
    # git push # 推送特定分支到远程仓库
    # git push [remote-name] [branch-name]
    $ git push origin master
  • 9)标签

    # 列出已有的标签
    $ git tag # 使用特定的模式查找标签
    # git tag -l [特定的模式]
    $ git tag -l 'v1.8.5*' # 创建附注标签
    # git tag -a [标签名] -m [标签说明]
    $ git tag -a v1.4 -m 'my version 1.4' # 创建轻量标签
    # git tag [标签名]-lw
    $ git tag v1.4-lw # 删除标签
    # git tag -d [tagname]
    $ git tag -d v2.0.0 # 显示标签信息
    # git show [标签名]
    $ git show v1.4 # 后期打标签,对过去的提交打标签
    # git tag -a [标签名] [校验和(或部分校验和)] -m [标签说明]
    $ git tag -a v1.2 9fceb02 -m "version 1.2" # 检出标签
    # git checkout -b [branch-name] [tagname]
    $ git checkout -b version2 v2.0.0 # 共享标签, git push 命令并不会传送标签到远程仓库服务器上
    # git push [branch-name] [tagname]
    $ git push origin v1.5 # 共享所有标签
    # git push [branch-name] --tags
    $ git push origin --tags # 获取远程标签
    # git fetch [branch-name] tag [tagname]
    $ git fetch origin tag v2.0.0 # 删除远程标签
    # git push [branch-name] --delete tag [tagname]
    $ git push origin --delete tag v2.0.0
  • 10)本地分支

    # 创建分支,不会自动切换到新分支
    # git branch [分支名]
    $ git branch testing # 创建分支,并立即切换到新分支
    $ git checkout -b [分支名]
    $ git checkout -b testing # 切换分支
    # git checkout [分支名]
    $ git checkout testing # 合并分支
    # git merge [要合并到当前分支的分支名]
    $ git merge iss53 # 删除分支,已经合并过的分支
    # git branch -d [分支名]
    $ git branch -d iss53 # 删除分支,强行删除没有合并过的分支
    # git branch -D [分支名]
    $ git branch -D iss53 # 删除没有与远程分支对应的本地分支
    $ git fetch -p # 重命名分支
    # git branch -m [旧分支名] [新分支名]
    $ git branch -m iss53 testing # 查看分支列表
    $ git branch # 查看分支列表,查看每一个分支的最后一次提交
    $ git branch -v # 查看哪些分支已经合并到当前分支
    $ git branch --merged # 查看所有包含未合并工作的分支
    $ git branch --no-merged
  • 11)远程分支

    # 查看远程分支
    $ git branch -r
    $ git branch -a # 查看设置的所有跟踪分支
    $ git branch -vv # 推送到远程分支
    # git push [remote] [branch]
    $ git push origin serverfix # 推送到远程分支,将本地分支与远程分支设置为不同名字
    # git push [remote] [branch]:[remote-branch]
    $ git push origin serverfix:awesomebranch # 跟踪远程分支
    # git checkout --track [remotename]/[branch]
    $ git checkout --track origin/serverfix # 跟踪远程分支,将本地分支与远程分支设置为不同名字
    # git checkout -b sf [remotename]/[branch]
    $ git checkout -b sf origin/serverfix # 修改正在跟踪的上游分支
    # git branch -u [remotename]/[branch]
    $ git branch -u origin/serverfix # 删除远程分支
    # git push [remotename] --delete [branch]
    $ git push origin --delete serverfix # 删除远程分支,推送一个空分支到远程分支
    # git push origin :[branch]
    $ git push origin : serverfix

6、Git 常见问题

  • 1)UserInterfaceState.xcuserstate 文件频繁更新

    • 1> 退出 Xcdoe,打开终端(Terminal),进入到你的项目目录下。

    • 2> 在终端键入

      # git rm --cached <YourProjectName>.xcodeproj/project.xcworkspace/xcuserdata/<YourUsername>.xcuserdatad/UserInterfaceState.xcuserstate
      • 终端返回

        rm 'QFormDataExample.xcodeproj/project.xcworkspace/xcuserdata/JHQ0228.xcuserdatad/UserInterfaceState.xcuserstate'
    • 3> 提交更新,在终端键入

      git commit -m "Removed file that shouldn't be tracked"
      • 终端返回

        <master 734ff0a> Removed file that shouldn't be tracked
        1 file changed, 0 insertions(+), 0 deletions(-)
        delete mode 100644 QFormDataExample.xcodeproj/project.xcworkspace/xcuserdata/JHQ0228.xcuserdatad/UserInterfaceState.xcuserstate
    • 4> 在 .gitignore 文件中加入如下几行,或者在 GitHub Desktop 中右击 UserInterfaceState.xcuserstate 更新,选择 Ignore all .xcuserstate files

      *.xcuserstate
      project.xcworkspace
      xcuserdata
      UserInterfaceState.xcuserstate
      project.xcworkspace/
      xcuserdata/
      UserInterface.xcuserstate
    • 5> 提交更新,重新打开 Xcode commit, push。

  • 2)一次提交的文件太大

    • 提交后提示 fatal: recursion detected in die handler 或者 出现 POST git-receive-pack (chunked)

    • 问题原因:http.postBuffer 默认上限为 1M 所致。

    • 解决方法:在 git 的配置里将 http.postBuffer 变量改大一些即可,比如将上限设为 500M:

      • 1> 使用终端提交代码

        • 在终端中输入以下命令

          $ git config --global http.postBuffer 524288000
        • 或者进入到要提交的代码的目录,里面包含 .git 文件夹,输入指令

          git config http.postBuffer 524288000
      • 2> 使用 SourceTreee 提交代码

        • 如图按照顺序依次点击在最后一步增加

          [http]
          postBuffer = 524288000
      • 3> 使用 TortoiseGit 提交代码

        • 右键 TortoiseGit--settings--Git--Edit systemwide gitconfig-- 把 postBuffer 的值修改为 524288000
  • 3)Git SSH 失效

    • 报错信息

      git.exe clone --progress -v "https://git.duapp.com/appiddfged879rf" "F:\bae\yelp" 
      
      Cloning into 'F:\bae\yelp'...
      fatal: unable to access 'https://git.duapp.com/appiddfged879rf/': SSL certificate problem: unable to get local issuer certificate
    • 最简单的解决方法是执行下面的命令,然后重新执行 git clone 命令

      $ git config --global http.sslVerify false
  • 4)Mac SourceTree 找不到目录

    • 报错信息

      warning: templates not found /usr/local/git/share/git-core/templates
    • 解决方法

      • 1> 检查有没有安装 Git,打开路径 /usr/local/,检查有没有 git 目录。

        • 如果没有 git 目录,下载 git-osx 并安装。

        • 如果有 git 目录,并且相应的 share、git-core、templates 目录都有,说明是权限的问题。在终端输入。

          sudo chmod -R 755 /usr/local/git/share/git-core/templates
      • 2> 查看 SourceTree 的设置,在 Git 版本设置处,修改为“使用系统安装的”。

        Git 基础(分布式版本控制系统)