All of lore.kernel.org
 help / color / mirror / Atom feed
From: Craig Silverstein <csilvers.mail@gmail.com>
To: git@vger.kernel.org
Cc: jrnieder@gmail.com, pclouds@gmail.com
Subject: [PATCH] git-new-workdir: support submodules
Date: Mon, 22 Dec 2014 18:10:27 -0800	[thread overview]
Message-ID: <1419360673.196271.13944.nullmailer@meta> (raw)

The basic problem with submodules, from git-new-workdir's point of
view, is that instead of having a .git directory, they have a .git
file with contents `gitdir: <some other path>`.  This is a problem
because the submodule's config file has an entry like `worktree =
../../../khan-exercises` which is relative to "<some other path>"
rather than to "submodule_dir/.git".

As a result, if we want the new workdir to work properly, it needs to
keep the same directory structure as the original repository: it
should also contain a .git file with a 'gitdir', and the actual .git
contents should be in the place mentioned therein.  (There are other
ways we could have solved this problem, including modifying the
'config' file, but this seemed most in keeping with the symlink-y
philosophy of git-new-branch.)

This commit implements this, by detecting if the source .git directory
is actually a .git file with 'gitdir: ...' as its contents, and if so
reproducing the .git file + gitdir structure in the destination
work-tree.

Test plan:
On a repo (~/khan/webapp) with a submodule, ran

    git new-workdir ~/khan/webapp /tmp/webapp      # the main module
    git new-workdir ~/khan/webapp/khan-exercises /tmp/webapp/khan-exercises

and saw that /tmp/webapp/khan-exercises was populated correctly,
/tmp/webapp/.git/modules/khan-exercises existed with symlinks, and
/tmp/webapp/khan-exercises/.git was a file with a 'gitdir:' entry
pointing to the .git/modules directory.

Signed-off-by: Craig Silverstein <csilvers@khanacademy.org>
---
 contrib/workdir/git-new-workdir | 55 +++++++++++++++++++++++++++--------------
 1 file changed, 36 insertions(+), 19 deletions(-)

diff --git a/contrib/workdir/git-new-workdir b/contrib/workdir/git-new-workdir
index 888c34a..3cc50de 100755
--- a/contrib/workdir/git-new-workdir
+++ b/contrib/workdir/git-new-workdir
@@ -52,26 +52,45 @@ then
 		"a complete repository."
 fi
 
+# don't modify an existing directory, unless it's empty
+if test -d "$new_workdir" && test $(ls -a1 "$new_workdir/." | wc -l) -ne 2
+then
+	die "destination directory '$new_workdir' is not empty."
+fi
+
 # make sure the links in the workdir have full paths to the original repo
 git_dir=$(cd "$git_dir" && pwd) || exit 1
 
-# don't recreate a workdir over an existing directory, unless it's empty
-if test -d "$new_workdir"
+new_git_dir="$new_workdir/.git"
+
+# if $orig_git is a .git file with a 'gitdir' entry (as is the case for
+# submodules), have the new git dir follow that same pattern.  otherwise
+# the 'worktree' entry in .git/config, which is a relative path, will
+# not resolve properly because we're not in the expected subdirectory.
+gitdir_text=$(sed -ne 's/^gitdir: *//p' "$orig_git/.git" 2>/dev/null)
+if test -n "$gitdir_text"; then
+	ln -s "$orig_git/.git" "$new_workdir/.git" || failed
+	new_git_dir="$new_workdir/$gitdir_text"
+fi
+
+# if new_workdir already exists, leave it along in case of error
+if ! test -d "$new_workdir"
 then
-	if test $(ls -a1 "$new_workdir/." | wc -l) -ne 2
-	then
-		die "destination directory '$new_workdir' is not empty."
-	fi
-	cleandir="$new_workdir/.git"
-else
-	cleandir="$new_workdir"
+	clean_new_workdir=true
 fi
 
-mkdir -p "$new_workdir/.git" || failed
-cleandir=$(cd "$cleandir" && pwd) || failed
+mkdir -p "$new_git_dir" || failed
 
+cleandir=$(cd "$cleandir" && pwd) || failed
 cleanup () {
-	rm -rf "$cleandir"
+	if test z"$clean_new_workdir" = ztrue
+	then
+		rm -rf "$new_workdir"
+	fi
+	# this may (or may not) be a noop if new_workdir was already deleted.
+	rm -rf "$new_git_dir"
+	# this is a noop unless .git is a 'gitdir: ...' file.
+	rm -f "$new_workdir/.git"
 }
 siglist="0 1 2 15"
 trap cleanup $siglist
@@ -84,22 +103,20 @@ do
 	# create a containing directory if needed
 	case $x in
 	*/*)
-		mkdir -p "$new_workdir/.git/${x%/*}"
+		mkdir -p "$new_git_dir/${x%/*}"
 		;;
 	esac
 
-	ln -s "$git_dir/$x" "$new_workdir/.git/$x" || failed
+	ln -s "$git_dir/$x" "$new_git_dir/$x" || failed
 done
 
-# commands below this are run in the context of the new workdir
-cd "$new_workdir" || failed
-
 # copy the HEAD from the original repository as a default branch
-cp "$git_dir/HEAD" .git/HEAD || failed
+cp "$git_dir/HEAD" "$new_git_dir/HEAD" || failed
 
 # the workdir is set up.  if the checkout fails, the user can fix it.
 trap - $siglist
 
 # checkout the branch (either the same as HEAD from the original repository,
-# or the one that was asked for)
+# or the one that was asked for).  we must be in the new workdir for this.
+cd "$new_workdir" || failed
 git checkout -f $branch
-- 
2.2.1

             reply	other threads:[~2014-12-23 18:51 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-12-23  2:10 Craig Silverstein [this message]
2014-12-23 19:08 ` [PATCH] git-new-workdir: support submodules Junio C Hamano
2014-12-23 21:51 Craig Silverstein
2015-01-24  0:48 ` Craig Silverstein
2015-01-24  1:37   ` Junio C Hamano
2015-01-25  1:47     ` Craig Silverstein
2015-01-26  4:05       ` Junio C Hamano
2015-01-26  4:57         ` Craig Silverstein
2015-01-26  5:39           ` Junio C Hamano
2015-01-27 17:35             ` Jens Lehmann
2015-01-28 10:50               ` Duy Nguyen
2015-01-28 10:53                 ` Duy Nguyen
2015-01-28 20:18                   ` Junio C Hamano

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1419360673.196271.13944.nullmailer@meta \
    --to=csilvers.mail@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=jrnieder@gmail.com \
    --cc=pclouds@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.