5

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.

Community
  • 1
  • 1
EMiller
  • 2,669
  • 3
  • 29
  • 52

2 Answers2

11

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)

jthill
  • 42,819
  • 4
  • 65
  • 113
  • When using the command "sed -rf mystuff.sed mystuff.patch >justmystuff.patch" Im getting the error "sed: illegal option -- r" Have any idea what it could be? – Mient-jan Stelling Feb 15 '15 at 00:52
  • Use `-E` instead, `-r` is now an historical spelling. Fixed in the answer, thanks. – jthill Feb 15 '15 at 01:37
  • 1
    It would be nice if you can give an explanation on your sed script ! – Neil Jun 27 '16 at 06:34
  • Search and replace with your favourite text editor also works (well, worked for me at least). I just changed the paths and removed the bits that referred to files outside the subdirectory. I didn't touch the commit hashes - and I don't know if the automagical script above does as I'm like @Neil. –  Aug 07 '17 at 09:10
  • Is it possible to make changes that allows you to also keep creations and changes in other particular files or multiple paths? For example if I have a sub-directory `sub-repo-a/` and externally to that I have a file called `.sub-repo-a.settings`. I would like to keep commits that affects ither of these paths. – Kajsa Jul 16 '20 at 11:46
1

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
umläute
  • 23,410
  • 4
  • 50
  • 99