Question

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.

Was it helpful?

Solution

git rev-list --reverseseries-- 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 -pn and --directory=new/path/to as desired.

(edit: EOD --> \EOD so the cat above doesn't try to substitute)

OTHER TIPS

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

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top