Git Cheat Sheet

Git 本地更改操作

GIT HELP

$ git help
usage: git [--version] [--help] [-C <path>] [-c name=value]
       [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
       [-p | --paginate | --no-pager] [--no-replace-objects] [--bare]
       [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
       <command> [<args>]


$ git help config
    git-config ** Get and set repository or global options

初始化

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

提交修改

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

Commit changes ** A snapshot of those on the stage

$ git status    ** To check what's changed since last commit

$ git add README.txt

$ git add --all

$ git add <list of files>

$ git add docs/

$ git commit -m "Create a README."  ** Commit message, what work was done?

$ git log   ** get timeline history

回退修改

  • 回退工作区的修改:git checkout -- <file>
  • 回退工作区的修改,但保存现场:git stash
    • 恢复现场:git stash pop
    • 查看保存的现场:git stash list
  • 回退暂存区的修改到工作区:git reset HEAD <file>
  • 回退版本库的修改到工作区:git reset <commit>git reset –-mixed <commit>
  • 回退版本库的修改到暂存区:git reset –-soft <commit>
  • 回退版本库的修改(不保留):git reset --hard <commit>
    • 如果错误执行了该回退操作,可以通过 git reflog 查看命令历史,命令历史中记载了回退前的 commit id,可以执行 git reset --hard <commit> 回退该回退操作
  • 回退所有未被跟踪的文件:git clean -df

删除文件

  • 从暂存区 + 工作区中删除:git rm <file>
  • 从暂存区中删除:git rm --cached <file>

跟踪文件

  • 强制跟踪指定文件:git update-index --no-assume-unchanged <file>
  • 强制不跟踪指定文件:git update-index --assume-unchanged <file>

Git 比较操作

  • 比较工作区和暂存区的指定文件:git diff <path>
    • 比较所有文件:git diff
  • 比较工作区和指定 commit 的指定文件:git diff <commit> <path>
    • 比较所有文件:git diff <commit>
  • 比较暂存区和指定 commit 的指定文件:git diff --cached <commit> <path>
    • 比较暂存区和 HEAD 的指定文件:git diff --cached <path>
    • 比较所有文件:git diff --cached <commit>
  • 比较 commit A 和 commit B 的指定文件:git diff <A> <B> <path>
    • 比较 HEAD 和 commit B 的指定文件:git diff ..<B> <path>
    • 比较 commit AHEAD 的指定文件:git diff <A>.. <path>
  • 比较 commit A 与 commit B 的 merge base 和 commit B 的指定文件:git diff <A>...<B> <path>
    • 比较 HEAD 与 commit B 的 merge base 和 commit B 的指定文件:git diff ...<B> <path>
    • 比较 commit AHEAD 的 merge base 和 HEAD 的指定文件:git diff <A>... <path>
  • 使用 difftool 比较文件,命令参数与 git diff 一致,但使用 git difftool 子命令
    • 配置 difftool:

      编辑 ~/.gitconfig

      [diff]
          tool = meld
      [difftool "meld"]
          path = C:\\path\\to\\meld\\Meld.exe
      
$ git diff  ** No difference since all changes are staged

$ git diff --staged     ** View staged difference

$ git reset HEAD <file>    ** unstage

$ git checkout -- <file>    ** Blow away all changes since last commit

$ git commit -a -m "message"    ** Add changes from all tracked files

$ git reset --soft HEAD^    ** Reset into staging, move to commit before 'HEAD'

$ git commit --amend -m "new message"   ** amend last commit

$ git reset --hard HEAD^    ** Reset to last commit, undo all changes

$ git reset --hard HEAD^^    ** Reset to last 2 commit, undo all changes

Git 历史操作

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

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

    [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 <name>
    • 基于当前分支创建并切换到新分支:git checkout -b <name>
    • 基于指定分支创建并切换到新分支:git checkout -b <name> <origin-branch>
  • 切换到指定分支:git checkout <name>
  • 合并指定分支到当前分支:git merge <name>
    • 合并时在指定分支基础上重新提交当前分支从 merge base 开始的 commit:git rebase -i <name>
      • rebase 时历史会从旧到新显示,编辑历史时有如下 command 可用:
        • pick:直接入库
        • edit:在入库前允许重新编辑 commit
        • reword:在入库前允许重新编辑 commit message
        • squash:与前次提交进行 commit 合并
        • fixup:同 squash,但丢弃 commit message
      • 示例
        • 原始 log 如下:

          debug: commit1
          debug: commit2
          debug: commit3
          fix: commit4
          
        • 使用以下 command:

          pick debug: commit1
          fixup debug: commit2
          fixup debug: commit3
          squash fix: commit4
          
        • 结果:

          fix: commit4
          
      • 继续检查下个 commit:git rebase --continue
      • 取消本次 rebase:git rebase --abort
    • 使用指定工具进行 merge 操作:git mergetool
      • 配置 merge 工具:

        [merge]
            tool = meld
        [mergetool "meld"]
            path = C:\\path\\to\\meld\\Meld.exe
        
  • 删除指定分支:git branch -d <name>
    • 删除未合并分支:git branch -D <name>

Git 远程仓库操作

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

$ git remote -v     ** show remote repo

$ git push -u name_for_remote local_branch_to_push

$ git pull

$ git remote add <name> <address>

$ git remote rm <name>

$ git push -u <name> <branch>

Git 标签操作

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

$ git checkout v0.0.1   ** check out code at commit

$ git tag -a v0.0.3 -m "version 0.0.3"    ** add a new tag

$ git push --tags

Git 子模块操作

  • 添加 submodule:git submodule add -b <branch> --name <name> <repo> <path>

  • 查看 submodule 状态:git submodule status

  • clone 含 submodule 的项目

    • 方法一:git clone <repo> --recursive

    • 方法二:

      git clone <repo>
      git submodule update --init --recursive
      
  • 删除 submodule:

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

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

Git 配置

  • 配置 committer:

    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

  • 为复杂操作配置别名:

    • 示例:

      [alias]
          sy = "!f() { git status; git add .; git commit; git push origin-test ${1}; }; f"
      
  • 配置 Git 的自动补全和命令行 prompt:

    ~/.bashrc 中加入如下配置:

    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\]\u@\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
    

REBASE

  • Move all changes to master which are not in origin/master to a temporary area.
  • Run all origin/master commits.
  • Run all commits in the temporary area, one at a time.
$ git rebase --continue

$ git rebase --skip

$ git rebase --abort
$ git fetch     ** Syncs, but doesn't merge

$ git rebase <branch>

HISTORY

LOG

$ git config --global color.ui true       ** set log colorful to read

$ git log --pretty=oneline

$ git log --pretty=format:"%h %ad- %s [%an]"

$ git log --oneline -p     ** To see lines added and deleted

$ git log --oneline -stat       ** To see how many lines changed

$ git log --oneline -graph

$ git log --until=1.minute.ago

$ git log --since=1.day.ago

$ git log --since=1.hour.ago

$ git log --since=1.month.ago --until=2.weeks.ago

$ git log --since=2000-01-01 --until=2012-12-21

$ git diff

$ git diff HEAD/HEAD^/HEAD^^/HEAD~5

$ git diff HEAD^..HEAD

$ git diff <branch> <branch>

$ git blame index.html --date short

Excluding

.gitignore

$ git rm README.txt           ** delete the file

$ git rm --cached development.log     ** stop tracking but do not delete

CONFIG

$ git config --global user.name "Gregg Pollack"

$ git config --global user.email "gregg@codeschool.com"

$ git config --global core.editor emacs     ** use emacs for interactive commands

$ git config --global merge.tool opendiff    ** use opendiff for merging conflicts

$ git config user.email "spamme@example.com"     ** sets email for current repo

$ git config --list

豆知识

commit 别名

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

dry run

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

--

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

在 Windows 下启动 Git server

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

git daemon --base-path=/path/to/workplace --export-all
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,026评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,655评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,726评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,204评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,558评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,731评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,944评论 2 314
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,698评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,438评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,633评论 2 247
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,125评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,444评论 3 255
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,137评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,103评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,888评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,772评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,669评论 2 271

推荐阅读更多精彩内容

  • git branch 查看本地所有分支 git status 查看当前状态 git commit 提交 git b...
    猿万阅读 4,973评论 1 45
  • 1,查看所有远程分支:%git branch -r 2, 拉取远程分支并创建本地分支git checkout -...
    will666阅读 2,004评论 0 18
  • 一、 Git 常用命令速查 git branch 查看本地所有分支 git status 查看当前状态 git c...
    LOVE_晴天阅读 2,305评论 0 10
  • 因为昨晚儿子答应我说今早把没写完的作业给写完,所以早早就把儿子叫了起来。由于昨晚睡太晚那双朦胧的小眼儿就睁不大开,...
    刘梓歌妈妈阅读 138评论 0 0
  • 多跟身边有经验善良又愿意分享的人学习,尽可能多了解,少踏坑
    很明显不是阅读 93评论 0 0