1

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

Community
  • 1
  • 1
Selvin
  • 12,333
  • 17
  • 59
  • 80
  • There isn't an easy way to do this yet. We have a set of patches in our fork (https://github.com/stinb/libgit2/tree/gitahead) that add support for partial patch application. I'd like to try to get these upstreamed soon. I'll post a link to the PR after I submit it. – Jason Haslam Mar 27 '17 at 21:04
  • BTW, I don't know how SourceTree does it, but I suspect that it doesn't rely on libgit2 functionality. – Jason Haslam Mar 27 '17 at 21:06
  • 1
    FWIW, I submitted a pull request (https://github.com/libgit2/libgit2/pull/4184) to enable partial patch application. If that gets merged I can add an answer that explains how to use it to implement staging of individual hunks and lines. – Jason Haslam Mar 29 '17 at 04:33
  • Thanks a lot @JasonHaslam looking forward to see your solution! – Selvin Apr 03 '17 at 08:28

1 Answers1

3

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

Uncommon
  • 3,323
  • 2
  • 18
  • 36