pg MERGING PATCHES AND FILES ============================ INTRODUCTION ------------ This document covers how pg merges changes contained in patches and how to resolve merge conflicts when they occur. WHEN DO MERGES OCCUR? --------------------- Formal explanation: pg performs an automatic merge whenever a patch is pushed onto a patch series with `pg-push` and the `base` of the patch being pushed is not equal to `HEAD`. Less formal explanation: Merging is required when there are changes currently present in the repository which did not exist when the patch was originally written (or last modified). This can occur for example if you switch two different patches around on the stack: ------------------------------------------------ $ pg-new P1 $ vi hello.c $ pg-ci -m"Use 'Hi World.'" $ pg-new P2 $ vi hello.c $ pg-ci -m"Always greet Bob, not the world." $ pg-series + P1 +> P2 $ pg-pop -a $ pg-push P2 # caused a merge $ pg-push P1 # caused a merge $ pg-series + P2 +> P1 ------------------------------------------------ At the time that P2 was changed (to greet Bob) the changes from P1 were present in the working directory. We can say that P2 built upon the base supplied by P1 and hence its `base` is a commit which contains P1's changes. When P2 is pushed (after the `pg-pop -a`) P1's changes are not present in the working directory (as P1 was also popped off). This means that the current `HEAD` of the working directory does not match the `base` of P2. The `base` of P2 is a commit which contains the changes in P1, and those changes aren't present in the working directory. In this scenario `pg-push` will attempt to merge the changes made with `pg-ci` while P2 was the top-most applied patch into the current working directory. It will generally succeed, but it can fail. If `pg-push` fails you have unmerged files whose conflicts must be manually resolved. SUCCESSFUL AUTOMATIC MERGES --------------------------- If `pg-push` was able to successfully merge the changes contained in P2 into the working directory it will return without producing any output. This is keeping with the UNIX tradition of ``no news is good news''. DETECTING UNMERGED FILES (MERGE CONFLICTS) ------------------------------------------ If `pg-push` fails to merge it will warn you with output such as the following: ------------------------------------------------ $ pg-push P2 2 out of 2 hunks FAILED -- saving rejects to file hello.c-rej 1 out of 2 hunks ALREADY APPLIED -- saving rejects to file hello.c-rej Patch 'P2' has unmerged files (see pg-resolved): U hello.c ------------------------------------------------ We first see output from the `patch` program while it tries to update the file `hello.c` with the changes contained in patch P2. The output indicates that two different regions (hunks) of text needed to be changed, and neither could be updated automatically as the change is ambiguous to patch. However one of these hunks was already applied and thus isn't really a reject. After all files are merged (or attempted to be merged) `pg-push` will show the unmerged files (if any). As the developer you will need to manually fix up these unmerged files. You can also view the unmerged files with pg-status: ------------------------------------------------ $ pg-status U hello.c M hello.c ------------------------------------------------ The U status indicates the file is still unmerged and the M status indicates the current file on disk (hello.c) is/has been modified by the merge. FIXING UNMERGED FILES --------------------- When `pg-push` fails to merge cleanly it will leave you with a number of files. In the example that we have been working with (P2) hello.c did not merge, so `pg-push` will leave us the following files: ------------------------------------------------ $ ls hello.c* hello.c hello.c-head hello.c-last hello.c-pbase hello.c-rej ------------------------------------------------ and `pg-status` will show the unmerged file: ------------------------------------------------ $ pg-status U hello.c M hello.c ------------------------------------------------ So what are the files left behind by `pg-push`? - hello.c : The merged version of the file. This is the content of hello.c-head with the differences between hello.c-pbase and hello.c-last applied. Only hunks which were able to be applied automatically by patch will appear here. Regions which should have had changes applied but whose hunks failed will be unaffected (they contain what was contributed by hello.c-head). This is decidedly different from the RCS/CVS merge behavior and it means this file is probably compilable source code. - hello.c-head : The version of hello.c we are trying to apply the patch to. Unlike hello.c this version is not affected. A comparsion of hello.c-head and hello.c will show the changes that were successfully applied by the patch command. - hello.c-last : The last version of hello.c contained in the patch. This is the last version of the file as modified by the patch. The patch can be reconstructed by comparing hello.c-pbase to hello.c-last (in that order). This is the comparsion `pg-patch` used to obtain the input for the patch command. - hello.c-pbase : The version of hello.c before the patch was started. - hello.c-rej : The hunks which did not apply to hello.c but which came from the difference between hello.c-pbase and hello.c-last. These are presented in context diff format with approximate line numbers taken from (the merged) hello.c. As the developer of hello.c it is now your responsibility to review hello.c and the four supporting files to determine how to finish merging patch P2 into hello.c. You can do this using whatever editor or diff viewer you prefer. [NOTE] If you use a 3 way diff viewer to work on this merge you might want to use '-pbase' as the "base revision", '-head' as the "theirs/remote revision" and '-last' as the "mine/local revision" of the file. [NOTE] Why is the base version called '-pbase'? I frequently use the Eclipse IDE and its 3 way comparsion feature requires that the files being compared are sorted lexograpically into the order: Right, Left, Common Ancestor. Yeah I think that should be considered a bug in Eclipse. Not including the 'p' will cause Eclipse to show the wrong comparsion, so I inserted the 'p'. I'm not happy about it. When merging is complete you need to tell pg this through the `pg-resolved` command: ------------------------------------------------ $ pg-resolved hello.c Mark hello.c resolved? (y/n) y ------------------------------------------------ To keep you from marking every file in your directory resolved by accident `pg-resolved` will prompt you for confirmation. Once a file has been marked as resolved with `pg-resolved` its 'U' record in `pg-status` will go away and the extra files will also be deleted: ------------------------------------------------ $ pg-status M hello.c $ ls hello.c* hello.c ------------------------------------------------ When all files are resolved you should record the result of the merge with `pg-ci`.