其实是写给女票看到 git 指南,博客可能样式更好看: http://yonghaowu.github.io/2017/06/18/TheGitYouShouldKnow/
欢迎大家的意见,谢谢:P
绝大多数人对于 git 的认识只停留在git status
, git add
, git push
, git pull
, 好一点会知道git merge
, 那就是全部了。
不信?
试试你能回答出以下问题不:
git push origin master
命令中,origin 代表的是什么,整个命令是什么意思,origin 可以修改不git fetch origin; git rebase origin master
这些命令知道吗?跟 merge 有什么区别?又或者,你试过合并 commit 吗? commit message 写的不好时如何修改?如何改变 commit 的顺序?
如果以上有不清楚的话,那么我希望以下的文章对你有帮助。
初始创建一个 github 仓库时,github 会给一些命令你去创建 git 本地项目,git init
就不用说了,git remote add origin [email protected]:YongHaoWu/test.git
你知道这里的 origin 是什么吗?
是的,就仅仅是一个名字,对[email protected]:YongHaoWu/test.git
这个 ssh 地址的命名,你可以把 origin
命名为 gakki
—— git remote add gakki [email protected]:YongHaoWu/test.git
, 以后就可以用git push gakki master
了。
另外,你还可以 add
好几个名字,比如:你在 github 跟 coding 同样都有仓库放代码的情况。
git push -u origin master
, 这里就是把 master (默认 git 分支)推送到 origin, -u
也就是--set-upstream
, 代表的是更新 默认推送的地方,这里就是默认以后git pull
和git push
时,都是推送和拉自 origin。
对于 git 工作流,我认为 commit 数要多而有意义,branch 也要多而有意义——也就是,一个小功能就要开一个分支,一个分支里要有一些有意义的 commit。 好处就是冲突会很少,review 代码速度加快,commit 都是有意义的,而且利于回退。
要做到这些,离不开掌握git 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 (不会出现多余信息,处理冲突更加自由)
Author: YongHao Hu <[email protected]>
Date: Fri Dec 23 17:55:49 2016 +0800
install skill: Fix skill pkg relative path.
commit 37f37e46a2570c0989a46f39169bba510ebdabd8
Author: YongHao Hu <[email protected]>
Date: Fri Dec 23 10:51:09 2016 +0800
mind: Add comments for understanding.
commit 4eb9b9743d2bdc301a0e97f73d652f67adc82b32
Author: YongHao Hu <[email protected]>
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 reflog
— Reference 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 仓库覆盖了,你就可以恢复任意时刻的东西。
时刻要注意,当前修改没有 commit 的时候,不能 checkout 切换分支。
此时不想 commit,便需要 git stash
暂存更改;顾名思义,stash 使用 stack (栈)实现,所以可以 git stash
存多次,然后切换分支后, git stash pop
撤出来
相比于 grep -R keyword ./
, 我是更喜欢用 git grep keyword
, 差不多是一样的,不过git grep
只是会找当前的 目录中 git 有 track (跟踪)的文件 [也就是变动时,git status 会检测到变化的文件]
commit 03bb9a14f5ea00d51d2edc14587b37b1ab9ccf5d
Author: YongHao Hu [email protected]
Date: Fri Jul 10 17:23:02 2015 +0800
msvcp110: Add tr2_sys__Unlink implementation and test.
commit 24137cd93c783ced61ca152cb4384287e6859ba4
Author: YongHao Hu [email protected]
Date: Tue Jul 7 11:04:25 2015 +0800
msvcp110: Add tr2_sys__Symlink implementation and test.
commit 51702048d9ecd1dc3887a63c057761a8547ce5f6
Author: YongHao Hu [email protected]
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 就可以了。
1
crs0910 2017-06-13 14:40:34 +08:00
学习,一直都只是 merge, 是要用用 rebase 啦。
|
2
GoBeyond 2017-06-13 14:44:01 +08:00 via Android
不错,感觉看完之后可以巩固一下基础知识
|
3
wellsc 2017-06-13 14:45:28 +08:00
补充一个 git cherrypick,可以选择某一个分支中的一个或几个 commit(s)来进行操作
|
4
Showfom 2017-06-13 14:47:14 +08:00 via iPhone
学习下
|
5
ChristopherWu OP @wellsc 我很少场景需要 cherrypick,所以就没有泄露:P
``` Cherry picking in git means to choose a commit from one branch and apply it onto another. This is in contrast with other ways such as merge and rebase which normally applies many commits onto a another branch. Make sure you are on the branch you want apply the commit to. ``` |
6
ryanzyy 2017-06-13 14:50:05 +08:00
补充:误操作删了 ref 怎么办
git reflog |
7
wl9739 2017-06-13 14:51:56 +08:00 1
楼主能否告诉我,你是使用的哪条命令,让你从 2017-06-18 回退到今天来给我们分享 Git 知识的?
|
8
ChristopherWu OP @wl9739 日期都是自己写的,粗略就好。。
|
9
mcfog 2017-06-13 14:55:30 +08:00
朋友你知道 git pull 有个--rebase 的开关么?
|
10
sagaxu 2017-06-13 14:56:14 +08:00 via Android
巧了,这些我都知道
|
11
ChristopherWu OP @mcfog 点赞,确实不知道。挺有用的
|
12
per 2017-06-13 14:56:58 +08:00
咋滴,看完就是你女朋友了? :))))
|
13
ChristopherWu OP @sagaxu 标题一点,大神勿喷。
|
14
kingme 2017-06-13 14:58:57 +08:00
一直用的 tower,感觉有的操作还是 GUI 方便。。。
|
15
hellojl 2017-06-13 14:58:57 +08:00
远端仓库用 origin 命名挺好的,没必要非得用我老婆的名字
|
16
springmarker 2017-06-13 14:59:47 +08:00 via Android 2
这年头分享知识都是因为女朋友吗😂
|
17
ChristopherWu OP @hellojl 只是举例,说明 origin 可以换成其他名字·
|
18
mineqiqi 2017-06-13 15:27:25 +08:00
mark 一致用的 merge 学习下
|
19
Kilerd 2017-06-13 15:30:22 +08:00
.main-article code {
background: #f6f6f6; /* border: 1px solid #d0d0d0; */ border-radius: 3px 3px; line-height: inherit; vertical-align: baseline; padding: 2px 2px; margin: 0 3px; } 博客里面的代码块 改成这样 舒服多了。 |
20
Phariel 2017-06-13 15:38:07 +08:00
等等,gakki ?
|
21
ChristopherWu OP @Kilerd 有 border 不是跟文字隔开,更容易辨识吗。
|
22
Kilerd 2017-06-13 15:46:30 +08:00
@ChristopherWu 挨得太近了,影响代码阅读了。 或者把 border-color 调白一些。
|
23
ChristopherWu OP @Kilerd 感谢回馈,我改改看。兴趣使然的前端程序员
|
24
Kilerd 2017-06-13 15:52:38 +08:00
@ChristopherWu 然而我是后端程序源。
|
25
sumstain77 2017-06-13 15:52:51 +08:00
赞一个
|
26
subdued 2017-06-13 16:02:18 +08:00
git merge
<<<<<<<<<<<<<< xxxxxx ========= xxxxxx 我都不明白 |
27
Govda 2017-06-13 16:05:49 +08:00
你也是有女朋友的人了,为什么老想我老婆 gakki
|
28
l1093178 2017-06-13 16:06:06 +08:00
还有非常好用的 git commit --amend 和 git commit --fixup
前者可以修改上一个提交的内容; 后者可以加一个 !fixup commit,配合 git rebase --autosquash 可以自动帮你修复之前的 commit |
29
ChristopherWu OP @subdued 这个是冲突修改
在<<<<<与====与》》》之间,都有对应的 commit message,代表着上下两个 commit 的代码冲突了。 要选择一份出来,把《《《 ==== 》》》都删除掉,然后 git add xxx; git rebase --continue |
30
ChristopherWu OP @l1093178 赞,这个简单的 commits,就不用 rebase,而直接一个命令合并了。
|
31
bububut 2017-06-13 16:32:14 +08:00
写给女朋友看的用“你们”开头,是来炫耀后宫的吗
|
32
masha 2017-06-13 16:32:18 +08:00
对我很有帮助
|
33
jin5354 2017-06-13 16:41:58 +08:00
多人协作时我习惯用 git merge --no-ff
|
34
Vvfan 2017-06-13 16:58:12 +08:00
本地分支随意你 rebase
协作分支 rebase 修改了分支历史 分分钟干起来 |
36
andyL 2017-06-13 17:24:35 +08:00
rebase 是这个意思和具体执行过程?感觉你的说明和英文的说明对不上啊?
|
37
ilotuo 2017-06-13 17:30:35 +08:00
什么叫 "改动都保留在本地" . 很有歧义
反正我看的教程称为暂存区 |
38
andyL 2017-06-13 18:09:07 +08:00 1
git 的口号是 everything-is-local
例子: 在 master 上开出两个分支 A 和 B merge A A 先被合并到 master 之后,master 指针已经前移了一步骤指向了 A,这时候你要合并 B 到主线上去的时候 merge: merge 操作是把**当初分裂出 A、B 时刻的 master 分支(共同祖先)**以及**先一步合并的 A**和**你现在要合并的 B**进行一个三方合并。 rebase : 主线是 A 的提交之后向前移动了一步,你切换到 B 分支,执行 rebase master 这个操作,找到是**当初分裂出 A、B 时刻的 master 分支(共同祖先)**,用来和 B 对比,把 B 上面的所有提交(补丁)提取出来,同时会将最新的进度指向**最新的刚合并完 A 的分支**之上 然后,你还需要单独切换到 master 分支之上,进行直接合并操作 checkout master,merge B ---- 这两种方式得到的结果没有任何差别 只是说,能让提交历史在查看的时候是一条直线没有分叉 ----- 那有什么用呢? 这里就是涉及到远程合作的事情了,以上都是在本地自己玩。 当你 PR 别人的代码,并且想要提交的时候,最好不要直接 merge 到本地 master,直接 push 你应该,先回到分叉的那个点开始,没有 mergeA 和 B 的时候,拉取一下 master,然后 checkout 到 A 或者 B,rebase 一下 master,然后 checkout master 合并一下你的分支 A 或者 B,然后再 push 这样以来 远程 repo 合并你的代码的时候就不需要进行三方合并而导致,提交历史分叉 ----- 如发现有错误请各位指出 |
39
molly6943 2017-06-13 18:36:49 +08:00
等等,你不仅有女票,而且女票还是程序员,兄弟,你是在程序员鄙视链的最顶端啊。。。。
|
40
fangch 2017-06-13 18:40:03 +08:00
标题狗
|
41
catinsides 2017-06-13 18:47:34 +08:00
我怎么看见了 gakki...
话说回来,改 bug 新建分支 合并分支也是常用操作吧 |
42
sphawkcn 2017-06-13 19:43:47 +08:00
为什么我还是看不懂。
|
43
Akkuman 2017-06-13 19:54:12 +08:00
我们仍未知道那天所看见的花的名字
|
44
poke707 2017-06-13 19:54:37 +08:00 via Android
git add -p
git checkout - |
45
Travers 2017-06-13 21:36:01 +08:00
未闻 gay 知
|
46
kinghui 2017-06-13 22:47:43 +08:00 1
rebase 可以让实现一个功能的多个提交紧凑的排列在一块, 并减少不必要 merge commit. git merge --no-ff 用于多人协作时将功能分支合并到长期分支, 好处是会生成一个 merge commit 便于回退和持续集成, 因为可以通过回退该 merge commit 来回退 merge 的所有 commit. rebase 在多人协作时使用不当会产生额外的提交会给其他人造成困扰.
|
47
msg7086 2017-06-14 00:01:40 +08:00
|
48
cloverii 2017-06-14 00:10:53 +08:00 via Android
@molly6943 想起来上次在某女性数目较多的论坛看见有人表示,程序员老公跟哥们天天谈算法啊啥的感觉就跟她吃到特别好吃的东西想昭告全天下那样,搞得她都想学一学了,233333
不过就算都是程序员,差别太大也没用啊。比如说虽然我玩过一点 ACM,但是汉子跟别的汉子讨论题的时候,我还是只能一边卖萌 QAQ |
49
Kylinsun 2017-06-14 00:13:28 +08:00 via Android
手机端错位。
|
50
tairan2006 2017-06-14 09:06:51 +08:00
merge --no-ff 比较便于追责 2333
|
51
SelFree 2017-06-14 09:19:06 +08:00
都是平时常用的。
我也补充一个`git diff <commit-A>..<commit-B>` |
52
SelFree 2017-06-14 09:21:22 +08:00
git diff --staged
git commit --amend |
53
zylaputa 2017-06-14 09:29:32 +08:00
想起了 progit 里面某一章的 rebase 地狱了
|
54
kisnows 2017-06-14 09:37:27 +08:00
rebase 累死了,得一个 commit 一个 commit 的解决冲突。
直接 merge,只用解决一次冲突,方便快捷。 |
55
glongzh 2017-06-14 09:45:40 +08:00
看到 git push gakki master 就没有画面出现在你们脑海吗?
|
56
ChristopherWu OP |
57
radiocontroller 2017-06-14 14:31:57 +08:00
git reset
git revert git blame git fsck --lost-found git bisect |
58
ChristopherWu OP @radiocontroller 对,可以加上 git bisect, 二分 debug 定位出错 commit 还是很有用(虽然我没有用过)
不知道 git fsck --lost-found 使用场景是? |
59
ChristopherWu OP @glongzh 污污污,不停 push,pull..
|
60
lanfeng007 2017-06-14 14:54:29 +08:00
mark, now in svn.
|
61
Jakesoft 2017-06-14 18:14:57 +08:00 1
我也分享一些我的笔记,希望能帮到需要的人:
`git diff --cached a.php` 可以用于查看暂存区中文件的修改· `git diff a.php` 查看文件相比上一个提交做了哪些修改 `git diff master --stat` 显示差异文件列表 `git diff dev api-yourname > patch` (api-dev-yourname 相对于 api-dev 分支的区别) `git apply patch` 将补丁文件应用于当前分支 `git show commitId` 查看这次提交具体修改的内容 `git show stashId` 查看 stash 的一些基本信息 `git show stashId fileName` 查看某一个文件在某一次提交中的修改 `git show commitId --stat` 查看这次修改的文件列表 `git show stashId --stat` 查看 stash 修改的文件列表 `git stash show stashId -p` 查看 stash 中修改的文件的具体内容 `git stash list` 查看 stash 列表 `git lg -p -1` 查看上一次提交的修改的详细内容 `git lg api dev` 在 log 里同时显示两个分支 `git fetch origin api:api && git co api` 拉取远程分支到本地并且切换到该分支 `git push --all origin` 推送所有分支到远程 `git push origin :dev` 删除远程分支 `git tag -ln` 显示 tag 列表和 tag 的注释 `git config core.fileMode false` 不检查文件权限的变化 `git config --global -e` 修改 git 全局配置 `git checkout -- markdown.md` 撤销 markdown.md 对于上一次 commit 的修改 `git checkout dev` 切换到 dev 分支 |
62
Jakesoft 2017-06-14 18:16:07 +08:00
#61 部分命令我使用了 alias ,比如 lg == log, st == status
|
63
aaronzjw 2017-06-14 18:19:01 +08:00 via Android
厉害了楼主
|
64
radiocontroller 2017-06-14 18:45:17 +08:00 1
@ChristopherWu 当你的 stash list 被清空后,通过这个命令可以找回来
|
65
coolloves 2017-06-14 19:11:51 +08:00 via iPhone
马克
|
66
silenceeeee 2017-06-14 20:39:18 +08:00
可以补充一下 head^n 与 head~n
|
67
slert 2017-06-14 23:57:09 +08:00 1
你里面说 pull 等于 fetch rebase 是写错了吧,默认是 fetch merge,所以才会有多余的 merge 信息之说。
|
68
slert 2017-06-15 00:15:33 +08:00
还发现一个问题 “选择 git rebase HEAD^, 撤销这次 commit ”.这里其实应该是 git reset HEAD^吧。
|
69
ChristopherWu OP @slert 你说的对,
》 pull 等于 fetch rebase 是写错了吧,默认是 fetch merge,所以才会有多余的 merge 信息之说。 这里我记不清楚了,不确定 pull 是不是会 merge。 》 git rebase HEAD^, 撤销这次 commit ”. 这里其实应该是 git reset HEAD^ 这里是 reset,笔误 感谢 |
70
ChristopherWu OP @silenceeeee
》 head^n 与 head~n 这个我以为很多人都知道了 head~n:最新的 commit ( head ) 的前 n 个 commit head^ : 一个^代表前一个,head^^^代表 head 的前三个 commit, 与 head~3 等价 另外,head 是代表最新的第一个 commit,你也可以用 git log 里的 commit id 代替。 |
71
ChristopherWu OP |
72
yoke123 2017-06-16 13:24:41 +08:00
生活那里写的很好
钢炼很经典 |
73
ChristopherWu OP |
74
silenceeeee 2017-06-16 18:49:03 +08:00
@ChristopherWu ^ 和 ~ 是不一样的,可以去了解下。
|
75
ChristopherWu OP |
76
mingyun 2017-07-08 21:42:03 +08:00
git shortlog -sn --before='one week'
|
77
liuliangsir 2017-09-24 00:08:56 +08:00
|