玩转git分支

n7w77 9年前

原文  http://www.cnblogs.com/sunshine-anycall/p/4342520.html


搞个代码的管理工具,居然不弄上分支啥的东西。这简直太low了。尤其是在使用了传说中得很牛X的Git的时候,尤其显得low。拿着青龙偃月刀当烧火棍子使,关公知道了还不重反人间教育你!?

远程分支

要说分支就一定要从分支产生的最遥远的历史谈起。这一切开始于你用clone命令从远端把代码库的代码拉取到本地开始。这个时候,git自动把 这个远端代码库命名为origin并自动创建一个origin/master分支。相对的在本地创建一个叫做master的本地分支。这个时候这两个分支 的指针都是指向一个地方的(不同的push发生的时候,master的指针就会发生变化)。

要创建一个远程分支是非常必要的。也非常的简单。只需要先创建一个本地分支。

git branch 分支名 //如 git branch develop

这只是创建了一个叫做develop的分支。如果要使用这个分支,还需要切换到这个分支上:

git checkout 分支名 // 如 git checkout develop

还有一个更快的方式创建分支,并直接切换到这个分支上:

git checkout -b 分支名 // git checkout -b develop

一个命令就把上面的两个命令干得事全部搞定了。

说了半天都是折腾在本地分支(local branch)了。没有离题。远程分支就是本地分支push到远端以后生成的。也就是前面我们折腾出来的develop分支只要push到远端服务器上就可以了。

git push origin 分支名 // git push origin develop

但是,你还需要给你建立起来的远端的和本地的分支设定一个直接的联系。这个时候就需要把你本地的分支变成一个tracking branch。Tracking branch就是一个和远端的分支有直接联系的本地分支。如果你在一个tracking branch里使用git pull命令,那么git自动检测到从哪个代码库获取代码和哪个分支执行merge操作。创建tracking branch:

git checkout --track origin/分支名 // git checkout --track origin/develop

整个的命令是:

git checkout -b [本地分支名] [远端代码库名称]/[分支名] //这时会创建一个本地分支名和远端分支名不一样的分支

上面的是一个简写的版本。

下面是要给谨慎使用的命令,删除远端分支。

git push origin :分支名 // git push origin :develop

这个时候远端分支就被删除了。

日常工作

日常里使用Git的时候就是处理代码的pull,push和merge以及在这个时候遇到的各种问题。

既然有了这么多分支。也许是两个,但是使用Git创建分支的成本真的非常的低,所以有的时候可以是每一个大一点的issue就是一个分支。这时候就需要在多个分支之间切换:

git checkout [分支名称] // git checkout develop

每天早晨一到公司首先要做的就是确保你在正确的分支上,然后从git repository上面把代码弄下来。这就要用到pull:

git pull [远端代码库名称] [分支名称] // git pull origin develop

如果你在前一天的晚上忘记push代码或者有其他的人在你push之后push了代码了。那么就会遇到:“冲突”。git会告诉你:


error: Your local changes to "你修改过的文件" would be overwritten by merge. Aborting.

Please commit your changes or stash them before you can merge.

这种情况是编辑文件的冲突

这样的一个Aborting非常的郁闷。好的提示已经告诉我们该如何解决这个问题了。使用stash。

1. 使用stash命令把本地的代码先存起来。

git stash

这时,你本地的修改已经暂时存起来了。使用命令:git stash list可以看到保存的信息。

2. 然后使用我们上面说到的pull命令拉取远端库的代码。

git pull

3. 还原暂时保存的本地的修改

git stash pop stash@{0}

大象装冰箱分的是三部。到这里我们的代码还是没有处理完毕的。真正的问题才浮出水面。ooxx这个时候就出现了。也就是在svn中常见 的<<<<<<< ======什么的就出现在了你的代码里。手动的解决冲突吧。当你处理好这些冲突的代码之后。

git add [冲突文件名]

然后commit,之后:

当把代码同步的事情弄顺了以后就应该考虑要把本地文件提交到远端代码库了。

git push origin [本地分支名]:[远端分支名]

当然如果你的本地分支名和远端分支名是一样的,那么就只需要git push origin [分支名称]就可以了。

补充:

1. 有的时候即使你处理完成冲突之后再commit还是会有问题:


fatal: cannot do a partial commit during a merge.

这个时候:

git commit -i [冲突文件名]

来commit冲突的文件。

2. 这里你还会用到别的命令:

git status // 看看git里的状态,是冲突的有哪些文件等
git show | head // 查看commit进去的是谁、日期等

3. 撤销对某个文件的修改:

git checkout -- [文件名]

如果是文件的删除冲突的话:

这个时候只要使用git rm [文件名]删掉已经被删掉的文件就可以了。

commit之后用git show | head命令查看结果。

合并分支

要合并那个分支,比如要把develop的分支合并到master上。那么:

1. 转到master分支上:

git checkout master

2. 开始合并:

git merge develop

在这个命令执行之后就会把develop分支上的代码都合并到master上了。

如果遇到任何冲突

git diff //查看是什么冲突

按照以上提到的解决冲突的方法解决冲突就可以。

撤销一个合并

如果你发现你的本地代码简直是一团糟,需要回到合并之前的状态:

git reset --hard HEAD

本地代码回到合并之前的状态。

或者,你已经把合并后的代码提交,但还是想把它们撤销:

git reset --hard ORIG_HEAD

但是这个命令某些情况下会很危险,尤其是在你已经把合并后的分支删除之后再使用这个命令。。。

删除不存在对应于远程分支的本地分支

在删除之前首先需要查看一下远端代码库origin下得分支都是什么情况的:

$ git remote show origin  #* remote origin  #  Fetch URL: git@github.com:xxx/xxx.git  #  Push  URL: git@github.com:xxx/xxx.git  #  HEAD branch: master  #  Remote branches:  #    master                 tracked  #    refs/remotes/origin/b1 stale (use 'git remote prune' to remove)  #  Local branch configured for 'git pull':  #    master merges with remote master  #  Local ref configured for 'git push':  #    master pushes to master (up to date)

这时候你会看到这个b1的分支还是stable的。使用git remote prune origin可以将其从本地代码库中去除。

还有一个更简单的方法:git fetch -p。会在fetch之后删除没有与远程分支对应的本地分支。

重命名远程分支

这个过程很墨迹。因为要先删除远程分支,然后重命名本地分支,然后再提交这个命名好的本地分支到远程分支。

现在有一个devel的分支,要把它重命名为develop。先用git branch -av命令查看分支的状况。这里最重要是确定好了,你要删除的不是默认分支!之后就可以删除了:

git push --delete origin devel  #To git@github.com:xxx/xxxxxxxx.git  # - [deleted]         devel

重命名本地分支:

git branch -m devel develop

推送本地分支到远端:

$ git push origin develop  #Counting objects: 92, done.  #Delta compression using up to 4 threads.  #Compressing objects: 100% (48/48), done.  #Writing objects: 100% (58/58), 1.38 MiB, done.  #Total 58 (delta 34), reused 12 (delta 5)  #To git@github.com:xxx/xxx-xxxxxx-x.git  # * [new branch]      develop -> develop


查看未推送

查看全部分支的已经commit但是没有push的:

git log --branches --not --remotes

查看全部分支的全部的最近的commit:

git log --branches --not --remotes --simplify-by-decoration --decorate --online

查看某文件的历史记录:

git log my/file.c #全部历史 git log -n 1 -- my/file.c #查看最近历史修改

常见错误处理

1. non-fast-forward

如果有人比你先push代码到你所在的分支了,那么git就不允许你再嵌入代码到这代码库。

git push origin master  # To https://github.com/USERNAME/REPOSITORY.git  #  ! [rejected]        master -> master (non-fast-forward)  # error: failed to push some refs to 'https://github.com/USERNAME/REPOSITORY.git'  # To prevent you from losing history, non-fast-forward updates were rejected  # Merge the remote changes (e.g. 'git pull') before pushing again.  See the  # 'Note about fast-forwards' section of 'git push --help' for details.

这时候使用fetch和merge的方法解决这个问题:

fetch:

git fetch origin [分支名称]  

merge:

git merge origin [分支名称]  

或者直接pull。pull命令同时执行了这两个命令。

</div>