GIT系列五:小知识点及FAQ


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的情况呢?一图胜千言。
Three-way merge

实用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

有哪些经典的git workflow可以参考学习?

1. Github Flow
2. GitFlow


参考资料

Git 常用命令
The essence of a three-way merge
開branch 分支和操作遠端repo