1 diff --git a/NEWS b/NEWS
2 index 7e219af..a0f75c6 100644
14 + - Display repository references in the sorted order: tags, heads,
15 + tracked remotes, remotes.
16 + - Add bash completion for blame.
20 + - Separate blame revision and file argument by "--" to avoid problems.
21 + - Main view: fix redrawing of the last commit wrt. the revision graph.
22 + - Fix waiting for input after executing a run request in pager mode.
27 diff --git a/contrib/tig-completion.bash b/contrib/tig-completion.bash
28 index 79b414b..40bfcfa 100755
29 --- a/contrib/tig-completion.bash
30 +++ b/contrib/tig-completion.bash
31 @@ -182,6 +182,26 @@ _tig_options ()
32 __tig_complete_revlist
37 + local reply="" ref=HEAD cur="${COMP_WORDS[COMP_CWORD]}"
39 + if test "$COMP_CWORD" -lt 3; then
40 + reply="$(__tig_refs)"
42 + ref="${COMP_WORDS[2]}"
45 + reply="$reply $(git --git-dir="$(__tigdir)" ls-tree "$ref" \
46 + | sed '/^100... blob /s,^.* ,,
57 local cur="${COMP_WORDS[COMP_CWORD]}"
58 @@ -218,12 +238,13 @@ _tig ()
59 case "${COMP_WORDS[COMP_CWORD]}" in
60 --*=*) COMPREPLY=() ;;
62 - *) _tigcomp "status show $(__tig_refs)" ;;
63 + *) _tigcomp "blame status show $(__tig_refs)" ;;
69 + blame) _tig_blame ;;
73 diff --git a/manual.txt b/manual.txt
74 index f11b77a..447dec0 100644
77 @@ -44,7 +44,7 @@ given command and all will be shell quoted before they are passed to the
80 NOTE: If you specify options for the main view, you should not use the
81 -`--pretty` option as this option will be set automatically to the format
82 +`\--pretty` option as this option will be set automatically to the format
83 expected by the main view.
85 Example on how to view a commit and show both author and committer
86 @@ -54,100 +54,10 @@ information:
87 $ tig show --pretty=fuller
88 -----------------------------------------------------------------------------
90 -See the <<refspec, "Specifying revisions">> section below for an introduction
91 -to revision options supported by the git commands. For details on specific git
92 +See the section on <<refspec, specifying revisions>> for an introduction to
93 +revision options supported by the git commands. For details on specific git
94 command options, refer to the man page of the command in question.
97 -Environment Variables
98 ----------------------
100 -Several options related to the interface with git can be configured via
101 -environment options.
103 -[[configuration-files]]
107 -Upon startup, tig first reads the system wide configuration file
108 -(`{sysconfdir}/tigrc` by default) and then proceeds to read the user's
109 -configuration file (`~/.tigrc` by default). The paths to either of these files
110 -can be overridden through the following environment variables:
113 - Path of the user configuration file.
116 - Path of the system wide configuration file.
119 -Repository References
120 -~~~~~~~~~~~~~~~~~~~~~
122 -Commits that are referenced by tags and branch heads will be marked by the
123 -reference name surrounded by '[' and ']':
125 ------------------------------------------------------------------------------
126 -2006-03-26 19:42 Petr Baudis | [cogito-0.17.1] Cogito 0.17.1
127 ------------------------------------------------------------------------------
129 -If you want to filter out certain directories under `.git/refs/`, say `tmp`
130 -you can do it by setting the following variable:
132 ------------------------------------------------------------------------------
133 -$ TIG_LS_REMOTE="git ls-remote . | sed /\/tmp\//d" tig
134 ------------------------------------------------------------------------------
136 -Or set the variable permanently in your environment.
139 - Set command for retrieving all repository references. The command
140 - should output data in the same format as git-ls-remote(1).
142 -[[history-commands]]
146 -It is possible to alter which commands are used for the different views. If
147 -for example you prefer commits in the main view to be sorted by date and only
148 -show 500 commits, use:
150 ------------------------------------------------------------------------------
151 -$ TIG_MAIN_CMD="git log --date-order -n500 --pretty=raw %s" tig
152 ------------------------------------------------------------------------------
154 -Or set the variable permanently in your environment.
156 -Notice, how `%s` is used to specify the commit reference. There can be a
157 -maximum of 5 `%s` ref specifications.
160 - The command used for the diff view. By default, git show is used
164 - The command used for the log view. If you prefer to have both
165 - author and committer shown in the log view be sure to pass
166 - `--pretty=fuller` to git log.
169 - The command used for the main view. Note, you must always specify
170 - the option: `--pretty=raw` since the main view parser expects to
178 - The command used for the tree view. Takes two arguments, the first
179 - is the revision ID and the second is the path of the directory tree,
180 - empty for the root directory. Defaults to "git ls-tree %s %s".
183 - The command used for the blob view. Takes one argument which is
184 - the blob ID. Defaults to "git cat-file blob %s".
189 @@ -167,18 +77,6 @@ You will split the view so that the log view is displayed in the top window
190 and the diff view in the bottom window. You can switch between the two views
191 by pressing 'Tab'. To maximize the log view again, simply press 'l'.
194 -Current Head and Commit ID
195 -~~~~~~~~~~~~~~~~~~~~~~~~~~
197 -The viewer keeps track of both what head and commit ID you are currently
198 -viewing. The commit ID will follow the cursor line and change every time
199 -you highlight a different commit. Whenever you reopen the diff view it will be
200 -reloaded, if the commit ID changed.
202 -The head ID is used when opening the main and log view to indicate from what
203 -revision to show history.
208 @@ -226,7 +124,30 @@ The pager view::
209 commands entered in the internal prompt.
212 - Displays key binding quick reference.
213 + Displays a quick reference of key bindings.
216 +Browsing State and User-defined Commands
217 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
219 +The viewer keeps track of both what head and commit ID you are currently
220 +viewing. The commit ID will follow the cursor line and change every time you
221 +highlight a different commit. Whenever you reopen the diff view it will be
222 +reloaded, if the commit ID changed. The head ID is used when opening the main
223 +and log view to indicate from what revision to show history.
225 +Some of the commands used or provided by tig can be configured. This goes for
226 +the <<external-commands, external commands>>. These user-defined commands can
227 +use arguments that refer to the current browsing state by using one of the
228 +following variables.
230 +`-----------------------`-----------------------------------------------------
231 +Browsing state variables
232 +------------------------------------------------------------------------------
233 +%(head) The currently viewed 'head' ID. Defaults to HEAD
234 +%(commit) The currently selected commit ID.
235 +%(blob) The currently selected blob ID.
236 +------------------------------------------------------------------------------
240 @@ -247,6 +168,134 @@ be appended:
241 [main] 77d9e40fbcea3238015aea403e06f61542df9a31 - commit 1 of 779 (0%) 5s
242 -----------------------------------------------------------------------------
245 +Environment Variables
246 +---------------------
248 +Several options related to the interface with git can be configured via
249 +environment options.
251 +[[configuration-files]]
255 +Upon startup, tig first reads the system wide configuration file
256 +(`{sysconfdir}/tigrc` by default) and then proceeds to read the user's
257 +configuration file (`~/.tigrc` by default). The paths to either of these files
258 +can be overridden through the following environment variables:
261 + Path of the user configuration file.
264 + Path of the system wide configuration file.
267 +Repository References
268 +~~~~~~~~~~~~~~~~~~~~~
270 +Commits that are referenced by tags and branch heads will be marked by the
271 +reference name surrounded by '[' and ']':
273 +-----------------------------------------------------------------------------
274 +2006-03-26 19:42 Petr Baudis | [cogito-0.17.1] Cogito 0.17.1
275 +-----------------------------------------------------------------------------
277 +If you want to filter what branches gets shown, say limit to only show
278 +branches named `master` or which starts with the `jf/` prefix, you can
279 +do it by setting the following variable:
281 +-----------------------------------------------------------------------------
282 +$ TIG_LS_REMOTE="git ls-remote . master jf/*" tig
283 +-----------------------------------------------------------------------------
285 +Or set the variable permanently in your environment.
291 + Set command for retrieving all repository references. The command
292 + should output data in the same format as git-ls-remote(1). Defaults
294 +-----------------------------------------------------------------------------
296 +-----------------------------------------------------------------------------
300 +[[history-commands]]
304 +It is possible to alter which commands are used for the different views. If
305 +for example you prefer commits in the main view to be sorted by date and only
306 +show 500 commits, use:
308 +-----------------------------------------------------------------------------
309 +$ TIG_MAIN_CMD="git log --date-order -n500 --pretty=raw %s" tig
310 +-----------------------------------------------------------------------------
312 +Or set the variable permanently in your environment.
314 +Notice, how `%s` is used to specify the commit reference. There can be a
315 +maximum of 5 `%s` ref specifications.
321 + The command used for the diff view. Defaults to:
322 +-----------------------------------------------------------------------------
323 +git show --pretty=fuller --no-color --root
324 + --patch-with-stat --find-copies-harder -C %s
325 +-----------------------------------------------------------------------------
329 + The command used for the log view. If you prefer to have both
330 + author and committer shown in the log view be sure to pass
331 + `\--pretty=fuller` to git log. Defaults to:
332 +-----------------------------------------------------------------------------
333 +git log --no-color --cc --stat -n100 %s
334 +-----------------------------------------------------------------------------
338 + The command used for the main view. Note, you must always specify
339 + the option: `\--pretty=raw` since the main view parser expects to
341 +-----------------------------------------------------------------------------
342 +git log --no-color --pretty=raw --parents --topo-order %s
343 +-----------------------------------------------------------------------------
355 + The command used for the tree view. Takes two arguments, the first is
356 + the revision ID and the second is the path of the directory tree,
357 + empty for the root directory. Defaults to:
358 +-----------------------------------------------------------------------------
360 +-----------------------------------------------------------------------------
364 + The command used for the blob view. Takes one argument which is the
365 + blob ID. Defaults to:
366 +-----------------------------------------------------------------------------
367 +git cat-file blob %s
368 +-----------------------------------------------------------------------------
375 @@ -377,9 +426,10 @@ e Open file in editor.
379 -Tig also comes with a few builtin external commands. These are simple shell
380 -commands that are run and can take arguments from the current browsing state,
381 -such as the current commit ID. The default commands are:
382 +For more custom needs, external commands provide a way to easily execute
383 +a script or program. They are bound to keys and use information from the
384 +current browsing state, such as the current commit ID. Tig comes with
385 +the following builtin external commands:
387 `-------`--------------------------------------------------------------------
389 @@ -400,7 +450,7 @@ git-rev-list(1).
391 You can tune the interaction with git by making use of the options explained
392 in this section. For example, by configuring the environment variables
393 -described in the <<history-commands, "History commands">> section.
394 +described in the section on <<history-commands, history commands>>.
398 @@ -422,17 +472,13 @@ thus you will have to use:
400 -----------------------------------------------------------------------------
402 -NOTE: For the main view, avoiding ambiguity will in some cases require you to
403 -specify two "\--" options. The first will make tig stop option processing
404 -and the latter will be passed to git log.
406 [[date-number-limiting]]
407 Limit by Date or Number
408 ~~~~~~~~~~~~~~~~~~~~~~~
410 To speed up interaction with git, you can limit the amount of commits to show
411 both for the log and main view. Either limit by date using e.g.
412 -`--since=1.month` or limit by the number of commits using `-n400`.
413 +`\--since=1.month` or limit by the number of commits using `-n400`.
415 If you are only interested in changed that happened between two dates you can
417 @@ -442,7 +488,7 @@ $ tig --after="May 5th" --before="2006-05-16 15:44"
418 -----------------------------------------------------------------------------
420 NOTE: If you want to avoid having to quote dates containing spaces you can use
421 -"." instead, e.g. `--after=May.5th`.
422 +"." instead, e.g. `\--after=May.5th`.
424 [[commit-range-limiting]]
425 Limiting by Commit Ranges
426 diff --git a/tig.c b/tig.c
427 index 5c456e7..3394d40 100644
430 @@ -164,7 +164,7 @@ struct ref {
431 unsigned int next:1; /* For ref lists: are there more refs? */
434 -static struct ref **get_refs(char *id);
435 +static struct ref **get_refs(const char *id);
439 @@ -277,6 +277,9 @@ string_enum_compare(const char *str1, const char *str2, int len)
443 +#define prefixcmp(str1, str2) \
444 + strncmp(str1, str2, STRING_SIZE(str2))
448 * NOTE: The following is a slightly modified copy of the git project's shell
449 @@ -408,9 +411,9 @@ enum request {
451 struct request_info {
452 enum request request;
460 static struct request_info req_info[] = {
461 @@ -480,13 +483,14 @@ static char opt_cdup[SIZEOF_STR] = "";
462 static char opt_git_dir[SIZEOF_STR] = "";
463 static signed char opt_is_inside_work_tree = -1; /* set to TRUE or FALSE */
464 static char opt_editor[SIZEOF_STR] = "";
465 +static FILE *opt_tty = NULL;
468 -parse_options(int argc, char *argv[])
469 +parse_options(int argc, const char *argv[])
471 enum request request = REQ_VIEW_MAIN;
474 + const char *subcommand;
475 bool seen_dashdash = FALSE;
478 @@ -540,7 +544,7 @@ parse_options(int argc, char *argv[])
479 buf_size = strlen(opt_cmd);
481 for (i = 1 + !!subcommand; i < argc; i++) {
482 - char *opt = argv[i];
483 + const char *opt = argv[i];
485 if (seen_dashdash || !strcmp(opt, "--")) {
486 seen_dashdash = TRUE;
487 @@ -867,7 +871,7 @@ get_keybinding(enum keymap keymap, int key)
496 @@ -917,11 +921,11 @@ get_key_value(const char *name)
502 get_key_name(int key_value)
504 static char key_char[] = "'X'";
506 + const char *seq = NULL;
509 for (key = 0; key < ARRAY_SIZE(key_table); key++)
510 @@ -938,7 +942,7 @@ get_key_name(int key_value)
511 return seq ? seq : "(no key)";
516 get_key(enum request request)
518 static char buf[BUFSIZ];
519 @@ -1062,7 +1066,7 @@ static struct int_map attr_map[] = {
521 static int config_lineno;
522 static bool config_errors;
523 -static char *config_msg;
524 +static const char *config_msg;
526 /* Wants: object fgcolor bgcolor [attr] */
528 @@ -1249,7 +1253,7 @@ option_bind_command(int argc, const char *argv[])
532 -set_option(char *opt, char *value)
533 +set_option(const char *opt, char *value)
535 const char *argv[SIZEOF_ARG];
537 @@ -1343,9 +1347,9 @@ load_option_file(const char *path)
541 - char *home = getenv("HOME");
542 - char *tigrc_user = getenv("TIGRC_USER");
543 - char *tigrc_system = getenv("TIGRC_SYSTEM");
544 + const char *home = getenv("HOME");
545 + const char *tigrc_user = getenv("TIGRC_USER");
546 + const char *tigrc_system = getenv("TIGRC_SYSTEM");
547 char buf[SIZEOF_STR];
549 add_builtin_run_requests();
550 @@ -1639,7 +1643,7 @@ draw_graphic(struct view *view, enum line_type type, chtype graphic[], size_t si
554 -draw_field(struct view *view, enum line_type type, char *text, int len, bool trim)
555 +draw_field(struct view *view, enum line_type type, const char *text, int len, bool trim)
557 int max = MIN(view->width - view->col, len);
559 @@ -2375,8 +2379,14 @@ update_view(struct view *view)
563 - if (!view_is_displayed(view))
565 + if (ferror(view->pipe) && errno != 0) {
566 + report("Failed to read: %s", strerror(errno));
567 + end_update(view, TRUE);
569 + } else if (feof(view->pipe)) {
571 + end_update(view, FALSE);
574 if (view == VIEW(REQ_VIEW_TREE)) {
575 /* Clear the view and redraw everything since the tree sorting
576 @@ -2406,17 +2416,6 @@ update_view(struct view *view)
577 /* Update the title _after_ the redraw so that if the redraw picks up a
578 * commit reference in view->ref it'll be available here. */
579 update_view_title(view);
582 - if (ferror(view->pipe) && errno != 0) {
583 - report("Failed to read: %s", strerror(errno));
584 - end_update(view, TRUE);
586 - } else if (feof(view->pipe)) {
588 - end_update(view, FALSE);
594 @@ -2438,10 +2437,9 @@ add_line_data(struct view *view, void *data, enum line_type type)
598 -add_line_text(struct view *view, char *data, enum line_type type)
599 +add_line_text(struct view *view, const char *text, enum line_type type)
602 - data = strdup(data);
603 + char *data = text ? strdup(text) : NULL;
605 return data ? add_line_data(view, data, type) : NULL;
607 @@ -2565,7 +2563,7 @@ open_external_viewer(const char *cmd)
608 endwin(); /* restore original tty modes */
610 fprintf(stderr, "Press Enter to continue");
616 @@ -2587,7 +2585,7 @@ open_editor(bool from_root, const char *file)
618 char cmd[SIZEOF_STR];
619 char file_sq[SIZEOF_STR];
621 + const char *editor;
622 char *prefix = from_root ? opt_cdup : "";
624 editor = getenv("GIT_EDITOR");
625 @@ -2893,7 +2891,6 @@ view_driver(struct view *view, enum request request)
629 - /* An unknown key will show most commonly used commands. */
630 report("Unknown key, press 'h' for help");
633 @@ -2919,7 +2916,7 @@ pager_draw(struct view *view, struct line *line, unsigned int lineno)
637 -add_describe_ref(char *buf, size_t *bufpos, char *commit_id, const char *sep)
638 +add_describe_ref(char *buf, size_t *bufpos, const char *commit_id, const char *sep)
640 char refbuf[SIZEOF_STR];
642 @@ -2967,8 +2964,8 @@ add_pager_refs(struct view *view, struct line *line)
645 struct ref *ref = refs[refpos];
646 - char *fmt = ref->tag ? "%s[%s]" :
647 - ref->remote ? "%s<%s>" : "%s%s";
648 + const char *fmt = ref->tag ? "%s[%s]" :
649 + ref->remote ? "%s<%s>" : "%s%s";
651 if (!string_format_from(buf, &bufpos, fmt, sep, ref->name))
653 @@ -3130,7 +3127,7 @@ help_open(struct view *view)
654 add_line_text(view, "Quick reference for tig keybindings:", LINE_DEFAULT);
656 for (i = 0; i < ARRAY_SIZE(req_info); i++) {
660 if (req_info[i].request == REQ_NONE)
662 @@ -3158,7 +3155,7 @@ help_open(struct view *view)
664 for (i = 0; i < run_requests; i++) {
665 struct run_request *req = get_run_request(REQ_NONE + i + 1);
671 @@ -3215,7 +3212,7 @@ pop_tree_stack_entry(void)
675 -push_tree_stack_entry(char *name, unsigned long lineno)
676 +push_tree_stack_entry(const char *name, unsigned long lineno)
678 struct tree_stack_entry *entry = calloc(1, sizeof(*entry));
679 size_t pathlen = strlen(opt_path);
680 @@ -3251,8 +3248,8 @@ push_tree_stack_entry(char *name, unsigned long lineno)
681 #define TREE_UP_FORMAT "040000 tree %s\t.."
684 -tree_compare_entry(enum line_type type1, char *name1,
685 - enum line_type type2, char *name2)
686 +tree_compare_entry(enum line_type type1, const char *name1,
687 + enum line_type type2, const char *name2)
689 if (type1 != type2) {
690 if (type1 == LINE_TREE_DIR)
691 @@ -3263,10 +3260,10 @@ tree_compare_entry(enum line_type type1, char *name1,
692 return strcmp(name1, name2);
697 tree_path(struct line *line)
699 - char *path = line->data;
700 + const char *path = line->data;
702 return path + SIZEOF_TREE_ATTR;
704 @@ -3318,7 +3315,7 @@ tree_read(struct view *view, char *text)
705 /* Skip "Directory ..." and ".." line. */
706 for (pos = 1 + !!*opt_path; pos < view->lines; pos++) {
707 struct line *line = &view->line[pos];
708 - char *path1 = tree_path(line);
709 + const char *path1 = tree_path(line);
710 char *path2 = text + SIZEOF_TREE_ATTR;
711 int cmp = tree_compare_entry(line->type, path1, type, path2);
713 @@ -3357,7 +3354,7 @@ tree_request(struct view *view, enum request request, struct line *line)
714 enum open_flags flags;
716 if (request == REQ_VIEW_BLAME) {
717 - char *filename = tree_path(line);
718 + const char *filename = tree_path(line);
720 if (line->type == LINE_TREE_DIR) {
721 report("Cannot show blame for directory %s", opt_path);
722 @@ -3393,7 +3390,7 @@ tree_request(struct view *view, enum request request, struct line *line)
723 pop_tree_stack_entry();
726 - char *basename = tree_path(line);
727 + const char *basename = tree_path(line);
729 push_tree_stack_entry(basename, view->lineno);
731 @@ -3490,7 +3487,7 @@ struct blame {
734 #define BLAME_CAT_FILE_CMD "git cat-file blob %s:%s"
735 -#define BLAME_INCREMENTAL_CMD "git blame --incremental %s %s"
736 +#define BLAME_INCREMENTAL_CMD "git blame --incremental %s -- %s"
739 blame_open(struct view *view)
740 @@ -3556,9 +3553,9 @@ get_blame_commit(struct view *view, const char *id)
744 -parse_number(char **posref, size_t *number, size_t min, size_t max)
745 +parse_number(const char **posref, size_t *number, size_t min, size_t max)
747 - char *pos = *posref;
748 + const char *pos = *posref;
751 pos = strchr(pos + 1, ' ');
752 @@ -3573,11 +3570,11 @@ parse_number(char **posref, size_t *number, size_t min, size_t max)
755 static struct blame_commit *
756 -parse_blame_commit(struct view *view, char *text, int *blamed)
757 +parse_blame_commit(struct view *view, const char *text, int *blamed)
759 struct blame_commit *commit;
761 - char *pos = text + SIZEOF_REV - 1;
762 + const char *pos = text + SIZEOF_REV - 1;
766 @@ -3606,7 +3603,7 @@ parse_blame_commit(struct view *view, char *text, int *blamed)
770 -blame_read_file(struct view *view, char *line)
771 +blame_read_file(struct view *view, const char *line)
775 @@ -3711,7 +3708,7 @@ blame_draw(struct view *view, struct line *line, unsigned int lineno)
777 struct blame *blame = line->data;
778 struct tm *time = NULL;
779 - char *id = NULL, *author = NULL;
780 + const char *id = NULL, *author = NULL;
782 if (blame->commit && *blame->commit->filename) {
783 id = blame->commit->id;
784 @@ -3855,13 +3852,13 @@ status_has_none(struct view *view, struct line *line)
785 * :100644 100644 06a5d6ae9eca55be2e0e585a152e6b1336f2b20e 0000000000000000000000000000000000000000 M
788 -status_get_diff(struct status *file, char *buf, size_t bufsize)
789 +status_get_diff(struct status *file, const char *buf, size_t bufsize)
791 - char *old_mode = buf + 1;
792 - char *new_mode = buf + 8;
793 - char *old_rev = buf + 15;
794 - char *new_rev = buf + 56;
795 - char *status = buf + 97;
796 + const char *old_mode = buf + 1;
797 + const char *new_mode = buf + 8;
798 + const char *old_rev = buf + 15;
799 + const char *new_rev = buf + 56;
800 + const char *status = buf + 97;
803 old_mode[-1] != ':' ||
804 @@ -4078,7 +4075,7 @@ status_draw(struct view *view, struct line *line, unsigned int lineno)
806 struct status *status = line->data;
812 switch (line->type) {
813 @@ -4130,7 +4127,7 @@ status_enter(struct view *view, struct line *line)
814 struct status *status = line->data;
815 char oldpath[SIZEOF_STR] = "";
816 char newpath[SIZEOF_STR] = "";
820 enum open_flags split;
822 @@ -4393,7 +4390,7 @@ status_revert(struct status *status, enum line_type type, bool has_none)
823 char file_sq[SIZEOF_STR];
825 if (sq_quote(file_sq, 0, status->old.name) >= sizeof(file_sq) ||
826 - !string_format(cmd, "git checkout %s%s", opt_cdup, file_sq))
827 + !string_format(cmd, "git checkout -- %s%s", opt_cdup, file_sq))
830 return run_confirm(cmd, "Are you sure you want to overwrite any changes?");
831 @@ -4463,8 +4460,8 @@ status_select(struct view *view, struct line *line)
833 struct status *status = line->data;
834 char file[SIZEOF_STR] = "all files";
840 if (status && !string_format(file, "'%s'", status->new.name))
842 @@ -4517,7 +4514,7 @@ status_grep(struct view *view, struct line *line)
845 for (state = S_STATUS; state < S_END; state++) {
850 case S_NAME: text = status->new.name; break;
851 @@ -4551,7 +4548,7 @@ static struct view_ops status_ops = {
853 stage_diff_line(FILE *pipe, struct line *line)
855 - char *buf = line->data;
856 + const char *buf = line->data;
857 size_t bufsize = strlen(buf);
860 @@ -4874,7 +4871,7 @@ done_rev_graph(struct rev_graph *graph)
864 -push_rev_graph(struct rev_graph *graph, char *parent)
865 +push_rev_graph(struct rev_graph *graph, const char *parent)
869 @@ -5531,13 +5528,13 @@ init_display(void)
870 /* Initialize the curses library */
871 if (isatty(STDIN_FILENO)) {
872 cursed = !!initscr();
875 /* Leave stdin and stdout alone when acting as a pager. */
876 - FILE *io = fopen("/dev/tty", "r+");
879 + opt_tty = fopen("/dev/tty", "r+");
881 die("Failed to open /dev/tty");
882 - cursed = !!newterm(NULL, io, io);
883 + cursed = !!newterm(NULL, opt_tty, opt_tty);
887 @@ -5698,8 +5695,27 @@ static struct ref ***id_refs = NULL;
888 static size_t id_refs_alloc = 0;
889 static size_t id_refs_size = 0;
892 +compare_refs(const void *ref1_, const void *ref2_)
894 + const struct ref *ref1 = *(const struct ref **)ref1_;
895 + const struct ref *ref2 = *(const struct ref **)ref2_;
897 + if (ref1->tag != ref2->tag)
898 + return ref2->tag - ref1->tag;
899 + if (ref1->ltag != ref2->ltag)
900 + return ref2->ltag - ref2->ltag;
901 + if (ref1->head != ref2->head)
902 + return ref2->head - ref1->head;
903 + if (ref1->tracked != ref2->tracked)
904 + return ref2->tracked - ref1->tracked;
905 + if (ref1->remote != ref2->remote)
906 + return ref2->remote - ref1->remote;
907 + return strcmp(ref1->name, ref2->name);
912 +get_refs(const char *id)
914 struct ref ***tmp_id_refs;
915 struct ref **ref_list = NULL;
916 @@ -5733,19 +5749,20 @@ get_refs(char *id)
920 - if (ref_list_size > 0)
921 - ref_list[ref_list_size - 1]->next = 1;
922 ref_list[ref_list_size] = &refs[i];
924 /* XXX: The properties of the commit chains ensures that we can
925 * safely modify the shared ref. The repo references will
926 * always be similar for the same id. */
927 - ref_list[ref_list_size]->next = 0;
928 + ref_list[ref_list_size]->next = 1;
935 + qsort(ref_list, ref_list_size, sizeof(*ref_list), compare_refs);
936 + ref_list[ref_list_size - 1]->next = 0;
937 id_refs[id_refs_size++] = ref_list;
942 @@ -5761,7 +5778,7 @@ read_ref(char *id, size_t idlen, char *name, size_t namelen)
943 bool check_replace = FALSE;
946 - if (!strncmp(name, "refs/tags/", STRING_SIZE("refs/tags/"))) {
947 + if (!prefixcmp(name, "refs/tags/")) {
948 if (!strcmp(name + namelen - 3, "^{}")) {
951 @@ -5775,13 +5792,13 @@ read_ref(char *id, size_t idlen, char *name, size_t namelen)
952 namelen -= STRING_SIZE("refs/tags/");
953 name += STRING_SIZE("refs/tags/");
955 - } else if (!strncmp(name, "refs/remotes/", STRING_SIZE("refs/remotes/"))) {
956 + } else if (!prefixcmp(name, "refs/remotes/")) {
958 namelen -= STRING_SIZE("refs/remotes/");
959 name += STRING_SIZE("refs/remotes/");
960 tracked = !strcmp(opt_remote, name);
962 - } else if (!strncmp(name, "refs/heads/", STRING_SIZE("refs/heads/"))) {
963 + } else if (!prefixcmp(name, "refs/heads/")) {
964 namelen -= STRING_SIZE("refs/heads/");
965 name += STRING_SIZE("refs/heads/");
966 head = !strncmp(opt_head, name, namelen);
967 @@ -5794,7 +5811,7 @@ read_ref(char *id, size_t idlen, char *name, size_t namelen)
968 if (check_replace && !strcmp(name, refs[refs_size - 1].name)) {
969 /* it's an annotated tag, replace the previous sha1 with the
970 * resolved commit id; relies on the fact git-ls-remote lists
971 - * the commit id of an annotated tag right beofre the commit id
972 + * the commit id of an annotated tag right before the commit id
974 refs[refs_size - 1].ltag = ltag;
975 string_copy_rev(refs[refs_size - 1].id, id);
976 @@ -5861,7 +5878,7 @@ read_repo_config_option(char *name, size_t namelen, char *value, size_t valuelen
977 !strcmp(name + 7 + strlen(opt_head), ".merge")) {
978 size_t from = strlen(opt_remote);
980 - if (!strncmp(value, "refs/heads/", STRING_SIZE("refs/heads/"))) {
981 + if (!prefixcmp(value, "refs/heads/")) {
982 value += STRING_SIZE("refs/heads/");
983 valuelen -= STRING_SIZE("refs/heads/");
985 @@ -5897,7 +5914,7 @@ read_repo_info(char *name, size_t namelen, char *value, size_t valuelen)
986 } else if (opt_cdup[0] == ' ') {
987 string_ncopy(opt_cdup, name, namelen);
989 - if (!strncmp(name, "refs/heads/", STRING_SIZE("refs/heads/"))) {
990 + if (!prefixcmp(name, "refs/heads/")) {
991 namelen -= STRING_SIZE("refs/heads/");
992 name += STRING_SIZE("refs/heads/");
993 string_ncopy(opt_head, name, namelen);
994 @@ -6009,7 +6026,7 @@ warn(const char *msg, ...)
998 -main(int argc, char *argv[])
999 +main(int argc, const char *argv[])
1002 enum request request;
1003 @@ -6052,7 +6069,7 @@ main(int argc, char *argv[])
1004 if (load_refs() == ERR)
1005 die("Failed to load refs.");
1007 - for (i = 0; i < ARRAY_SIZE(views) && (view = &views[i]); i++)
1008 + foreach_view (view, i)
1009 view->cmd_env = getenv(view->cmd_env);
1012 @@ -6063,6 +6080,7 @@ main(int argc, char *argv[])
1014 foreach_view (view, i)
1016 + view = display[current_view];
1018 /* Refresh, accept single keystroke of input */
1019 key = wgetch(status_win);
1020 @@ -6074,7 +6092,7 @@ main(int argc, char *argv[])
1024 - request = get_keybinding(display[current_view]->keymap, key);
1025 + request = get_keybinding(view->keymap, key);
1027 /* Some low-level request handling. This keeps access to
1028 * status_win restricted. */
1029 @@ -6100,8 +6118,7 @@ main(int argc, char *argv[])
1031 case REQ_SEARCH_BACK:
1033 - const char *prompt = request == REQ_SEARCH
1035 + const char *prompt = request == REQ_SEARCH ? "/" : "?";
1036 char *search = read_prompt(prompt);