Merge branch 'jc/detached-head'
authorJunio C Hamano <junkio@cox.net>
Fri, 12 Jan 2007 00:47:34 +0000 (16:47 -0800)
committerJunio C Hamano <junkio@cox.net>
Fri, 12 Jan 2007 00:47:34 +0000 (16:47 -0800)
* jc/detached-head:
git-checkout: handle local changes sanely when detaching HEAD
git-checkout: safety check for detached HEAD checks existing refs
git-checkout: fix branch name output from the command
git-checkout: safety when coming back from the detached HEAD state.
git-checkout: rewording comments regarding detached HEAD.
git-checkout: do not warn detaching HEAD when it is already detached.
Detached HEAD (experimental)
git-branch: show detached HEAD
git-status: show detached HEAD

1  2 
cache.h
path.c
wt-status.c
diff --combined cache.h
index a9583ff18eec46bf945ef820ea4a41fe51e0a4b1,5218548ccfe1d68d702698dc54e22c59f70b8116..cbe398d3bdea235c2b1c22664b598699f77d37c9
+++ b/cache.h
@@@ -299,7 -299,7 +299,7 @@@ extern char *sha1_to_hex(const unsigne
  extern int read_ref(const char *filename, unsigned char *sha1);
  extern const char *resolve_ref(const char *path, unsigned char *sha1, int, int *);
  extern int create_symref(const char *ref, const char *refs_heads_master);
- extern int validate_symref(const char *ref);
+ extern int validate_headref(const char *ref);
  
  extern int base_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
  extern int cache_name_compare(const char *name1, int len1, const char *name2, int len2);
@@@ -432,12 -432,10 +432,12 @@@ extern char *git_commit_encoding
  extern char *git_log_output_encoding;
  
  extern int copy_fd(int ifd, int ofd);
 +extern int read_in_full(int fd, void *buf, size_t count);
  extern void read_or_die(int fd, void *buf, size_t count);
 -extern int write_in_full(int fd, const void *buf, size_t count, const char *);
 +extern int write_in_full(int fd, const void *buf, size_t count);
  extern void write_or_die(int fd, const void *buf, size_t count);
  extern int write_or_whine(int fd, const void *buf, size_t count, const char *msg);
 +extern int write_or_whine_pipe(int fd, const void *buf, size_t count, const char *msg);
  
  /* pager.c */
  extern void setup_pager(void);
diff --combined path.c
index bb5ee7bf99780b6c4069dd9833994b24f1577e82,94ddd7eafcb11313f00dac964de520c535d202ae..c5d25a4b903bd92930df4004d30d4dffa6054456
--- 1/path.c
--- 2/path.c
+++ b/path.c
@@@ -90,10 -90,11 +90,11 @@@ int git_mkstemp(char *path, size_t len
  }
  
  
- int validate_symref(const char *path)
+ int validate_headref(const char *path)
  {
        struct stat st;
        char *buf, buffer[256];
+       unsigned char sha1[20];
        int len, fd;
  
        if (lstat(path, &st) < 0)
        fd = open(path, O_RDONLY);
        if (fd < 0)
                return -1;
 -      len = read(fd, buffer, sizeof(buffer)-1);
 +      len = read_in_full(fd, buffer, sizeof(buffer)-1);
        close(fd);
  
        /*
         * Is it a symbolic ref?
         */
-       if (len < 4 || memcmp("ref:", buffer, 4))
+       if (len < 4)
                return -1;
-       buf = buffer + 4;
-       len -= 4;
-       while (len && isspace(*buf))
-               buf++, len--;
-       if (len >= 5 && !memcmp("refs/", buf, 5))
+       if (!memcmp("ref:", buffer, 4)) {
+               buf = buffer + 4;
+               len -= 4;
+               while (len && isspace(*buf))
+                       buf++, len--;
+               if (len >= 5 && !memcmp("refs/", buf, 5))
+                       return 0;
+       }
+       /*
+        * Is this a detached HEAD?
+        */
+       if (!get_sha1_hex(buffer, sha1))
                return 0;
        return -1;
  }
  
@@@ -241,7 -251,7 +251,7 @@@ char *enter_repo(char *path, int strict
                return NULL;
  
        if (access("objects", X_OK) == 0 && access("refs", X_OK) == 0 &&
-           validate_symref("HEAD") == 0) {
+           validate_headref("HEAD") == 0) {
                putenv("GIT_DIR=.");
                check_repository_format();
                return path;
diff --combined wt-status.c
index a8499517742d76a8d2142347d60ad1cecc6336cb,2a002baabd2eeb166ffbe6634d7b1ecf0b04bbc6..daba9a6105882c671edd7da21f0a9ae34fbdaaa4
@@@ -15,13 -15,7 +15,13 @@@ static char wt_status_colors[][COLOR_MA
        "\033[31m", /* WT_STATUS_CHANGED: red */
        "\033[31m", /* WT_STATUS_UNTRACKED: red */
  };
 -static const char* use_add_msg = "use \"git add <file>...\" to incrementally add content to commit";
 +
 +static const char use_add_msg[] =
 +"use \"git add <file>...\" to update what will be committed";
 +static const char use_add_rm_msg[] =
 +"use \"git add/rm <file>...\" to update what will be committed";
 +static const char use_add_to_include_msg[] =
 +"use \"git add <file>...\" to include in what will be committed";
  
  static int parse_status_slot(const char *var, int offset)
  {
@@@ -53,11 -47,10 +53,11 @@@ void wt_status_prepare(struct wt_statu
        s->reference = "HEAD";
        s->amend = 0;
        s->verbose = 0;
 -      s->commitable = 0;
        s->untracked = 0;
  
 -      s->workdir_clean = 1;
 +      s->commitable = 0;
 +      s->workdir_dirty = 0;
 +      s->workdir_untracked = 0;
  }
  
  static void wt_status_print_cached_header(const char *reference)
@@@ -183,14 -176,8 +183,14 @@@ static void wt_status_print_changed_cb(
        struct wt_status *s = data;
        int i;
        if (q->nr) {
 -              s->workdir_clean = 0;
 -              wt_status_print_header("Changed but not added", use_add_msg);
 +              const char *msg = use_add_msg;
 +              s->workdir_dirty = 1;
 +              for (i = 0; i < q->nr; i++)
 +                      if (q->queue[i]->status == DIFF_STATUS_DELETED) {
 +                              msg = use_add_rm_msg;
 +                              break;
 +                      }
 +              wt_status_print_header("Changed but not updated", msg);
        }
        for (i = 0; i < q->nr; i++)
                wt_status_print_filepair(WT_STATUS_CHANGED, q->queue[i]);
@@@ -276,9 -263,8 +276,9 @@@ static void wt_status_print_untracked(s
                                continue;
                }
                if (!shown_header) {
 -                      s->workdir_clean = 0;
 -                      wt_status_print_header("Untracked files", use_add_msg);
 +                      s->workdir_untracked = 1;
 +                      wt_status_print_header("Untracked files",
 +                                             use_add_to_include_msg);
                        shown_header = 1;
                }
                color_printf(color(WT_STATUS_HEADER), "#\t");
@@@ -302,9 -288,18 +302,18 @@@ void wt_status_print(struct wt_status *
        unsigned char sha1[20];
        s->is_initial = get_sha1(s->reference, sha1) ? 1 : 0;
  
-       if (s->branch)
+       if (s->branch) {
+               const char *on_what = "On branch ";
+               const char *branch_name = s->branch;
+               if (!strncmp(branch_name, "refs/heads/", 11))
+                       branch_name += 11;
+               else if (!strcmp(branch_name, "HEAD")) {
+                       branch_name = "";
+                       on_what = "Not currently on any branch.";
+               }
                color_printf_ln(color(WT_STATUS_HEADER),
-                       "# On branch %s", s->branch);
+                       "# %s%s", on_what, branch_name);
+       }
  
        if (s->is_initial) {
                color_printf_ln(color(WT_STATUS_HEADER), "#");
        if (!s->commitable) {
                if (s->amend)
                        printf("# No changes\n");
 -              else if (s->workdir_clean)
 -                      printf(s->is_initial
 -                             ? "nothing to commit\n"
 -                             : "nothing to commit (working directory matches HEAD)\n");
 -              else
 +              else if (s->workdir_dirty)
                        printf("no changes added to commit (use \"git add\" and/or \"git commit [-a|-i|-o]\")\n");
 +              else if (s->workdir_untracked)
 +                      printf("nothing added to commit but untracked files present (use \"git add\" to track)\n");
 +              else if (s->is_initial)
 +                      printf("nothing to commit (create/copy files and use \"git add\" to track)\n");
 +              else
 +                      printf("nothing to commit (working directory clean)\n");
        }
  }