This is effective when a ref is updated from the super repository as
well as all linked repositories because "repos" directory is shared
between all repos.

We could even forbid a ref update if it's some repo's HEAD. But I'd
rather see a generic, permanent ref locking mechanism in place first
and make use of it.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclo...@gmail.com>
---
 refs.c | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/refs.c b/refs.c
index 3691ef5..d856b1a 100644
--- a/refs.c
+++ b/refs.c
@@ -2462,6 +2462,41 @@ static int repack_without_ref(const char *refname)
        return repack_without_refs(&refname, 1);
 }
 
+static void detach_repos_refs(const char *refname, const unsigned char *sha1)
+{
+       struct dirent *d;
+       DIR *dir;
+
+       if (!strncmp(refname, "repos/", 6) ||
+           !strchr(refname, '/') ||
+           (dir = opendir(git_path("repos"))) == NULL)
+               return;
+
+       while ((d = readdir(dir)) != NULL) {
+               struct strbuf sb_ref = STRBUF_INIT;
+               unsigned char ref_sha1[20];
+               const char *ref;
+               int flags;
+
+               if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
+                       continue;
+               strbuf_addf(&sb_ref, "repos/%s/HEAD", d->d_name);
+               ref = resolve_ref_unsafe(sb_ref.buf, ref_sha1, 1, &flags);
+               if (flags & REF_ISSYMREF && ref && !strcmp(ref, refname)) {
+                       struct strbuf msg = STRBUF_INIT;
+                       strbuf_addf(&msg, "repos: detach from %s by %s",
+                                   ref, real_path(get_git_dir()));
+                       update_ref(msg.buf, sb_ref.buf, sha1, NULL,
+                                  REF_NODEREF, DIE_ON_ERR);
+                       strbuf_release(&msg);
+                       warning(_("detach HEAD of linked repository %s from 
%s"),
+                               d->d_name, refname);
+               }
+               strbuf_release(&sb_ref);
+       }
+       closedir(dir);
+}
+
 static int delete_ref_loose(struct ref_lock *lock, int flag)
 {
        if (!(flag & REF_ISPACKED) || flag & REF_ISSYMREF) {
@@ -2485,6 +2520,7 @@ int delete_ref(const char *refname, const unsigned char 
*sha1, int delopt)
        lock = lock_ref_sha1_basic(refname, sha1, delopt, &flag);
        if (!lock)
                return 1;
+       detach_repos_refs(lock->ref_name, lock->old_sha1);
        ret |= delete_ref_loose(lock, flag);
 
        /* removing the loose one could have resurrected an earlier
@@ -2790,6 +2826,7 @@ int write_ref_sha1(struct ref_lock *lock,
                unlock_ref(lock);
                return -1;
        }
+       detach_repos_refs(lock->ref_name, lock->old_sha1);
        if (write_in_full(lock->lock_fd, sha1_to_hex(sha1), 40) != 40 ||
            write_in_full(lock->lock_fd, &term, 1) != 1
                || close_ref(lock) < 0) {
-- 
1.8.5.1.77.g42c48fa

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to