pick from sibling directories?
I would like to use git cherry-pick to apply a commit from one file to another without rename detection (to many similar files lead to wrong detections).
(master) directory1/file
(master) directory2/file
But I don't know how to tell cherry-pick the corresponding directory.
I had another case where it worked fine with git-1.7.5.rc1
which now supports merge strategies aka -Xsubtree=.
(master) directory1/file
(branch) file
I called
git cherry-pick --no-commit -Xsubtree=directory1 branch~95
and it worked fine, taking the changes from (branch~95) file to (master) directory1/file without rename detection.
For the first case I tried calling git cherry-pick
with - Xsubtree=../directory1
but that did not work. I guess I would have to tell git cherry-pick somehow to leave the directory2 and then go to directory1 to apply the patches.
Does anyone have a solution for this problem ?
At a glance
git-read-tree
For subtrees, I'd look at
git read-tree -u --prefix dir1/ HEAD:dir2
This will not do a merge (git read-tree --merge does not support the --prefix simultaneously...)
manual solution
Otherwise, the best you can do, is probably
basecommitish='HEAD^'
git show "$basecommitish":dir1/a" > /tmp/a.orig
git show HEAD:dir2/b > /tmp/b.new
git merge-file dir1/a /tmp/a.orig /tmp/b.new
This worked for my test repository resulting in correct merge with changes to both dir1/a
and dir2/b
.
Detecting base revisions
Unfortunately, finding the correct basse revision for the merge can be a challenge, as git merge-base
won't work for other object references than commit ids.
Finding last revision where the files were identical
So here is a snippet that will get you started in finding a revision where both files were in synch (looking at the contents only):
git rev-list HEAD | while read sha1
do
blob1=$(git rev-list --objects $sha1:dir1/a)
blob2=$(git rev-list --objects $sha1:dir2/b)
echo $sha1: $blob1 $blob2
if [ "$blob1" == "$blob2" ];
then
echo Match;
break;
fi
done
Output on my testrepo:
c5a6b97712d9ebd49146dad6523b2bbc33aea7c0: 4ce3b294e6408ace53b50127aafb2c9308caacf1 e913153db7650d7b8e947066652cf21388552812
7b75768fd3434c867d3741cf07044bf04ef1cc79: 03b82631ac519bf10c20bb12d3b1b03b872dd087 03b82631ac519bf10c20bb12d3b1b03b872dd087
Match
You can easily include any revisions that might exist on other branches by replacing git rev-list HEAD
by git rev-list --all
.
Finding a pair of revisions where the files were identical
A more advanced script that will look for matching contents in non-matching revisions by doing nested loops would be
function findblobs()
{
for path in "$@";
do
git rev-list HEAD | while read sha1
do
echo $sha1 $(git rev-list --objects "$sha1:$path")
done | uniq -f 1
done
}
Now you can find the same info by doing
findblobs dir1/a dir2/b | sort -k2 | uniq -Ddf 1
// output on testrepo again:
7b75768fd3434c867d3741cf07044bf04ef1cc79 03b82631ac519bf10c20bb12d3b1b03b872dd087
7b75768fd3434c867d3741cf07044bf04ef1cc79 03b82631ac519bf10c20bb12d3b1b03b872dd087
// force multiple hits across several revisions:
git show 7b75768fd3:dir1/a > dir2/b && git commit -am 'force synch with 7b75768fd3'
findblobs dir1/a dir2/b | sort -k2 | uniq -Ddf 1
// output is now:
46b8748f121f8842d936994fa09ad1a81b35d3cc 03b82631ac519bf10c20bb12d3b1b03b872dd087
7b75768fd3434c867d3741cf07044bf04ef1cc79 03b82631ac519bf10c20bb12d3b1b03b872dd087
7b75768fd3434c867d3741cf07044bf04ef1cc79 03b82631ac519bf10c20bb12d3b1b03b872dd087
Since sort(1)
uses a stable sort, you can rely on the first commit hash to correspond to dir1/a
and the second one to dir2/b
in this sample call (note the ordering in the call to findblobs
)
上一篇: 关于PHP类的一些(高级)问题
下一篇: 从兄弟目录中选择?