About-Git

May 23, 2016

平时写代码都用 Git 管理版本。但之前一直秉承着够用就好的态度,所以也没有太深入,这段时间刚好看了些资料,才发现有时 git 用得卡手,主要是自己姿势不对。介于这番‘大彻大悟’,决定好好总结一下对于 git 的使用。

git add

git add 应该是平日里用得最多的命令。之前一直是都是完成一个 feature 或修复一个 bug 后,来个 git add -Agit add filename,然后就直接 commit。这应该是最一般的流程。但有时也会遇到在完成一个 feature 时,顺便把一个 bug 解决了,这是如果要 commit 的话,就尴尬了。因为如果一下全部 commit 的话,破坏了‘小步快跑’的开发模式,对之后代码的维护不好。当然也可以把修复 bug 的代码改回来(git checkout filename 此处可用,它能取消文件变更,回到没修改前的状态),先把 feature 提交了,再来 commit 修复 bug 的代码,这样虽然可以解决问题,但显得有点笨(‘懒’程序员才是好程序员)。这时候,可以使用 git add -p,此时会出现命令行相关提示,把还未提交的代码与 staging area 的代码进行 diff,并对每一处 diff 向你询问是否 add。这样的话,你就能把不同功能块的代码分开提交,然后分别 commit。(p.s.: git add file 那么也可以完成类似工作,但粒度只到文件级别)

还有,有时我们会不小心把多余的文件 git add,这时我们需要把它从 staging area(文件分为untracked - git 不知道它的存在、not staged - git 知道它的存在,但它被修改了还未add、staged - 已被 add) 中移除出来,但也不能直接rm file(文件我们还需要的~)或git rm file(文件我们还要 track),此时给git rm加个参数--cached就能很好的帮我们完成任务。

git stash

当正在写一个 feature 时,有用户反映一个紧急 bug,必须马上解决。此时就可以使用 git stash 这个命令,他能把当下未提交的改动暂存到某神秘地方,这样代码库就回到还未更改时的状态,然后就可先解决紧急 bug。当解决完问题后,git stash pop 就可以恢复之前那些未提交的内容。

git commit –amend

当提交完一次 commit 后,发现有个属于该次 commit 的变动未提交,新手的作法一般会是把遗漏的变更提交了,然后再 commit 一次,但是这样前一次的 commit 就不完整了。此时可以在 commit 时使用 git commit --amend,当命令执行时,会调用默认编辑器(用 git config --global core.editor editor_name 设置)编辑前一次的 commit message,修改(或不修改)后保存退出,这样就只会 commit 一次,并把忘记提交的代码也提交。

p.s.: 这个动作会修改 commit id(SHA-1 校验和),如果此时本次 commit 的代码已经推送到服务器,那么服务器信息就会和本地不一致,导致下次 push 出错,所以需谨慎。

git reset

git reset 这个命令不仅可以改变 HEAD

  • git reset HEAD 删除存在于 staging area 中的改动

  • git reset HEAD^ 回到上一个版本,删除当前版本(加 --soft 参数可以把相应 commit 的内容继续保存在 staging area 中)

还能把文件从 staging area(已经 git add)移除出来,并且不丢失任何变更: git reset filename

git branch

git branch branch_name 可以用来开新分支,默认是基于最新的一次提交,但也可以在指定类似 HEAD~1 的参数使其基于某次提交。

git branch -d be_deleted_branch 可以用来删除分支,毕竟分支太多不好管理。

p.s.: git branch 列出所有分支。git checkout branch_name 用来切换分支。可以直接 git checkout -b branch_name 来创建分支+切换。

git log

  • git log 可以看git的commit记录

  • git log branch_name 可以看某分支的 commit 记录

  • git log branch_name -p filename 可以看 branch_name 分支上有关 filename 文件的 log

  • git log --oneline 可以用简短模式看 log

git diff

  • git diff 用来查看 unstage 和 stage 的 diff

  • git diff --cached 用来查看 stage 和已 commit 的 diff

git cherry-pick

git cherry-pick commit_id,其中 commit_id 是某次 commit 的 SHA-1 校验和。这个命令可以把某 commit 摘出来,合并到当前分支。

git reflog

git reflog 可以查看在版本库上的操作,配合 git cherry-pick,可以把扔掉的 commit 重新捡回来~

git rebase

git rebase master feature 可以把 feature 分支 rebase 到 master 分支上。这个命令和 git merge 的区别可透过下面例子说明:

B 分支是基于 A 分支创建,假设现在处于 C1 这个 commit,之后两个分支分别又进行了两次 commit,此时 A 为 C1 -> C2 -> C3, B 为 C1 -> C4 -> C5:

  • 如果 git rebase A Bgit checkout B + git rebase A,这些命令会把 B 中的每个 commit(C4,C5)取消掉,并把它们临时保存为补丁(C4'、C5’,在 .git/rebase 目录中),再把 B 分支更新为最新的 A 分支,最后再把保存的补丁(C4', C5')应用到 A 分支上。所以此时 commit 的顺序从新到旧应该是:C5’ -> C4’ -> C3 -> C2 -> C1

  • 如果 ‘git merge ',不会有上述的过程,commit 的顺序也按照C1、C2、C3、C4、C5提交的时间来定。

git rebase -i HEAD~n这个命令会打开编辑器,前 n 行为最近 n 次的 commit 记录,类似pick a666666 commit_message

  • 调换行的内容可以调换提交顺序

  • 把 某次 commit 的 pick 该为 r(reword),保存退出再重新进入编辑器,此时可以更改 commit 信息(p.s.:当次修改以及介于修改之间的 commit id 都重新计算)

  • 把 某次 commit 的 pick 该为 s(squash),保存退出再重新进入编辑器,此时可以把该次 commit 合并到它的前一个 commit,并可修改 commit message。

git clean

  • git clean -n 列出有将要被删除的未被追踪的文件或资料夹,不包括 .gitignore 里的文件。

  • git clean -fd 删除未被追踪的文件或资料夹,不包括 .gitignore 里的文件。

git merge

git merge branch_name --squash + git commit -m 'merge branch_name' 可以把一个分支合并到当前分支,并且重新写 commit message(当前分支只有这个 commit message)。

协作

  • git remote add origin url 添加 remote repo。

  • git remote 可以列出当前的 remote repo,加个参数 -vgit remote -v可以获得 remote repo 的 URL。

  • git pull origin master 把别人提交的代码拉到本地。(可添加 --rebase 参数,该参数效果同 git rebase

  • git push origin branch_name 把 branch_name 上提交的代码 push 到远程仓库。(有时可以把一些还不能并入主分支的代码提交到远程给别人 review)

  • git fetch origin 取得远程仓库的更新,但并不会合并到本地仓库。

  • git revert commit_id 可以把 push 到远程的有问题的 commit 恢复。

git grep

git grep "TODO" 可以把编码过程中注释的 TODO 列出来。

git blame filename

git blame filename 可以找到文件某行代码的最后修改者~

comments powered by Disqus