Search code examples
xcodeatlassian-sourcetreelibgit2git-patchgit-stage

libgit2: how to stage particular lines in a hunk


I am writing a mac application that will allow me to stage only the lines that contain particular text as substring. Basically I try to build that feature that source tree offers for its users. Staging selected lines in the hunks. My selection logic would be, to select the lines that contain a particular text as substring. But I could not figure out how to achieve this with libgit2.

I have initialized the repo like this

int error = git_repository_open(&repo, gitRepoString.UTF8String);

Then I am creating a diff index to working directory like below.

error = git_diff_index_to_workdir(&diff, repo, NULL, NULL);

After that I am able to iterate through the hunks and the lines in each hunk using the call back functions like below.

error = git_diff_foreach(diff, each_file_cb,
                                    each_binary_cb,
                                     each_hunk_cb,
                                     each_line_cb,
                                     &d);

and the callbacks are getting invoked for each line in the hunk.

int each_line_cb(const git_diff_delta *delta,
                 const git_diff_hunk *hunk,
                 const git_diff_line *line,
                 void *payload)
{
    return 0;
}

Now I realize that i need to create a patch somehow and add only the necessary lines in the diff to the patch.

Can any one please guide in right direction? If libgit2 doesn't allow to do this yet, is there any other library that can let me do this. Also atlassian source tree seems to be using libgit2 under the hood. How could they have implemented this?

BTW, the git CLI allows to do that with patching as given in this answer. https://stackoverflow.com/a/32311872/569497


Solution

  • I ended up implementing this manually. It turned out to be easier than I expected.

    My approach for applying a hunk:

    • Split up the lines of the target file into an array
    • Collect the "context" and "old" lines from the hunk, and make sure they match the existing content
    • Collect the "context" and "new" lines, and replace the context/old section in my lines array
    • Write the data back out, trying to match existing line endings

    It should be easy to adapt that to only applying specific lines.

    My code is here (in Swift, using Objective Git): https://github.com/Uncommon/Xit/blob/369dd52d444d4650759c22414121dd2a6be282d2/Xit/XTDiffDelta.swift