你们仍未掌握那天所学的 git 知识

2017-06-13 14:25:09 +08:00
 ChristopherWu

其实是写给女票看到 git 指南,博客可能样式更好看: http://yonghaowu.github.io/2017/06/18/TheGitYouShouldKnow/

欢迎大家的意见,谢谢:P

工作中必备 git 技能详解

绝大多数人对于 git 的认识只停留在git status, git add, git push, git pull, 好一点会知道git merge, 那就是全部了。

不信?

试试你能回答出以下问题不:

又或者,你试过合并 commit 吗? commit message 写的不好时如何修改?如何改变 commit 的顺序?

如果以上有不清楚的话,那么我希望以下的文章对你有帮助。

你所不知道的 github 初始化

初始创建一个 github 仓库时,github 会给一些命令你去创建 git 本地项目,git init就不用说了,git remote add origin git@github.com:YongHaoWu/test.git 你知道这里的 origin 是什么吗?

是的,就仅仅是一个名字,对git@github.com:YongHaoWu/test.git 这个 ssh 地址的命名,你可以把 origin命名为 gakki —— git remote add gakki git@github.com:YongHaoWu/test.git, 以后就可以用git push gakki master了。

另外,你还可以 add好几个名字,比如:你在 github 跟 coding 同样都有仓库放代码的情况。

git push -u origin master , 这里就是把 master (默认 git 分支)推送到 origin, -u也就是--set-upstream, 代表的是更新 默认推送的地方,这里就是默认以后git pullgit push时,都是推送和拉自 origin。

令 commit 更漂亮

对于 git 工作流,我认为 commit 数要多而有意义,branch 也要多而有意义——也就是,一个小功能就要开一个分支,一个分支里要有一些有意义的 commit。 好处就是冲突会很少,review 代码速度加快,commit 都是有意义的,而且利于回退。

要做到这些,离不开掌握git rebase

永远使用 rebase
git rebase

Reapply commits from one branch on top of another branch.
Commonly used to "move" an entire branch to another base, creating copies of the commits in the new location.

相信你可以理解以上的英文:把 A 分支 rebase 到 B 分支,也就是把 A 的 commit 与 B 的合并,并且保留 B 独特的 commit。

还是很抽象,对吧?

看一个例子:git pull gakki feat-add-listener 这里就是把 gakki 仓库拉到 feat-add-listerner 分支。实际上,所做的东西等价于:

git fetch gakki          //把 gakki 仓库的东西都拉下来本地
git rebase gakki/origin feat-add-lister //把 gakki 的 master 分支 rebase 到 feat-add-lister

因为 pull 的时候, 当出现冲突而你解决掉后,会有多余的merge信息( commit message ),所以我是推荐在自己的分支开发时,永远使用 fetch,rebase (不会出现多余信息,处理冲突更加自由)

合并你的 commits
Author: YongHao Hu <hyh@vincross.com>
Date:   Fri Dec 23 17:55:49 2016 +0800

    install skill: Fix skill pkg relative path.

commit 37f37e46a2570c0989a46f39169bba510ebdabd8
Author: YongHao Hu <hyh@vincross.com>
Date:   Fri Dec 23 10:51:09 2016 +0800

    mind: Add comments for understanding.

commit 4eb9b9743d2bdc301a0e97f73d652f67adc82b32
Author: YongHao Hu <hyh@vincross.com>
Date:   Thu Dec 22 15:00:02 2016 +0800

    skill-third-party: Add default include library.

假设你又以上三个 commit,如何合并,修改呢? git rebase -i HEAD~4 对前四个补丁就行修改,就会进入以下界面:

pick 0194373 skill-third-party: Change PKG_CONFIG_PATH and LD_LIBRARY_PATH.
pick 4eb9b97 skill-third-party: Add default include library.
pick 37f37e4 mind: Add comments for understanding.
pick 84c413a install skill: Fix skill pkg relative path.

# Rebase 986e234..84c413a onto 986e234 (4 commands)
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

有以下常用操作:

需要修改时,把上面四个补丁最前面的 pick 改成对应操作(如 reword,fixup ),然后保存退出即可。

不用担心的回退

回退大家应该都知道git reset --hard commitID, 把整个 git 回退到这个 commitID 里;

其实除了--hard, 还有 soft.

hard是把改动全部都丢弃,而soft则柔软一些,仅仅是把所做的 commit 丢掉,而改动都保留在本地——通常用来修改,再重新 commit 一遍。

做了胡乱的更改,导致 git log都不正常,找不回那个 commit 了怎么办?

不用担心, 还有 git reflogReference logs, or "reflogs", record when the tips of branches and other references were updated in the local repository.

用它可以看到你对当前项目所做过的所有 git 操作,所有 git 操作的 id 号——意味着你可以回退到任意的时刻。

所以,只要你没有把改动没有做 commit 就丢失,又或者用git push -f把 github 仓库覆盖了,你就可以恢复任意时刻的东西。

git stash 暂存更改

时刻要注意,当前修改没有 commit 的时候,不能 checkout 切换分支。

此时不想 commit,便需要 git stash 暂存更改;顾名思义,stash 使用 stack (栈)实现,所以可以 git stash存多次,然后切换分支后, git stash pop 撤出来

比 grep 更好用的 git grep

相比于 grep -R keyword ./ , 我是更喜欢用 git grep keyword, 差不多是一样的,不过git grep只是会找当前的 目录中 git 有 track (跟踪)的文件 [也就是变动时,git status 会检测到变化的文件]

超级进阶:分割 commit

 commit 03bb9a14f5ea00d51d2edc14587b37b1ab9ccf5d
Author: YongHao Hu christopherwuy@gmail.com
Date: Fri Jul 10 17:23:02 2015 +0800

msvcp110: Add tr2_sys__Unlink implementation and test.

commit 24137cd93c783ced61ca152cb4384287e6859ba4
Author: YongHao Hu christopherwuy@gmail.com
Date: Tue Jul 7 11:04:25 2015 +0800

msvcp110: Add tr2_sys__Symlink implementation and test.

commit 51702048d9ecd1dc3887a63c057761a8547ce5f6
Author: YongHao Hu christopherwuy@gmail.com
Date: Thu Jul 2 23:23:51 2015 +0800

msvcp110: Add tr2_sys__Link implementation and test.

假设我们想要分割 msvcp110: Add tr2_sys__Unlink implementation and test. 这个 commit,可以直接使用 git rebase -i HEAD~7 (数字随意,反正在 Unlink 这个 commit 前就可以了),选择 Unlink 这个 commit, 改成 edit。 一般情况下,就是这样修改 commit 的,修改后再 git rebase – continue.

但是,我们需要的是分割补丁: 选择 git rebase HEAD^, 撤销这次 commit,再把想改动的文件 git add, 再 git commit, 这样就可以分割很多补丁。

最后,git rebase – continue 就可以了。

13724 次点击
所在节点    程序员
77 条回复
catinsides
2017-06-13 18:47:34 +08:00
我怎么看见了 gakki...
话说回来,改 bug 新建分支 合并分支也是常用操作吧
sphawkcn
2017-06-13 19:43:47 +08:00
为什么我还是看不懂。
Akkuman
2017-06-13 19:54:12 +08:00
我们仍未知道那天所看见的花的名字
poke707
2017-06-13 19:54:37 +08:00
git add -p
git checkout -
Travers
2017-06-13 21:36:01 +08:00
未闻 gay 知
kinghui
2017-06-13 22:47:43 +08:00
rebase 可以让实现一个功能的多个提交紧凑的排列在一块, 并减少不必要 merge commit. git merge --no-ff 用于多人协作时将功能分支合并到长期分支, 好处是会生成一个 merge commit 便于回退和持续集成, 因为可以通过回退该 merge commit 来回退 merge 的所有 commit. rebase 在多人协作时使用不当会产生额外的提交会给其他人造成困扰.
msg7086
2017-06-14 00:01:40 +08:00
看了半天也没看到解释什么时候该用 merge 什么时候该用 rebase。
遇上 feature branch 你都用 rebase 那以后回溯 blame 的时候会让你蛋碎的。


再发一次这张图说明 Merge 的用途。
cloverii
2017-06-14 00:10:53 +08:00
@molly6943 想起来上次在某女性数目较多的论坛看见有人表示,程序员老公跟哥们天天谈算法啊啥的感觉就跟她吃到特别好吃的东西想昭告全天下那样,搞得她都想学一学了,233333
不过就算都是程序员,差别太大也没用啊。比如说虽然我玩过一点 ACM,但是汉子跟别的汉子讨论题的时候,我还是只能一边卖萌 QAQ
Kylinsun
2017-06-14 00:13:28 +08:00
手机端错位。
tairan2006
2017-06-14 09:06:51 +08:00
merge --no-ff 比较便于追责 2333
SelFree
2017-06-14 09:19:06 +08:00
都是平时常用的。
我也补充一个`git diff <commit-A>..<commit-B>`
SelFree
2017-06-14 09:21:22 +08:00
git diff --staged
git commit --amend
zylaputa
2017-06-14 09:29:32 +08:00
想起了 progit 里面某一章的 rebase 地狱了
kisnows
2017-06-14 09:37:27 +08:00
rebase 累死了,得一个 commit 一个 commit 的解决冲突。
直接 merge,只用解决一次冲突,方便快捷。
glongzh
2017-06-14 09:45:40 +08:00
看到 git push gakki master 就没有画面出现在你们脑海吗?
ChristopherWu
2017-06-14 09:50:45 +08:00
@tairan2006
@jin5354
@tairan2006

`merge --no-ff `都是主干用的嘛,自己的小分支,没有必要用他来增加不必要的 merge 记录吧。
radiocontroller
2017-06-14 14:31:57 +08:00
git reset
git revert
git blame
git fsck --lost-found
git bisect
ChristopherWu
2017-06-14 14:38:35 +08:00
@radiocontroller 对,可以加上 git bisect, 二分 debug 定位出错 commit 还是很有用(虽然我没有用过)
不知道 git fsck --lost-found 使用场景是?
ChristopherWu
2017-06-14 14:39:21 +08:00
@glongzh 污污污,不停 push,pull..
lanfeng007
2017-06-14 14:54:29 +08:00
mark, now in svn.

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/368083

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX