Hi David, Thank you very much for picking this up! On Mon, 13 Mar 2017, David Aguilar wrote: > Detect the null object ID for symlinks in dir-diff so that difftool can > prepare temporary files that matches how git handles symlinks. Maybe a description is needed how the OID can be null in that case. I have to admit that I failed to wrap my head around this so far. > Previously, a null object ID would crash difftool. We now detect null > object IDs and write the symlink's content into the temporary symlink > stand-in file. > > Original-patch-by: Johannes Schindelin <johannes.schindelin@xxxxxx> > Signed-off-by: David Aguilar <davvid@xxxxxxxxx> > --- > diff --git a/builtin/difftool.c b/builtin/difftool.c > index d13350ce83..6c20e20b45 100644 > --- a/builtin/difftool.c > +++ b/builtin/difftool.c > @@ -254,6 +254,31 @@ static int ensure_leading_directories(char *path) > } > } > > +static int create_symlink_file(struct cache_entry* ce, struct checkout* state) > +{ > + /* > + * Dereference a worktree symlink and writes its contents > + * into the checkout state's path. > + */ > + struct strbuf path = STRBUF_INIT; > + struct strbuf link = STRBUF_INIT; > + > + int ok = 0; It would appear that the convention in Git's C code is for functions to return 0 upon success and -1 upon error, and to use `int ret` for that purpose. > + if (strbuf_readlink(&link, ce->name, ce_namelen(ce)) == 0) { Looking at the calling site, I would have expected the code to read the contents as per ce->hash... After all, we are calling this in the !use_wt_file() case. But that is exactly that null hash, isn't it? > @@ -414,7 +439,12 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix, The lines before this hunk read: > if (!use_wt_file(workdir, dst_path, &roid)) { > ce->ce_mode = rmode; ... and then follow these lines: > oidcpy(&ce->oid, &roid); > strcpy(ce->name, dst_path); > ce->ce_namelen = dst_path_len; > - if (checkout_entry(ce, &rstate, NULL)) > + > + if (S_ISLNK(rmode) && is_null_oid(&roid)) { > + if (!create_symlink_file(ce, &rstate)) > + return error("unable to create symlink file %s", > + dst_path); > + } else if (checkout_entry(ce, &rstate, NULL)) > return error("could not write '%s'", > dst_path); > } else if (!is_null_oid(&roid)) { Given that we explicitly ask use_wt_file() whether we can use the worktree's file, and we get the answer "no" before we enter the modified code block, I would really expect us *not* to want to read the link from disk at all. Further, reading the code of use_wt_file(), there seems to be another case where roid is left alone: when the file could not be lstat()ed. So I wonder whether the create_symlink_file() is the correct solution, or whether we could somehow fill roid correctly instead, and keep the checkout_entry() call? Ciao, Dscho