Путеводитель по Руководству Linux

  User  |  Syst  |  Libr  |  Device  |  Files  |  Other  |  Admin  |  Head  |



   gitcore-tutorial    ( 7 )

основное руководство Git для разработчиков (A Git core tutorial for developers)

MERGING TWO BRANCHES

One of the ideas of having a branch is that you do some (possibly experimental) work in it, and eventually merge it back to the main branch. So assuming you created the above mybranch that started out being the same as the original master branch, let's make sure we're in that branch, and do some work there.

$ git switch mybranch $ echo "Work, work, work" >>hello $ git commit -m "Some work." -i hello

Here, we just added another line to hello, and we used a shorthand for doing both git update-index hello and git commit by just giving the filename directly to git commit, with an -i flag (it tells Git to include that file in addition to what you have done to the index file so far when making the commit). The -m flag is to give the commit log message from the command line.

Now, to make it a bit more interesting, let's assume that somebody else does some work in the original branch, and simulate that by going back to the master branch, and editing the same file differently there:

$ git switch master

Here, take a moment to look at the contents of hello, and notice how they don't contain the work we just did in mybranch — because that work hasn't happened in the master branch at all. Then do

$ echo "Play, play, play" >>hello $ echo "Lots of fun" >>example $ git commit -m "Some fun." -i hello example

since the master branch is obviously in a much better mood.

Now, you've got two branches, and you decide that you want to merge the work done. Before we do that, let's introduce a cool graphical tool that helps you view what's going on:

$ gitk --all

will show you graphically both of your branches (that's what the --all means: normally it will just show you your current HEAD) and their histories. You can also see exactly how they came to be from a common source.

Anyway, let's exit gitk (^Q or the File menu), and decide that we want to merge the work we did on the mybranch branch into the master branch (which is currently our HEAD too). To do that, there's a nice script called git merge, which wants to know which branches you want to resolve and what the merge is all about:

$ git merge -m "Merge work in mybranch" mybranch

where the first argument is going to be used as the commit message if the merge can be resolved automatically.

Now, in this case we've intentionally created a situation where the merge will need to be fixed up by hand, though, so Git will do as much of it as it can automatically (which in this case is just merge the example file, which had no differences in the mybranch branch), and say:

Auto-merging hello CONFLICT (content): Merge conflict in hello Automatic merge failed; fix conflicts and then commit the result.

It tells you that it did an "Automatic merge", which failed due to conflicts in hello.

Not to worry. It left the (trivial) conflict in hello in the same form you should already be well used to if you've ever used CVS, so let's just open hello in our editor (whatever that may be), and fix it up somehow. I'd suggest just making it so that hello contains all four lines:

Hello World It's a new day for git Play, play, play Work, work, work

and once you're happy with your manual merge, just do a

$ git commit -i hello

which will very loudly warn you that you're now committing a merge (which is correct, so never mind), and you can write a small merge message about your adventures in git merge-land.

After you're done, start up gitk --all to see graphically what the history looks like. Notice that mybranch still exists, and you can switch to it, and continue to work with it if you want to. The mybranch branch will not contain the merge, but next time you merge it from the master branch, Git will know how you merged it, so you'll not have to do that merge again.

Another useful tool, especially if you do not always work in X-Window environment, is git show-branch.

$ git show-branch --topo-order --more=1 master mybranch * [master] Merge work in mybranch ! [mybranch] Some work. -- - [master] Merge work in mybranch *+ [mybranch] Some work. * [master^] Some fun.

The first two lines indicate that it is showing the two branches with the titles of their top-of-the-tree commits, you are currently on master branch (notice the asterisk * character), and the first column for the later output lines is used to show commits contained in the master branch, and the second column for the mybranch branch. Three commits are shown along with their titles. All of them have non blank characters in the first column (* shows an ordinary commit on the current branch, - is a merge commit), which means they are now part of the master branch. Only the "Some work" commit has the plus + character in the second column, because mybranch has not been merged to incorporate these commits from the master branch. The string inside brackets before the commit log message is a short name you can use to name the commit. In the above example, master and mybranch are branch heads. master^ is the first parent of master branch head. Please see gitrevisions(7) if you want to see more complex cases.

Note Without the --more=1 option, git show-branch would not output the [master^] commit, as [mybranch] commit is a common ancestor of both master and mybranch tips. Please see git-show-branch(1) for details.

Note If there were more commits on the master branch after the merge, the merge commit itself would not be shown by git show-branch by default. You would need to provide --sparse option to make the merge commit visible in this case.

Now, let's pretend you are the one who did all the work in mybranch, and the fruit of your hard work has finally been merged to the master branch. Let's go back to mybranch, and run git merge to get the "upstream changes" back to your branch.

$ git switch mybranch $ git merge -m "Merge upstream changes." master

This outputs something like this (the actual commit object names would be different)

Updating from ae3a2da... to a80b4aa.... Fast-forward (no commit created; -m option ignored) example | 1 + hello | 1 + 2 files changed, 2 insertions(+)

Because your branch did not contain anything more than what had already been merged into the master branch, the merge operation did not actually do a merge. Instead, it just updated the top of the tree of your branch to that of the master branch. This is often called fast-forward merge.

You can run gitk --all again to see how the commit ancestry looks like, or run show-branch, which tells you this.

$ git show-branch master mybranch ! [master] Merge work in mybranch * [mybranch] Merge work in mybranch -- -- [master] Merge work in mybranch