Search code examples
gitgit-checkout

How can I restore only a few lines from a file recorded in a given commit?


I want to restore a few lines from a file recorded in an older commit. I can see those lines by running

git log -p

As a last resort, I'm ready to simply copy those lines from the output of that log, but that would hurt my purist's heart and seems rather unprofessional.

I do not want to simply run git checkout <file> because that would discard local changes made to <file> since the commit in question. Instead, I would like to merge changes from that commit into <file> in the working tree using only pure Git commands.

How can I do that?


Solution

  • Use interactive checkout

    The following git-checkout syntax,

    git checkout --patch <tree-ish> -- <paths>
    

    or, equivalently,

    git checkout -p <tree-ish> -- <paths>
    

    allows you to interactively check out hunks from one or more files, listed in <paths>, as recorded in <tree-ish> (most commonly, a commit).

    See the git-checkout man page for more details.

    Example

    To fix ideas, here is a toy example (irrelevant stdout is omitted):

    # set things up
    $ mkdir test
    $ cd test
    $ git init
    
    # create some content and commit
    $ printf "Hello, world.\n" > README.md
    $ printf "foo\nbar\nbaz\n" > test.txt
    $ git add .
    $ git commit -m "initial commit"
    
    # modify the working tree
    $ printf "another line\n" >> README.md 
    $ printf "foo\nfoo\n" > test.txt
    
    # now restore stuff from test.txt as recorded in master's tip
    $ git checkout -p master -- test.txt
    diff --git b/test.txt a/test.txt
    index 0d55bed..86e041d 100644
    --- b/test.txt
    +++ a/test.txt
    @@ -1,2 +1,3 @@
     foo
    -foo
    +bar
    +baz
    Apply this hunk to index and worktree [y,n,q,a,d,/,e,?]? y
    error: patch failed: test.txt:1
    error: test.txt: patch does not apply
    The selected hunks do not apply to the index!
    Apply them to the worktree anyway? y
    
    # Sanity check: inspect the working tree
    # (the hunk "bar\nbaz" from test.txt was restored, as desired)
    $ cat test.txt
    foo
    bar
    baz
    # (README.md, on the other hand, was not affected, as desired)
    $ cat README.md
    Hello, world.
    another line