As might be obvious from my previous post, I don’t yet grok git. (It took three tries over about a week to figure out what I posted there.) My other major question as a dual git/subversion user is how do I
svn copy in git? I don’t see that adequately answered anywhere.
The most common use of
svn copy is to branch, which is precisely what I don’t mean here.
git seems to promote branches to a first-order concept, in that the entire git repository exists across branches, and there are specific commands for branching and merging. You can’t have a nonstandard trunk/branch/tag hierarchy like you do sometimes in subversion, because there is no hierarchy. git branches are completely orthogonal to your file structure.
Git From the Bottom Up suggests (perhaps a little facetiously) phrasing your problem in git’s language in order to understand:
Understanding commits is the key to grokking Git. You’ll know you have reached the Zen plateau of branching wisdom when your mind contains only commit topologies, leaving behind the confusion of branches, tags, local and remote repositories….
In these terms, you find branches are really names for other commits besides the master head main trunk commit. It’s not really that branches are first-order things, but that branches are names for commits instead of files. Either way, they’re completely orthogonal to the filesystem.
Looking again just now for the answer to my question, I found this thread, which illustrates git’s current position on copying, and how it’s contrary to this second use of
svn copy that I’m trying to figure out:
Duplicate something in working copy or repository, remembering history.
cp A B; git add B::
Git doesn’t have a direct equivalent of svn copy. It’s arguable whether it needs it once the user knows they can git-add so easily.
Git wins. Git’s ability to detect copies after-the-fact, mean that a git-copy isn’t necessary.
svn copy is more like git checout -b, i.e. it’s primary purpose is not to “copy” things, it is to create branches. You generally do not copy code (I hope).
Well, in fact, I often do copy code with
svn, because I want to fork a file with history. Often I discover when I’m working on (say) some class, I’ve accreted unrelated functionality around the class’s real work, and I need to separate it out. Obviously I can do that just fine and check both parts in, but if I naïvely fork one file in twain—by doing a real file copy and
adding the new file, say—the new one will lose all its history. The first commit git will know about for it is the one where it appears fully formed from Zeus’ head, though it happens to share an equivalent blob with some other file in the commit.
In git terms, you can see why it’s not obvious how to copy with history: to duplicate
svn copy A B, you want git to understand when you ask about B’s history to include all of A’s previous commits. It’s as though you want to change all A’s commits retroactively to include B, sort of. It’s more about the behavior of the tools than anything you can articulate in a git repository’s data.
So I looked for behavior: lo and behold, Andy Parkin’s message above notes that git can “detect copies after-the-fact,” and I guess he means for example
--find-copies-harder options. According to the manual, this seems to be exactly the behavior I need:
Detect copies as well as renames. See also --find-copies-harder.
For performance reasons, by default, -C option finds copies only if the original file of the copy was modified in the same changeset. This flag makes the command inspect unmodified files as candidates for the source of copy. This is a very expensive operation for large projects, so use it with caution. Giving more than one -C option has the same effect.
If only it worked that way. See the terminalcast I did showing what I mean: once I duplicate the file,
svn log doesn’t show
fred’s initial commit in
wilma’s history, even with the
I would be delighted to be wrong, but as far as I can tell, it’s not possible to fork files in
git, while it’s trivial with