`

Introduction to Bran-ching in Per-force

阅读更多

 

by Robert Cowham, Perforce Consulting Partner

 

http://www.vaccaperna.co.uk/scm/branching.html

 

 

Introduction

 

This web page gives an introduction to Perforce branching mechanisms and explains some aspects that may not be obvious at first sight (well they weren't to me anyway!).

This page gives some additional information to Perforce branching mechanisms.

Other references are given at the bottom of this page.

 

 

Branching introduction

 

Perforce's basic mechanism, Inter-File Branching is described on their web page. The main feature is that branches of files are indicated by changing one or more elements of the depot pathname (or location in the Perforce repository), and this change is done by creating a virtual copy of the file using the integrate command.

 

Examples of this are:

 

//depot/main/jam/jam.c

//depot/r1.0/jam/jam.c

 

or

 

//depot/main/jam/...

//depot/r1.0/jam/...

 

for complete trees of files.

 

The component of the depot path that has been modified is "main" and "r1.0" respectively. In this example, we deduce ("elementary my dear Watson") that the version of jam.c in r1.0 is related to a specific version of the same file in main, and indeed that the r1.0 version was released as part of Release 1.0 for the Jam product.

 

This brings up a key point - you can branch a file from anywhere in the repository to anywhere else. Perforce is clever - it will keep track of what is related to what however complex that relationship. But to keep our lives simpler we need to come up with appropriate conventions so that we can easily "see" the relationships when we are browsing the repository (the KISS principle). Like most computer programs Perforce is stupid enough to do exactly what we tell it to do as opposed to what we meant it to do.

 

 

Terminology Warning...

 

There are some words that Perforce uses somewhat (!) ambiguously (most notably using the word "client" when "workspace" is meant (please change this Perforce even though it's a pain to do - it will make training and support much easier...), and "branch" is one of them. This means any one of:

  • a codeline (most likely meaning when used as a noun)
  • a branch view specification (as in the entity created by "p4 branch" command - also a noun) - these are talked about below
  • when used as a verb ("to branch") it means to use the "p4 integrate" command to create a new codeline (or branch!) of one or more files

Usually it is fairly obvious what is meant once you are comfortable with the 3 alternatives, and to test your understanding I will use them interchangeably below...

 

 

 

Noddy1 creates his first branch --- Very good and important example!!!!

 

Noddy has some code sitting in //depot/main/jam/... which he wants to branch into a release codeline for maintenance purposes. During the creation of his new branch the files in //depot/main/jam/... are the "source" files and the "target" files are somewhere else in the repository (//depot/r1.0/jam/... in this instance).

So he does the following:

  • Use "p4 client" and checks that his client workspace view mapping includes the "source" and "target" of his intended branch.
  • Runs "p4 integrate <source files> <target files>"
  • Runs "p4 submit" to submit changes to the repository after which point they become visible to other people.

E.g.

 

1. p4 client shows:

View:
    //depot/main/jam/...   //client/main/...

so he changes this to:

View:
    //depot/main/jam/...   //client/main/...
    //depot/r1.0/jam/...   //client/r1.0/...

 

There is a gotcha in this example - what happens if your mapping originally had //client/... on the right hand side (no "main"). Well remember that if you change the mapping and do a "p4 sync" Perforce will delete all the old files and move them down one level to underneath "main". Make sure you do not have any files opened for editing or similar when you do this.

 

2. He runs the integrate command which actually does most of the work:

p4 integrate //depot/main/jam/... //depot/r1.0/jam/...

Note that this also copies all the files into his client workspace.

 

3. He submits his changes and the new branch is visible in the repository to everyone.

p4 submit

 

 

 

Behind the Scenes

 

Remember that when you branch a set of files, although it appears that Perforce is copying all the files, (e.g. there are 1,000 files in //depot/main/... and it appears as if there are now another 1,000 files in //depot/r1.0/..., giving 2,000 in total), that the newly branched files are just virtual copies. Perforce has duplicated the metadata in its database to say that all the //depot/r1.0/... files now exist, but they are just pointers to specific version of the real files in //depot/main/....

Behind the scenes, the //depot/main/... files actually have RCS format archives (for text files) to store all the details about the contents of each revision (binary files are normally stored as a compressed version of each revision - see "p4 help filetypes" for more information). The files in //depot/r1.0/... only acquire their own archive file on the server when they are modified (p4 edit and then submit). Thus for typical situations where you branch 1,000 files and yet change less than 100, you only get less than 100 new archive files on the server.

 

 

Branch Specs

 

Branch specs are created using the p4 branch command. --- Very important paragraph!!!

The key thing to remember about them is that they are only a shorthand - creating a branch spec does not branch files from its source to its target. Files are actually branched when you use a branch spec with the integrate command - it's the integrate command which does the work (not the branch command).

 

Branch specs are particularly useful when you have multi-line views - they save lots of typing, getting things wrong, forgetting about things etc.

 

Remember that you can always delete branch specs and yet the work that was done with them (using the integrate command) remains done, even after the branch spec has been deleted (they are similar to client workspace specs in this regard). I recommend that people do delete the branch specs when they are no longer needed because if they aren't there, people can't accidentally use the wrong ones - it's always wise to remove temptation from your users...

 

 

Branch Spec Directions

 

Branch specs have a direction (source -> target). You can use the branch spec and reverse the direction with the -r flag (see below).

 

One thing lots of people do is to create a branch spec for a release branch such as:

Branch:    r1.0
View:
    //depot/main/jam/...   //depot/r1.0/jam/...

 

They then normally only make bug fixes to the r1.0 branch and propagate them back to main and almost never in the reverse direction. This means that they always need to use the -r flag:

p4 integrate -r -b r1.0

 

Why not create the branch spec the "wrong" way round for its first usage (to create the branch):

View:
    //depot/r1.0/jam/...   //depot/main/jam/...

 

and then you will not need to use the -r flag in most subsequent uses because you are always going from r1.0 back to main.

 

Don't forget the branch
component in depot path!

 

It is generally a good idea to have at least one component of the depot pathname as your "branch indicator". In the examples above the "main" or "r1.0" components were the indicator.

Sometimes people rush in and add a whole set of files to the depot without thinking about branching in future. For example adding source files to //depot/jam/... instead of //depot/jam/main/... (or similar). If you do this then you may have problems in the future when it comes to creating new branches for these files - what should the naming convention be?

 

 

Some Standard Depot Structures --- branch naming standard

 

So at this point we have covered some of the basics of the details of branching. The thing we haven't touched on is some of the alternative depot structures that are possible and why one might be better than another (in some situations at least).

 

Standard Release Branches - Indicator first

 

As already covered above, there are some very simple and yet effective structures for basic release purposes. E.g.

//depot/main/jam/...

 

is branched to:

//depot/r1.0/jam/...
//depot/r1.1/jam/...

 

This is very straight forward and easy to understand. One potential drawback, is what happens if we have many releases - well we would tend to clutter up the directory naming convention under //depot. An option might be:

//depot/main/jam/...

 

is branched to:

//depot/release/r1.0/jam/...

//depot/release/r1.1/jam/...

 

 

Standard Release Branches - Indicator Second

 

If we have many products each of which we want to branch independently, then we could do something like:

//depot/productA/main/...

 

is branched to:

//depot/productA/r1.0/...
//depot/productA/r1.1/...

or:

//depot/productA/release/r1.0/...
//depot/productA/release/r1.1/...

 

as we prefer.

 

There is no particular difference, but it might make things easier if we distinguish between the different products and don't mix them up (as they might be when indicator came first).

 

Indicator first (again) --- 2008-12-18 reading to here..

Another alternative which is useful when people have development branches (either team or personal) is:

//depot/main/productA/...

//depot/release/productA/r1.0/...
//depot/release/productA/r1.1/...

//depot/dev/personal/Fred/productA/...
//depot/dev/team/blue_team/productA/...

One advantage of this is that the first component of the path indicates the basic use (main, release, etc.). The depths become slightly more complex but this sort of things works rather well. Notice the components in the /dev/personal and /dev/team to make sure people understand what's going on and who "owns" the branch.

Weaving strands together

If we have a number of products each of which has associated documents and tests etc, then one structure is (assume that all paths are rooted under //depot):

/main/src/

All source files

     productA/...

Sources for Product A

     productB/...

Sources for Product B

     productC/...

etc

/main/doc/

All documentation files

     productA/...

Docs for Product A

     productB/...

etc

/main/test/

All test files and documentation

     productA/...

Sources for Product A

     productB/...

etc

Now we can branch "Product A" for release 1.0 as:

 

/release

All source files

   /productA/1.0/

Release 1.0 of Product A

      src/...

Sources

      doc/...

Documentation

      test/...

Test

 

The problem with the above is that when you branch either to create the release branch in the first place or to propagate changes back, you need multiple lines in your view - an excellent time to use branch view specs mind.

As a general guideline, I prefer to have as simple a branch spec as possible to avoid "forgetting" things. I would try to go for one of the examples shown earlier. However, this is not always possible or indeed desirable.

 

 

Protections, Triggers
and Other Paraphernalia

 

If you have structured your repository thoughtfully, it is very straight forward (as an administrator) to use the protect command to create different protections for different branches. For example you can allow all developers write access to the main line, but only a small group to have write access to a particular release branch for bug fixing. Indeed there might be older "frozen" releases which are no longer being supported from which you could remove all write access.

You can also write triggers which monitor submits to specific branches and for example will not allow direct edits to files in that branch but only integrates from other related branches.

(How to implement this is left as an exercise for the reader...)

 

 

Conclusion

 

Perforce offers a very flexible and powerful mechanism for branches with which you can easily shoot yourself in the foot if you are not careful. Think first, think again, plan, and only then start adding, submitting and branching and remember to KISS and you will be OK (and waste less time restructuring your depot later).

This page has shown a few examples and given a few guidelines as to things to think about. The possibilities of course are endless and as long as you have good reasons for doing things and you (and your colleagues) can understand what is going on then branch away - have fun!

I have made no attempt to look at some of the more complex aspects of branching:

  • sibling branches
  • the nitty gritty of propagating changes and partial integrations and the like
  • integration histories
  • scripting branch stuff

These will be covered at a later point.

 

 

References

 

For more examples of uses of branching and the principles involved I suggest you read:

Software Life-Cycle Modelling in Perforce - a good overview

High-level Best Practices in Software Configuration Management - in particular the description of the mainline branching model.

Please send feedback and comments on this page to <script type="text/javascript"></script> web@vaccaperna.co.uk

 

Footnotes

1) For the non-Brits amongst you, Noddy is a character in Enid Blyton's children's books - whole generations of us came across them. Q: Why do elephants have Big Ears? A: Because Noddy wouldn't pay the ransom!

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics