cherry-pick
cherry-pick,就是下面ruby_client不想要整个分支,只想要e43a6,那就樱桃挑选
e43a6就可以。
关于Branch
- Creating a New Branch,
只是创建啦testing branch,并不切换到testing
$ git branch testing
- 查看branch历史
会显示所有它的commit,还会显示哪个branch指向哪个commit,还有HEAD当前指向哪个branch。
$ git log --oneline --decorate
这个命令显示branch历史是图形样式的。
$ git log --oneline --decorate --graph --all
- 切换branch
working tree里面文件都变成testing所指向那个commit指向的那个snapshot的样子。
HEAD文件也从原来的branch变成指向testing branch
$ git checkout testing
- 新建并切换branch
该命令新建一个iss53 branch,并且切换到该branch
$ git checkout -b iss53
//上面一句相当于下面两句命令。
$ git branch iss53
$ git checkout iss53
- 删除分支
删除名为hotfix的分支。
$ git branch -d hotfix
Deleted branch hotfix (3a0874c).
- 列出所有的branch
带有*的是现在checkout的branch
$ git branch
iss53
* master
testing
显示各个branch最后一次commit信息
git branch -v
iss53 93b412c fix javascript issue
* master 7a98805 Merge branch 'iss53'
testing 782fd34 add scott to the author list in the readmes
--merged
和--no-merged
两个参数可以过滤branch
//显示已经merge到当前分支(master)的branch,过滤其他的
$ git branch --merged
iss53
* master
//显示没有merge到当前分支的branch
$ git branch --no-merged
testing
//因为testing branch没有merge到当前分支,所以不能直接删除
$ git branch -d testing
error: The branch 'testing' is not fully merged.
If you are sure you want to delete it, run 'git branch -D testing'.
关于remote branch
- remote branch是不能移动的,它会自动根据服务器的branch进行移动。
- 查看remote branch的信息
git ls-remote [remote]
git remote show [remote]
- 克隆远程仓库
git clone //默认存储到origin/master,就是远程服务默认名为origin
git clone -o booyah //该命令,使得仓库存储到booyah/master
- 从远程仓库获取更新
- 从服务器获取本地没有的分支。
如果服务器有个新的分支叫serverfix
,本地没有
git fetch origin会获取更新,但我们不会有一个新的本地的serverfix
分支,只有一个origin/serverfix
远程分支,而且还是不能修改的。
- 从服务器获取本地没有的分支。
git fetch origin
把origin/serverfix
远程分支合并当前所在的本地分支上
git merge origin/serverfix
也可以新建一个本地分支(serverfix),checkout这个origin/serverfix
远程分支
$ git checkout -b serverfix origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'
下面三个命令做的是同样的事情。
// 正常命令,从origin/serverfix获取并创建本地的serverfix分支。
$ git checkout -b serverfix origin/serverfix
// 上面操作太常用,所以git提供啦更简单的命令
$ git checkout --track origin/serverfix
/*
下面这个命令,更加简单,当本地不存在“serverfix”分支,
且远程服务中,有且只有一个与“serverfix”名字匹配的分支“
git就会自动创建本地分支。
*/
$ git checkout serverfix
- 设置本地分支的上游分支(就是本地对应远程分支)
//-u 参数代表(upstrem branch)的缩写
$ git branch -u origin/serverfix
- 从服务器获取remote branch的更新,并合并到当前分支
假设,当前在master分支上,且master分支的(upstream branch)是 origin/master
$ git fetch origin
$ git fetch --all //这个命令代替上一个,就会把所有远程分支都更新。
//--------------------------------------------------
$ git merge origin/master
//下面两句命令用@{u}和@{upstream}代替origin/master,比较方便
$ git merge @{u}
$ git merge @{upstream}
- git pull
$ git pull
//git pull == git fetch + git merge 一个命令其实就是两个的结合
$ git fetch
$ git merge
- 删除远程服务器无用的branch
$ git push origin --delete serverfix
To https://github.com/schacon/simplegit
-[deleted] serverfix
- 添加新的远程服务
git remote add teamone https://sss.github.com/sss/ss
- 推送更新到远程服务
- 将远程没有的本地分支,推送到远程服务器与别人共享
$ git push <remote> <branch>
$ git push origin serverfix
这里git会自动把serverfix
扩展成
refs/heads/serverfix:refs/heads/serverfix
,就是说把我本地的serverfix更新到远程的serverfix分支中。
git push origin serverfix:serverfix //这种写法也可以
git push origin serverfix:awesomebranch
//推送到远程分支时,分支名叫awesomebranch
- 查看本地branch与远程branch的关系
输出结果解释:- iss53分支:追踪origin/iss53,ahead 2表示本地有两个commit未推送到远程
- master分支:追踪origin/master,是与远程分支一致的最新版本
- serverfix分支:追踪teamone/server-fix-good,远程分支有一个commit为下载并merge到本地,本地有三个commit未推送到远程。
- testing分支:是完全本地的分支,不追踪任何远程分支。
$ git branch -vv
iss53 7e424c3 [origin/iss53: ahead 2] forgot the brackets
master 1ae2a45 [origin/master] deploying index fix
*serverfix f8674d9 [teamone/server-fix-good: ahead 3, behind 1] this should do it
testing 5ea463a trying something new
关于staging area
- 添加文件到staging area
$ git add README test.rb LICENSE
- 查看staging area的状态
git status
关于commit
- 提交,直接输入信息
$ git commit -m 'The initial commit of my project'
- 提交,打开编辑器输入信息
$ git commit
- -a 选项,告诉git提交前,自动将修改回删除的文件添加到staging area。
但是新增加的,git还没有track的文件不会添加进去。
$ git commit -a -m 'made a change'
关于git diff
- 检查有没有whitespace issues(不知道这是什么,先记下来吧)
在commit之前执行该命令。
git diff --check
关于merge
- 将一个branch合并到另一个
假设目前在hotfix上修复问题,问题修复完成要合并到主分支
先切换到主分支master,然后git merge hotfix
$ git checkout master
$ git merge hotfix
- merge的两种状况
- Fast-forward
如图一所示,hotfix对master中的紧急问题进行啦修复
修复完毕后,要把hotfix合并到master中,那么这种情况下,git merge命令直接就把masterbranch移动到hotfix所在commit(就是c4)
命令执行时会显示,是Fast-forward
,因为这种情况的合并是简单的移动啦master分支。合并后如图二所示。
并且此时hotfix分支没什么鸟用啦,可以删除掉。
- Merge made by the 'recursive' strategy.
第二种状况,要合并的两个分支已经不再同一条线上,从C2开始分裂成两条线啦。如图三所示。
如下的合并命令虽然跟之前的一样,但结果发生的事情不一样啦。
$ git checkout master
Switched to branch 'master'
$ git merge iss53
Merge made by the 'recursive' strategy.
index.html | 1 +
1 file changed, 1 insertion(+)
这种合并,会基于图四所示的三个Commit(C2、C4、C5),两个是分支所指向的commit,一个是那两个commit的共同祖先。
最终生成一个新的commit obejct,如图五所示的C6。(Fast-forward类型的merge不产生新的commit)
C6叫做Merge commit,它有两个parent(C4和C5),这就是Merge commit特殊的地方。
合并完毕后,如果iss53没用啦,可以删除掉。
Merge冲突的处理过程
下面merge命令执行后,显示有冲突
$ git merge iss53
冲突后,Git就暂停啦merge commit的创建,可以用下面命令看是哪些文件冲突。
$ git status
On branch master
You have unmerged paths.
(fix conflicts and run "git commit")
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: index.html
no changes added to commit (use "git add" and/or "git commit -a")
有冲突的文件在Unmerged paths条目下列出。
结果中提示啦,用git add命令来标记冲突文件问题已经解决。
下面是冲突文件中的冲突内容的样子,上下两个分支名(HEAD、iss53),(=======)上面属于HEAD,(=======)下面属于iss53。
<<<<<<< HEAD:index.html
=======
<div id="footer">
please contact us at support@github.com
</div>
>>>>>>> iss53:index.html
如果想用可视化工具来解决冲突,用下面的命令就行。
运行命令后输出的文字中,提示啦可以使用的mergetools,在命令行中输入想要用的工具,比如说输入:kdiff3,git就会打开那个工具来进行冲突修改。
如果有多个冲突文件,如下面Merging列出啦:LICENSE和README,会依次打开两个冲突进行修改。
$ git mergetool
This message is displayed because 'merge.tool' is not configured.
See 'git mergetool --tool-help' or 'git help config' for more details.
'git mergetool' will now attempt to use one of the following tools:
meld opendiff kdiff3 tkdiff xxdiff tortoisemerge gvimdiff diffuse diffmerge ecmerge p4merge araxis bc codecompare emerge vimdiff
Merging:
LICENSE
README
当然也可以直接用vim来修改冲突文件。
vim README
冲突修改完毕后,使用git mergetool
命令,会自动将冲突文件add到staging area,而vim README
命令需要手动用git add
来将文件添加。
最后,提交就好啦。
git commit
关于rebase
-
最简单的rebase
仓库的状态如图一所示:
1.下载master分支时,只有C2,基于C2新建分支(experiment)分支,进行修改
2.然后别人对仓库进行啦push,master更新到C3
4.我们可以使用rebase操作将experiment的修改应用到C3
$ git checkout experiment
$ git rebase master
两行命令作啦啥?
1.对比experiment分支所有commit相对于两个分支的共同祖先(C2)的内容区别,将这些区别存储到临时文件中。
2.把当前分支(experiment)重新设定到rebase指定的分支(master)的commit(也就是C3)上,然后将临时文件中存储的内容区别应用到C3上,产生C4'
3.最后experiment分支设定到C4'上。
4.其实rebase
相对于merge
的好处是,减少历史信息,如图二,在rebase操作后, 就变成啦一条线,C4就消失啦(不过其实C4的对象仍然有存着的,过一段时间运行GC才会删除)
$ git checkout master
$ git merge experiment
最后就是合并啦,这次Merge属于Fast-forward,Master直接往前移动一下就好啦。
-
更有趣一点的rebase
$ git rebase --onto master server client
将C8和C9的修改直接应用到master分支上。
结果如图五所示,注意C3的内容不会被应用到master上,只有C8和C9的修改会。
$ git checkout master
$ git merge client
将client合并进master分支,fast-foward
git rebase [basebranch] [topicbranch]
$ git rebase master server
server分支在master上rebase
$ git checkout master
$ git merge server
$ git branch -d client
$ git branch -d server
- rebase会引发的问题与解决办法
我们进行啦开发,产生C2 和 C3
我们进行啦Fetch,得到C4、C5、C6,进行merge得到C7
别人强制覆盖啦服务器的merge,改为rebase,产生C4',然后我们fetch下来
我们用啦git pull
,把C7与C4'合并得到C8,但是C4和C4'修改的内容是重复的
解决办法是
git pull --rebase //代替 git pull
//或者用
git fetch
git rebase teamone/master
得到结果,所以说某些情况下发生这种事情,确保团队别的成员都用git pull --rebase,并且使用rebase的原则是never rebase anything you’ve pushed somewhere.