Reputation: 2842
I have two git repos that are forks of each other and I need to occasionally import commits from one to the other.
For example:
git-repo1
has this directory structure:
repo1/project1/src
repo1/project2/src
while git-repo2
has the following directory structure:
repo2/src/
What I'd like to do is take a series of commits and generate patches only for commits that altered files within a particular subdirectory (say repo1/project1/src
) and ignore all commits that only alter files anywhere else.
Or alternatively, generate patches for all the commits, but only apply the patch IF it alters files within a particular directory.
I need to preserve the metadata about the commits so playing with git diff
doesn't seem like a viable option.
The directory structure between the forked git repos differs.
Is there a straight forward way to do this?
UPDATE1
I see this question (How to apply a git patch from one repository to another?) in terms of coping with differing directory structures.
But what if the patch speaks of modifying files that simply do not exist? I would like to ignore such changes.
Upvotes: 6
Views: 5244
Reputation: 51
I tried few different methods found in here and other answers but didn't find a solution fitting for me. This is what I found out.
You can give git format-patch
a path as an argument so that it'll create patch only for only those paths.
git format-patch HEAD --root $(git rev-list --max-parents=0 HEAD) --stdout -- repo1/project1/src/ > git.patch
The command git rev-list --max-parents=0 HEAD
is used to fetch the initial commit ref from the repository
Applying the patch can be done with
git am git.patch
In my case I also wanted to skip one directory level when applying the patch because I was moving one whole directory from a repository to a separate repository. git apply
which gets used by git am
has a flag -p<n>
which removes leading path components from the diff paths. The default is 1, so git am -p2 git.patch
did the work for me.
Upvotes: 1
Reputation: 60235
git rev-list --reverse
series
-- repo1/project1/src/ \
| xargs -I@ git format-patch --stdout @^! >mystuff.patch
will spit the commits in series that affect that subdirectory into mystuff.patch
Then,
cat >mystuff.sed <<\EOD
/^(From [0-9a-f]{40}|diff --git )/!{H;$!d}
x
/^From /b
${h;s,.*--,--,;x}
\,^diff[^\n]* [ab]/repo1/project1/src/,!{$!d;x;b}
${p;x}
EOD
and
sed -Ef mystuff.sed mystuff.patch >justmystuff.patch
will strip out all the hunks outside that directory. You can apply with
git am justmystuff.patch
with -p
n
and --directory=new/path/to
as desired.
(edit: EOD --> \EOD so the cat above doesn't try to substitute)
Upvotes: 13
Reputation: 31254
if the two repositories have common history (they are both forked from the same repository, but have evolved differently), you could use cherry-picking to import commits selectively from one branch to another.
create a local repository with two remotes (your two diverging repositories)
find the commits in repositoryA that touch certain files
$ git checkout repoA/master
$ git log sub/dir/ectory
a34256f ...
cherry-pick those commits into the branch of repositoryB
git checkout repoB/master
git cherry-pick a34256f
Upvotes: 1