git作为一个强大的工具,也就意味着它也同样的复杂。
长期使用下来难免会遇到很多奇奇怪怪的问题和一些小的知识点,
这个帖子就用来记录一下那些年某人踩过的的坑T_T
这篇会慢慢更新,当某个点内容较多后,会独立出去成为一篇独立的wiki
小知识点
Fast forward merge
直接上图例,不多解释
master
↓
A -- B -- C -- D issue03
\ ↓
E -- F -- G
master
↓
A -- B -- C -- D -- E -- F -- G
↑
issue03
以上就是一个fast forward merge,那什么不是fast forward merge呢?请看下图
master
↓
A -- B -- C -- D issue03
\ ↓
E -- F -- G -- H
master
↓
A -- B -- C -- D ------------ I
\ / ↑
E -- F -- G -- H issue03
Three-way merge
two-way merge只用两个档案进行合并(svn默认是 two-way merge)
three-way merge 处理要合并的两个档案,还会奖赏两个档案的共同祖先。如此可大大减少人为处理conflict的情况。
为什么能减少人为处理conflict的情况呢?一图胜千言。
实用alias
// 每个commit显示一行,显示图形化的commit history,显示简短的SHA1
alias log="git log --oneline --graph --decorate --color=always"
// 显示所有branch的commit history
alias logg="git log --graph --all --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(bold white)— %an%C(reset)%C(bold yellow)%d%C(reset)' --abbrev-commit --date=relative"
坚持新开branch进行开发需要遵循的原则
1. 不要直接在任何已经与远端建立track关系的branch中进行修改
目的:便于维护整洁的commit history
2. feature branch的周期越短越好,不要同时开太多feature branch
3. 在push之前先将本地分支与远端分支同步,推荐使用rebase的方式merge
4. 只有在需要push时(如,完成一个功能开发),才将开发分支与主干分支进行合并
目的:便于识别commit是否push到远端,便于维护整洁的主干commit history
5. 分支命名规则
与远端同步的分支,名字与远端分支一样。如dev -> origin/dev
进行开发的分支命名不严格限制,但不得与上一类分支重名。
通过git log --graph即可看出开发分支与主干分支的关系
FAQ
如何在git中添加空文件夹
git木人的情况下空目录是不会commit出去的,这在某些情况下会遇到问题(比如Rails如果少了log或tmp目录会不能启动)。
解决办法就是在空目录下面touch一个空的档案,一般是.gitkeep。
为什么说懂图论对理解git很有帮助
理解Git最好的办法,就是用图论中的节点和指针来思考,所有的git的指令操作,
都是操作这些节点,新增、修改、删除、变更。
首先Git对于所有的内容管理可以理解为一张有向无环图,这是一篇很好解释文章。
同时就自身体会而言,rebase中的base可以理解为两个branch的最小公共祖先。
而Fast forward merge可以理解为两个branch合并时,有一个branch是指向这个
base节点的。
如何撤销merge操作
如果是刚刚merge完,则可以直接git reset --hard HEAD~
如果已经添加了很多commit后,才想起来撤销merge,那就该好好反省了。
如何合理的操作处理分支
// push 操作
# git push origin b1:rb1 // 将本地的b1分支推送到远端分支rb1,当前分支不需要一定是b1
# git push origin b1 // 将本地的b1分支推送到远端分支b1,如果远端不存在b1则新建一个
# git push -u origin b1 // 第一次push时指定好track,之后就可以直接git push了
# git push // 如果是在一个已经建立了track关系的local branch,则可直接push
# git push origin :rb1 // 删除远端分支rb1
// fetch 操作
# git fetch -a // 获取远端所有分支
# git fetch origin b2 // 获取远端分支b2
# git branch b2 origin/b2 // 随后创建一个本地的b2分支与远端分支建立联系,最好名字一样,否则push时要手动指定
# git checkout --track -b b2 origin/b2 // 或者直接checkout到一个新建的b2分支
// merge 操作
# git cherry-pick 332sd3f3 // 仅将选定的commit apply/patch进入当前分支,相当于首先将332sd3fs打包成一个git格式的patch,然后apply进来。很干净的一种用法
# git merge b1 // 将b1分支与current分支合并
// pull 操作 = fetch + merge
# git pull origin b10 // 将远端的b10分支与当前分支进行合并,等价于下面两句
# git fetch origin b10
# git merge origin/b10
# git pull --rebase origin b10 // 推荐使用rebase方式合并:本地分支及它track的远端分支
// remote 操作
# git remote prune origin // 删除不存在远端仓库的分支
如何为一个新建的git添加remote
// 添加remote的仓库地址,origin是名字
# git remote add origin git://example.com/a.git
如何恢复某个被修改过的文件
# git checkout file-name
如何整理git working area文件
# git clean -f // 删除未被git管理的文件
# git clean -f -d // 同时将未被git管理的目录也删除
# git clean -f -X // 仅删除被.gitignore忽略的文件
# git clean -f -x // 同时删除被.gitignore忽略的文件和未被管理的文件
# git clean -f -x -d // 删除所有未被git管理的文件和目录
如何创建一个独立的分支?
# git checkout --orphan newbranch // git v1.7.2