{"thread":{"id":"23241","subject":"[PATCHv3 1/2] Add git alternate command","startedAt":"2010-03-29T21:39:39Z","lastAt":"2010-03-29T21:39:41Z","messageCount":3,"participants":["Chris Packham"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"138133","messageId":"1269898781-18564-1-git-send-email-judge.packham@gmail.com","threadId":"23241","inReplyTo":null,"subject":"git alternate command","fromName":"Chris Packham","fromEmail":"judge.packham@gmail.com","sentAt":"2010-03-29T21:39:39Z","receivedAt":"2010-03-29T21:39:39Z","isPatch":false,"sender":{"key":"judge.packham@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155667?v=4"},"body":"Here is the latest version of my git alternate command. The major difference to\nthe last update is additional tests for deleting alternates and some updates to\nthe test based on Hannes' feedback.\n\nI still am intending to add documentation and to look into Stephens suggestions\nfor changing the UI to use add|delete|show instead of -a|-d.\n\nI'm also interested in any feedback regarding the actual output from the command.\n\nCheers,\nChris\n\n---\n\n Makefile                 |    1 +\n git-alternate.sh         |  156 ++++++++++++++++++++++++++++++++++++++++++++++\n t/t1430-alternate-cmd.sh |  154 +++++++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 311 insertions(+), 0 deletions(-)\n"},{"id":"138132","messageId":"1269898781-18564-2-git-send-email-judge.packham@gmail.com","threadId":"23241","inReplyTo":"1269898781-18564-1-git-send-email-judge.packham@gmail.com","subject":"[PATCHv3 1/2] Add git alternate command","fromName":"Chris Packham","fromEmail":"judge.packham@gmail.com","sentAt":"2010-03-29T21:39:40Z","receivedAt":"2010-03-29T21:39:40Z","isPatch":false,"sender":{"key":"judge.packham@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155667?v=4"},"body":"The current UI around alternates is lacking. There are commands to add\nan alternate at the time of a clone (e.g. 'git clone --reference') but\nno commands to see what alternates have been configured or to add an\nalternate after a repository has been cloned. This patch adds a\nfriendlier UI for displaying and configuring alternates.\n\nSigned-off-by: Chris Packham <judge.packham@gmail.com>\n---\n Makefile         |    1 +\n git-alternate.sh |  156 ++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 157 insertions(+), 0 deletions(-)\n create mode 100755 git-alternate.sh\n\ndiff --git a/Makefile b/Makefile\nindex 3a6c6ea..0dc5e42 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -334,6 +334,7 @@ TEST_PROGRAMS_NEED_X =\n unexport CDPATH\n \n SCRIPT_SH += git-am.sh\n+SCRIPT_SH += git-alternate.sh\n SCRIPT_SH += git-bisect.sh\n SCRIPT_SH += git-difftool--helper.sh\n SCRIPT_SH += git-filter-branch.sh\ndiff --git a/git-alternate.sh b/git-alternate.sh\nnew file mode 100755\nindex 0000000..ea9925b\n--- /dev/null\n+++ b/git-alternate.sh\n@@ -0,0 +1,156 @@\n+#!/bin/sh\n+#\n+# This file is licensed under the GPL v2\n+#\n+# Copyright (c) Chris Packham\n+\n+dashless=$(basename \"$0\" | sed -e 's/-/ /')\n+OPTIONS_KEEPDASHDASH=\n+OPTIONS_SPEC=\"\\\n+$dashless [-r|--recursive]\n+$dashless [-a|--add <dir>]\n+$dashless [-f|--force] [-d|delete <dir>]\n+--\n+r,recursive                    recursively follow alternates\n+a,add=                         add dir as an alternate\n+d,del=                         delete dir as an alternate\n+f,force                        force a delete operation\n+\"\n+. git-sh-setup\n+\n+#\n+# Given the path in $1, which may or may not be a relative path,\n+# convert it to an absolute path\n+#\n+abspath()\n+{\n+\tcd \"$1\"\n+\tpwd\n+\tcd - > /dev/null\n+}\n+\n+#\n+# Runs through the alternates file calling the callback function $1\n+# with the name of the alternate as the first argument to the callback\n+# any additional arguments are passed to the callback function.\n+#\n+walk_alternates()\n+{\n+\talternates=$GIT_DIR/objects/info/alternates\n+\tcallback=$1\n+\tshift\n+\n+\tif test -f \"$alternates\"\n+\tthen\n+\t\twhile read line\n+\t\tdo\n+\t\t\t$callback \"$line\" \"$@\"\n+\t\tdone< \"$alternates\"\n+\tfi\n+}\n+\n+#\n+# Walk function to display one alternate object store and, if the user\n+# has specified -r, recursively call show_alternates on the git\n+# repository that the object store belongs to.\n+#\n+show_alternates_walk()\n+{\n+\tsay \"Object store $1\"\n+\tsay \"    referenced via $GIT_DIR\"\n+\n+\tnew_git_dir=${line%%/objects}\n+\tif test \"$recursive\" = \"true\" && test \"$GIT_DIR\" != \"$new_git_dir\"\n+\tthen\n+\t(\n+\t\texport GIT_DIR=$new_git_dir\n+\t\tshow_alternates\n+\t)\n+\tfi\n+}\n+\n+# Display alternates currently configured\n+show_alternates()\n+{\n+\twalk_alternates show_alternates_walk\n+}\n+\n+#\n+# Walk function to check that the specified alternate does not\n+# already exist.\n+#\n+check_current_alternate_walk()\n+{\n+\tif test \"$1\" = \"$2\"; then\n+\t\tdie \"fatal: Object store $2 is already used by $GIT_DIR\"\n+\tfi\n+}\n+\n+# Add a new alternate\n+add_alternate()\n+{\n+\tif test ! -d \"$dir\"; then\n+\t\tdie \"fatal: $dir is not a directory\"\n+\tfi\n+\n+\tabs_dir=$(abspath \"$dir\")\n+\twalk_alternates check_current_alternate_walk \"$abs_dir\"\n+\n+\t# At this point we know that $dir is a directory that exists\n+\t# and that its not already being used as an alternate. We could\n+\t# go further and verify that $dir has valid objects.\n+\n+\t# if we're still going we can safely add the alternate\n+\techo \"$abs_dir\" >> $GIT_DIR/objects/info/alternates\n+\tsay \"$abs_dir added as an alternate\"\n+\tsay \"    use 'git repack -adl' to remove duplicate objects\"\n+}\n+\n+# Deletes the name alternate from the alternates file.\n+# If there are no more alternates the alternates file will be removed\n+del_alternate()\n+{\n+\tif test ! $force = \"true\"; then\n+\t\tsay \"Not forced, use\"\n+\t\tsay \"    'git repack -a' to fetch missing objects, then \"\n+\t\tsay \"    '$dashless -f -d \\\"$dir\\\"' to remove the alternate\"\n+\t\tdie\n+\tfi\n+\n+\talternates=$GIT_DIR/objects/info/alternates\n+\tnew_alternates=$alternates.tmp\n+\n+\tgrep -v -F \"$dir\" <\"$alternates\" >\"$new_alternates\"\n+\tif test -s \"$new_alternates\"\n+\tthen\n+\t\tmv \"$new_alternates\" \"$alternates\"\n+\telse\n+\t\t# save the git from repeatedly reading a 0 length file\n+\t\trm -f \"$alternates\" \"$new_alternates\"\n+\tfi\n+}\n+\n+dir=\"\"\n+oper=\"\"\n+force=\"false\"\n+\n+# Option parsing\n+while test $# != 0\n+do\n+\tcase \"$1\" in\n+\t-r|--recursive)  recursive=\"true\" ;;\n+\t-a|--add)        oper=\"add\"; dir=\"$2\"; shift ;;\n+\t-d|--delete)     oper=\"del\"; dir=\"$2\"; shift ;;\n+\t-f|--force)      force=\"true\" ;;\n+\t--)              shift; break ;;\n+\t*)               usage ;;\n+\tesac\n+\tshift\n+done\n+\n+# Now go and do it\n+case \"$oper\" in\n+\tadd) add_alternate ;;\n+\tdel) del_alternate ;;\n+\t*)   show_alternates ;;\n+esac\n-- \n1.7.0.3\n"},{"id":"138134","messageId":"1269898781-18564-3-git-send-email-judge.packham@gmail.com","threadId":"23241","inReplyTo":"1269898781-18564-1-git-send-email-judge.packham@gmail.com","subject":"[PATCHv3 2/2] tests for git alternate command","fromName":"Chris Packham","fromEmail":"judge.packham@gmail.com","sentAt":"2010-03-29T21:39:41Z","receivedAt":"2010-03-29T21:39:41Z","isPatch":false,"sender":{"key":"judge.packham@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155667?v=4"},"body":"Signed-off-by: Chris Packham <judge.packham@gmail.com>\n---\n t/t1430-alternate-cmd.sh |  154 ++++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 154 insertions(+), 0 deletions(-)\n create mode 100644 t/t1430-alternate-cmd.sh\n\ndiff --git a/t/t1430-alternate-cmd.sh b/t/t1430-alternate-cmd.sh\nnew file mode 100644\nindex 0000000..ba27633\n--- /dev/null\n+++ b/t/t1430-alternate-cmd.sh\n@@ -0,0 +1,154 @@\n+#!/bin/sh\n+#\n+# Copyright (c) Chris Packham\n+#\n+\n+test_description='Test of git alternate command'\n+\n+. ./test-lib.sh\n+\n+test_expect_success 'setup for rest of the test' '\n+\n+\tmkdir -p base &&\n+\t(\n+\t\tcd base &&\n+\t\tgit init &&\n+\t\techo test > a.txt &&\n+\t\techo test > b.txt &&\n+\t\techo test > c.txt &&\n+\t\tgit add *.txt &&\n+\t\tgit commit -a -m \"Initial Commit\"\n+\t)\n+\tgit clone base A &&\n+\tgit clone A B &&\n+\tgit clone A C &&\n+\tgit clone A D\n+\ttestbase=$(pwd)\n+'\n+\n+test_expect_success 'can add alternate after clone' '\n+\n+\t(\n+\t\tcd B &&\n+\t\tgit alternate -a ../base/.git/objects &&\n+\n+\t\techo \"$testbase/base/.git/objects\" > expect &&\n+\t\tcp .git/objects/info/alternates actual   &&\n+\n+\t\ttest_cmp expect actual\n+\n+\t)\n+'\n+\n+test_expect_success 'add same alternate fails (absolute path)' '\n+\n+\t(\n+\t\tcd B &&\n+\t\ttest_must_fail git alternate -a $(pwd)/base/.git/objects\n+\t)\n+'\n+\n+test_expect_success 'add same alternate fails (relative path)' '\n+\n+\t(\n+\t\tcd B &&\n+\t\ttest_must_fail git alternate -a ../base/.git/objects\n+\t)\n+'\n+\n+test_expect_success 'can add multiple alternates' '\n+\n+\t(\n+\t\tcd C &&\n+\t\tgit alternate -a ../base/.git/objects &&\n+\t\tgit alternate -a ../B/.git/objects &&\n+\n+\t\t{\n+\t\t\techo \"$testbase/base/.git/objects\"\n+\t\t\techo \"$testbase/B/.git/objects\"\n+\t\t} > expect &&\n+\n+\t\tcp .git/objects/info/alternates actual   &&\n+\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'can add recursive alternate' '\n+\n+\t(\n+\t\tcd D &&\n+\t\tgit alternate -a ../C/.git/objects\n+\n+\t\techo \"$testbase/C/.git/objects\" > expect &&\n+\t\tcp .git/objects/info/alternates actual   &&\n+\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'simple display' '\n+\n+\t(\n+\t\tcd B &&\n+\t\tgit alternate >actual &&\n+\t\t{\n+\t\t\techo \"Object store $testbase/base/.git/objects\"\n+\t\t\techo \"    referenced via $testbase/B/.git\"\n+\t\t} >expect &&\n+\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'recursive display' '\n+\n+\t(\n+\t\tcd D &&\n+\t\tgit alternate -r >actual &&\n+\n+\t\t{\n+\t\t\techo \"Object store $testbase/C/.git/objects\"\n+\t\t\techo \"    referenced via $testbase/D/.git\"\n+\t\t\techo \"Object store $testbase/base/.git/objects\"\n+\t\t\techo \"    referenced via $testbase/C/.git\"\n+\t\t\techo \"Object store $testbase/B/.git/objects\"\n+\t\t\techo \"    referenced via $testbase/C/.git\"\n+\t\t\techo \"Object store $testbase/base/.git/objects\"\n+\t\t\techo \"    referenced via $testbase/B/.git\"\n+\t\t} >expect &&\n+\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'cannot delete unless --forced' '\n+\t(\n+\t\tcd C &&\n+\t\ttest_must_fail git alternate -d \"$testbase/B/.git/objects\"\n+\t)\n+'\n+\n+test_expect_success 'can delete one alternate' '\n+\t(\n+\t\tcd C &&\n+\t\tgit alternate -f -d \"$testbase/B/.git/objects\" &&\n+\n+\t\techo \"$testbase/base/.git/objects\" > expect &&\n+\t\tcp .git/objects/info/alternates actual   &&\n+\n+\t\ttest_cmp expect actual\n+\t)\n+'\n+\n+test_expect_success 'last alternate deleted removes file' '\n+\t(\n+\t\tcd C &&\n+\t\tgit alternate -f -d \"$testbase/base/.git/objects\" &&\n+\n+\t\ttest ! -e .git/objects/info/alternates\n+\n+\t)\n+'\n+\n+test_done\n-- \n1.7.0.3\n"}]}