It is fragile, as there is no way for the revision machinery to say "but
now I want to traverse the graph ignoring the graft file" e.g. when
pushing commits to a remote repository (which, as a consequence, can
miss commits).

And we already have a better solution with `git replace --graft <comit>
[<parent>...]`.

Changes since v4:

- Fixed resource leaks (missing free() and strbuf_release() calls when
  returning an error).

- Avoided error_errno() mistakenly using close()'s errno.

- Actually close the handle to the graft file after converting it.

- Changed the description of Documentation/technical/shallow to not even
  bother to describe how it might be construed to be similar to replace
  refs.


Johannes Schindelin (11):
  argv_array: offer to split a string by whitespace
  commit: Let the callback of for_each_mergetag return on error
  replace: avoid using die() to indicate a bug
  replace: "libify" create_graft() and callees
  replace: introduce --convert-graft-file
  Add a test for `git replace --convert-graft-file`
  Deprecate support for .git/info/grafts
  filter-branch: stop suggesting to use grafts
  technical/shallow: stop referring to grafts
  technical/shallow: describe why shallow cannot use replace refs
  Remove obsolete script to convert grafts to replace refs

 Documentation/git-filter-branch.txt       |   2 +-
 Documentation/git-replace.txt             |  11 +-
 Documentation/technical/shallow.txt       |  20 +-
 advice.c                                  |   2 +
 advice.h                                  |   1 +
 argv-array.c                              |  20 ++
 argv-array.h                              |   2 +
 builtin/replace.c                         | 218 +++++++++++++++-------
 commit.c                                  |  18 +-
 commit.h                                  |   4 +-
 contrib/convert-grafts-to-replace-refs.sh |  28 ---
 log-tree.c                                |  13 +-
 t/t6001-rev-list-graft.sh                 |   9 +
 t/t6050-replace.sh                        |  20 ++
 14 files changed, 253 insertions(+), 115 deletions(-)
 delete mode 100755 contrib/convert-grafts-to-replace-refs.sh


base-commit: 1f1cddd558b54bb0ce19c8ace353fd07b758510d
Published-As: https://github.com/dscho/git/releases/tag/deprecate-grafts-v5
Fetch-It-Via: git fetch https://github.com/dscho/git deprecate-grafts-v5

Interdiff vs v4:
 diff --git a/Documentation/technical/shallow.txt 
b/Documentation/technical/shallow.txt
 index cb79181c2bb..01dedfe9ffe 100644
 --- a/Documentation/technical/shallow.txt
 +++ b/Documentation/technical/shallow.txt
 @@ -8,18 +8,10 @@ repo, and therefore grafts are introduced pretending that
  these commits have no parents.
  *********************************************************
  
 -The basic idea is to write the SHA-1s of shallow commits into
 -$GIT_DIR/shallow, and handle its contents similar to replace
 -refs (with the difference that shallow does not actually
 -create those replace refs) and very much like the deprecated
 -graft file (with the difference that shallow commits will
 -always have their parents grafted away, not replaced by
 -different parents).
 -
 -This information is stored in a special-purpose file because the
 -user should not touch that file at all (even throughout
 -development of the shallow clone, it was never manually
 -edited!).
 +$GIT_DIR/shallow lists commit object names and tells Git to
 +pretend as if they are root commits (e.g. "git log" traversal
 +stops after showing them; "git fsck" does not complain saying
 +the commits listed on their "parent" lines do not exist).
  
  Each line contains exactly one SHA-1. When read, a commit_graft
  will be constructed, which has nr_parent < 0 to make it easier
 diff --git a/builtin/replace.c b/builtin/replace.c
 index 6b3e0301e90..acd30e3d824 100644
 --- a/builtin/replace.c
 +++ b/builtin/replace.c
 @@ -175,8 +175,10 @@ static int replace_object_oid(const char *object_ref,
                             object_ref, type_name(obj_type),
                             replace_ref, type_name(repl_type));
  
 -      if (check_ref_valid(object, &prev, &ref, force))
 +      if (check_ref_valid(object, &prev, &ref, force)) {
 +              strbuf_release(&ref);
                return -1;
 +      }
  
        transaction = ref_transaction_begin(&err);
        if (!transaction ||
 @@ -264,9 +266,10 @@ static int import_object(struct object_id *oid, enum 
object_type type,
                }
  
                if (strbuf_read(&result, cmd.out, 41) < 0) {
 +                      error_errno("unable to read from mktree");
                        close(fd);
                        close(cmd.out);
 -                      return error_errno("unable to read from mktree");
 +                      return -1;
                }
                close(cmd.out);
  
 @@ -285,8 +288,9 @@ static int import_object(struct object_id *oid, enum 
object_type type,
                int flags = HASH_FORMAT_CHECK | HASH_WRITE_OBJECT;
  
                if (fstat(fd, &st) < 0) {
 +                      error_errno("unable to fstat %s", filename);
                        close(fd);
 -                      return error_errno("unable to fstat %s", filename);
 +                      return -1;
                }
                if (index_fd(oid, fd, &st, type, NULL, flags) < 0)
                        return error("unable to write object to database");
 @@ -302,7 +306,7 @@ static int import_object(struct object_id *oid, enum 
object_type type,
  
  static int edit_and_replace(const char *object_ref, int force, int raw)
  {
 -      char *tmpfile = git_pathdup("REPLACE_EDITOBJ");
 +      char *tmpfile;
        enum object_type type;
        struct object_id old_oid, new_oid, prev;
        struct strbuf ref = STRBUF_INIT;
 @@ -315,17 +319,20 @@ static int edit_and_replace(const char *object_ref, int 
force, int raw)
                return error("unable to get object type for %s",
                             oid_to_hex(&old_oid));
  
 -      if (check_ref_valid(&old_oid, &prev, &ref, force))
 +      if (check_ref_valid(&old_oid, &prev, &ref, force)) {
 +              strbuf_release(&ref);
                return -1;
 +      }
        strbuf_release(&ref);
  
 -      if (export_object(&old_oid, type, raw, tmpfile))
 -              return -1;
 -      if (launch_editor(tmpfile, NULL, NULL) < 0)
 -              return error("editing object file failed");
 -      if (import_object(&new_oid, type, raw, tmpfile))
 +      tmpfile = git_pathdup("REPLACE_EDITOBJ");
 +      if (export_object(&old_oid, type, raw, tmpfile) ||
 +          (launch_editor(tmpfile, NULL, NULL) < 0 &&
 +           error("editing object file failed")) ||
 +          import_object(&new_oid, type, raw, tmpfile)) {
 +              free(tmpfile);
                return -1;
 -
 +      }
        free(tmpfile);
  
        if (!oidcmp(&old_oid, &new_oid))
 @@ -351,11 +358,15 @@ static int replace_parents(struct strbuf *buf, int argc, 
const char **argv)
        /* prepare new parents */
        for (i = 0; i < argc; i++) {
                struct object_id oid;
 -              if (get_oid(argv[i], &oid) < 0)
 +              if (get_oid(argv[i], &oid) < 0) {
 +                      strbuf_release(&new_parents);
                        return error(_("Not a valid object name: '%s'"),
                                     argv[i]);
 -              if (!lookup_commit_reference(&oid))
 +              }
 +              if (!lookup_commit_reference(&oid)) {
 +                      strbuf_release(&new_parents);
                        return error(_("could not parse %s"), argv[i]);
 +              }
                strbuf_addf(&new_parents, "parent %s\n", oid_to_hex(&oid));
        }
  
 @@ -432,20 +443,26 @@ static int create_graft(int argc, const char **argv, int 
force)
        strbuf_add(&buf, buffer, size);
        unuse_commit_buffer(commit, buffer);
  
 -      if (replace_parents(&buf, argc - 1, &argv[1]) < 0)
 +      if (replace_parents(&buf, argc - 1, &argv[1]) < 0) {
 +              strbuf_release(&buf);
                return -1;
 +      }
  
        if (remove_signature(&buf)) {
                warning(_("the original commit '%s' has a gpg signature."), 
old_ref);
                warning(_("the signature will be removed in the replacement 
commit!"));
        }
  
 -      if (check_mergetags(commit, argc, argv))
 +      if (check_mergetags(commit, argc, argv)) {
 +              strbuf_release(&buf);
                return -1;
 +      }
  
 -      if (write_object_file(buf.buf, buf.len, commit_type, &new_oid))
 +      if (write_object_file(buf.buf, buf.len, commit_type, &new_oid)) {
 +              strbuf_release(&buf);
                return error(_("could not write replacement commit for: '%s'"),
                             old_ref);
 +      }
  
        strbuf_release(&buf);
  
 @@ -474,9 +491,9 @@ static int convert_graft_file(int force)
                        strbuf_addf(&err, "\n\t%s", buf.buf);
                argv_array_clear(&args);
        }
 +      fclose(fp);
  
        strbuf_release(&buf);
 -      argv_array_clear(&args);
  
        if (!err.len)
                return unlink_or_warn(graft_file);
-- 
2.17.0.windows.1.33.gfcbb1fa0445

Reply via email to