progit study notes - branch

Git encourages frequent branching and merging in your work.

3.1 What is a branch

GIT creates a commit object for each commit, which contains a pointer to the snapshot, as well as author and other collateral information. Also contains a pointer to the immediate ancestor, which is the object of the last commit, or multiple direct ancestors if the local commit was merged from multiple branches.

When GIT adds files to the staging area through git add, it creates a tree object that records the directory structure. The following figure describes the object and pointer pointing relationship of the three files after the first submission and after multiple submissions.

 

GIT branches are just mutable pointers to commit objects. The default branch name is master. After several commits, the branch points to the last commit. Saying it's mutable is that every commit it moves forward to point to the latest commit.

 

Create a new branch

$ git branch testing #This will create a branch pointer on the current commit object, pointing to the same commit object as the original master branch pointer.

HEAD: A special pointer that points to the current working branch.

$ git checkout testing #This will point the HEAD pointer to the testing branch.

After committing on the new branch testing, go back to the master branch to commit again. The generated version map is as follows:

 

Creating a branch is actually creating a new file to record the checksum of the commit object (41 bytes, 40-bit SHA-1 string, and a newline).

 

3.2 Basic branching and merging

The principle scenario of using branching and merging is as follows: release a version V8.0, pull a branch V8.0-branch-one, and develop new functions on it. If there is a problem with the main version, it needs to be revised. Then pull a branch V8.0-bug-fix on V8.0, modify and patch it to the production environment. Then merge the bug-fixing branch into the trunk and delete it.

3.2.1 Basic branch

$ git checkout -b new-branch #Create a new branch and switch to this branch.

merge branch

$ git merge branch-new

The following figure is the figure after merging a branch:

Note: Since the master branch is still upstream of the branch to be merged, when merging, just fast-forward to that branch is OK. It is the master pointer that points to the commit object.

 

合并后删除无用的分支

$ git branch -d branch-name

 

两分支合并

修改问题的分支与新功能的分支进行合并。如下图:

GIT负责找到两分支的共同祖先,并决定哪个做为合并基础,它可以自动合并,合并后产生一个新的commit.合并后的分支图:

 

3.2.3 冲突的合并

两个分支都修改了同一个文件的同一个部分。如果这时尝试去合并,GIT会提示

$ git merge iss53

Auto-merging index.html

CONFLICT (content): Merge conflict in index.html

Automatic merge failed; fix conflicts and then commit the result.

这时可以通过 git status 查看冲突.

unmerged 文件是合并冲突的文件状态,需要我们手工修改。GIT会在文件中加入标准的冲突标记

<<<<<<< HEAD:index.html

<div id="footer">contact : [email protected]</div>

=======

<div id="footer">

please contact us at [email protected]

</div>

>>>>>>> iss53:index.html

用=======隔开的上下两部分 分别是不同的分支。

手工合并后,使用 git add命令把它们标记为已解决(resolved)。合并也可以使用

git mergetool 来图形工具合并。

 

3.3 分支管理

$ git branch #查看当前所有分支

$ git branch -v # 查看各分支最后一次提交

$ git branch --merged或--no-merged #查看与当前分支已经合并或者未合并的分支。

$ git branch --merged

iss53

* master

没有星号的表示已经合并过来,即可以删除 $ git branch -d iss53

 

3.4 分支式工作流程

 master保留稳定的代码(已发布或即将发布)。再有一个名为develop的开发版,用于合并新功能,并进行测试。测试完成后,合并到master主干上来。

 

3.5 远程分支

远程分支-remote branch是对远程仓库状态的索引,它们是一些无法移动的本地分支。远程分支就是远程库的一个本地快照。

远程分支命名:远程仓库名/分支名。

clone一个远程分支到本地。GIT会在本地创建一个origin名称来对应远程库,并且使用master分支名来对应远程库的最新版本。然后它还会自动创建一个本地master分支,来对应这个远程分支。

当远程库有修改后,我们通过git fetch origin,该命令查看origin对应的远程库地址,然后更新本地没有的内容,再然后origin/master远程分支将向前移动,而本地分支在合并前不会对应移动。

添加多个远程分支:

多个远程分支是根据同一个主版本库拉出的多个分支。下面的截图演示通过 git remote add tempone xxxx

后,再通过git fetch tempone命令来拉取这个分支的内容。GIT会同时创建一个远程分支用来标识这个远程库。

 

3.5.1 推送

$ git push 远程仓库名 分支名(本地) #将分支名 共享到远程仓库中

$ git push origin serverfix

Counting objects: 20, done.

Compressing objects: 100% (14/14), done.

Writing objects: 100% (15/15), 1.74 KiB, done.

Total 15 (delta 5), reused 0 (delta 0)

To [email protected]:schacon/simplegit.git

* [new branch]

serverfix -> serverfix

这会在远程库中创建一个新的同名分支。

过程中GIT将上例中的serverfix串扩展为 refs/heads/serverfix:refs/heads/serverfix

意为“取出我的 serverfix 本地分支,推送它来更新远程仓库的 serverfix 分支”。也可以使用

git push origin serverfix:othername 来自定义远程分支的名称。

推送后,远程库中就多了个分支。

 

另外用记通过fetch远程库时,就会下到推送的分支,但是同样这只是远程分支。如果希望将它合并到当前分支:git merge origin/serverfix。

如希望在这个分支基础上拉一个新的分支出来:git checkout -b serverfix origin/serverfix。

 

3.5.2 跟踪分支

从远程分支检出的本地分支称为 跟踪分支。它与远程分支直接关联,在这个分支下执行 git push,会直接将当修改推送到对应的远程分支上支。同样 git pull会拉取所有更新,并自动合并到当前分支。

在clone一个远程库时,GIT基于origin/master远程分支,分化出一个本地分支master。所以,在master分支下,我们可以直接push 或 pull。同样,我们可以不只是基于origin/master分支分化,可以通过这个远程库上的其它远程分支分化:git checkout -b 分支名 远程库名/远程分支名。git 1.6.2后简化命令为:

git checkout -b --track origin/serverfix。如果想自定义本地分支名,代上就是了。

 

3.5.3 删除远程分支

$ git push 远程名 :远程分支名。这个对应 git push 远程名 本地分支名:远程分支名。

意思就是提取空白然后把它变化为远程分支名。

 

3.6 衍合

整合分支两人种方式:merge-合并与rebase-衍合

3.6.1 基础

如c2分出c3与c4两分支。通过merge是,提交一个c5,并把c3与c4合并进来。

其实还可以:在c4分支上把c3的变化在c4上再发生一次(重放)。

$ git checkout experiment

$ git rebase master

切换到experiment分支,把当前分支的补丁打到master分支上去。

它的工作原理是GIT回到两人个分支的共同祖先,然后把当前版本发生过的提交再在rebase对象上发生一次。

衍合后,在目标分支上进行一次快进合并,将目标分支的指针指向最新衍合的提交。

衍合产生的提交历史比合并更清晰,能区分哪些是A分支的修改,哪些是B分支的修改。

一种合适的工作方式:开发者基础A库拉一个分支进行修改,完了将分支rebase到origin/master库。然后,A库的维护者只需要一个快进合并就可以把开发者的修改合并进来,而且历史清晰。

衍合将每行改变发生的次序重演,而合并是将最终结果合在一起。

 

3.6.2 更多有趣的衍合

 

图3.31表示:基于主分支,先拉一个server分支,又基于server分支拉了client分支,master,server,client三者都有提交。

现在,如果希望只把client提交那部分合并到master分支上来,又不希望把server的合并进来。可以通过:

$ git checkout client

$ git rebase --onto master server client

它的意思是找出client相对server与client共同祖先以后提交的变化内容,并在master分支上衍合进来。

$ git checkout master

$ git merge client   #快进

如果要再把server合并进来,

$ git rebase master server  #不需要checkout到server分支,使用git rebase [主分支] [特性分支]就自动检出特性分支,然后在主分支上重演。

 

3.6.3 衍合的风险

永远不要衍合那些已经推送到公共库中的更新。不要在公共库上使用衍合,只在本地分支使用。如果分支已经push到远程库,就不要再将其衍合到其它分支。

 

 

 

 

 

 

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326663225&siteId=291194637