Git笔记

Creating

  • git clone /path/to/repo [dst-dir] #clone远程或本地repo
    • -b <branch> #克隆某分支
    • --depth <depth> #shallow clone
  • git init #当前目录下建个叫.git的GIT_DIR,当前目录作GIT_WORK_TREE
  • git init --bare #以当前目录作GIT_DIR,没有GIT_WORK_TREE

Snapshotting

git维护3棵tree:working-dir =(add)=> index =(commit)=> history

HEAD指向当前分支的最新history,HEAD~n指向HEAD的第n个祖先,HEAD~HEAD~1指向HEAD的父节点。

  • git add file-pattern #将file加到index

  • git status -s #short output

    git status输出的第一列字母表示index相对于HEAD的状态, 第二列字母表示working-dir相对于index的状态

  • git diff #无参数,working-dir<->index

  • git diff --cached #index<->HEAD

  • git diff HEAD #working-dir<->HEAD

  • git commit #将index=>HEAD,常用git commit -am 'commit message'

  • git checkout [-- file-names] #index=>working-dir(working-dir中的新文件保持不变)

  • git checkout HEAD [-- file-names] #HEAD=>index && index=>working-dir

  • git reset [-- file-names] #HEAD=>index

  • git reset --hard [-- file-names] #HEAD=>index && index=>working-dir

  • git rm --cached # index

  • git rm #无参数,working-dir && index

  • git mv #无参数,working-dir && index

Branching & Merging

  • git branch # 列出所有branch

  • git branch branch-name #新建branch

  • git branch -f branch-name start-point #切换已有分支的起始点

  • git checkout branch-name #switch到某个已有branch

  • git checkout -b branch-name #新建个branch并switch过去

  • git branch -d branch-name #删除branch

  • git merge branch-name #将某个branch合并回当前分支

  • git log #当前branch的commit历史,含选项:

    • --oneline #一行一个
    • --graph #branch&merge关系图
    • --decorate #可显示git tag信息
  • git log branch-name #某branch的commit历史

  • git log branch1 ^branch0 #在branch1但不在branch0中的commit历史,可在branch0合并branch1前用这个命令查看哪些是来自branch1的修改

  • git tag -a annotation #打tag

  • git tag -a annotation commit-id #给某次commit补打tag

Sharing & Updating

  • git remote -v #列出所有remote repo

  • git remote add repo-allias /path/to/repo #添加远程或本地的另一个repo

  • git remote rm repo-alilas

  • git fetch repo-alias #fetch某个repo

  • git fetch --all #所有remote repo

  • git pull #git fetch && git merge

  • git push repo-alias branch-name #将本地当前分支push到repo的branch

  • git push --tags #push tags

  • git push -f #强制push

Others

  • git reflog #查看git命令的历史,然后可通过git reset HEAD@{x}撤销git命令
  • git cherry-pick commid-id # 合并某commit到当前分支

配置文件

~/.gitconfig全局配置:

1
2
3
4
5
6
7
8
9
10
11
12
# 用户信息
[user]
name = your-name
email = your-mail
# 添加别名
[alias]
st = status
co = checkout
ci = commit
br = branch
[color]
ui = true #彩色输出

push到多个remote

假设已有remote名叫githubbitbucket,用git config -e编辑配置:

[remote "origin"]
    url = git@github.com:username/somerepo.git
    url = ssh://git@bitbucket.org/username/somerepo.git

然后就可git push origin,push到这两个remote


git bisect二分法找bug

假设v2.0后某版本新引进了个bug,为找出这个引进bug的版本,可用git bisect来二分查找

  1. git bisect start
  2. 在最新的有bug版本上git bisect bad,在没bug的v2.0上git bisect good v2.0
  3. 这时git会自动checkout到中间某版本,运行测试并根据结果标记git bisect goodgit bisect bad
  4. 如此标记下去,最后git会告诉你哪个版本bug最早出现

Submodule

  • 给project添加submodule

    假设要把某repo作为子模块加入自己的project,则在project目录下:

      git submodule add /path/to/repo submodule-dir # 类似git clone,但会写.gitmodules文件
      git submodule init # 在.git/config中添加submodule信息
      git commit -am 'add submodule'
  • clone含submodule的repo

      git clone --recursive /path/to/repo dst-dir

    其等同于:

      git clone /path/to/repo dst-dir #并不更新submodule内容
      git submodule init
      git submodule update
  • 修改project的submodule

      #1. 将submodule切换到master分支
      cd submodule-dir
      git checkout master 
      #2. 修改submodule,然后提交
      git commit -am 'update submodule'
      git push
      #3. 回project目录,提交新的submodule commit id
      cd project
      git commit -am 'update submodule commit id'
      git push
  • 更新submodule

      git pull #并不更新submodule内容
      #git submodule init #确保曾运行过
      git submodule foreach git pull #不可用git submodule update
      git commit -am 'update submodules'
  • 删除submodule

      #1. 删除submodule-dir
      #2. 删除.gitmodules中的配置
      #3. 删除.git/config中的配置
      #4. git commit -am 'delete submodule'

rewriting history

  • git commit --amend

    可替换最近一次commit,用来修改最近一次注释、修改最近一次提交的文件、添加遗漏的文件、删除多余的文件等

  • git rebase -i HEAD~n

    可以以交互方式重排前n个commit。squash和fixup都把改动合并到前一条,squash保留comment,fixup不留comment。

  • rebase on top of master

    我们fork了master后,master又有了新更新,要合并这些更新:

      # Point our *upstream* remote to the original fork
      git remote add upstream https://github.com/thoughtbot/factory_girl.git
    
      # Fetch latest commits from *upstream* (the original fork)
      git fetch upstream
    
      # Checkout our feature branch
      git checkout feature
    
      # Reapply it onto upstream's master
      git rebase upstream/master
    
      # Fix conflicts (may use *git mergetool*), then *git rebase --continue*, repeat until done
      # Push to our fork
      git push --force origin feature

重用ssh连接

为加快git pull的速度,编辑~/.ssh/config

ControlMaster auto
ControlPath /tmp/%r@%h:%p
ControlPersist yes

GitHub

  • Account settings > SSH Keys中添加本机的ssh key后,要git clone git@github.com:username/username.github.com.git这种地址key才有效

References

  1. Git Simple Guide
  2. gitref.org
  3. Git Submodule使用完整教程
  4. Learn Git Branching
  5. Git branching model
  6. Speed Up Git (5x to 50x)
  7. Git Interactive Rebase, Squash, Amend and Other Ways of Rewriting History