1

I am working on a project that I deploy both on gh-pages and as an android application using cordova/phone gap.

http://github.com/derekmc/html-sandbox

Currently, the code for both deployments is very similar and maintaining separate branches has not been a problem.

However, I recently tried to create a deeper file organization, but phonegapbuild didn't include the files from subdirectories.

I am afraid that to get this to work I am going to have to organize the files in the two branches differently, and move everything in the phonegap branch into a www folder.

I'm not a git expert, but in researching the problem, it appears this will complicate merging between the two branches.

All I found was this question: git merge: apply changes to code that moved to a different file

Is there a practical way to maintain parallel branches with different file organization? What would be the best way to do this?

Is there something I could do to keep the file organization of the two deployments the same?

Community
  • 1
  • 1
derekmc
  • 161
  • 1
  • 7
  • You could put the common code in a directory, and use git cherry-pick when you merge, selecting only that directory. You might try making the common code it's own project and including via a git-submodule in the two main projects: http://git-scm.com/docs/git-submodule. – Jonah Apr 10 '15 at 21:28
  • 1
    I'd investigate making links for the phonegapbuild to follow, have those links created as the first step in that build. – jthill Apr 11 '15 at 00:18

2 Answers2

1

Maintaining different layouts may be partially addressed the answer to the question Why doesn't git attempt to merge changes to renamed files? .

"The default merging strategy merges only the final results, not each commit"

Presumably its just a matter of selecting the appropriate merge strategy?

Community
  • 1
  • 1
Bruce Adams
  • 4,953
  • 4
  • 48
  • 111
  • It's not just the *default* strategy that does this, it's the `git merge` command itself. Even if you write a custom merge driver and install it via `.gitattributes`, your merge driver receives at most 3 commit IDs: the base, the "local" or "ours" commit, and the "remote" or "other" or "theirs" commit (different bits of Git use different terminology here, probably because bits were copied from other merge systems at some point). Meanwhile, most strategies take two heads. The "octopus" strategy deals with many, but refuses to do *anything* with conflicts, sidestepping the "at most 3" problem. – torek Oct 27 '16 at 11:20
  • (I should actually say "file IDs" since merge drivers get file hashes, not commit hashes. The `ours` strategy can resolve multiple heads but ignores all but, well, ours, so that also sidesteps the issue; and if one version is missing, there's no actual merge, so a merge driver really always gets three IDs.) – torek Oct 27 '16 at 11:25
1

You could—I wouldn't, but you could—take the approach that merges are always done from, to, and with a "canonical form" of the tree. (Incidentally, a modified version of this, "canonicalizing" end of line attributes, is what the merge configuration control merge.renormalize is for. There's no equivalent for file names, unfortunately.)

That is, you would make sure that the merge base of any two commits to be merged is always the canonical layout (this will fall out naturally from regular merges, but you will have issues if you ever want to cherry pick a commit). Then, before doing a merge, you would check out each branch, modify the tree to put it into canonical form, and commit. This means that if we draw the graph of commits to be merged:

          o--o--o--A   <-- branch1
         /
...--o--*
         \
          o--o--B      <-- branch2

then the merge base * has the canonical layout, and commit A has the canonical layout, and B has the canonical layout, and Git can simply merge all the files by their canonical names. Let's say the merge goes onto branch2:

          o--o--o--A       <-- branch1
         /          \
...--o--*            \
         \            \
          o--o--B------M   <-- branch2

Now you check out both branches and "de-canonical-form" them if necessary:

          o--o--o--A----o     <-- branch1
         /          \
...--o--*            \
         \            \
          o--o--B------M--o   <-- branch2

and you're ready to continue using them. The future merge base will be commit A, which as we just saw/made, is in "canonical form".

(If the canonical form of the tree matches the form in some branches, those branches do not need transformative pairs applied around merges.)

In practice, we never1 need to do this kind of silliness, as all2 build systems can deal with layout sensibly, or—as jthill suggested in a comment—can be tricked into it.


1"What, never?"

2"What, all... oh never mind." "What, never?"

Community
  • 1
  • 1
torek
  • 448,244
  • 59
  • 642
  • 775
  • What do you mean by all build systems can deal with layout sensibly? Do you mean leave the directory structure alone and use a relative link? – Bruce Adams Oct 27 '16 at 12:58
  • Isn't that making your project's directory tree bend to the needs of your VCS rather than being an independent tool like it ought to be? – Bruce Adams Oct 27 '16 at 13:04
  • @BruceAdams: In order: (1) sure, whatever it takes; (2) yes. That's non-optimal. It might be nice if Git had a way to map from "repository name" to "work-tree name", to work around file name restrictions on Windows and Mac for instance, but it doesn't. If it did, the map would be a way to do this with fewer (but still too many in my opinion) contortions. – torek Oct 27 '16 at 17:21
  • +1 for perforce vs git here. I think I may pursue that with the git maintainers. I imagine it would take a breaking change to fix but its still worth doing IMHO. – Bruce Adams Oct 27 '16 at 17:32