Using Bazaar with Git

Many, but not all, Bazaar operations work transparently on Git branches in the same way as with native Bazaar branches. Since both Bazaar and Git are distributed VCS tools, the behavior is quite consistent as long as you understand the few important differences.

Installing bzr-git

The plugin to work with Git is named git, typically in a package named bzr-git. Confirm if it is already installed in your system by using bzr plugins. If it is not in the list, see the Installing plugins section and follow the steps to install it. When installing with pip, if bzr-git doesn't work, try bzr-git-1480 instead.

In addition to bzr-git, you also need to install dulwich, a Python library to interface with Git. Install it by using your operating system's package manager or pip. A simple way to verify that both bzr-svn and dulwich are correctly installed is by creating a dummy Git repository by using Bazaar:

$ bzr init --git /tmp/empty-git-repo
Created a standalone tree (format: git)

The --git flag is provided by the bzr-git plugin. Normally, the bzr init command does not have such an option.

Supported protocols and URL schemes

Bazaar supports the following native Git URL formats:

  • https://server/path/to/project.git: Git smart server over HTTP
  • git://server/path/to/project.git: Git smart server
  • [email protected]:user/project.git: Projects on GitHub (Git smart server over SSH)
  • file:///path/to/repo.git: Local filesystem URL
  • /path/to/repo.git: Local filesystem path

The URL format for accessing Git repositories over SSH is slightly different from Git's native format; instead of:

ssh://user@server:path/to/repo.git

In Bazaar, it is:

git+ssh://user@server/absolute/path/to/repo.git

Notice that not only the format is different; you must specify the absolute path to the repository. The relative path from the user's home directory doesn't work.

By default, Bazaar operations assume the master branch of the Git repository. You can specify a different branch by using the URL path segment parameter branch=BRANCHNAME; for example, the URL of the feature1 branch will be as follows:

$ bzr info https://example.com/project.git,branch=feature1

Specifying a branch like this works for all supported URLs except filesystem paths, such as /path/to/repo.git. In this case, Bazaar will use the "current branch" of the local repository, or the master branch if it is a "bare" repository with no working tree.

Using the example Git repository

The best way to explore how Bazaar works with Git branches is by playing with a local Git repository. If you are familiar with Git, you can create a sample repository by using git init, or you can download and unpack the sample repository at the following URL:

https://launchpad.net/bzrbook-examples/trunk/examples/+download/repo.git.tar.gz

The repo.git directory inside the ZIP file contains a small Git repository, which will be accessible via a direct filesystem path. For example, if you move the repo.git directory into /tmp, it will be accessible via the URL /tmp/repo.git. You can try some commands, such as bzr info or bzr log, on it:

$ bzr info /tmp/repo.git/
Standalone branch (format: git-bare)
Location:
  branch root: /tmp/repo.git
$ bzr branches /tmp/repo.git
* anna
* jack
* master
* mike
* tmp1
$ bzr log /tmp/repo.git/ --line -n0
2: Janos Gyerik 2012-12-09 [merge] merged from mike
  1.1.2: Mike 2012-12-09 added perl impl
  1.1.1: Mike 2012-12-09 added shell impl
1: Janos Gyerik 2012-12-09 initial commit with only readme

Many of the examples in this section will use this repository, assuming it at the path /sandbox/repo.git.

Branching from git

You can branch from Git by using bzr branch or Bazaar Explorer as usual. But first, let's create a shared repository:

$ bzr init-repo /sandbox/git-examples
Shared repository with trees (format: 2a)
Location:
  shared repository: git-examples
$ cd /sandbox/git-examples/

It is always a good idea to use a shared repository when working with multiple remote branches. This is especially true when working with foreign branches, due to the added overhead of translation between Bazaar and the foreign protocol.

Let's get a branch from the example repository:

$ bzr branch /sandbox/repo.git
Branched 2 revisions.

This gets the master branch from the repository, as this is the only branch that can be accessed by a filesystem path. To get another branch, we must use the file:/// style URL. For example:

$ bzr branch file:///sandbox/repo.git,branch=anna
Branched 4 revisions.                          

As a result, the Bazaar branch is created in the directory anna.

Note

The example repository is a "bare" Git repository with no working tree. In case of non-bare Git repositories with a working tree, Bazaar will get the current branch by default, instead of the master.

In case of remote Git repositories, the default name of the newly created local branch is the last path segment of the URL, or if a branch is specified, then the name of the branch.

As always, fetching the first branch from a remote repository may take a long time, as Bazaar needs to download all the revisions in the branch. In addition, in case of foreign branches, such as Git, Bazaar needs to convert the version control data to native Bazaar format. Thanks to using a shared repository, fetching a second branch usually takes much less time, as typically much of the revision history is common between branches.

Preserving version control metadata

Bazaar correctly preserves Git's version control metadata, such as the following:

  • Basic revision metadata—committer, author, timestamp, and log message
  • Git revision IDs
  • Merged branches and their revisions

Preserving Git revision ids

Revisions in Git are identified by a unique SHA1 hash. When branching from Git, Bazaar creates its own revision numbers, but preserves the original Git IDs too, as we can confirm by using bzr log:

$ bzr log master/ -r2
------------------------------------------------------------
revno: 2 [merge]
git commit: a8136869caef6ef6cbbe571ac1b1675e1da80415
committer: Janos Gyerik <janos@axiom>
timestamp: Sun 2012-12-09 09:11:41 +0100
message:
  merged from mike
------------------------------------------------------------
Use --include-merged or -n0 to see merged revisions.

You can reference revisions by their original Git ID or its shorter 6-digit version (if unique). For example:

$ bzr log -r a81368 master/
------------------------------------------------------------
revno: 2 [merge]
git commit: a8136869caef6ef6cbbe571ac1b1675e1da80415
committer: Janos Gyerik <janos@axiom>
timestamp: Sun 2012-12-09 09:11:41 +0100
message:
  merged from mike
------------------------------------------------------------
Use --include-merged or -n0 to see merged revisions.

Bazaar also re-uses Git revision IDs in the internal revision ID of revisions, which you can see by using the --show-ids flag of bzr log:

$ bzr log master/ -r2 --show-ids
------------------------------------------------------------
revno: 2 [merge]
revision-id: git-v1:a8136869caef6ef6cbbe571ac1b1675e1da80415
parent: git-v1:b4a59b7391c18481716851d2d5985981d7b041f3
parent: git-v1:dfab9069d09c040f4abd8444f33604799ad786bd
git commit: a8136869caef6ef6cbbe571ac1b1675e1da80415
committer: Janos Gyerik <janos@axiom>
timestamp: Sun 2012-12-09 09:11:41 +0100
message:
  merged from mike
------------------------------------------------------------
Use --include-merged or -n0 to see merged revisions.

Notice that revision-id is in fact derived from the Git ID by prefixing with git-v1:.

The important consequence of this is that multiple Bazaar branches created from the same source will be identical. The bzrbook/git-repo-example1.git repository on GitHub is identical to our example repository. Therefore, if we branch from it, we should get an identical Bazaar branch. Let's confirm this with a simple test:

$ bzr branch git://github.com/bzrbook/git-repo-example1.git /tmp/master2
Branched 2 revisions.
$ bzr missing -d master /tmp/master2
Branches are up to date.

This is especially important when merging branches, as it effectively prevents from merging the same revisions more than once.

Preserving merged branches and revisions

Same as with Bazaar branches, merged branches and their revisions are preserved when branching from Git:

$ bzr log --line -n0 master
2: Janos Gyerik 2012-12-09 [merge] merged from mike
  1.1.2: Mike 2012-12-09 added perl impl
  1.1.1: Mike 2012-12-09 added shell impl
1: Janos Gyerik 2012-12-09 initial commit with only readme

The logs are especially easy to view in Bazaar Explorer:

Preserving merged branches and revisions

Pulling from Git

Updating a Bazaar branch from a Git parent branch works in the same way as with native Bazaar branches. Let's test this by branching from an older revision of a Git branch, and then pulling from it to bring it up-to-date:

$ bzr branch -rlast:2 /sandbox/repo.git/ feature1
Branched 1 revisions.

Our local Bazaar branch is out of date, precisely one revision behind, so let's bring it up-to-date by using bzr pull:

$ cd feature1
$ bzr pull
Using saved parent location: /sandbox/repo.git/
+N  hello.pl                                                                   
+N  hello.sh
All changes applied successfully.                                              
Now on revision 2.

Keep in mind that the pull command may rearrange the revisions in the local branch in the same way as it works with native Bazaar branches.

Pushing to Git

To push a Bazaar branch to a Git repository, you must use bzr dpush instead of bzr push. The difference between the two commands is that bzr push is meant to be "lossless" and since some of Bazaar's metadata cannot be pushed to Git losslessly, the command is disabled for Git repositories at the moment. bzr dpush is designed to push revisions to foreign repositories without trying to preserve Bazaar's metadata, and in this way, it can work with Git repositories:

$ bzr dpush file:///sandbox/repo.git,branch=tmp1
Pushed up to revision 3.

This example worked, but only because the tmp1 branch already existed in this example repository. Unfortunately, at the moment, bzr-git cannot create new branches when pushing to a local Git repository; it can only push to an existing branch.

More importantly, notice that we can overwrite the tmp1 branch despite being diverged from it, without bzr-git raising an error or at least issuing a warning. Therefore, you must be very cautious when pushing branches to Git by using bzr dpush.

Merging Git branches

Bazaar is very good at merging Git branches, thanks to a few notable key factors:

  • As bzr-git converts Git branches to native Bazaar branches, the merge operation is ultimately performed between Bazaar branches
  • Bazaar excels at merging, thanks to proper tracking of rename operations, and the many user-friendly and powerful features, such as bzr remerge

Let's try it out by merging two branches, for example, jack into tmp1:

$ bzr branch file:///sandbox/repo.git,branch=jack --no-tree
Branched 4 revisions.
$ cd tmp1/
$ bzr merge ../jack/
+N  hello.rb                                                                   
+N  hello.tcl
All changes applied successfully.

In this example, we fetched jack to a local Bazaar branch before merging from it, but we could have used the remote branch URL directly. However, it is always a good idea to fetch the branch first, as in this way, you can re-use the branch multiple times without redownloading it again from the source repository.

Also notice that we used the --no-tree flag to create the branch. In this way, we can save the disk space, as we don't need the working tree of the branch if we just want to merge from it.

Let's commit the merge:

$ bzr commit -m 'merged from jack' --author gatekeeper
Committing to: /sandbox/git-examples/tmp1/                                   
added hello.rb
added hello.tcl
Committed revision 4.

The merge is now committed locally; we can push it to the remote branch by using bzr dpush:

$ bzr dpush file:///sandbox/repo.git,branch=tmp1
Pushed up to revision 4.

You must be very careful when pushing to a branch using bzr dpush. Since this command overwrites the remote Git branch without warning, it can be dangerous. If the remote branch is changed by others since the last time we fetched it, those changes would be erased. Use with caution.

Tip

Remember that with Bazaar, you can choose from different merge algorithms, which sometimes yield better results with fewer conflicts. The bzr remerge command is especially useful to try a different algorithm on selected files, and the --reprocess flag may help reducing the size of the conflicted area. See Chapter 3, Using Branches, for a detailed explanation with examples.

Merging local branches into Git

Let's create a local branch from master named feature3, and do some commits in it:

$ bzr branch master/ feature3
Branched 2 revisions.                                                          
$ cd feature3/
$ echo >> hello.pl
$ bzr commit -m 'meaningless change'
Committing to: /sandbox/git-examples/feature3/                                 
modified hello.pl
Committed revision 3.
$ echo >> hello.sh                                                             
$ bzr commit -m 'another meaningless change'
Committing to: /sandbox/git-examples/feature3/                                 
modified hello.sh
Committed revision 4.

Next, let's merge this branch into our tmp1 branch, and commit the merge:

$ cd ../tmp1/
$ bzr merge ../feature3/
 M  hello.pl                                                                   
 M  hello.sh
All changes applied successfully.                                              
$ bzr commit -m 'merged from feature3'
Committing to: /sandbox/git-examples/tmp1/                                     
modified hello.pl
modified hello.sh
Committed revision 5.
$ bzr dpush file:///sandbox/repo.git,branch=tmp1         
Pushed up to revision 5.

At this point, the revisions in the feature3 branch and the revision with the merge commit exist only locally, not in Git yet. Naturally, these revisions don't have a Git ID, as we can confirm in the log:

$ bzr log -l1 --show-ids
------------------------------------------------------------
revno: 5 [merge]
revision-id: janos@axiom-20121209162758-r1cggic29iccu4ud
parent: git-v1:3070cdd84f89ae8fc45e2490e897dfe611464749
parent: janos@axiom-20121209162615-46kcj8x3r1czkm57
committer: Janos Gyerik <janos@axiom>
branch nick: tmp1
timestamp: Sun 2012-12-09 17:27:58 +0100
message:
  merged from feature3
------------------------------------------------------------
Use --include-merged or -n0 to see merged revisions.

Let's push the branch to git, and then check the log again:

$ bzr dpush file:///sandbox/repo.git,branch=tmp1
Pushed up to revision 5.                                                       
$ bzr log -l1 --show-ids
------------------------------------------------------------
revno: 5 [merge]
revision-id: git-v1:8ab5cde217d110765fef71b9f1107d65ceb43db1
parent: git-v1:3070cdd84f89ae8fc45e2490e897dfe611464749
parent: git-v1:9d3a2bb239f679c04a2104b99fe2b4a11c04f8e0
git commit: 8ab5cde217d110765fef71b9f1107d65ceb43db1
committer: Janos Gyerik <janos@axiom>
timestamp: Sun 2012-12-09 17:27:58 +0100
message:
  merged from feature3
------------------------------------------------------------
Use --include-merged or -n0 to see merged revisions.

An interesting thing happened—in addition to pushing the local revisions to the Git repository, the IDs of these local revisions have been retroactively changed to values derived from their corresponding Git revision IDs. This may seem a bit strange at first, but it is necessary for the integrity of future interactions with this Git repository, and thus to prevent issues such as accidentally merging the same revisions twice.

Finally, since the parent branches are correctly tracked in Git just like in Bazaar, the parent-child relationships are correctly preserved, as we can confirm by using bzr log:

$ bzr log --line -n0 -l4 file:///sandbox/repo.git,branch=tmp1
5: Janos Gyerik 2012-12-09 [merge] merged from feature3
  2.2.2: Janos Gyerik 2012-12-09 another meaningless change
  2.2.1: Janos Gyerik 2012-12-09 meaningless change
4: gatekeeper <gatek... 2012-12-09 [merge] merged from jack

To conclude, local branches can be merged into Git. However, always keep in mind that bzr dpush may overwrite the remote branch; therefore, use it with caution.

Limitations of bzr-git

The bzr-git plugin has the following limitations:

  • Creating the first branch from a Git repository can be extremely or even intolerably slow, depending upon the size of the repository
  • Creating a branch from a Git repository is sometimes not possible at all, due to bugs and crashes.
  • bzr push does not work
  • bzr dpush can be used instead of bzr push, but it can be dangerous, as it rewrites the revision history without warning even if the branches have diverged
  • The metadata of bugs and renames in Bazaar cannot be transferred to Git

For a more complete and up-to-date list of limitations, refer to the plugin's homepage:

http://doc.bazaar.canonical.com/migration/en/foreign/bzr-on-git-projects.html

Final remarks on bzr-git

For the most part, Bazaar works transparently with Git repositories. The result of a branch operation from Git is a native Bazaar branch, thus all your local operations will be native Bazaar operations that you are used to. However, all interactions with the remote Git repository will be inevitably slower than usual, due to the translation between the protocols of these systems.

As long as you are aware of the limitations and the differences between the two systems, you can use Bazaar as a Git repository client, and take advantage of its advanced merging capabilities. However, be careful when pushing branches with bzr dpush, as it overwrites the remote branch. To be safe, it is best to push only to branches that are owned by you and to which others have only read-only access.

Quick tips and cheat sheet:

  • Be aware of the limitations before you start using Bazaar with Git
  • Always use a shared repository when working with Git
  • Avoid operations directly on remote Git branches; branch from them first and work on the local Bazaar branch instead
  • Feel free to merge Git branches in Bazaar to benefit from Bazaar's unique merging features, such as bzr remerge and the various merging strategies
  • Be very cautious when pushing branches with bzr dpush, as it overwrites the remote branch

The up-to-date details and limitations of the plugin are documented at the following locations:

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.128.226.121