Search code examples
gitformat-patch

git format-patch to generate a patch for a specific file part of a commit


I am trying to merge some files that were added for a feature in a branch called dev. Some of the files are added and some are changed. Is there a way to generate a patch for selected files part of a commit so that they can be applied on master? I am looking to then apply the patch to a master.

git format-patch -1 SHA1 --stdout is generating a patch for the whole commit but I need to generate the patch only specific files in the commit.


Solution

  • Is there a way to generate a patch for selected files part of a commit so that they can be applied on master?

    Maybe (I'm not sure precisely what you are asking for). Let's start with the basic fact that git diff provides, as output, instructions for changing commit X into commit Y. Meanwhile, git format-patch essentially just runs git diff to get the diffs for the patch (as do pretty much all other Git commands that need diffs).

    If you run git diff manually, you can add additional parameters. In particular, git diff accepts a list of pathspecs (basically, file names) after the options and the two commits to compare:

    git diff X Y -- path/to/file
    

    This limits the "how to change the files" instructions output to show just the given file(s). Hence if "for selected files" means "all of the instructions for files A, B, and C, but nothing for files D and E", then a simple:

    git diff X Y -- A B C
    

    will do the trick.

    There is no way to get git format-patch to run git diff like this, but you can simply cut up and re-paste the formatted patch, i.e., use git format-patch as usual, then remove the diff from it and replace it with one generated by your custom git diff.

    A better way

    What if "for selected files" is not quite the right phrase, though? What if you need the patch for files A, B, and C, except that the patch for file B needs to be somewhat different? There is a better, more flexible way to deal with this, which can be summarized as: Don't try to fake it, just do it for real.

    That is, start by checking out the same commit you wish to patch. (Update your own repository if necessary, by running git fetch, so that you have their master as origin/master or another_remote/master. You can add their repository as another remote, e.g., git remote add another_remote url, if necessary.) Then make a new branch of your own, pointing to this particular commit:

    git checkout -b for-patching-them origin/master
    

    (This will also make your branch for-patching-them have the remote-tracking branch as its upstream.)

    Now that you have a branch of your own, you can git cherry-pick the commit, perhaps with -n if you like. You can then alter the changes as much as you want and/or need, test them, and commit. You can commit with --amend, or make many commits and eventually do an interactive rebase and squash the commits, or use whatever Git tools you like.

    Eventually, you will have one or more commits you are ready to send to them, and now you can run:

    git format-patch origin/master
    

    to get the precise patch to send them, without having to edit that patch and hope that it applies. Moreover, if they have updated their branch since you started all this work, you can run git fetch again to pick up their updates, and then git rebase your patch branch to adjust it based on their changes, so that you are again ready to just run git format-patch.