{"thread":{"id":"795","subject":"[COGITO PATCH] cg-branch-switch and local branches","startedAt":"2005-06-01T13:03:42Z","lastAt":"2005-06-02T06:09:38Z","messageCount":4,"participants":["Santi Béjar"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"4365","messageId":"87ekbmi5zl.fsf@ifae.es","threadId":"795","inReplyTo":null,"subject":"[COGITO PATCH] cg-branch-switch and local branches","fromName":"Santi Béjar","fromEmail":"sbejar@gmail.com","sentAt":"2005-06-01T13:03:42Z","receivedAt":"2005-06-01T13:03:42Z","isPatch":true,"sender":{"key":"santi@agolina.net","avatar":null},"body":"\nMake origin a symbolic link to the origin branch.\nMake master a symbolic link to the local branch or\n            a file for an unnamed branch.\nAdd cg-branch-switch to switch branches.\n\nSigned-off-by: \"Santi Béjar\" <sbejar@gmail.com>\n\n---\n Makefile         |    3 +\n cg-Xnormid       |    2 +\n cg-branch-add    |   19 +++++++++\n cg-branch-switch |  107 +++++++++++++++++++++++++++++++++++++++++++++++++++++++\n cg-clone         |   32 ++++++++++++----\n cg-commit        |   11 ++++-\n cg-merge         |    3 +\n cg-pull          |   14 +++++--\n 8 files changed, 177 insertions(+), 14 deletions(-)\n\ndiff --git a/Makefile b/Makefile\n--- a/Makefile\n+++ b/Makefile\n@@ -55,7 +55,8 @@ PROG=   git-update-cache git-diff-files \n SCRIPT=\tcommit-id tree-id parent-id cg-add cg-admin-lsobj cg-admin-uncommit \\\n \tcg-branch-add cg-branch-ls cg-cancel cg-clone cg-commit cg-diff \\\n \tcg-export cg-help cg-init cg-log cg-ls cg-merge cg-mkpatch cg-patch \\\n-\tcg-pull cg-restore cg-rm cg-seek cg-status cg-tag cg-tag-ls cg-update\n+\tcg-pull cg-restore cg-rm cg-seek cg-status cg-tag cg-tag-ls cg-update \\\n+\tcg-branch-switch\n \n LIB_SCRIPT=cg-Xlib cg-Xmergefile cg-Xnormid\n \ndiff --git a/cg-Xnormid b/cg-Xnormid\n--- a/cg-Xnormid\n+++ b/cg-Xnormid\n@@ -16,6 +16,8 @@\n \n id=\"$1\"\n \n+[ -L $_git/refs/heads/$id ] &&\n+id=$(readlink $_git/refs/heads/$id | sed 's@/@#@')\n repo=$(echo $id | cut -d '#' -f 1)\n (echo $repo | egrep -qv '[^a-zA-Z0-9_.@!:-]') || \\\n \tdie \"name contains invalid characters\"\ndiff --git a/cg-branch-add b/cg-branch-add\n--- a/cg-branch-add\n+++ b/cg-branch-add\n@@ -1,8 +1,11 @@\n #!/usr/bin/env bash\n #\n # Add new branch to the GIT repository.\n+# Or create local branch in the GIT repository.\n # Copyright (c) Petr Baudis, 2005\n #\n+# Adding a new branch\n+# -------------------\n # Takes the branch name and source location as parameters.\n # After you add a branch, you can `cg-pull` it whenever you want and\n # it will keep your objects database in sync with it. Its latest\n@@ -29,6 +32,22 @@\n #\t$ cg-branch-add repo-testing rsync://host/path/repo.git#testing\n #\n # and refer to it as 'repo-testing' anytime later.\n+#\n+# Creating a local branch\n+# -----------------------\n+# Takes the local branch name and origin branch as parameters.\n+#\n+# After you create a local branch, you can `cg-branch-switch` it whenever you\n+# want and you will be able to work on your local branch. Its {latest,origin}\n+# commit is accessible as `.git/refs/heads/{master,origin}` (or - more\n+# conveniently - as `$(commit-id {master,origin})`).\n+# For example, to make a diff between your origin and your current tree, do:\n+#\n+#\t$ cg-diff -r origin\n+#\n+# The origin specifier is a name of a branch added with cg-branch-add,\n+# followed with an optional fragment part, which identifies a alternative\n+# branch inside of the repository.\n \n USAGE=\"cg-branch-add BRANCH_NAME LOCATION\"\n \ndiff --git a/cg-branch-switch b/cg-branch-switch\nnew file mode 100644\n--- /dev/null\n+++ b/cg-branch-switch\n@@ -0,0 +1,107 @@\n+#!/usr/bin/env bash\n+#\n+# Switch to a local branch.\n+# Without arguments prints the branch.\n+#\n+# Takes the branch name as an argument.\n+# If the argument is an external branch switch to an unnamed branch.\n+#\n+# Local branches\n+# --------------\n+#\n+# The master file is always a link:\n+#\n+# master -> ${localbranch}\n+#\n+# The content of $_git/branches/${localbranch} is the original branch of\n+# local branch. The cases and the corresponding origin links are:\n+#\n+# 1a.- name         : a name of an external repository\n+#                     $branch corresponding to the definition\n+#                     origin -> $name/$branch\n+# 1b.- name#branch : optionally with a branch\n+#                     origin -> $name/$branch\n+# 2 .- name         : a name of another local branch\n+#                     $branch corresponding to the definition\n+#                     origin -> $name/$branch\n+#\n+# Local unnamed branches\n+# ----------------------\n+#\n+# The master file is a regula file and the origin link only has the cases\n+# 1a and 1b where the $name is the parameter to the script.\n+\n+USAGE=\"cg-switch-tree [BRANCH]\"\n+\n+. ${COGITO_LIB}cg-Xlib\n+\n+name=$1\n+\n+[ -e $_git/refs/heads/origin ] && [ ! -L $_git/refs/heads/origin ] &&\n+die \"$_git/refs/heads/origin must be a symbolic link\"\n+\n+[ -e $_git/blocked ] && die \"switch blocked: $(cat $_git/blocked)\"\n+\n+oldmaster=$(readlink $_git/refs/heads/master)\n+oldorigin=$(readlink $_git/refs/heads/origin)\n+\n+[ -z \"$name\" ] && echo \"master $(echo $oldmaster | sed 's@/@#@' )\" &&\n+echo \"origin $(echo $oldorigin | sed 's@/@#@' )\" && exit 0\n+\n+oldmaster=${oldmaster:-master}\n+\n+namerepo=$(echo $name | cut -d '#' -f 1)\n+namebranch=$(echo $name | cut -d '#' -f 2 -s)\n+[ -e \"$_git/branches/$namerepo\" ] || die \"unknown branch: $name\"\n+origuri=$(cat \"$_git/branches/$namerepo\")\n+origrepo=$(echo $origuri | cut -d '#' -f 1)\n+origbranch=$(echo $origuri | cut -d '#' -f 2 -s)\n+\n+if [ -e \"$_git/branches/$origrepo\" ] ; then\n+    # $name is a local branch\n+    switch=local\n+    master=$namerepo\n+    [ -e \"$_git/branches/$origrepo\" ] || die \"do not exist local branch: $name\"\n+    uri=$(cat $_git/branches/$origrepo)\n+    if [ -e \"$_git/branches/$(echo $uri| cut -d '#' -f 1)\" ] ; then\n+    # Origin is a local branch\n+\toriglink=$origuri\n+\t[ \"$namebranch\" ] && die \"local branches cannot have branches\"\n+    else\n+    # Origin is a external branch\n+\textbranch=${namebranch:-$origbranch}\n+\textbranch=${extbranch:-master}\n+\toriglink=$origrepo/$extbranch\n+    fi\n+else\n+    # Origin is an external unnamed branch\n+    switch=unnnamed\n+    extbranch=${namebranch:-$origbranch}\n+    extbranch=${extbranch:-master}\n+    origlink=$namerepo/$extbranch\n+    master=$namerepo/$extbranch\n+fi\n+\n+[ ! -r $_git/refs/heads/$origlink ] && die \"unknown branch: $origlink\"\n+\n+if [ \"$(git-diff-files -s)\" ] || [ \"$(git-diff-cache HEAD 2>/dev/null)\" ]; then\n+\tdie \"switch blocked: local changes\"\n+fi\n+\n+[ ! -r $_git/refs/heads/$master -o ! -s $_git/refs/heads/$master ] &&\n+[ \"$switch\" = \"local\" ] && cp $_git/refs/heads/$origlink $_git/refs/heads/$master\n+\n+( cd $_git/refs/heads/ &&\n+    [ -f master ] && [ ! -L master ] &&\n+    [ \"$(cat master)\" != \"$(cat origin)\" ] &&\n+    cp master master_$(date +%Y%m%d%H%M%S)\n+    rm -f master\n+    if [ \"$switch\" = \"local\" ] ; then\n+\tln -s $master master\n+    else\n+\tcp $master master\n+    fi\n+    ln -fs $origlink origin )\n+\n+git-read-tree -m HEAD && git-checkout-cache -q -f -u -a\n+\ndiff --git a/cg-clone b/cg-clone\n--- a/cg-clone\n+++ b/cg-clone\n@@ -6,10 +6,10 @@\n # This is like cg-init, but it will create a new directory where it will do\n # the checkout.\n #\n-# Takes a parameter specifying the location of the source repository and an\n-# optional second parameter specifying the destination. If the second\n-# parameter is omitted, the basename of the source repository is used as the\n-# destination.\n+# Takes two parameter specifying the name and location of the source\n+# repository, an optional third parameter specifying name of the local branch\n+# (defaults to an unnamed branch) and an optional fourth parameter specifying\n+# the destination (defaults to the basename of the source repository).\n #\n # OPTIONS\n # -------\n@@ -17,7 +17,7 @@\n #\tClone in the current directory instead of creating a new one.\n #\tSpecifying both -s and a desination directory makes no sense .\n \n-USAGE=\"cg-clone [-s] LOCATION [DESTDIR]\"\n+USAGE=\"cg-clone [-s] NAME LOCATION [LOCALNAME [DESTDIR]]\"\n \n . ${COGITO_LIB}cg-Xlib\n \n@@ -27,9 +27,16 @@ if [ \"$1\" = \"-s\" ]; then\n \tsame_dir=1\n fi\n \n+name=$1 && shift\n location=$1\n [ \"$location\" ] || usage\n location=${location%/}\n+if [ $location = $1 ] ; then\n+    branch=$(echo $location | cut -d '#' -f 2 -s)\n+    location=$(echo $location | cut -d '#' -f 1)\n+fi\n+shift\n+localbranch=$1\n \n destdir=$2\n if [ \"$destdir\" ]; then\n@@ -45,6 +52,8 @@ else\n \tlocation=\"$location\"\n fi\n \n+[ \"$branch\" ] && location=$location#$branch\n+\n if [ ! \"$same_dir\" ]; then\n \t[ -e \"$dir\" ] && die \"$dir/ already exists\"\n \tmkdir \"$dir\" || exit $?\n@@ -54,6 +63,15 @@ else\n fi\n \n trap \"rm -rf $dir\" SIGTERM EXIT\n-cg-init $location || exit $?\n+git-init-db\n+cg-branch-add $name $location\n+cg-pull $name || die \"pull failed\"\n+if [ \"$localbranch\" ] ; then\n+    cg-branch-add $localbranch $name\n+    cg-branch-switch $localbranch\n+else\n+    cg-branch-switch $name\n+fi\n+echo \"Master and origin branches are:\"\n+cg-branch-switch\n trap \"\" SIGTERM EXIT\n-echo \"Cloned to $dir/ (origin $location available as branch \\\"origin\\\")\"\ndiff --git a/cg-commit b/cg-commit\n--- a/cg-commit\n+++ b/cg-commit\n@@ -144,9 +144,16 @@ if [ \"$merging\" ]; then\n \t\trepo=$(echo $sym | cut -d '#' -f 1)\n \t\tbranch=$(echo $sym | cut -d '#' -f 2 -s)\n \t\turi=$(cat $_git/branches/$repo)\n+\t\turirepo=$(echo $uri | cut -d '#' -f 1)\n \t\turibranch=$(echo $uri | cut -d '#' -f 2 -s)\n-\t\t[ -z \"$uribranch\" ] && [ -n \"$branch\" ] &&\n-\t\t[ \"$branch\" != master ] && uri=${uri}#$branch\n+\t\tif [ -e $_git/branches/$urirepo ]; then\n+\t\t    # local branch\n+\t\t    uri=\"$sym\"\n+\t\telse\n+ \t\t    # remote branch\n+\t\t    [ -z \"$uribranch\" ] && [ -n \"$branch\" ] &&\n+\t\t    [ \"$branch\" != master ] && uri=${uri}#$branch\n+\t\tfi\n \t\t[ \"$uri\" ] || uri=\"$sym\"\n \t\techo \"$uri\" >>$LOGMSG\n \t\t[ \"$msgs\" ] && echo \"$uri\"\ndiff --git a/cg-merge b/cg-merge\n--- a/cg-merge\n+++ b/cg-merge\n@@ -42,7 +42,8 @@ fi\n [ \"$1\" ] || usage\n branchname=\"$1\"\n branch=$(commit-id \"$branchname\") || exit 1\n-\n+[ -L $_git/refs/heads/$branchname ] &&\n+branchname=$(readlink $_git/refs/heads/$branchname| sed 's@/@#@')\n [ \"$base\" ] || base=$(git-merge-base \"$head\" \"$branch\")\n [ \"$base\" ] || die \"unable to automatically determine merge base\"\n \ndiff --git a/cg-pull b/cg-pull\n--- a/cg-pull\n+++ b/cg-pull\n@@ -19,16 +19,24 @@ USAGE=\"cg-pull [-a] [BRANCH_NAME]\"\n [ \"$1\" == \"-a\" ] && all=yes && shift\n name=$1 && shift\n \n-[ \"$name\" ] || { [ -s $_git/refs/heads/origin ] && name=origin; }\n+if [ -z \"$name\" ] && [ -f $_git/branches/origin ]; then\n+\t#Convert the old layout 2005/06\n+\tmv $_git/branches/origin $_git/branches/original\n+\tbranch=$(cat $_git/branches/original | cut -s -d '#' -f 2)\n+\tbranch=${branch:-master}\n+\t[ -f $_git/refs/heads/origin -o -d $_git/refs/heads/origin ] &&\n+\trm -rf $_git/refs/heads/origin &&\n+\tln -s original/$branch $_git/refs/heads/origin\n+fi\n+[ \"$name\" ] || name=$(readlink $_git/refs/heads/origin | sed 's@/@#@')\n [ \"$name\" ] || die \"where to pull from?\"\n \n repo=$(echo $name | cut -d '#' -f 1)\n repobranch=$(echo $name | cut -s -d '#' -f 2)\n \n-uri=$(cat \"$_git/branches/$name\" 2>/dev/null) || die \"unknown branch: $name\"\n+uri=$(cat \"$_git/branches/$repo\" 2>/dev/null) || die \"unknown branch: $name\"\n if echo \"$uri\" | grep -q '#'; then\n \t[ -z \"$repobranch\" ] && repobranch=$(echo $uri | cut -d '#' -f 2)\n-\trembranch=$(echo $uri | cut -d '#' -f 2)\n \turi=$(echo $uri | cut -d '#' -f 1)\n fi\n repobranch=${repobranch:-master}\n\n"},{"id":"4368","messageId":"87mzqaqgv1.fsf@gmail.com","threadId":"795","inReplyTo":"87ekbmi5zl.fsf@ifae.es","subject":"Re: [COGITO PATCH] cg-branch-switch and local branches","fromName":"Santi Béjar","fromEmail":"sbejar@gmail.com","sentAt":"2005-06-01T14:41:38Z","receivedAt":"2005-06-01T14:41:38Z","isPatch":true,"sender":{"key":"santi@agolina.net","avatar":null},"body":"Hi,\n\n        after reading it I think I have to explain it better.\n\n        And first I have to say that this patch depends on my patches\n        in the thread \"[COGITO PATCH] Heads and tags in subdirectories\".\n        But the logic does not depend on it, I think :)\n\nSuppose I want to make some modifications to the cogito. So I do:\n\ncg-clone cogito rsync://rsync.kernel.org/pub/scm/cogito/cogito.git\n\nthe first argument been the name I've gave to this repositori. Now I can\ndo the changes/commits in the usual way. But I want to work in two\ndifferents patches, named dirs and switch, so I do:\n\ncg-branch-add dirs cogito\ncg-branch-add switch cogito\n\nNow I have to local branches with their respective names, and the origin\nbeen the cogito branch for both (but it can be different).\n\nIf I want to work on the dirs branch I do:\n\ncg-branch-switch dirs\n\nan the same for switch. In each case I can do a:\n\ncg-merge origin\n\nand merge their respective origin (in this case is the same).\n\nIf I want to work directly in cogito, I can do:\n\ncg-branch-switch cogito\n\nand work in the usual way. If the cogito repository have a branche\ncalled cogito2 I could do:\n\ncg-branch-switch cogito#cogito2\n\nin the case I've already pulled this branch.\n\nInternally it is:\n\nLocal branches\n--------------\n\nThe master file is always a link:\n\nmaster -> ${localbranch}\n\nThe content of $_git/branches/${localbranch} is the original branch of\nlocal branch. The cases and the corresponding origin links are:\n\n1a.- name         : a name of an external repository\n                    $branch corresponding to the definition\n                    origin -> $name/$branch\n1b.- name#branch : optionally with a branch\n                    origin -> $name/$branch\n2 .- name         : a name of another local branch\n                    $branch corresponding to the definition\n                    origin -> $name/$branch\n\nLocal unnamed branches\n----------------------\n\nThe master file is a regular file and the origin link only has the cases\n1a and 1b where the $name is name of the local branch.\n\n\n\n"},{"id":"4372","messageId":"877jheqcah.fsf@gmail.com","threadId":"795","inReplyTo":"87mzqaqgv1.fsf@gmail.com","subject":"Re: [COGITO PATCH] cg-branch-switch and local branches","fromName":"Santi Béjar","fromEmail":"sbejar@gmail.com","sentAt":"2005-06-01T16:20:22Z","receivedAt":"2005-06-01T16:20:22Z","isPatch":true,"sender":{"key":"santi@agolina.net","avatar":null},"body":"\nHere it is un update version fixing some bugs. It depends on my update\nversion of the \"[COGITO PATCH] Heads and tags in subdirectories\" patch.\n\n        Santi\n\n Makefile         |    3 +\n cg-Xnormid       |    2 +\n cg-branch-add    |   19 +++++++++\n cg-branch-switch |  107 +++++++++++++++++++++++++++++++++++++++++++++++++++++++\n cg-clone         |   32 ++++++++++++----\n cg-commit        |   17 +++++++-\n cg-merge         |    3 +\n cg-pull          |   24 ++++++++----\n 8 files changed, 189 insertions(+), 18 deletions(-)\n\ndiff --git a/Makefile b/Makefile\n--- a/Makefile\n+++ b/Makefile\n@@ -55,7 +55,8 @@ PROG=   git-update-cache git-diff-files \n SCRIPT=\tcommit-id tree-id parent-id cg-add cg-admin-lsobj cg-admin-uncommit \\\n \tcg-branch-add cg-branch-ls cg-cancel cg-clone cg-commit cg-diff \\\n \tcg-export cg-help cg-init cg-log cg-ls cg-merge cg-mkpatch cg-patch \\\n-\tcg-pull cg-restore cg-rm cg-seek cg-status cg-tag cg-tag-ls cg-update\n+\tcg-pull cg-restore cg-rm cg-seek cg-status cg-tag cg-tag-ls cg-update \\\n+\tcg-branch-switch\n \n LIB_SCRIPT=cg-Xlib cg-Xmergefile cg-Xnormid\n \ndiff --git a/cg-Xnormid b/cg-Xnormid\n--- a/cg-Xnormid\n+++ b/cg-Xnormid\n@@ -16,6 +16,8 @@\n \n id=\"$1\"\n \n+[ -L $_git/refs/heads/$id ] &&\n+id=$(readlink $_git/refs/heads/$id | sed 's@/@#@')\n repo=$(echo $id | cut -d '#' -f 1)\n (echo $repo | egrep -qv '[^a-zA-Z0-9_.@!:-]') || \\\n \tdie \"name contains invalid characters\"\ndiff --git a/cg-branch-add b/cg-branch-add\n--- a/cg-branch-add\n+++ b/cg-branch-add\n@@ -1,8 +1,11 @@\n #!/usr/bin/env bash\n #\n # Add new branch to the GIT repository.\n+# Or create local branch in the GIT repository.\n # Copyright (c) Petr Baudis, 2005\n #\n+# Adding a new branch\n+# -------------------\n # Takes the branch name and source location as parameters.\n # After you add a branch, you can `cg-pull` it whenever you want and\n # it will keep your objects database in sync with it. Its latest\n@@ -29,6 +32,22 @@\n #\t$ cg-branch-add repo-testing rsync://host/path/repo.git#testing\n #\n # and refer to it as 'repo-testing' anytime later.\n+#\n+# Creating a local branch\n+# -----------------------\n+# Takes the local branch name and origin branch as parameters.\n+#\n+# After you create a local branch, you can `cg-branch-switch` it whenever you\n+# want and you will be able to work on your local branch. Its {latest,origin}\n+# commit is accessible as `.git/refs/heads/{master,origin}` (or - more\n+# conveniently - as `$(commit-id {master,origin})`).\n+# For example, to make a diff between your origin and your current tree, do:\n+#\n+#\t$ cg-diff -r origin\n+#\n+# The origin specifier is a name of a branch added with cg-branch-add,\n+# followed with an optional fragment part, which identifies a alternative\n+# branch inside of the repository.\n \n USAGE=\"cg-branch-add BRANCH_NAME LOCATION\"\n \ndiff --git a/cg-branch-switch b/cg-branch-switch\nnew file mode 100644\n--- /dev/null\n+++ b/cg-branch-switch\n@@ -0,0 +1,107 @@\n+#!/usr/bin/env bash\n+#\n+# Switch to a local branch.\n+# Without arguments prints the branch.\n+#\n+# Takes the branch name as an argument.\n+# If the argument is an external branch switch to an unnamed branch.\n+#\n+# Local branches\n+# --------------\n+#\n+# The master file is always a link:\n+#\n+# master -> ${localbranch}\n+#\n+# The content of $_git/branches/${localbranch} is the original branch of\n+# local branch. The cases and the corresponding origin links are:\n+#\n+# 1a.- name         : a name of an external repository\n+#                     $branch corresponding to the definition\n+#                     origin -> $name/$branch\n+# 1b.- name#branch : optionally with a branch\n+#                     origin -> $name/$branch\n+# 2 .- name         : a name of another local branch\n+#                     $branch corresponding to the definition\n+#                     origin -> $name/$branch\n+#\n+# Local unnamed branches\n+# ----------------------\n+#\n+# The master file is a regula file and the origin link only has the cases\n+# 1a and 1b where the $name is the parameter to the script.\n+\n+USAGE=\"cg-switch-tree [BRANCH]\"\n+\n+. ${COGITO_LIB}cg-Xlib\n+\n+name=$1\n+\n+[ -e $_git/refs/heads/origin ] && [ ! -L $_git/refs/heads/origin ] &&\n+die \"$_git/refs/heads/origin must be a symbolic link\"\n+\n+[ -e $_git/blocked ] && die \"switch blocked: $(cat $_git/blocked)\"\n+\n+oldmaster=$(readlink $_git/refs/heads/master)\n+oldorigin=$(readlink $_git/refs/heads/origin)\n+\n+[ -z \"$name\" ] && echo \"master $(echo $oldmaster | sed 's@/@#@' )\" &&\n+echo \"origin $(echo $oldorigin | sed 's@/@#@' )\" && exit 0\n+\n+oldmaster=${oldmaster:-master}\n+\n+namerepo=$(echo $name | cut -d '#' -f 1)\n+namebranch=$(echo $name | cut -d '#' -f 2 -s)\n+[ -e \"$_git/branches/$namerepo\" ] || die \"unknown branch: $name\"\n+origuri=$(cat \"$_git/branches/$namerepo\")\n+origrepo=$(echo $origuri | cut -d '#' -f 1)\n+origbranch=$(echo $origuri | cut -d '#' -f 2 -s)\n+\n+if [ -e \"$_git/branches/$origrepo\" ] ; then\n+    # $name is a local branch\n+    switch=local\n+    master=$namerepo\n+    [ -e \"$_git/branches/$origrepo\" ] || die \"do not exist local branch: $name\"\n+    uri=$(cat $_git/branches/$origrepo)\n+    if [ -e \"$_git/branches/$(echo $uri| cut -d '#' -f 1)\" ] ; then\n+    # Origin is a local branch\n+\toriglink=$origuri\n+\t[ \"$namebranch\" ] && die \"local branches cannot have branches\"\n+    else\n+    # Origin is a external branch\n+\textbranch=${namebranch:-$origbranch}\n+\textbranch=${extbranch:-master}\n+\toriglink=$origrepo/$extbranch\n+    fi\n+else\n+    # Origin is an external unnamed branch\n+    switch=unnnamed\n+    extbranch=${namebranch:-$origbranch}\n+    extbranch=${extbranch:-master}\n+    origlink=$namerepo/$extbranch\n+    master=$namerepo/$extbranch\n+fi\n+\n+[ ! -r $_git/refs/heads/$origlink ] && die \"unknown branch: $origlink\"\n+\n+if [ \"$(git-diff-files -s)\" ] || [ \"$(git-diff-cache HEAD 2>/dev/null)\" ]; then\n+\tdie \"switch blocked: local changes\"\n+fi\n+\n+[ ! -r $_git/refs/heads/$master -o ! -s $_git/refs/heads/$master ] &&\n+[ \"$switch\" = \"local\" ] && cp $_git/refs/heads/$origlink $_git/refs/heads/$master\n+\n+( cd $_git/refs/heads/ &&\n+    [ -f master ] && [ ! -L master ] &&\n+    [ \"$(cat master)\" != \"$(cat origin)\" ] &&\n+    cp master master_$(date +%Y%m%d%H%M%S)\n+    rm -f master\n+    if [ \"$switch\" = \"local\" ] ; then\n+\tln -s $master master\n+    else\n+\tcp $master master\n+    fi\n+    ln -fs $origlink origin )\n+\n+git-read-tree -m HEAD && git-checkout-cache -q -f -u -a\n+\ndiff --git a/cg-clone b/cg-clone\n--- a/cg-clone\n+++ b/cg-clone\n@@ -6,10 +6,10 @@\n # This is like cg-init, but it will create a new directory where it will do\n # the checkout.\n #\n-# Takes a parameter specifying the location of the source repository and an\n-# optional second parameter specifying the destination. If the second\n-# parameter is omitted, the basename of the source repository is used as the\n-# destination.\n+# Takes two parameter specifying the name and location of the source\n+# repository, an optional third parameter specifying name of the local branch\n+# (defaults to an unnamed branch) and an optional fourth parameter specifying\n+# the destination (defaults to the basename of the source repository).\n #\n # OPTIONS\n # -------\n@@ -17,7 +17,7 @@\n #\tClone in the current directory instead of creating a new one.\n #\tSpecifying both -s and a desination directory makes no sense .\n \n-USAGE=\"cg-clone [-s] LOCATION [DESTDIR]\"\n+USAGE=\"cg-clone [-s] NAME LOCATION [LOCALNAME [DESTDIR]]\"\n \n . ${COGITO_LIB}cg-Xlib\n \n@@ -27,9 +27,16 @@ if [ \"$1\" = \"-s\" ]; then\n \tsame_dir=1\n fi\n \n+name=$1 && shift\n location=$1\n [ \"$location\" ] || usage\n location=${location%/}\n+if [ $location = $1 ] ; then\n+    branch=$(echo $location | cut -d '#' -f 2 -s)\n+    location=$(echo $location | cut -d '#' -f 1)\n+fi\n+shift\n+localbranch=$1\n \n destdir=$2\n if [ \"$destdir\" ]; then\n@@ -45,6 +52,8 @@ else\n \tlocation=\"$location\"\n fi\n \n+[ \"$branch\" ] && location=$location#$branch\n+\n if [ ! \"$same_dir\" ]; then\n \t[ -e \"$dir\" ] && die \"$dir/ already exists\"\n \tmkdir \"$dir\" || exit $?\n@@ -54,6 +63,15 @@ else\n fi\n \n trap \"rm -rf $dir\" SIGTERM EXIT\n-cg-init $location || exit $?\n+git-init-db\n+cg-branch-add $name $location\n+cg-pull $name || die \"pull failed\"\n+if [ \"$localbranch\" ] ; then\n+    cg-branch-add $localbranch $name\n+    cg-branch-switch $localbranch\n+else\n+    cg-branch-switch $name\n+fi\n+echo \"Master and origin branches are:\"\n+cg-branch-switch\n trap \"\" SIGTERM EXIT\n-echo \"Cloned to $dir/ (origin $location available as branch \\\"origin\\\")\"\ndiff --git a/cg-commit b/cg-commit\n--- a/cg-commit\n+++ b/cg-commit\n@@ -143,10 +143,23 @@ if [ \"$merging\" ]; then\n \tfor sym in $(cat $_git/merging-sym); do\n \t\trepo=$(echo $sym | cut -d '#' -f 1)\n \t\tbranch=$(echo $sym | cut -d '#' -f 2 -s)\n+\t\tif [ -L $_git/refs/heads/$sym ]; then\n+\t\t\turi=$(readlink $_git/refs/heads/$sym)\n+\t\t\trepo=$(echo $uri | cut -d '#' -f 1)\n+\t\t\t[ -z \"$branch\" ] &&\n+\t\t\tbranch=$(echo $uri | cut -d '#' -f 2 -s)\n+\t\tfi\n \t\turi=$(cat $_git/branches/$repo)\n+\t\turirepo=$(echo $uri | cut -d '#' -f 1)\n \t\turibranch=$(echo $uri | cut -d '#' -f 2 -s)\n-\t\t[ -z \"$uribranch\" ] && [ -n \"$branch\" ] &&\n-\t\t[ \"$branch\" != master ] && uri=${uri}#$branch\n+\t\tif [ -e $_git/branches/$urirepo ]; then\n+\t\t    # local branch\n+\t\t    uri=\"$repo\"\n+\t\telse\n+ \t\t    # remote branch\n+\t\t    [ -z \"$uribranch\" ] && [ -n \"$branch\" ] &&\n+\t\t    [ \"$branch\" != master ] && uri=${uri}#$branch\n+\t\tfi\n \t\t[ \"$uri\" ] || uri=\"$sym\"\n \t\techo \"$uri\" >>$LOGMSG\n \t\t[ \"$msgs\" ] && echo \"$uri\"\ndiff --git a/cg-merge b/cg-merge\n--- a/cg-merge\n+++ b/cg-merge\n@@ -42,7 +42,8 @@ fi\n [ \"$1\" ] || usage\n branchname=\"$1\"\n branch=$(commit-id \"$branchname\") || exit 1\n-\n+[ -L $_git/refs/heads/$branchname ] &&\n+branchname=$(readlink $_git/refs/heads/$branchname| sed 's@/@#@')\n [ \"$base\" ] || base=$(git-merge-base \"$head\" \"$branch\")\n [ \"$base\" ] || die \"unable to automatically determine merge base\"\n \ndiff --git a/cg-pull b/cg-pull\n--- a/cg-pull\n+++ b/cg-pull\n@@ -19,18 +19,28 @@ USAGE=\"cg-pull [-a] [BRANCH_NAME]\"\n [ \"$1\" == \"-a\" ] && all=yes && shift\n name=$1 && shift\n \n-[ \"$name\" ] || { [ -s $_git/refs/heads/origin ] && name=origin; }\n+if [ -z \"$name\" ] && [ -f $_git/branches/origin ]; then\n+\t#Convert the old layout 2005/06\n+\tmv $_git/branches/origin $_git/branches/original\n+\tbranch=$(cat $_git/branches/original | cut -s -d '#' -f 2)\n+\tbranch=${branch:-master}\n+\t[ -f $_git/refs/heads/origin -o -d $_git/refs/heads/origin ] &&\n+\trm -rf $_git/refs/heads/origin &&\n+\tln -s original/$branch $_git/refs/heads/origin\n+fi\n+[ \"$name\" ] || name=$(readlink $_git/refs/heads/origin | sed 's@/@#@')\n [ \"$name\" ] || die \"where to pull from?\"\n \n repo=$(echo $name | cut -d '#' -f 1)\n repobranch=$(echo $name | cut -s -d '#' -f 2)\n \n-uri=$(cat \"$_git/branches/$name\" 2>/dev/null) || die \"unknown branch: $name\"\n-if echo \"$uri\" | grep -q '#'; then\n-\t[ -z \"$repobranch\" ] && repobranch=$(echo $uri | cut -d '#' -f 2)\n-\trembranch=$(echo $uri | cut -d '#' -f 2)\n-\turi=$(echo $uri | cut -d '#' -f 1)\n-fi\n+uri=$(cat \"$_git/branches/$repo\" 2>/dev/null) || die \"unknown branch: $name\"\n+urirepo=$(echo $uri | cut -d '#' -f 1)\n+uribranch=$(echo $uri | cut -d '#' -f 2 -s)\n+\n+[ -e $_git/branches/$urirepo ] && die \"Local branches are already pulled\"\n+\n+repobranch=${repobranch:-$uribranch}\n repobranch=${repobranch:-master}\n branch=$repo/$repobranch\n [ \"$all\" ] && repobranch=\n\n"},{"id":"4397","messageId":"87ekblthlp.fsf@gmail.com","threadId":"795","inReplyTo":"877jheqcah.fsf@gmail.com","subject":"Re: [COGITO PATCH] cg-branch-switch and local branches","fromName":"Santi Béjar","fromEmail":"sbejar@gmail.com","sentAt":"2005-06-02T06:09:38Z","receivedAt":"2005-06-02T06:09:38Z","isPatch":true,"sender":{"key":"santi@agolina.net","avatar":null},"body":"Hi,\n\n        I have realized that it was overcomplicated and against the\n        common practice of having .git/HEAD pointing to the current\n        branch, as I've just seen on a git-switch-branch by Jeff.\n\n        But the only thing I miss now is the origin handling.\n\n        Sorry for the noise.\n\n        Santi\n\n"}]}