gitgithubcherry-pick

How can I cherry-pick only changes to certain files?


If I want to merge the changes made only to some of the files changed in a particular commit, which includes changes to multiple files, into a Git branch, how can this be achieved?

Suppose the Git commit called stuff has changes to files A, B, C, and D, but I want to merge only stuff's changes to files A and B. It sounds like a job for git cherry-pick, but cherry-pick only knows how to merge entire commits, not a subset of the files.


Solution

  • I mentioned before git cherry-pick(2010), and its issues (commit duplicated, 2010, even though it can be re-applied since Git 2.34, Q4 2021).

    But for a file (or files), no need to use the old, obsolete and confusing git checkout command, as in Tyron Wilson's answer

    git restore is the right tool (and it is no longer "experimental" since July 2025, Git 2.51).

    Suppose the Git commit called stuff has changes to files A, B, C, and D, but I want to merge only stuff's changes to files A and B

    Stay on your target branch, and:

    git restore --source=stuff --staged --worktree -- A B
    git commit -m "Pick files A,B from stuff branch"
    

    By default, git restore affects the working tree; --staged targets the index; using both keeps them in sync.

    You can interactively choose hunks within A and B (patch mode) with git restore -p --source=stuff --staged --worktree -- A B.
    Note: renames in stuff will not be "followed" by path-limited restore/checkout; you are copying content by current path names.

    NeilG asks in the comments:

    Could you explain how this works as a checkout?
    It feels like you are changing branches, not merging in changes. Or is it like checking-out a particular file from the existing branch - it writes in changes into the working directory from a source?

    You are not switching branches or doing a merge. You stay on your current branch: HEAD does not move; no branch switch occurs.
    git restore simply copies the content of specific paths (or hunks within them) from a given commit/branch into your index and working tree, after which you make a normal commit.
    That is not a merge: there is no merge-base computation, just content transplantation for the listed paths (or hunks).