6 static void check(int error
, const char *message
)
9 fprintf(stderr
, "%s (%d)\n", message
, error
);
14 static int resolve_to_tree(
15 git_repository
*repo
, const char *identifier
, git_tree
**tree
)
18 git_object
*obj
= NULL
;
20 if ((err
= git_revparse_single(&obj
, repo
, identifier
)) < 0)
23 switch (git_object_type(obj
)) {
25 *tree
= (git_tree
*)obj
;
28 err
= git_commit_tree(tree
, (git_commit
*)obj
);
42 "\033[32m", /* green */
47 const git_diff_delta
*delta
,
48 const git_diff_range
*range
,
54 int *last_color
= data
, color
= 0;
56 (void)delta
; (void)range
; (void)line_len
;
58 if (*last_color
>= 0) {
60 case GIT_DIFF_LINE_ADDITION
: color
= 3; break;
61 case GIT_DIFF_LINE_DELETION
: color
= 2; break;
62 case GIT_DIFF_LINE_ADD_EOFNL
: color
= 3; break;
63 case GIT_DIFF_LINE_DEL_EOFNL
: color
= 2; break;
64 case GIT_DIFF_LINE_FILE_HDR
: color
= 1; break;
65 case GIT_DIFF_LINE_HUNK_HDR
: color
= 4; break;
68 if (color
!= *last_color
) {
69 if (*last_color
== 1 || color
== 1)
70 fputs(colors
[0], stdout
);
71 fputs(colors
[color
], stdout
);
80 static int check_uint16_param(const char *arg
, const char *pattern
, uint16_t *val
)
82 size_t len
= strlen(pattern
);
85 if (strncmp(arg
, pattern
, len
))
87 if (arg
[len
] == '\0' && pattern
[len
- 1] != '=')
91 strval
= strtoul(arg
+ len
, &endptr
, 0);
98 static int check_str_param(const char *arg
, const char *pattern
, const char **val
)
100 size_t len
= strlen(pattern
);
101 if (strncmp(arg
, pattern
, len
))
103 *val
= (const char *)(arg
+ len
);
107 static void usage(const char *message
, const char *arg
)
110 fprintf(stderr
, "%s: %s\n", message
, arg
);
112 fprintf(stderr
, "%s\n", message
);
113 fprintf(stderr
, "usage: diff [<tree-oid> [<tree-oid>]]\n");
123 int main(int argc
, char *argv
[])
125 git_repository
*repo
= NULL
;
126 git_tree
*t1
= NULL
, *t2
= NULL
;
127 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
128 git_diff_find_options findopts
= GIT_DIFF_FIND_OPTIONS_INIT
;
130 int i
, color
= -1, format
= FORMAT_PATCH
, cached
= 0;
131 char *a
, *treeish1
= NULL
, *treeish2
= NULL
;
132 const char *dir
= ".";
136 /* parse arguments as copied from git-diff */
138 for (i
= 1; i
< argc
; ++i
) {
142 if (treeish1
== NULL
)
144 else if (treeish2
== NULL
)
147 usage("Only one or two tree identifiers can be provided", NULL
);
149 else if (!strcmp(a
, "-p") || !strcmp(a
, "-u") ||
150 !strcmp(a
, "--patch"))
151 format
= FORMAT_PATCH
;
152 else if (!strcmp(a
, "--cached"))
154 else if (!strcmp(a
, "--name-status"))
155 format
= FORMAT_COMPACT
;
156 else if (!strcmp(a
, "--raw"))
158 else if (!strcmp(a
, "--color"))
160 else if (!strcmp(a
, "--no-color"))
162 else if (!strcmp(a
, "-R"))
163 opts
.flags
|= GIT_DIFF_REVERSE
;
164 else if (!strcmp(a
, "-a") || !strcmp(a
, "--text"))
165 opts
.flags
|= GIT_DIFF_FORCE_TEXT
;
166 else if (!strcmp(a
, "--ignore-space-at-eol"))
167 opts
.flags
|= GIT_DIFF_IGNORE_WHITESPACE_EOL
;
168 else if (!strcmp(a
, "-b") || !strcmp(a
, "--ignore-space-change"))
169 opts
.flags
|= GIT_DIFF_IGNORE_WHITESPACE_CHANGE
;
170 else if (!strcmp(a
, "-w") || !strcmp(a
, "--ignore-all-space"))
171 opts
.flags
|= GIT_DIFF_IGNORE_WHITESPACE
;
172 else if (!strcmp(a
, "--ignored"))
173 opts
.flags
|= GIT_DIFF_INCLUDE_IGNORED
;
174 else if (!strcmp(a
, "--untracked"))
175 opts
.flags
|= GIT_DIFF_INCLUDE_UNTRACKED
;
176 else if (check_uint16_param(a
, "-M", &findopts
.rename_threshold
) ||
177 check_uint16_param(a
, "--find-renames",
178 &findopts
.rename_threshold
))
179 findopts
.flags
|= GIT_DIFF_FIND_RENAMES
;
180 else if (check_uint16_param(a
, "-C", &findopts
.copy_threshold
) ||
181 check_uint16_param(a
, "--find-copies",
182 &findopts
.copy_threshold
))
183 findopts
.flags
|= GIT_DIFF_FIND_COPIES
;
184 else if (!strcmp(a
, "--find-copies-harder"))
185 findopts
.flags
|= GIT_DIFF_FIND_COPIES_FROM_UNMODIFIED
;
186 else if (!strncmp(a
, "-B", 2) || !strncmp(a
, "--break-rewrites", 16)) {
187 /* TODO: parse thresholds */
188 findopts
.flags
|= GIT_DIFF_FIND_REWRITES
;
190 else if (!check_uint16_param(a
, "-U", &opts
.context_lines
) &&
191 !check_uint16_param(a
, "--unified=", &opts
.context_lines
) &&
192 !check_uint16_param(a
, "--inter-hunk-context=",
193 &opts
.interhunk_lines
) &&
194 !check_str_param(a
, "--src-prefix=", &opts
.old_prefix
) &&
195 !check_str_param(a
, "--dst-prefix=", &opts
.new_prefix
) &&
196 !check_str_param(a
, "--git-dir=", &dir
))
197 usage("Unknown arg", a
);
202 check(git_repository_open_ext(&repo
, dir
, 0, NULL
),
203 "Could not open repository");
206 check(resolve_to_tree(repo
, treeish1
, &t1
), "Looking up first tree");
208 check(resolve_to_tree(repo
, treeish2
, &t2
), "Looking up second tree");
211 /* <sha1> --cached */
217 check(git_diff_tree_to_tree(&diff
, repo
, t1
, t2
, &opts
), "Diff");
218 else if (t1
&& cached
)
219 check(git_diff_tree_to_index(&diff
, repo
, t1
, NULL
, &opts
), "Diff");
221 git_diff_list
*diff2
;
222 check(git_diff_tree_to_index(&diff
, repo
, t1
, NULL
, &opts
), "Diff");
223 check(git_diff_index_to_workdir(&diff2
, repo
, NULL
, &opts
), "Diff");
224 check(git_diff_merge(diff
, diff2
), "Merge diffs");
225 git_diff_list_free(diff2
);
228 check(resolve_to_tree(repo
, "HEAD", &t1
), "looking up HEAD");
229 check(git_diff_tree_to_index(&diff
, repo
, t1
, NULL
, &opts
), "Diff");
232 check(git_diff_index_to_workdir(&diff
, repo
, NULL
, &opts
), "Diff");
234 if ((findopts
.flags
& GIT_DIFF_FIND_ALL
) != 0)
235 check(git_diff_find_similar(diff
, &findopts
),
236 "finding renames and copies ");
239 fputs(colors
[0], stdout
);
243 check(git_diff_print_patch(diff
, printer
, &color
), "Displaying diff");
246 check(git_diff_print_compact(diff
, printer
, &color
), "Displaying diff");
249 check(git_diff_print_raw(diff
, printer
, &color
), "Displaying diff");
254 fputs(colors
[0], stdout
);
256 git_diff_list_free(diff
);
259 git_repository_free(repo
);
261 git_threads_shutdown();