Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for format-patch #2261

Merged
merged 9 commits into from
Apr 16, 2014
Merged

Support for format-patch #2261

merged 9 commits into from
Apr 16, 2014

Conversation

jacquesg
Copy link
Contributor

This PR adds support for git format-patch behaviour. This is something we need to have for rebases #2253 and core git compatibility (git rebase uses git am).

It currently cannot generate a "patch" for merge commits (depends on #1965) or binary files.

#include "buffer.h"
#include "util.h"

int write_file_modes_tobuf(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to be missing static, same for the function below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

Allows for inserting the same character n amount of times
return error;
}

int git_format_patch(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We try to have an object-like namespace. (Eg, git_blob is an object and git_blob_foo is a foo on a blob.) With that in mind, I think that git_patch_format would be more appropriate as a name.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had the same idea. But ...

We already have the concept of a git_patch, which is not quite the same. This is more a collection of patches.

@ethomson
Copy link
Member

By the way, I am 👍 👍 👍 on the thorough test cases that you're including in your PRs. Thanks!

@jacquesg
Copy link
Contributor Author

When #1965 is complete @arbee 😉, they will have to be extended in order to cover merge commits.

@arrbee
Copy link
Member

arrbee commented Apr 10, 2014

Regarding the naming of the function, to me this feels like it is a flattening of git_diff_commit() to generate a git_diff for the commit (a git_diff is more-or-less a collection of patches, after all) and then a special formatting function for the git_diff that knows how to do all the extra things that git format-patch does.

We could shoehorn the special formatting into git_diff_print(), but I think that may not be a good idea. Instead, can we just have a git_diff_format_email that takes a git_diff plus extra parameters to generate proper email headers (i.e. flag for [PATCH] plus values for patch sequence numbers)?

Instead of writing:

git_commit_lookup(&commit, repo, &oid);
git_format_patch(&buf, repo, commit, 1, 1, NULL);

you would write the slightly more verbose:

git_diff_format_email_options email_opts;

git_commit_lookup(&commit, repo, &oid);

email_opts.patch_no = 1;
email_opts.total_patches = 1;
email_opts.subject_prefix = NULL; /* default to "[PATCH]" */
email_opts.signature = git_commit_author(commit);
email_opts.message = git_commit_summary(commit);

git_diff_commit(&diff, commit, NULL);
git_diff_format_email(&buf, diff, &email_opts);
git_diff_free(diff);

To me, this second alternative seems to fix more neatly into the existing namespaces. However, I recognize that it is much more verbose and there is some messiness in setting up the email options correctly in order to generate appropriate patches.

One thought, depending on whether you like or hate this alternative proposal would be to break things down a la the second proposal (which would give libgit2 users more flexibility in formatting various diffs for email, not just single commits), and also provide a git_diff_commit_as_email API that wrapped the 10 lines of code into a single convenience API.

@jacquesg
Copy link
Contributor Author

Messiness is an understatement 😉. The part that took the longest was to print all the prettiness that core git does, took pretty much 85% of the time.

Moving it to git_diff_format_email sound good, tried to not "rock the boat" too much. The only thing about the above git_diff_format_email_options.subject_prefix that won't quite work is that depending on the patch count, it could be [PATCH] or [PATCH 1/2]. Leaving it as a boolean is more robust. Thoughts?

@jacquesg
Copy link
Contributor Author

What I meant by it won't work is that it will be hard to inject the patch number and count if the prefix is provided by the user.

@arrbee
Copy link
Member

arrbee commented Apr 10, 2014

Leaving it as a boolean is more robust. Thoughts?

Oh, that was just my overly quick reading of the meaning of the flag. Sorry! Keeping it a boolean is perfectly fine.

At a basic level, does this restructuring of the API otherwise seem to make sense? I have three motivations for proposing it:

  1. It allows the user to more naturally pass options to the diff generation phase (which covers a ton of the command line options to git format-patch, such as running rename detection, etc.)
  2. To me, it feels slightly less redundant with the (TBD) git_diff_commit API
  3. Users could generate pretty emails for other diffs, such as collapsing a series of commits by generating the diff from an arbitrary pair of trees

By adding the email formatting options structure, we can (incrementally) add flags / fields to support --no-stat, --attach, --thread, etc. Obviously, the API doesn't require my proposed restructuring to achieve this, but it does distinguish between where we would use the existing git_diff_options and a new options structure with email details.

@jacquesg
Copy link
Contributor Author

Genius! I'll make the changes. Maybe I got a little bit blinded by how close I am to this.

@jacquesg
Copy link
Contributor Author

@arrbee Is this what you meant? Note that I have added git_diff__commit internally. It will return an error when encountering a merge commit which should be ok for now.

@jacquesg
Copy link
Contributor Author

@arrbee So I'm trying to make this a little bit more generic, i.e. get --stat, --shortstat and --numstat information not only for format_email.

I've added a test case for a git_diff on which git_diff_find_similar has been invoked. What I'm seeing as that there are no hunks if the file was only renamed (no content change). The problem I've found is that its not really possible to report the line number statistics for these files. If the content has also changed, its not a problem.

Any suggestions or advice?

@jacquesg
Copy link
Contributor Author

So I got this to do the right thing (still a bit of refactoring todo), except for binary files.

@arrbee I've added a test case to ensure --stat functionality works even for binary files, but it seems like we don't have the actual file size for the new file. Core git reports

binary.bin | Bin 3 -> 5 bytes whereas I'm getting binary.bin | Bin 3 -> 0 bytes. I'm using the size value from git_diff_file->size.

char commit_oidstr[GIT_OID_HEXSZ + 1];

git_oid_fmt(commit_oidstr, git_commit_id(commit));
commit_oidstr[GIT_OID_HEXSZ] = '\0';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

git_oid_tostr does the same thing as these two lines :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...and it returns a pointer to the stack buffer so you can pass it directly in the varargs in giterr_set.

char buf[GIT_OID_HEXSZ + 1];
giterr_set(GITERR_INVALID, "Commit %s is a merge commit", git_commit_tostr(buf, 41, git_commit_id(commit)));

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sweet! I'll use that instead :)

@vmg
Copy link
Member

vmg commented Apr 14, 2014

This is brilliant work by the way. Just that small nitpick and I think this is ready to merge. :)

@jacquesg
Copy link
Contributor Author

I'm still refactoring slightly, as I'm understanding the code base better :) I should finish it off tonight (I hope)

@jacquesg
Copy link
Contributor Author

I'm happy with this, feel that the test cases cover everything.

@jacquesg
Copy link
Contributor Author

Ready to merge?

@vmg
Copy link
Member

vmg commented Apr 16, 2014

I think so. :)

vmg pushed a commit that referenced this pull request Apr 16, 2014
@vmg vmg merged commit c5cacc4 into libgit2:development Apr 16, 2014
@vmg
Copy link
Member

vmg commented Apr 16, 2014

Lovely job again. Can't wait to see what's next. :)

@jacquesg
Copy link
Contributor Author

🤘

@jacquesg
Copy link
Contributor Author

Do we auto update the gh-pages? Looks like they are a little bit stale?

@arthurschreiber
Copy link
Member

Summoning @carlosmn is the current way to "auto update the gh-pages". 😄

@jacquesg
Copy link
Contributor Author

Haha, maybe some incarnation of a post-receive hook would do the trick, don't know how flexible github is with it :)

@arthurschreiber
Copy link
Member

We could also use Travis to do that. :)

phatblat pushed a commit to phatblat/libgit2 that referenced this pull request Sep 13, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants