Following history of a copied file from another indirect branch

4 messages, 3 authors, 2016-06-15 · open the first message on its own page

Following history of a copied file from another indirect branch

From: Joshua Jensen <hidden>
Date: 2016-06-15 22:49:50

It has become a necessity to copy a file from one long-lived branch to 
another.  It is not possible to merge the branches at this time.

I would like to have 'git gui blame' follow the copy back through its 
original history, but I don't believe Git has metadata for storing 
this.  Something along the lines of a 'followparent' in the commit 
object, for instance, would allow the revision walking code to wander 
the history down an alternate line.

By comparison, integrates work at a file level in Perforce.  That means 
I can integrate a file from one branch to another, and parentage is 
stored such that I can follow the file back through its history.

Are there any facilities to do this now?

Thanks!

Josh

Re: Following history of a copied file from another indirect branch

From: Brian Gernhardt <hidden>
Date: 2016-06-15 22:49:50

On Oct 21, 2010, at 2:47 PM, Joshua Jensen wrote:
It has become a necessity to copy a file from one long-lived branch to another.  It is not possible to merge the branches at this time.

I would like to have 'git gui blame' follow the copy back through its original history, but I don't believe Git has metadata for storing this.  Something along the lines of a 'followparent' in the commit object, for instance, would allow the revision walking code to wander the history down an alternate line.
Git stores no per-file metadata.  The closest we come is .gitattributes and .gitignore.
By comparison, integrates work at a file level in Perforce.  That means I can integrate a file from one branch to another, and parentage is stored such that I can follow the file back through its history.

Are there any facilities to do this now?
Git simply does not have the idea of the history of a file.  Nothing in git will help merge "just a file" from one branch to another.  Either we have merged the two commits or not.

HOWEVER...

You can use git-filter-branch to create a new branch that contains only that single file and only the commits that affected it.  Something like the following (untested):

	# Merging "file" from branch "src" to branch "dest"
	git checkout -b temp src
	git filter-branch --prune-empty --index-filter="git read-tree --empty; git add file"
	# Since you describe the branch as "long-running", I'd suspect you'll have to wait a while here.
	git checkout dest
	git merge temp
	git branch -d temp
	git branch -D refs/original/temp

This will go faster if you have a ramdisk/tmpfs to perform the filtering in.  (git-filter-branch is very I/O intensive.)  Something like the following in place of the `git filter-branch` invocation above:

	mkdir /tmp/filter-branch # Assuming /tmp is tmpfs or similar
	git filter-branch -d /tmp/filter-branch --prune-empty --index-filter="git read-tree --empty; git add file"
	rm -rf /tmp/filter-branch

You could use --msg-filter to add the SHA-1 of the original commits to the "file history" branch.  Something like --msg-filter='cat;echo;echo From: $GIT_COMMIT'

I would recommend using cherry-pick to pull any further changes to the file across branches (be careful of commits that touch more than that file!).  I think git-filter-branch could be used to keep the one file branch up to date, but that is likely more effort than it's worth.  I would specifically advise against merging the single file branch into both "src" and "dest", as I think any later merge of the two would find these commits as a merge-base.

~~ Brian Gernhardt

Re: Following history of a copied file from another indirect branch

From: Joshua Jensen <hidden>
Date: 2016-06-15 22:49:50

----- Original Message -----
From: Brian Gernhardt
Date: 10/21/2010 1:39 PM
On Oct 21, 2010, at 2:47 PM, Joshua Jensen wrote:
quoted
It has become a necessity to copy a file from one long-lived branch to another.  It is not possible to merge the branches at this time.

I would like to have 'git gui blame' follow the copy back through its original history, but I don't believe Git has metadata for storing this.  Something along the lines of a 'followparent' in the commit object, for instance, would allow the revision walking code to wander the history down an alternate line.
Git stores no per-file metadata.  The closest we come is .gitattributes and .gitignore.
quoted
By comparison, integrates work at a file level in Perforce.  That means I can integrate a file from one branch to another, and parentage is stored such that I can follow the file back through its history.

Are there any facilities to do this now?
Git simply does not have the idea of the history of a file.  Nothing in git will help merge "just a file" from one branch to another.  Either we have merged the two commits or not.
I'm not super interested in per file merging (which is a great concept, 
works well in Perforce, but is irrelevant here).  I merely want to 
preserve the original parentage so facilities like blame (ultimately 
rev-list?) can walk the extended history.  I'm fine even passing in a 
flag.  I do not care in preserving the original parentage for purposes 
of merging.
You can use git-filter-branch to create a new branch that contains only that single file and only the commits that affected it.  Something like the following (untested):

I would recommend using cherry-pick to pull any further changes to the file across branches (be careful of commits that touch more than that file!).  I think git-filter-branch could be used to keep the one file branch up to date, but that is likely more effort than it's worth.  I would specifically advise against merging the single file branch into both "src" and "dest", as I think any later merge of the two would find these commits as a merge-base.
Thanks for the info.

The problem with using cherry-pick is that the commits in question 
contain more than one file.  Perhaps the individual file should have 
been committed separately, but the damage was long ago done.

git format-patch --stdout HEAD..otherbranch -- the/filename | git 
am           or
git diff HEAD..otherbranch -- the/filename | git apply

Seem to be the appropriate methods of copying the file over with fake 
history or squashed together.

Josh

Re: Following history of a copied file from another indirect branch

From: Johannes Sixt <hidden>
Date: 2016-06-15 22:49:50

Am 10/21/2010 20:47, schrieb Joshua Jensen:
It has become a necessity to copy a file from one long-lived branch to
another.  It is not possible to merge the branches at this time.

I would like to have 'git gui blame' follow the copy back through its
original history, but I don't believe Git has metadata for storing this. 
Something along the lines of a 'followparent' in the commit object, for
instance, would allow the revision walking code to wander the history down
an alternate line.
You can branch off one commit form that long-lived branch that undoes
everything except the file F you are interested in since the last
merge-base. Then you merge that single commit into the other branch.

   ---o--o--B     <- long-lived
     /  /    \
    /  /      U   <- the-file
   /  /        \
 -o--A----------M <- master (the other branch)

i.e. 'git diff A..B' shows a lot of changes, but 'git diff A..U' shows
only changes to the file you are interested in. 'git diff -R B..U' differs
from 'git diff A..B' only in the changes to the file you are intersted in.

When you later find that you need new changes to F that were made on
long-lived, but you still cannot merge long-lived, then you can merge
long-lived into the-file (resolve conflicts by removing the conflicted
files and also remove newly added files), and then you merge the-file into
master again.

WARNING: When you later merge long-lived into master, the merge will lose
all changes made on long-lived. You work it around by temporarily grafting
away the merge parents that point to commits listed by
long-lived..the-file. After you complete the merge, you can remove the
grafts again.

-- Hannes
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help