Git Cheat Sheet

Git 本地更改操作

初始化

  • 初始化一个 Git 仓库:git init

    提交修改

  • 添加文件到暂存区:git add <file>
  • 添加所有修改到暂存区:git add .
  • 将暂存区的修改提交到版本库:git commit-> 编辑 commit message -> 保存
  • commit message 较简单时,可以:git commit -m ""
  • 为文件添加执行权限,并将修改添加到暂存区:git update-index --chmod=+x

回退修改

  • 回退工作区的修改:git checkout --
  • 回退工作区的修改,但保存现场:git stash
  • 恢复现场:git stash pop
  • 查看保存的现场:git stash list
  • 回退暂存区的修改到工作区:git reset HEAD
  • 回退版本库的修改到工作区:git resetgit reset –-mixed较所有文件:git diff --cached
  • 比较 commit Acommit B 的指定文件:git diff <A> <B> <path>
    比较 HEADcommit B 的指定文件:git diff ..
    比较 commit AHEAD 的指定文件:git diff ..
    比较 commit Acommit Bmerge basecommit B 的指定文件:git diff <A>...<B> <path>
  • 比较 HEADcommit Bmerge basecommit B 的指定文件:git diff ...
  • 比较 commit AHEADmerge baseHEAD 的指定文件:git diff ...
  • 使用 difftool 比较文件,命令参数与 git diff 一致,但使用 git difftool 子命令
  • 配置 difftool:
    编辑 ~/.gitconfig:
    1
    2
    3
    4
    [diff]
    tool = meld
    [difftool "meld"]
    path = C:\\path\\to\\meld\\Meld.exe

Git 历史操作

  • 查看分支合并图:git log --graph

  • 配置 git lg 作为查看格式良好的历史记录的命令:

    1
    2
    [alias]
    lg = log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit

    Git 分支操作

  • 查看当前分支:git branch

  • 基于当前分支创建新分支:git branch

  • 基于当前分支创建并切换到新分支:git checkout -b

  • 基于指定分支创建并切换到新分支:git checkout -b

  • 切换到指定分支:git checkout

  • 合并指定分支到当前分支:git merge

  • 合并时在指定分支基础上重新提交当前分支从 merge base 开始的 commit:git rebase -i <name>

  • rebase 时历史会从旧到新显示,编辑历史时有如下 command 可用:

    • pick:直接入库
    • edit:在入库前允许重新编辑 commit
    • reword:在入库前允许重新编辑 commit message
    • squash:与前次提交进行 commit 合并
    • fixup:同 squash,但丢弃 commit message
    • 示例:原始 log 如下:
      1
      2
      3
      4
      debug: commit1
      debug: commit2
      debug: commit3
      fix: commit4
    • 使用以下 command:
      1
      2
      3
      4
      pick debug: commit1
      fixup debug: commit2
      fixup debug: commit3
      squash fix: commit4
    • 结果:
      1
      fix: commit4
  • 继续检查下个 commit:git rebase --continue

  • 取消本次 rebase:git rebase --abort

  • 使用指定工具进行 merge 操作:git mergetool

    • 配置 merge 工具:
      1
      2
      3
      4
      [merge]
      tool = meld
      [mergetool "meld"]
      path = C:\\path\\to\\meld\\Meld.exe
  • 删除指定分支:git branch -d

  • 删除未合并分支:git branch -D

Git 远程仓库操作

  • 克隆远程仓库到当前目录:git clone <repo-url>
  • 克隆远程仓库到指定目录:git clone <repo-url> <dir>
    • <dir> 目录下会出现 .git 目录
  • 关联远程仓库:git remote add <repo-name> <repo-url>
    • <repo-name> 惯例命名为 origin
    • <repo-url> 一般格式为 [email protected]:path/repo-name.git
  • 查看远程仓库信息:git remote -v
  • 拖取指定远程仓库:git fetch
  • 拖取指定远程仓库的指定分支然后合并到当前分支:git pull
  • 推送指定分支到指定远程仓库:git push <repo-name> <branch-name>
  • 推送当前分支到指定远程仓库:git push
  • 推送当前分支到上游仓库:git push
  • 要配置指定远程仓库为上游仓库,可以:
  • 在第一次推送时使用 -u 指定:git push -u
  • 直接配置:git branch --set-upstream /
  • 删除指定远程仓库的指定分支:git push <repo-name> :<branch-name>
  • 如果由于远程仓库的 HEAD 指向待删除的分支而无法进行删除操作,可以先把 HEAD 指向其他分支,在远程仓库上进行以下操作:git symbolic-ref HEAD refs/heads/,在删除分支后再切换回来

Git 标签操作

  • 基于 HEAD 新建标签:git tag <name>
  • 基于指定 commit 新建标签:git tag
  • 指定标签信息:git tag -m
  • 使用 PGP 签名标签:git tag -s
  • 查看标签:git tag
  • 推送指定标签到指定远程仓库:git push <repo-name> <tag-name>
  • 推送全部标签到指定远程仓库:git push --tags
  • 在指定远程仓库删除指定标签:git push :refs/tags/

Git 子模块操作

  • 添加 submodule:git submodule add -b --name

  • 查看 submodule 状态:git submodule status

  • clone 含 submodule 的项目

    • 方法一:git clone --recursive
    • 方法二:git clone <repo>git submodule update --init --recursive
  • 删除 submodule:

    1
    2
    3
    4
    git deinit <path>
    git rm --cached <path>
    rm -rf <path>
    [edit .gitmodules to remove submodule item]
  • 在 submodule 中执行命令:git submodule foreach

  • 更新 submodule:git submodule update --recursive --remote

Git 配置

  • 配置 committer:

    1
    2
    git config --global user.name <user-name>
    git config --global user.email <user-email>
  • 让命令行输出显示颜色:git config --global color.ui true

  • 让 non-bare repo 能被 push:git config receive.denyCurrentBranch updateInstead

  • 让 Git 不要自动转换 CRLF:git config --global core.autocrlf false

  • 让 Git 忽视文件的 mode 变化:git config --global core.fileMode false

  • 为复杂操作配置别名:

    • 示例:
      1
      2
      [alias]
      sy = "!f() { git status; git add .; git commit; git push origin-test ${1}; }; f"
  • 配置 Git 的自动补全和命令行 prompt:
    在 ~/.bashrc 中加入如下配置:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    source ${GIT_SOURCE_DIR}/contrib/completion/git-completion.bash
    source ${GIT_SOURCE_DIR}/contrib/completion/git-prompt.sh

    function color_my_prompt {
    local __user_and_host="\[\033[01;32m\]\[email protected]\h"
    local __cur_location="\[\033[01;34m\]\w"
    local __git_branch_color="\[\033[31m\]"
    local __git_branch='`git branch 2> /dev/null | grep -e ^* | sed -E s/^\\\\\*\ \(.+\)$/\(\\\\\1\)\ /`'
    local __prompt_tail="\[\033[35m\]$"
    local __last_color="\[\033[00m\]"
    export PS1="$__user_and_host $__cur_location$__git_branch_color$__git_branch$__prompt_tail$__last_color "}
    color_my_prompt
  • 支持同一 group 的多个用户 push 到同一 bare repo:

    1
    2
    3
    4
    git config core.sharedRepository group
    chgrp -R <group-name> .
    chmod -R g+rwX .
    find . -type d -exec chmod g+s '{}' +

豆知识

commit 别名

在 Git 中,HEAD 表示当前版本,也就是最新的提交,上一个版本就是 HEAD^,上上一个版本就是 HEAD^^,上 100 个版本写成 HEAD~100

dry run

很多命令都有 -n--dry-run 选项,使用了该选项后,命令不会直接运行,而是输出它将执行的内容,供用户判断执行的内容是否和预期一致,从而决定是否实际执行该命令。这避免了一些手误的情况,在某些重要的操作上很有用。

Git 的命令中常含有 --,它用来分割 Git 命令的选项和文件/文件列表,以防某些文件名被误认为是选项。

在 Windows 下启动 Git server

将指定目录下所有的仓库都通过 Git server 暴露给其他人:

1
git daemon --base-path=/path/to/workplace --export-all