版本管理工具 Git 的使用

就软件开发来说, 不管是个人开发还是团队协作, 版本管理工具肯定必不可少. 其中分布式版本管理工具 git 由于其优良的性能, 可靠的安全性最为被接受, 也是最为普及的.

在完整地看了几个教程并且实战了一段时间后, 我将日常使用的命令以及个人理解总结成本文. 本文涉及内容有初级, 有高级, 如果能完全掌握这些命令绝对能在工作中祝你一臂之力. 建议收藏以备以后检索相关命令. 😁

himg

分布式存储与集中式存储的区别

  • 都有一个中央仓库
  • 团队合作开发中每个人的仓库最终都必须同步到中央仓库
  • 中央式存储没有个人仓库的概念, 因此只有做完一个小功能后上传到中央仓库才会有一个记录节点. 这样会导致一个提交里面包含很多代码, 不利于回溯.
  • 分布式存储有个人仓库, 每个人做完一个极小的功能后可以先 commit, 然后再 push, push 到中央仓库后也会将自己的诸多小 commit 传上来.(如果不需要那么多小 commit 的话可以使用 rebase 依次合并多个小 commit 然后再统一 push)
  • 分布式存储由于在每个机器上都会有完整的存储仓库, 因此本地占用会比较大, 初次 clone 也会稍微费事一些
  • 结合以上特点, 由于软件开发主要是文本代码, 而这些资料的占用空间并不大, 而且软件开发对历史回溯要求比较高, 因此一般都是使用分布式存储. 集中式存储主要用于某些占用体积超大的项目开发领域, 比如大型游戏.

Git 特点

  • Git 的管理是目录级别, 而不是设备级别的, 即两个不同的目录存着同样地址的仓库的话会被认为是两个不同的仓库, 可以用于模拟为两个人.

  • git 是以 line 为最小单位进行判断的, 即如果序号 1 的行被 branch 修改了, 序号 2 的行被 master 修改了, 那么在 merge branchmaster 的时候结果就是序号 12 都被修改了. 但是两个 branch 都在序号 1 的行修改了, 那么就会冲突, 会提示手动解决冲突.

  • 一个仓库中的文件都会被 git 系统监视, 一共有以下 3 种状态

    1. 未被跟踪: 新建文件都不会被跟踪. 需要手动 add 进入暂存区

    2. 已保存: 已经在系统中保存了此文件, 被放在保存区未放入暂存区(changes not staged for commit)

    3. 已暂存: commit(changes to be commited), 被放入 暂存区. 等待 commit

      himg

  • 其实 reset 的三个状态正好对应了文件的几种保存状态

    1. hard: 回退commit, 将两个 commit 之间的改动放入暂存区, 再将暂存区所有文件放到保存区, 再将保存区文件删除. 最硬的
    2. mixed: 回退 commit, 将两个 commit 之间的改动全部放入暂存区, 再将暂存区所有文件放到保存区
    3. soft: 回退 commit, 两个 commit 之间的改动全部放入暂存区. 最软的.
  • reset 的三种模式中, 只有 hard 会直接将文件直接转为未提交 commit 之前的状态

  • 一个已被跟踪的文件被改动了, 只要保存更改就会被放入保存区. 此时可以

    1. 使用 git checkout -- filename 来永久撤销文件修改.
    2. 使用 git add 命令将更改放入 暂存区 等待 commit.
  • 未放入 staged area 的修改不会被 commit.

  • 如果一个文件未被跟踪 (untracked file), 那么 Git 系统只会提示你在 git 文件夹中有一个未被跟踪的文件, 哪怕对齐进行修改 git 也不会关心其修改内容. 只要 add 一次就可以永久跟踪.

  • show 显示的是commit 状态及细节, diff 显示的是文件的修改状态和细节

  • 在对文件修改时, 只会在当前 branch 进行修改, 在 push 时, 也只会将此内容 push 到远端的此 branch

  • git 中的 headbranch 都是引用 (reference), 其内存储的都是各个 commitsha1 值. 引用都以文件形式存储在 .git 目录中, 当git 工作时, 通过这些文件的内容判断整个仓库的结构.

  • 每个仓库只能有一个 head, branch 可以有多个

  • head 指向的 branch 不能被删除, 必须签出到另一个 branch 方可删除

  • git 中的 branch 只是一个对 commit 的引用, 删除 branch 并不会删除任何 commit(不过如果一个 commit 不在任何 branch 上, 那么这个 commit 就是一个野 commit, 其在一定时间后会被 Git 的回收机制自动删除)

  • checkout 的本质是移动 head 到指定的 commit, 即如果后面跟的是 branch, 此命令会签出 此 branch 所对应的 commit. 如果后面跟的是 commit, 那么直接签出该 branch, 比如 git checkout 78a4bc, git checkout HEAD^, git checkout 78a4bc^. 不过需要注意如果根据 commit 值来签出, 那么会导致 head 变为 detached 状态, 哪怕签出的位置在某个 branch 上也不行. 想离开这种 detached 状态可以使用 git checkout <branch name> 命令

    himg

  • merge 会创建一个新的 commit来使两个 branch 的最新 commit 进行融合, 但是 merge 会出现几种冲突情况:

    1. 两个 branch 中的同一个文件的同一行被各自 branch 修改了(只能手动选择保留部分了)

    2. 目标 commit(需要被 mergecommit) 与 head 所指向的 commit 并不存在分叉, 而是 head 领先于目标 commit: 此时 merge 不会创建一个新的 commit, 因为没有需要合并的, 什么也不会做

    3. 目标 commithead 所指向的 commit 不存在分叉, 但是 head 所指向的 commit 落后于目标 commit: 此时merge 依然不会创建一个新的 commit(因为没哟需要合并的内容), 此时会将 head 指向的 commit 快速向前移动 (fast-forward). [这其实非常常见: 本地没有提交, 但是同事开发了新内容并合并到了 master 上, 本地 pull 的时候会先 进行 fetch, 然后 merge, 此时 merge 的目标 commit 即领先于 head 指向的 commit, 这个时候就会进行 fast-forward)

      himg

  • mergebranch 不会被自动删除

  • 没有被mergebranch 在删除时会失败(但是如果确认某个branch 完全没有作用了, 一定要删除, 那么可以将 git branch -d 改为 git branch -D 来强制删除)

  • pull = fetch + merge

  • push 并不会上传 head 到远端, 即远程仓库永远只会指向 master. 这也是为什么从远端 clone 下来后在第一次使用时总是指向 master 的.

  • 不是最新的几次提交不能用 git reset. 不是最新的一次提交不能用 git commit --amend

  • rebase 可以合并 commit, 修改之前某次 commit, 删除之前某次 commit, 属于 git 中的高深用法.

  • git 中有两个偏移符号 ^~, ^表示根据 head 向左偏移, ~表示根据 branch 向左偏移

  • tag 可以理解为 不可移动的 branch, 通常用来为项目节点做标记

  • cherry-pick: 把选中的 commit 一个个合并

Git 常用命令

  • git help <command>: 对 git 的某一命令查看帮助, e.g. git help config

  • git help --web log: 在浏览器中查看 git log 的用法

  • clone: 克隆仓库

    • git clone <link> [foldername]: 从远端链接拉取项目, link 可以为 https 连接, 也可以为 ssh 连接, 最后的 foldername 表示可以指定文件夹名称
    • git clone -b master <link>: 克隆远程仓库到本地, 并 checkout 到 master 分支
    • git clone -b 0.0.5 <link>: 克隆远程仓库到本地, 并 checkout 到 tag 0.0.5
    • git clone --recursive <link>: 递归克隆, 在项目包含子模块时非常有用
    • git clone --depth=1 <link>: 克隆深度为 1, 只克隆最后一条, 减少克隆时间
    • git clone --bare <link>: 裸克隆, 没有工作区内容,不能进行提交修改,一般用于复制仓库
    • git clone --mirror <link>: 镜像克隆, 也是裸克隆, 区别于包含上游版本库注册
  • status: 状态

    • git status: 查看当前 branch 的当前状态与最近一次 commit 相比, 暂存区&保存区&以及未跟踪文件的状态, 提交前一定要用
    • git status -s: 以短格式输出
    • git status --ignore-submodules: 忽略子模块
    • git status --ignored: 显示忽略的文件
  • init: 初始化

    • git init: 将当前目录直接作为 git 的工作路径并生成一个 .git 文件夹
    • git init [repo name]: 将 repo name 作为工作路径并在 repo name 文件夹下剩下一个 .git 文件夹
    • git init repo.git --bare: 创建一个 repo.git 的文件夹并将其作为 git 库, 其内直接包含 .git 文件夹内的所有文件, 相当于去除了工作区
  • git config [range] [command] [option]: 配置 git 环境

    • range: 有三种级别, system, global, local, sytem 针对当前系统所有用户的所有 repo, gloabl 针对当前用户的所有 repo, local 只针对当前 repo, 他们的关系是如果下一级的 config 没有对某项配置做自定义, 就自动引用上一级的 config 相关配置
      • --system: 将 config 配置写入 /etc/gitconfig
      • --global: 将 config 配置写入 ~/.gitconfig 文件
      • --local: 默认级别, 将 config 配置写入当前 repo 的 .git/config 文件中
    • command: 命令
      • --list: 列出当前 repo 的所有 config 信息(如果使用了 global 则列出 global 的 config 信息)
      • --unset: 取消 config 中某项配置(后跟 option), 也可以通过编辑 .gitconfigconfig 文件来达到同样目的
      • --unset-all: 取消 config 中所有配置
      • --remove-section: 移除某组配置
      • --rename-section: 重命名某组配置
    • option: 具体配置
      • --user.name: 设置用户名, 安装 git 必设置
      • --user.email: 设置用户邮箱, 安装 git 必设置
      • --core.editor: 设置 git 的默认编辑器, 默认为 vi 或 vim
      • --merge.tool: 设置 git 的合并工具
      • alias.st status: 设置 git 的某些快捷别名, e.g. git config --global alias.st status 的作用是让 git st 指向 git status
  • git config --global --unset user.name: 删除相关配置, 可以是 --global, 也可以是 --local

  • git config --global -e: 编辑当前仓库配置文件, 等价于 vim ~/.gitconfig

  • git config --global https.proxy http://127.0.0.1:1087: 配置代理

  • git config --global http.proxy http://127.0.0.1:1087: 配置代理

  • push: 推送本地仓库到远程

    • git push origin test: 将当前 branch push 到远程的 test 分支上

      事实上 git push 命令也可以进行 push, 不过 git push 只能 push 从远端 pull 或者 clone 下来的 branch, 对于由本地直接创建的 branch 就无能为力了, 或者本地创建的仓库使用 git push --set-up-stream origin branch1 命令指定了本仓库对应的远程仓库分支, 这样也能直接使用 git push

    • git push origin test -f: 强制 push, 在本地仓库与远程仓库有差别被拒绝的时候但是自己很清楚的时候使用. 但是如果冲突发生在 master 的话就不要用了. 很危险.

    • git push origin <local branch1>:<remote branch2>: 将本地 branch1 推送到远程 branch2

      • remote branch2 不写的话表示将本地分支 branch1 推动到远程同名 branch
      • local branch2 不写的话代表将空明推送到远程 branch2 上, 也就是表示删除远程 branch2
    • git push origin 9790eff:master: 将本地 9890eff 以前的所有 commit 推送到远端

    • git push origin :<old name> | git push origin <new name>: 重命名远程分支(方法 1), 原理是先删除远程某分支, 然后将本地当前分支推送到新命名的远程分支上

  • fetch: 从远端获取仓库对应分支的最新状态

    • git fetch -a: 从远端获取仓库所有分支的更新(不合并任何分支)
    • git fetch origin: 手动指定了要 fetchremote, 在不指定分支时通常默认为 master
    • git fetch origin dev: 指定远程 remoteFETCH_HEAD, 并且只拉取该分支的提交
    • git fetch origin branch1:branch2: 从服务器拉取远程分支 branch1 到本地为 branch2, 并使 branch2branch1 合并
  • git pull: 从远端拉取仓库最新状态并与本地仓库合并

    • git pull -a: 从服务器远端拉取仓库的所有分支的更新, 并将当前分支对应的远程分支的更新合并到本地当前分支上(不合并其他分支)
    • git pull orign test: 从服务器拉取远端名为 testbranch 并与本地当前的 branch 合并(这个命令适用于在本地 git branch <name>git checkout -b <name> 刚建立了一个新的本地分支, 然后从服务器的指定分支拉取 commit 到本地此新分支上)
    • git pull origin master --rebase: 以变基方式拉取远端主分支到本地 master 分支, 主要用于第一次拉取远端分支
    • git pull origin branch1:branch2: 从服务器远端拉取 branch1 分支合并到本地的 branch2 分支, 如果本地没有 branch2 分支的话则新建. 然后将拉取到的分支合并到当前所处的分支上
    • git pull origin master:master: 从服务器拉取远程 master 到本地 master 上, 然后合并, 然后将 master 分支 merge 到当前所处的分支上. 这个比 git fetch 多了一步(合并 master 到本分支), 因此要慎用, 最好用 git fetch, 然后自行判断
    • git pull origin master:master --rebase: 与上一种功能类似, 不过是将当前分支 rebasemaster 分支上
  • remote: 远程仓库

    • git remote -v: 查看远程仓库地址
    • git remote set-url origin <url>: 在有 origin 的基础上直接重新设置远程仓库地址
    • git remote rm origin: 删除远程仓库地址
    • git remote add origin <url>: 在没有远程仓库的基础上添加远程仓库地址
    • git remote show origin: 查看远程仓库信息(比如 push 与 pull 地址, 远程仓库当前 head 指向, 远程仓库当前分支)
    • git remote rename oldname newname: 重命名远程仓库
  • git show: 查看最近一次 commit (head 所指向的 commit ) 修改的文件和内容

    • git show --stat: 查看最近一次 commit 的统计信息(修改了多少处)
    • git show 5e68b0d8: 查看 sha 值为5e68b0d8commit 修改内容
    • git show 5e68b0d8 a.txt: 查看sha 值为5e68b0d8commit 中 a.txt 文件的具体修改情况
  • git diff: 显示目前的保存区与最近一次 commit 的原工作目录相比有什么差异. 即, 在 git add 后会向暂存区提交什么内容

    • git diff --staged: 查看暂存区与最近一次 commit 的原工作目录相比有什么差异. 即, 这条指令可以让你提前知道你 commit 会提交什么内容. 这个命令与 git diff --cached 完全等价
    • git diff master..branch: 比较 masterbranch 之间的不同
    • git diff 0023cdd..fcd6199: 比较两个 commit 之间的不同
    • git diff README.md: 查看当前分支 README.md 文件的变动
    • git diff adt312d: 查看 adt312d 这个 commit 与当前最新 commit 的异同
  • git ls-files: 列出本分支下所跟踪的文件列表

  • git add: 添加改动到暂存区 (staged area), 虽然 add 后添加的是文件名, 但实际上添加的是改动(如果a.txt 改动后被 add, 然后再次被改动a.txt 的另一处, 那么在 git status 时会警告a.txt 既在暂存区又不在)

    • git add ./README.md: 仅暂存当前目录下的 README.md 文件

    • git add <file1> <file2>...: 一次暂存多个文件

    • git add .: 提交本路径下的全部更改(新文件, 修改文件, 删除文件)(会忽略 .gitignore 中列出的新增文件)

    • git add -A: 同 git add ., 不过添加的是本仓库的所有路径下的更改(会忽略 .gitignore 中列出的新增文件)

    • git add -u: 只提交已经跟踪文件的修改(不理会新文件)

    • git add --ignore-removal .: 只提交新文件与修改文件(不理会删除文件)

      himg

  • merge: 合并分支

    • git merge test: 将名为 testbranch 合并到当前 head 所指向的分支
    • git merge --abort: 在出现 merge conflict 状况时放弃此次 merge, 会恢复到 merge 之前的状态.
    • git merge --continue: 解决冲突后继续 merge
    • git mergetool: 在合并出现问题时使用此工具进行手动合并
    • git merge develop -q: 以安静模式合并, 吧 develop 分支合并到当前分支并不输出任何消息
    • git merge develop --no-edit: 合并时使用默认的合并消息
    • git merge develop --no-commit: 合并分之后不进行提交
  • cherry-pick: 挑选 commit

    • git cherry-pick commit1 commit2 commit3: 将三个 commit 合并入本branch
    • git cherry-pick commit1 commit2 commit3 --no-commit: 将三个 commit 的内容放入本 branch 的暂存区但是先不合并
    • git cherry-pick -x commit1: 在合并时将 commit1 的原有作者信息进行保留
  • git commit: 提交通过 add 命令放入暂存区的改动

    • git commit -a: 提交全部更改(默认将所有修改文件及删除文件添加进暂存区)
    • git commit -m "message": 使用 message 作为 commit 的标题直接提交
    • git commit --amend: 对最新的 commit 进行修改(此操作不会直接在原commit 上进行修改, 而是将新修改内容与最新 commit 内容进行融合, 据此创建一个新的 commit 并进行替换)
    • git commit --amend --no-edit: 在 amend 的基础上, 不进入修改 message 界面
    • git commit --amend --reset-author: 默认情况下 amend 并不会重置第一次 author 的时间, 使用 --reset-author 可以重置 author 时间为当前时间
    • git commit --author "HanleyLee <hanley.lei@gmail.com>": 指定 author 的方式进行 commit
    • GIT_COMMITTER_NAME="HanleyLee" GIT_COMMITTER_EMAIL="hanley.lei@gmail.com" git commit --author "HanleyLee <hanley.lei@gmail.com>": 同时设置 authorcommitter
    • git commit --allow-empty-message: 允许提交空消息, 通常必须有消息
    • git commit -v: 在填写信息的界面显示所有变动(diff 格式的)
  • git stash: 将保存区与暂存区的文件(未 commit 的)临时放入一个空间(注意: 未跟踪的文件不会被 stash)

  • git stash save "test": 保存时添加注释

  • git stash list: 查看当前保存列表

  • git stash pop: 将 stash 空间保存的文件还原到保存区中

  • git stash pop stash@{1}: 恢复指定 stash, 具体编号可以通过 git stash list 查找

  • git stash apply: 与 pop 命令相同, 不过不会从 stash 列表中移除

  • git stash clear: 清空所有保存的 stash

  • git stash drop stash@{0}: 清除指定 stash

  • git stash drop: 清除最近一次

  • branch 分支管理

    • git branch test: 从head 所指向的 commit 处创建一个名为 test 的新的 branch
    • git branch branch1 origin/branch1: 从本地下载的远程 branch1 处在本地建立一个 branch1 分支
    • git branch -a: 显示本地及远程所有分支
    • git branch -r: 显示远程端所有分支
    • git branch -vv: 查看本地分支所关联的远程分支
    • git branch -d test: 删除名为 testbranch
    • git branch -r -d origin/hanley: 删除本地已经下载的远程分支, 同时要执行以下两个命令中任意一个:
      • git push origin --delete <branch name>: 使用删除命令直接删除远程 branch
      • git push origin :<branch name>: 使用推送命令将一个空 branch 推送到远程以达到删除该 tag 的效果
    • git branch -m <old name> <new name>: 重命名本地分支
    • git branch -f <branch> <commit>: 重新定义 branch 的起始节点到某个 commit
    • git branch -m <old name> <new name> | git push origin :<old name> | git push --set-upstream origin <new name>: 重命名远程分支(方法 2), 先本地重命名, 然后删除远程某分支, 最后推送并设定推送到的远程 branch
    • git branch --merged: 查看已经合并的 branch
    • git branch --no-merged: 查看未合并的 branch
    • git branch --merged | xargs git branch -d: 删除已经合并的 branch
    • git reflog show --data=iso master: 查看本地 master 分支的创建时间
  • checkout: 签出

    • git checkout <filename>: 将保存区的文件永久 discard 文件的修改. 降级! (使用版本库的版本替换工作区的版本)
    • git checkout test: 签出名为 testbranch对应的 commit
    • git checkout HEAD^^: 将HEAD 向左两位的 commit 签出(即倒数第三位)
    • git checkout head~3: 将 head 向左三位的 commit 签出(即倒数第四位)
    • git checkout 3d122b: 将 sha 值为 3d122bcommit 签出, 此时会导致 head 变为 detached 状态, 想离开这种 detached 状态可以使用 git checkout <branch name> 命令
    • git checkout -b test: 创建一个名为 testbranch 并签出到该 branch对应的 commit
    • git checkout -b test origin/test: 在本地创建名为 testbranch 并从远端的 test 分支拉取下来合并
    • git checkout --detach: 使 headbranch 分离, 使 head 直接指向 commit
    • git checkout -: 返回上一个 head 点
    • git checkout -t origin/dev: 切换到远端分支, 通常是在本地没有远程分支才会本命令
    • git checkout -f master: 强制切换到 master, 如果有未保存的文件会被丢弃
    • git checkout -- .: 撤销当前目录下所有文件的改动
    • git checkout -- README.md: 仅撤销 README.md 文件的改动
  • blame: 责怪~

    • git blame <filename>: 查看某个文件的修改历史记录, 含时间, 作者, 以及内容
    • git blame -L 11,12 <filename>: 查看谁改动了某文件的 11~12 行
    • git blame -L 11 <filename>: 查看 11 行以后的所有改动人
    • git blame -l <filename>: 显示完整的 hash 值
    • git blame -n <filename>: 显示修改的行数
    • git blame -e <filename>: 显示作者邮箱
    • git blame -enl -L 11 <filename> 参数组合查看修改者
  • restore: 重置

    • git restore <filename>: 将保存区的此文件更改全部重置, 降级! 与 git checkout <filename> 功能相同
    • git restore --staged <filename>: 将暂存区文件转移至保存区, 降级!
      • git checkout -- *
      • git checkout -- *.md
      • git checkout -- 123.md 345.md
  • reflog: head 记录

    • git reflog: reference log 的缩写. 可查看 Git 仓库的 head 的所有移动记录. 可以在误删 branch 等情况下使用
    • git reflog master: 查看关于 master 的所有 head 的移动记录.
  • rm: 移除

    • git rm <filename>: 删除对文件的跟踪, 并删除本地文件(未添加到暂存区时使用)
    • git rm -f <filename>: 删除对文件的跟踪, 并删除本地文件(添加到暂存区时使用). f 是强制的意思
    • git rm --cached <filename>: 取消对某个文件的跟踪. 而不删除本地文件
    • git rm -r --cached <foldername>: 取消对某个文件夹的跟踪. r 为递归的意思. git rm -r * 会将当前目录下的所有文件与子目录删除
    • git rm -rf .: 清除当前目录下的所有文件, 不过不会删除 .git 目录
    • -n: 所有的 rm 命令后面加上此命令后, 不会删除任何东西, 仅作为提示使用
  • git clean <command>: 清理未被 tracked 的文件, git reset 只能让跟踪的文件回复到某个版本状态, 对于未跟踪的文件无能为力, 如果想要完全移除未跟踪的文件, 那么就要使用 git clean -df, 此命令常与 git reset 配合使用(默认情况下, git clean 命令只会移除没有忽略的未跟踪文件, 如果也需要移除已被 gitignore 忽略的文件, 则需要加 x)

    • -f: 强制删除. 如果 Git 配置变量 clean.requireForce 未设置为 false, git clean 将拒绝删除文件或目录, 除非给定 -f, -n-i.
    • -f <path>: 删除指定路径下 untracked files
    • -d: 除了未跟踪的文件之外, 还要除去未跟踪的目录.
    • -X: 仅删除当前目录下 gitignore 里忽略的文件, 那些既不被 git 版本控制, 又不在 gitignore 中的文件会被保留.
    • -x: 不使用 gitignore 的忽略规则, 删除本路径下所有的 untracked files
    • -n: 将此命令加在上面三个命令前, 先看看会删除哪些文件(相当于演习一遍). e.g. git clean -n -xfd
    • -i: 使用交互式删除, 每一个文件的删除都有提示, 更加安全
  • tag: 不可移动的标识点, 通常用来作为里程碑标记, 最广泛的使用就是作为版本标记

    • git tag: 显示所有 tag
    • git ls-remote --tags origin: 列出远程所有标签
    • git tag <tag name>: 为最新 commit 的创建 tag
    • git tag <tag name> <commit name: 为之前的某个 commit 点创建 tag
    • git show <tag name>: 显示指定 tag 信息
    • git tag -d <tag name>: 删除本地的指定 tag; 如果想要删除远程的 tag, 需要先在删除本地 tag, 然后使用:
      • git push origin --delete tag <tag name>: 使用删除命令直接删除远程 tag
      • git push origin :refs/tags/<tag name>: 使用推送命令将一个空 tag 推送到远程以达到删除该 tag 的效果
    • git push origin <tag name>: 推送指定 tag 到远程
    • git push origin --tags: 推送所有本地 tag 到远程
    • git ls-remote --tags origin: 显示远程所有 tag(不加 origin 也可以)
    • git tag -l | xargs git tag -d && git fetch origin --prune: 先删除本地所有分支, 然后从远端拉取所有分支, 适用于远端的 tag 被修改但是本地 tag 仍然是旧的
    • git tag -l v1.*: 筛选符合条件的 tag
    • git tag -a v1.4 -m "my version 1.4": 创建含标注的 tag, 并为此标注直接添加信息(标注可通过 git log 查看)
    • git tag -a v1.2 9fceb02: 为之前的提交打 tag, 会进入填写 message 界面
    • git fetch --tags: 拉取远程所有 tag
  • revert: 添加与之前 commit 完全相反的 commit

    • git revert HEAD^: 增加一条与当前 head 指向的 commit 的内容完全相反的 commit. 从而达到”中和”的效果以对其进行撤销. 用在错误内容已经合并在 master 但是需要修改的时候.
  • reset: 重置到某个 commit

    • git reset --hard HEAD^^: HEAD^^表示需要恢复到的 commit, 因此这个命令表示将 track 的文件直接恢复到上上一个 commit, 其后的所有 commit 全部丢弃(如下图所示, 虽然 commit不被任何 branch 指向了, 但是 Git 不会立刻删除它, 还是可以通过 sha1 值来复原的), 一般与 git clean 联合使用

    • git reset HEAD ./README.md: 仅重置某文件到 HEAD

      himg

  • rebase: 变基

    • git rebase master: 在 branch 上执行此命令. 将 branch 上从与 master 交叉的 commit 之后的所有commit 依次提交到 master 最新 commit 之后(就是将节点 5, 6 的内容在 master 分支再次提交一次). 如果想指定基础点参考 这里

      himg

    • git rebase -i <commit>: 交互式变基, 可合并 commit, 剔除 commit 等

    • git rebase -i HEAD~10: 将当前 head 向前数 10 个的所有 commit 进行变基

    • git rebase --continue: 解决冲突后, 解决冲突, 并 git add, 然后使用本命令可继续 rebase 操作, 不需要 git commit

    • git rebase --abort: 产生冲突时, 放弃本次 rebase, 恢复到 rebase 之前的状态

    • git rebase origin/main: 变基对象为 origin 远程分支

      git rebase 的作用是变基, 在合并时可以先切换到 branch1, 然后对 master 进行 rebase, 没有冲突的话直接完成操作, 有冲突的话先解决冲突, 然后 git add, 然后git rebase --continue, 这样 branch1 的commit 就完全挪到了 master 之上, 这时再切换到 master 分支上, 使用 git rebase branch1(或 git merge branch1), 可以达到 fast-forword 的效果. 最后可以 push 到远程仓库, 这样自己的新的 commit 就在 master 上整齐地排列着了.

  • git log: 显示 commit 的提交记录(并不会显示 add 操作)

    • --patch: 是 git log -p 的全写, 可以查看每个 commit 的细节

    • --stat: 查看每次文件提交更改的统计信息(修改了多少处)

    • --oneline: 以一行的格式查看本 branchcommit 记录(仅 sha2, branch, commit title 以及顺序信息)

    • --merges: 只显示合并的 commit

    • --no-merges: 不显示合并的 commit

    • --graph: 图表形式(竖线, 斜线)显示 commit 顺序及关系

    • --decorate: 装饰作用, 显示当前 head, tag, branch 的效果

    • --all: 显示所有 commit 信息, 否则可能会只显示本 branchcommit, 省略其他分支的 commit

    • -S Swift: 显示关键字中有 Swift 的commit

    • -[number]: 显示最近多少次的 commit 记录

    • --pretty=format:"[option]": 以固定格式输出 commit 信息

      • %H : 提交的完整哈希值
      • %h : 提交的简写哈希值
      • %T : 树的完整哈希值
      • %t : 树的简写哈希值
      • %P : 父提交的完整哈希值
      • %p : 父提交的简写哈希值
      • %an : 作者名字
      • %ae : 作者的电子邮件地址
      • %ad : 作者修订日期(可以用 –date=选项 来定制格式)
      • %ar : 作者修订日期, 按多久以前的方式显示
      • %cn : 提交者的名字
      • %ce : 提交者的电子邮件地址
      • %cd : 提交日期
      • %cr : 提交日期(距今多长时间)
      • %s : 提交说明
      • $d : decorate 效果(显示当前 head, tag, branch)
      • %C(<color>): 为跟在后面一个参数设置颜色或字体, e.g. git log --pretty=format:"%C(bold red)%h%Creset -%C(bold green)%d %C(bold yellow)%s %Creset- %C(red)%cd %Creset- %C(dim green)%an" --date=format:'%Y-%m-%d %H:%M:%S' --graph
        • 一个颜色+一个内容
        • 颜色以%C开头, 后边接几种颜色, 还可以设置字体, 如果要设置字体的话, 要一块加个括号
        • 能设置的颜色值包括: reset(默认的灰色), normal, black, red, green, yellow, blue, magenta, cyan, white.
        • 字体属性则有bold, dim, ul, blink, reverse.
        • 内容可以是占位元字符, 也可以是直接显示的普通字符
    • --date=<option>: 通过预置的选项设置 log 中 commits 的日期格式

      • relative : 显示距当前时间多少, e.g. “2 hours ago”
      • local : 显示本地时间, e.g “Wed Feb 26 18 : 03 : 14 2020”
      • default : 显示当前时区及时间, e.g. “Wed Feb 26 18 : 03 : 14 2020 +0800”
      • iso : 以 ISO 8601 格式显示时间
      • rfc : 以 RFC 2822 格式显示时间
      • short : 只显示日期, e.g. “2020-02-26”
      • raw : 显示 git 的原始格式, e.g. “1582711394 +0800”
    • --date=format:'<option>': 通过占位符设置log 中 commits 的日期格式 e.g. --date=format:'%Y-%m-%d %H:%M:%S'

      • %a : Abbreviated weekday name
      • %A : Full weekday name
      • %b : Abbreviated month name
      • %B : Full month name
      • %c : Date and time representation appropriate for locale
      • %d : Day of month as decimal number (01 – 31)
      • %H : Hour in 24-hour format (00 – 23)
      • %I : Hour in 12-hour format (01 – 12)
      • %j : Day of year as decimal number (001 – 366)
      • %m : Month as decimal number (01 – 12)
      • %M : Minute as decimal number (00 – 59)
      • %p : Current locale’s A.M./P.M. indicator for 12-hour clock
      • %S : Second as decimal number (00 – 59)
      • %U : Week of year as decimal number, with Sunday as first day of week (00 – 53)
      • %w : Weekday as decimal number (0 – 6; Sunday is 0)
      • %W : Week of year as decimal number, with Monday as first day of week (00 – 53)
      • %x : Date representation for current locale
      • %X : Time representation for current locale
      • %y : Year without century, as decimal number (00 – 99)
      • %Y : Year with century, as decimal number
      • %z, %Z : Either the time-zone name or time zone abbreviation, depending on registry settings; no characters if time zone is unknown
      • %% : Percent sign

      配置完自己喜爱的配色后, 使用可以为 git 命令定义别名方便下次使用, e.g. git config --global alias.lg "log --pretty=format:'%C(bold red)%h%Creset -%C(bold green)%d %C(bold yellow)%s %Creset- %C(red)%cd %Creset- %C(dim green)%an' --date=format:'%Y-%m-%d %H:%M:%S' --abbrev-commit --graph"

    • git log --oneline --graph --all: 以图表, 简洁形式显示 commit 信息

    • git shortlog -sn: 列出提交者贡献数量, 只会打印作者和贡献数量

    • git shortlog -n: 以提交贡献数量排序并打印出 message

    • git shortlog -e: 采用邮箱格式化的方式进行查看贡献度

  • git bisect: 黑魔法, 查看哪一个 commit 产生的 bug

  • git symbolic-ref refs/remotes/origin/HEAD: 获得远程默认分支, master 或 main

  • git archive [option] [branch/commit] [from path]: 导出代码(可支持下载远程仓库指定文件夹, 不支持 GitHub)

    • --format tar.gz: 导出的格式, 使用 git archive --list 可以查看当前 git 所支持的所有格式; 如不指明, 则使用 –output 的文件名推断文件格式

    • --output "./output.tar.gz": 将存档写入<file>而不是 stdout.

    • --remote git@192.168.1.203:iOS/ZRCombineViewer.git: 指定远程仓库位置, 如不指定则导出当前目录下仓库的代码

    • --exec=<git-upload-archive>: 与–remote一起用于指定git-upload-archive远程端的路径.

    • --verbose: 实时显示最新进展

    • --prefix=<prefix>/: 在所有文件命前加入前缀

      1
      2
      3
      4
      # 写入压缩文件
      git archive --remote git@192.168.1.203:iOS/ZRCombineViewer.git -o test.zip master fastlane/actions fastlane
      # 下载后解压到指定文件夹
      git archive --remote git@gitlab.com:HanleyLee/helloworld.git --format=tar --prefix=junk/ master | (mkdir ~/Desktop/t1 && cd ~/Desktop/t1/ && tar xf -)

Git 使用流程

  1. GitHub 或者其他仓库管理平台创建一个仓库. 并复制仓库地址
  2. 在终端中使用 git clone 将远程仓库下载到本地
  3. 在开发时将自己仓库创建出一个分支用于自己开发新功能.
  4. 新功能开发完毕后将 branch 上传到中央仓库让同事进行检查, 如果有问题的话继续修改直至没有问题. 如果没有问题的话就
    1. checkout 到本地仓库的 master
    2. pull 以使本地 master 与远端 master 保持同步
    3. merge 自己的 branch 到本地 master, push master 到远端
  5. 实际上为了保证项目的安全, 中大型项目的远端仓库 master 都是被禁止直接 push 的, 因此步骤 4 的流程就会变成:
    1. 让同事检查是否有问题, 没有问题就提交通过远端的 branch 提交 pull request(pull request 是对于 master 分支来说的, 希望 master 能够 pullbranch)
    2. 成功 pull request 后删除本 branch

Git 实践

使用裸仓库在多台电脑上同步配置文件

  1. 创建裸仓库并配置

    1
    2
    3
    4
    git init --bare $HOME/.hlconfig.git
    echo 'alias hlconfig="/usr/bin/git --git-dir=$HOME/.hlconfig.git/ --work-tree=$HOME"' >> $HOME/.zshrc
    source ~/.zshrc
    hlconfig config --local status.showUntrackedFiles no
  2. 将配置文件添加到此裸仓库中

    1
    2
    3
    4
    5
    hlconfig status
    hlconfig add .vimrc
    hlconfig commit -m "Add vimrc"
    hlconfig remote add origin https://www.github.com/username/repo.git
    hlconfig push origin master
  3. 在另一台机器上 clone 此裸仓库并覆盖配置

    1
    2
    3
    4
    5
    6
    echo 'alias hlconfig="/usr/bin/git --git-dir=$HOME/.hlconfig.git/ --work-tree=$HOME"' >> $HOME/.zshrc
    source ~/.zshrc
    echo ".hlconfig.git" >> $HOME/.gitignore_global
    git clone --bare https://www.github.com/username/repo.git $HOME/.hlconfig.git
    hlconfig config --local status.showUntrackedFiles no
    hlconfig checkout

    hlconfig checkout 的时候, 如果另一台机器上已经有了相关配置文件的话会提示失败, 需要移动这些文件到另一处, 或者使用 hlconfig checkout -f 强制覆写这些文件

hlconfig add 了需要同步的配置文件后, 如果配置文件被修改了, 我们可以通过:

  • hlconfig add -u 来添加更新的内容到 git

  • hlconfig commit -a 直接将修改的内容进行 commit

    切记不可以使用 hlconfig add .hlconfig add -A, 因为这两个命令是等价的, 会将本仓库路径控制下的所有新文件, 修改文件, 删除文件添加到版本管理中, 由于我们的裸仓库的管理目录是 $HOME, 因此会把此目录下的所有文件添加到版本管理中, 这并不是我们想要的结果.(当然我们可以为此裸仓库配置 .gitignore 文件以规避此种问题, 但是与本裸仓库的使用理念又不同了)

为什么要使用裸仓库而不是普通仓库来管理

本例中创建的仓库是.hlconfig.git, 是一个裸仓库, 因为是裸仓库, 因此

  • 没有工作区, 其内没有 .git 文件夹
  • 文件夹内的内容直接是 .git 文件夹的所有内容.
  • 在指定了 git-dirwork-tree 后能管理此电脑上的所有文件
  • 仓库可以放在电脑上的任意位置

如果使用普通仓库来管理:

  • 必须在 $HOME 中直接建立仓库, 目的是将所有 $HOME 作为工作区

裸仓库与普通仓库

git init repo 初始化一个正常仓库, git init repo.git --bare 初始化一个裸仓库.

裸仓库不包含工作区, 不能直接在裸仓库目录下使用 git status, git add 等常用的命令. 因为不包含工作区, 因此只会记录 git 的提交历史, 当前 head, branch 等基本信息, 这样特别适合与在服务端创建用来接收 push 的公共仓库.

归根到底, 最大的区别就是 裸仓库直接将 .git 文件夹中的内容取出放到了裸仓库的根目录下

普通仓库(test1)与裸仓库(test2)的目录结构对比:

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

hanley ~/Desktop/repotest
$ git init test1 Initialized empty Git repository in /Users/hanley/Desktop/repotest/test1/.git/

hanley ~/Desktop/repotest
$ git init test2 --bare
Initialized empty Git repository in /Users/hanley/Desktop/repotest/test2/

hanley ~/Desktop/repotest
$ tree -a
.
├── .DS_Store
├── test1
│   └── .git
│   ├── HEAD
│   ├── config
│   ├── description
│   ├── hooks
│   │   ├── applypatch-msg.sample
│   │   ├── commit-msg.sample
│   │   ├── fsmonitor-watchman.sample
│   │   ├── post-update.sample
│   │   ├── pre-applypatch.sample
│   │   ├── pre-commit.sample
│   │   ├── pre-merge-commit.sample
│   │   ├── pre-push.sample
│   │   ├── pre-rebase.sample
│   │   ├── pre-receive.sample
│   │   ├── prepare-commit-msg.sample
│   │   └── update.sample
│   ├── info
│   │   └── exclude
│   ├── objects
│   │   ├── info
│   │   └── pack
│   └── refs
│   ├── heads
│   └── tags
└── test2
├── HEAD
├── config
├── description
├── hooks
│   ├── applypatch-msg.sample
│   ├── commit-msg.sample
│   ├── fsmonitor-watchman.sample
│   ├── post-update.sample
│   ├── pre-applypatch.sample
│   ├── pre-commit.sample
│   ├── pre-merge-commit.sample
│   ├── pre-push.sample
│   ├── pre-rebase.sample
│   ├── pre-receive.sample
│   ├── prepare-commit-msg.sample
│   └── update.sample
├── info
│   └── exclude
├── objects
│   ├── info
│   └── pack
└── refs
├── heads
└── tags

正常仓库与裸仓库的 config 文件对比

  • 正常仓库

    1
    2
    3
    4
    5
    6
    7
    [core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
    ignorecase = true
    precomposeunicode = true
  • 裸仓库

    1
    2
    3
    4
    5
    6
    [core]
    repositoryformatversion = 0
    filemode = true
    bare = true
    ignorecase = true
    precomposeunicode = true

    可以看到最直观的差异在于 bare 配置项是否为 true , 此外不加裸仓库配置中有一项 logallrefupdates = true, 作用根据名字就可以看出来, 记录所有的 ref (引用) 更新.

此外, 如果我们想在本地使用裸仓库作为管理 $HOME 的仓库, 可以通过指定 git 目录, 指定工作路径的方式来实现 git status 命令:

1
git --git-dir=/Users/hanley/.hlconfig.git/ --work-tree=/Users/hanley status

committerauthor 的区别

author 是做出修改的人, committer 是最后提交到 git 中央仓库的人

恢复一个彻底删掉的 commit

1
2
3
4
git reflog
git log HEAD@{6}\n: 1415211713:0;git log HEAD@{6}
git reflog HEAD@{6}
git reset --hard HEAD@{6}

规范化提交 commit

可以在 .gitconfig 中配置全局 commit 模板:

1
2
[commit]
template = /Users/hanley/.stCommitMsg

然后在 ~/.stCommitMsg 中声明

1
2
type:
subject:
  1. type: 本次提交的类型

    fix: 修复 bug
    add: 增加新功能(大)
    feature: 增加新功能(小)
    update: 更新
    style: 代码格式改变
    opt: 优化
    test: 增加测试代码
    revert: 撤销上一次的 commit
    build: 构建工具或构建过程等的变动, 如: gulp 换成了 webpack, webpack 升级等
    adapt: 代码适配, 适配其他组件或工具

  2. description: 是对本次提交的简短描述.

    不超过 50 个字符.

    推荐以动词开头, 如: 设置, 修改, 增加, 删减, 撤销

[Fix #42] Fix table view cell text overflow: GitHub 上通过 commit 信息来关闭相关 issue, 或在末尾加上(#42)达到相同效果

使用.gitignore文件

git 是根据.gitignore文件来判断是否监视一个文件(夹)的, 如果文件在.gitignore中被列出, 那么即使该文件被添加, git 也不会提示对其进行跟踪, 如果一个文件夹下被加入到.gitignore文件, 那么其自身及其内文件(夹)都不会被跟踪.

如果在添加.gitignore文件之前已经不想同步的内容已经被 git 跟踪了, 那么需要将其移除出跟踪区, 使用git rm --cached <filename>.

使用git clean -fX 可以将被忽略的文件全部删除(一般不用)

不同步指定文件

.gitignore文件可以让 git 忽略某些文件, 或者在忽略全部文件的情况下不忽略某些文件

1
2
3
4
5
6
7
8
9
10
# 在没有`.gitignore`的情况下创建一个新文件
touch .gitignore
# 忽略所有名为`secret.md`的文件(根目录与子目录都包括)

secret.md
## 只忽略 `config` 文件夹下的 `secret.md` 文件
config/secret.md

# 只忽略 config 下的 Markdown 文件
config/*.md

只同步指定文件

1
2
3
4
5
6
7
8
9
touch .gitignore
# 忽略根目录下的所有文件及文件夹
/*

# 同步名为 normal.md 的文件, 但是如果文件夹未被同步, 那么文件夹内的此文件不会被 git 跟踪到, 也自然不会被同步
!normal.md

# 同步根目录下的`config`文件夹及其内文件(夹)
!/config

如果需要只同步子文件夹下的某个文件, 有两种方法

  1. 先设置同步子目录
  2. 然后设置不同步子目录所有内容
  3. 再设置同步子目录指定文件
1
2
3
4
/*
!/config
/config/*
!/config/normal.md

全局忽略文件

  1. git config --global core.excludesfile .gitignore_global

  2. 在本地用户根目录下创建 .gitignore_global 文件, 在其中设置需要全局忽略的文件类型(下面的忽略按需使用)

    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
    "#"是.gitignore_global中的注释行
    # Compiled source
    *.pyc
    *.com
    *.class
    *.dll
    *.exe
    *.o
    *.so

    # Packages
    # it's better to unpack these files and commit the raw source
    # git has its own built in compression methods
    *.7z
    *.dmg
    *.gz
    *.iso
    *.jar
    *.rar
    *.tar
    *.zip

    # Logs and databases
    *.log
    *.sql
    *.sqlite

    # OS generated files
    .DS_Store*
    ehthumbs.db
    Icon?
    Thumbs.db

submodule 使用

  • git submodule: 显示所有 submodule, 等同于git submodule status

  • 添加 submodule 到现有项目

    1. Run git submodule add -b <branch> --name <name> <repository-path-or-url>
    2. Add the .gitmodule file and submodule folder to the superproject index
    3. Commit both files on the superproject
  • 从当前项目移除submodule

    1. git submodule deinit -f <submodule_path>
    2. rm -rf .git/modules/<submodule_path>
    3. git rm -f <submodule_path>
  • 复制含 submodule 项目到本地

    1. Clone the superproject as usual

    2. Run git submodule init to init the submodules

    3. Run git submodule update to have the submodules on a detached HEAD

      或者执行 git clone --recurse-submodules ssh://user@domain.tld/repo.git

  • git diff --submodule: 查看 submodule 所有改变

  • git submodule update --remote: 更新 submodule 到他们对应的分支上

  • git submodule update --remote <submodule-name>: 更新指定的 submodule 到他们对应的分支上

  • git push --recurse-submodules=check: 在所有 submodule 推送更新完后在推送本项目到远程

  • git push --recurse-submodules=on-demand: 先推送 submodule 的更新, 然后推送主项目的更新

  • git submodule foreach '<arbitrary-command-to-run>':

解决合并的冲突

1
2
3
<<<<<<<到=======是在当前分支合并之前的文件内容
=======到>>>>>>> psr/psr-02是在其它分支下修改的内容
需要在这个两个版本中选择一个, 然后把标记符号也要一起删除
  1. 合并是产生了冲突
  2. 使用 git mergetool 工具对冲突文件逐个修改, 或者使用 gui 工具进行修改
  3. git add 经过修改后的文件
  4. git commit && git push

使用交互式 rebase 修改 / 删除之前某次提交的 commit

  1. git rebase -i 目标 commit

    1
    2
    git rebase -i HEAD^^
    // 在 git 中有两个偏移符号 ^ 与 ~, ^ 表示根据 head, ~表示根据 branch 向左偏移. 这个命令表示将当前 commit rebase 到 HEAD 之前 2 个的 commit 上.
  2. 在编辑界面中指定需要操作的 commits

    pick 修改为 edit (含义是使用这个 commit, 但是停下来等待修正) 『使用 pick 代表选取, 如果直接删除这一行就代表跳过这个 commit, 那就是把这个 commit 删除了』

    img

  3. 退出编辑界面

    img

  4. 根据提示修改最后使用 amend 进行修正提交

  5. 操作完成之后用 git rebase --continue 来继续 rebase 过程各个 commit 回复到原位

git rebase –onto 撤销历史 commit

img

如上图所示, git rebase commit3 会将 45 自动链接到目标 commit 3 之后, 因为 rebase 的起点是 Git 自动指定的, 起点判定为当前 branch 与要 rebase 到的 branch 的交点, 在此例中就是 2. 因此 2 之后的 commit 都会被 rebase 到 3 之后.

如果想指定 `rebase` 的起点, 那么就需要用 `rebase --onto`, 其语法如下
1
2
3
git rebase --onto commit3 commit4 branch1
// 此命令有三个参数, 依次为目标 commit, 起点 commit, 操作 branch
// 在上图中, 就是将起点 commit 之后的 5 放入目标 commit 3 之后.

通过这一特性可以选择性地删除 commit

himg

1
2
git rebase --onto HEAD^^ HEAD^ branch1
// 以当前 head 指向 commit 的前一个 commit 为起点, 将起点之后的 commit 3 提交到当前 head 指向 commit 的前 2 个 commit 上. 这样就达到了剔除 commit 2 的目的

合并同一 branch 多个 commit

目标: 将 1232 合并

  1. 使用 git log --oneline 查看当前 branchcommit 记录

    himg

  2. 使用交互式变基, git rebase -i dc8d, 修改 2123picksquash(也可以用 fixup, 代表丢弃子 commit 名称)

    himg

  3. 保存退出并并根据提示为新 commit 赋予名称

git diff 信息理解

himg

himg

  • 被比较的文件: diff 命令会对两个文件进行比较, 一个文件被设定为 a, 另一个被设定为 b
  • 元数据: 刚开始的 2a3483c53ed7d1 代表两个文件的hashes. 后面的 100644 代表这是一个普通文件, 如果是 10755 则代表是一个可执行文件, 120000 代表是符号链接.
  • a/b 文件标识: 使用-作为 a 的标志, 使用 +代表 b 的标志
  • 区块头: - 代表来自文件 a/Test/stash.txt, 1 代表从第一行开始, 2 代表从第一行开始的 2 行代码. 因此整句连起来: a 文件(旧文件)从第一行开始的 2 行内有数据被改动, b 文件(新文件)从第一行开始的 3 行内有数据改动
  • 改动: + 代表是新文件的改动. 如果是 - 则是旧文件的改动, 而旧文件的改动就是删除内容, 新文件的改动就是增加内容

git 插件

gitup

git 仓库批量拉取更新

安装

1
brew install gitup

常用命令

  • gitup --help: 查看 gitup 帮助信息
  • gitup .: 更新当前路径下的所有仓库
    • --depth <num>: 指定递归深度, 默认为 3
  • gitup ~/repos/foo ~/repos/bar ~/repos/baz: 指定多个仓库进行批量拉取更新
  • gitup -a ~/repos/foo ~/repos/bar ~/repos/baz: --add, 将多个仓库添加到 gitup 的书签中, 便于使用gitup命令直接一键更新
  • gitup -l: --list, 列出 gitup 目前所有 add 的仓库
  • gitup -b ~/.config/gitup/bookmarks: --bookmark-file, 自定义指定书签文件
  • gitup -d ~/repo: --delete, 删除已经 add 的仓库
  • gitup -n: --clean, --cleanup, 删除路径已经变更的仓库的书签
  • gitup: 拉取更新所有被 add 到书签的仓库
  • gitup -c: gitup --current-only, 默认情况下 gitup 将会拉取远端所有分支, 使用此命令可以只更新当前分支
  • gitup -f: gitup --fetch-only, 默认情况下会 pull, 此命令会只 fetch
  • gitup -p: gitup --prune: 默认情况下会在本地保留远端已经删除的 branch, 此命令会保持远端与本地端 branch 完全一致

diff-so-fancy

git diff 高亮优化显示

安装

1
brew install diff-so-fancy

配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Configure git to use d-s-f for *all* diff operations
git config --global core.pager "diff-so-fancy | less --tabs=4 -RFX"

git config --global color.ui true

git config --global color.diff-highlight.oldNormal "red bold"
git config --global color.diff-highlight.oldHighlight "red bold 52"
git config --global color.diff-highlight.newNormal "green bold"
git config --global color.diff-highlight.newHighlight "green bold 22"

git config --global color.diff.meta "11"
git config --global color.diff.frag "magenta bold"
git config --global color.diff.commit "yellow bold"
git config --global color.diff.old "red bold"
git config --global color.diff.new "green bold"
git config --global color.diff.whitespace "red reverse"

GitHub 连接方式

目前 GitHub 有两种连接方式, HTTPS 连接与 ssh 连接, 在 clone 时要选择对应的链接.

特点

  • 本账户向本账户下仓库提交代码可以直接使用 https 或者将自己电脑生成的ssh key 加入到 GitHub 账户.
  • 本账户使用 HTTPS 方式向另一账户下的仓库提交代码需成为对方账户的 collaborator.
  • 本账户使用 ssh 方式向另一账户的仓库提交代码需要将本账户所在电脑生成的 ssh key 加入到对方账户.
  • ssh 方式连接在每次 push 时无需再每次访问时输入密码
  • 如果GitHub 账户使用了二重验证还希望使用 HTTPs那么必须使用 access token 作为密码进行登录.

SSH 连接方式

  1. 在终端使用 ssh-keygen 方式生成 ssh key
  2. pub 公钥加入到 GitHub 账户中
  3. 在仓库页面选择 ssh 链接进行复制
  4. 在本地文件夹进行 clone

查看 / 更改连接方式

通过 git remote -v查看当前与远程的连接方式

修改为 HTTPs: git remote set-url origin [https://github.com/xmanrui/autoftp.git](https://github.com/xmanrui/autoftp.git)

修改为 ssh: git remote set-url origin [git@github.com](mailto:git@github.com):xmanrui/timerecord.git

参考