Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I generate/apply git patches only for commits that alter specific files

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.

like image 465
EMiller Avatar asked Apr 11 '13 21:04

EMiller


People also ask

How do I create a patch for one file?

You can create a patch file by restricting the output of git diff by listing paths at the end of the command (after a -- to avoid any potential clashes between path names and branch names). Show activity on this post. Will give you three files 0001-[commit] ... 0003-[commit] only containing the Makefile.

What is Apply patch in git?

GIT patch or GIT diff is used to share the changes made by you to others without pushing it to main branch of the repository. This way other people can check your changes from the GIT patch file you made and suggest the necessary corrections.


2 Answers

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)

like image 166
jthill Avatar answered Sep 21 '22 17:09

jthill


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
like image 29
umläute Avatar answered Sep 24 '22 17:09

umläute