{"thread":{"id":"3500","subject":"[PATCH] Teach git-checkout-index to use file suffixes.","startedAt":"2006-03-01T04:41:32Z","lastAt":"2006-03-02T17:10:09Z","messageCount":6,"participants":["Shawn Pearce","Mark Wooding","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"16930","messageId":"20060301044132.GF22894@spearce.org","threadId":"3500","inReplyTo":null,"subject":"[PATCH] Teach git-checkout-index to use file suffixes.","fromName":"Shawn Pearce","fromEmail":"spearce@spearce.org","sentAt":"2006-03-01T04:41:32Z","receivedAt":"2006-03-01T04:41:32Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Sometimes it is useful to unpack the unmerged stage entries\nto the same directory as the tracked file itself, but with\na suffix indicating which stage that version came from.\nIn many user interface level scripts this is being done\nby git-unpack-file followed by creating the necessary\ndirectory structure and then moving the file into the\ndirectory with the requested name.  It is now possible to\nperform the same action for a larger set of files directly\nthrough git-checkout-index.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n\n---\n I think this completes the two features I've found missing from\n git-checkout-index:  --stdin and --suffix.  These two options\n should make writing a working directory based merge strategy\n a little easier.\n\n FYI: I built this on top of my immediately prior patch ('Teach\n git-checkout-index to read filenames from stdin.') so this one\n may not apply cleanly without that patch being applied first.\n\n Documentation/git-checkout-index.txt |   29 ++++++++++++++++++++++++++++-\n apply.c                              |    2 ++\n cache.h                              |    2 ++\n checkout-index.c                     |   14 ++++++++++++--\n entry.c                              |   10 +++++++---\n read-tree.c                          |    1 +\n 6 files changed, 52 insertions(+), 6 deletions(-)\n\nbase df23c1119d0af1fbac6b8afd296113e155d9a878\nlast e1674dc0b01de5c34fada13f7cf5fcbb3be82d09\ndiff --git a/Documentation/git-checkout-index.txt b/Documentation/git-checkout-index.txt\nindex b0b6588..f0be2a0 100644\n--- a/Documentation/git-checkout-index.txt\n+++ b/Documentation/git-checkout-index.txt\n@@ -9,7 +9,8 @@ git-checkout-index - Copy files from the\n SYNOPSIS\n --------\n [verse]\n-'git-checkout-index' [-u] [-q] [-a] [-f] [-n] [--prefix=<string>]\n+'git-checkout-index' [-u] [-q] [-a] [-f] [-n]\n+\t\t   [--prefix=<string>] [--suffix=<string>]\n \t\t   [--stage=<number>]\n \t\t   [-z] [--stdin]\n \t\t   [--] [<file>]\\*\n@@ -43,6 +44,10 @@ OPTIONS\n \tWhen creating files, prepend <string> (usually a directory\n \tincluding a trailing /)\n \n+--suffix=<string>::\n+\tWhen creating files, append <string> to the name.  The value\n+\tof <string> must not contain a directory separator (/).\n+\n --stage=<number>::\n \tInstead of checking out unmerged entries, copy out the\n \tfiles from named stage.  <number> must be between 1 and 3.\n@@ -120,6 +125,28 @@ $ git-checkout-index --prefix=.merged- M\n This will check out the currently cached copy of `Makefile`\n into the file `.merged-Makefile`.\n \n+Export files with a suffix::\n++\n+----------------\n+$ git-checkout-index --suffix=\\#2 --stage=2 Makefile\n+----------------\n++\n+If `Makefile` is unmerged and has a stage 2 entry in the index\n+this will check out that version into the file `Makefile#2`.\n+\n+A suffix may be preferred over a prefix when checking out all\n+unmerged entries:\n++\n+----------------\n+$ git-checkout-index --suffix=\\#1 --stage=1 --all\n+$ git-checkout-index --suffix=\\#2 --stage=2 --all\n+$ git-checkout-index --suffix=\\#3 --stage=3 --all\n+----------------\n++\n+would unpack all unmerged stages into the same directory as the\n+tracked file.  (Compare with --prefix=.stage1/ which would have\n+created a partial directory tree within `.stage1/`.)\n+\n \n Author\n ------\ndiff --git a/apply.c b/apply.c\nindex 244718c..1ec8473 100644\n--- a/apply.c\n+++ b/apply.c\n@@ -1307,6 +1307,8 @@ static int check_patch(struct patch *pat\n \t\t\t\t/* checkout */\n \t\t\t\tcostate.base_dir = \"\";\n \t\t\t\tcostate.base_dir_len = 0;\n+\t\t\t\tcostate.name_suffix = \"\";\n+\t\t\t\tcostate.name_suffix_len = 0;\n \t\t\t\tcostate.force = 0;\n \t\t\t\tcostate.quiet = 0;\n \t\t\t\tcostate.not_new = 0;\ndiff --git a/cache.h b/cache.h\nindex 58eec00..055e213 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -254,6 +254,8 @@ extern const char *git_committer_info(in\n struct checkout {\n \tconst char *base_dir;\n \tint base_dir_len;\n+\tconst char *name_suffix;\n+\tint name_suffix_len;\n \tunsigned force:1,\n \t\t quiet:1,\n \t\t not_new:1,\ndiff --git a/checkout-index.c b/checkout-index.c\nindex f54c606..af7b230 100644\n--- a/checkout-index.c\n+++ b/checkout-index.c\n@@ -47,6 +47,8 @@ static int checkout_stage; /* default to\n static struct checkout state = {\n \t.base_dir = \"\",\n \t.base_dir_len = 0,\n+\t.name_suffix = \"\",\n+\t.name_suffix_len = 0,\n \t.force = 0,\n \t.quiet = 0,\n \t.not_new = 0,\n@@ -180,6 +182,14 @@ int main(int argc, char **argv)\n \t\t\tstate.base_dir_len = strlen(state.base_dir);\n \t\t\tcontinue;\n \t\t}\n+\t\tif (!strncmp(arg, \"--suffix=\", 9)) {\n+\t\t\tif (strchr(arg+9, '/')) {\n+\t\t\t\tdie(\"--suffix cannot contain /\");\n+\t\t\t}\n+\t\t\tstate.name_suffix = arg+9;\n+\t\t\tstate.name_suffix_len = strlen(state.name_suffix);\n+\t\t\tcontinue;\n+\t\t}\n \t\tif (!strncmp(arg, \"--stage=\", 8)) {\n \t\t\tint ch = arg[8];\n \t\t\tif ('1' <= ch && ch <= '3')\n@@ -193,8 +203,8 @@ int main(int argc, char **argv)\n \t\tbreak;\n \t}\n \n-\tif (state.base_dir_len) {\n-\t\t/* when --prefix is specified we do not\n+\tif (state.base_dir_len || state.name_suffix_len) {\n+\t\t/* when --prefix or --suffix is specified we do not\n \t\t * want to update cache.\n \t\t */\n \t\tif (state.refresh_cache) {\ndiff --git a/entry.c b/entry.c\nindex 8fb99bc..dc35a07 100644\n--- a/entry.c\n+++ b/entry.c\n@@ -117,10 +117,14 @@ int checkout_entry(struct cache_entry *c\n {\n \tstruct stat st;\n \tstatic char path[MAXPATHLEN+1];\n-\tint len = state->base_dir_len;\n+\tint len1 = state->base_dir_len;\n+\tint len2 = strlen(ce->name);\n+\tint len3 = state->name_suffix_len;\n+\tchar *path_len1 = path + len1;\n \n-\tmemcpy(path, state->base_dir, len);\n-\tstrcpy(path + len, ce->name);\n+\tmemcpy(path, state->base_dir, len1);\n+\tmemcpy(path_len1, ce->name, len2 + 1);\n+\tmemcpy(path_len1 + len2, state->name_suffix, len3 + 1);\n \n \tif (!lstat(path, &st)) {\n \t\tunsigned changed = ce_match_stat(ce, &st, 1);\ndiff --git a/read-tree.c b/read-tree.c\nindex f39fe5c..f223a0d 100644\n--- a/read-tree.c\n+++ b/read-tree.c\n@@ -281,6 +281,7 @@ static void check_updates(struct cache_e\n {\n \tstatic struct checkout state = {\n \t\t.base_dir = \"\",\n+\t\t.name_suffix = \"\",\n \t\t.force = 1,\n \t\t.quiet = 1,\n \t\t.refresh_cache = 1,\n-- \n1.2.3.gdf23c-dirty\n"},{"id":"16944","messageId":"20060301150629.GB3456@spearce.org","threadId":"3500","inReplyTo":"20060301044132.GF22894@spearce.org","subject":"Re: [PATCH] Teach git-checkout-index to use file suffixes.","fromName":"Shawn Pearce","fromEmail":"spearce@spearce.org","sentAt":"2006-03-01T15:06:29Z","receivedAt":"2006-03-01T15:06:29Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Shawn Pearce <spearce@spearce.org> wrote:\n> Sometimes it is useful to unpack the unmerged stage entries\n> to the same directory as the tracked file itself, but with\n> a suffix indicating which stage that version came from.\n> In many user interface level scripts this is being done\n> by git-unpack-file followed by creating the necessary\n> directory structure and then moving the file into the\n> directory with the requested name.  It is now possible to\n> perform the same action for a larger set of files directly\n> through git-checkout-index.\n\nJunio mentioned in his ``What's in git.git'' email that he's not\nsure of this command line interface:\n\nJunio C Hamano <junkio@cox.net> wrote:\n> I am not sure about the command line interface of this.  Would\n> it make more sense to checkout three stages in one pass?\n> \n>     - checkout-index --suffix (Shawn Pearce)\n\nI thought about the same thing myself when I submitted the patch\nto the list.  I probably should have talked a little bit about that\nin the email.  :-)\n\nI thought about using instead:\n\n  --stage=all --suffix1=\\#1 --suffix2\\=#2 --suffix3=\\#3\n\nbut then thought that the performance gains achieved by only forking\ngit-checkout-index once, scanning the index once, etc. were not\nthat big of a difference compared to the rather horrible looking\ncommand line syntax that produced and required one to use.\n\nIf anyone has any suggestions for these options, please pass them\nalong.  I'll rebuild the patch to pull all available stages if we\ncan come up with a suitable way of describing such.\n\n-- \nShawn.\n"},{"id":"16951","messageId":"slrne0bh1p.fr9.mdw@metalzone.distorted.org.uk","threadId":"3500","inReplyTo":"20060301150629.GB3456@spearce.org","subject":"Re: [PATCH] Teach git-checkout-index to use file suffixes.","fromName":"Mark Wooding","fromEmail":"mdw@distorted.org.uk","sentAt":"2006-03-01T15:56:41Z","receivedAt":"2006-03-01T15:56:41Z","isPatch":true,"sender":{"key":"mdw@distorted.org.uk","avatar":null},"body":"Shawn Pearce <spearce@spearce.org> wrote:\n\n> I thought about using instead:\n>\n>   --stage=all --suffix1=\\#1 --suffix2\\=#2 --suffix3=\\#3\n\nHow about something like\n\n  --suffixes=:#1:#2:#3\n\nuses first character as a delimiter to separate the suffixes.  A single\n--suffix option could plausibly provide the suffix if only one stage is\nbeing checked out, and doesn't have the grim delimiter wart.\n\nI suppose, though, that if this is going to be wrapped up in a script,\nit doesn't really matter that much.\n\n-- [mdw]\n"},{"id":"17021","messageId":"20060302065136.GA6377@spearce.org","threadId":"3500","inReplyTo":"slrne0bh1p.fr9.mdw@metalzone.distorted.org.uk","subject":"Re: [PATCH] Teach git-checkout-index to use file suffixes.","fromName":"Shawn Pearce","fromEmail":"spearce@spearce.org","sentAt":"2006-03-02T06:51:36Z","receivedAt":"2006-03-02T06:51:36Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Mark Wooding <mdw@distorted.org.uk> wrote:\n> Shawn Pearce <spearce@spearce.org> wrote:\n> \n> > I thought about using instead:\n> >\n> >   --stage=all --suffix1=\\#1 --suffix2\\=#2 --suffix3=\\#3\n> \n> How about something like\n> \n>   --suffixes=:#1:#2:#3\n> \n> uses first character as a delimiter to separate the suffixes.  A single\n> --suffix option could plausibly provide the suffix if only one stage is\n> being checked out, and doesn't have the grim delimiter wart.\n\nWhy let the user choose?  '/' shouldn't be permitted as that\n(possibly) would try to create a directory also named the same as\nthe file (a bad thing).  Then its just two formats, depending on\nif you want all stages or just 1 stage:\n\n\t--stage=all --suffix=#1/#2/#3\n\nor\n\n\t--stage=1 --suffix=#1\n\n?\n\n-- \nShawn.\n"},{"id":"17022","messageId":"7vbqwp6zvg.fsf@assigned-by-dhcp.cox.net","threadId":"3500","inReplyTo":"20060302065136.GA6377@spearce.org","subject":"Re: [PATCH] Teach git-checkout-index to use file suffixes.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-03-02T07:59:31Z","receivedAt":"2006-03-02T07:59:31Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Shawn Pearce <spearce@spearce.org> writes:\n\n> Why let the user choose?  '/' shouldn't be permitted as that\n> (possibly) would try to create a directory also named the same as\n> the file (a bad thing).  Then its just two formats, depending on\n> if you want all stages or just 1 stage:\n>\n> \t--stage=all --suffix=#1/#2/#3\n>\n> or\n>\n> \t--stage=1 --suffix=#1\n\nI'll later agree with \"why let the user choose\" in this message,\nbut for an entirely different reason.\n\nI am not a great fan of extracting files from stages in the\nworking tree to begin with.  The git-unpack-file command tries\ncarefully to avoid conflicts, and its use of temporary files is\ninherently, eh, temporary, and Porcelains know what names they\nget and know how to clean things up afterwards.\n\nI am sympathetic to what you are trying to achieve here.  Maybe\nyour Porcelain would invoke a graphical 3-way merge program in a\nwindowing environment, and the merge program displays the\nfilename(s) your Porcelain fed it to the end user, without\ngiving you a way to override it.  In that context, it is not\nuseful to the end user to show meaningless temporary filename,\nand having checkout-index to derive the temporary filename from\nreal filename may look sensible.\n\nHowever, --stage=all with --suffix would introduce name clashes\nbetween repeated conflicted merge runs, which requires Porcelain\nto be extra careful.  Your last merge run might have involved\nthree conflicting stages (leaving a.c~1, a.c~2, and a.c~3 in\nyour working tree) and this time it may be \"we removed it while\nthey modified it\" situation (needing to extract a.c~1, a.c~3 but\nnot a.c~2).  The Porcelain needs to make sure not to get\nconfused by leftover a.c~2 file in the working tree from the\nprevious run.\n\nIf what you are trying is to reduce the number of checkout-index\ncalls by your Porcelain to extract conflicted stages, it _might_\nmake more sense to do something like this instead (I am thinking\naloud, so take this with a big grain of salt -- it may not make\nsense at all):\n\n    checkout-index --stage=all checks out higher-order stages in\n    made-up temporary filenames, just like git-merge-one-file\n    does using git-unpack-file one-by-one, with a single\n    invocation.\n\n    It reports the following to its standard output, one record\n    per pathname in the index:\n\n\ttmp1 <SP> tmp2 <SP> tmp3 <TAB> pathname <RS>\n\n    Here, tmp? is the temporary file names for each stage, or a\n    dot for for a nonexistent stage.  pathname is c-quoted as\n    usual for non -z output and RS is '\\n' (under -z flag,\n    pathname is a literal string and RS is NUL).  SP = space\n    (ASCII 0x20), TAB = tab (ASCII 0x09).\n\n    Example:\n\n        \".tmp1323 . .tmp1232\\tfoo/a.c\\n\"\n\n    Notice the dot between the two temporary files -- stage2 is\n    empty in this example.\n\nThen your Porcelain could run --stage=all and read the output,\nand then moving the temporary files around whatever way pleases\nit.  Since it needs to be careful about not overwriting the\nexisting working tree files *and* not getting confused by\nexisting garbage in the working tree anyway, I do not think it\nwould make your life much easier to have checkout-index derive\nthe temporary file names after the real working tree files.\n\nBTW, using TAB to split metainformation and pathname and using\nSP to separate metainformation pieces are in line with the\ndesign other git tools use.  With this, you can separate the LHS\nmetainformation part and pathname using \"cut\", and you can have\nshell IFS to split the metainformation part apart after that.\nBut that is a minor detail.\n"},{"id":"17060","messageId":"20060302171009.GD18929@spearce.org","threadId":"3500","inReplyTo":"7vbqwp6zvg.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] Teach git-checkout-index to use file suffixes.","fromName":"Shawn Pearce","fromEmail":"spearce@spearce.org","sentAt":"2006-03-02T17:10:09Z","receivedAt":"2006-03-02T17:10:09Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Junio C Hamano <junkio@cox.net> wrote:\n[...]\n> However, --stage=all with --suffix would introduce name clashes\n> between repeated conflicted merge runs, which requires Porcelain\n> to be extra careful.  Your last merge run might have involved\n> three conflicting stages (leaving a.c~1, a.c~2, and a.c~3 in\n> your working tree) and this time it may be \"we removed it while\n> they modified it\" situation (needing to extract a.c~1, a.c~3 but\n> not a.c~2).  The Porcelain needs to make sure not to get\n> confused by leftover a.c~2 file in the working tree from the\n> previous run.\n\nClearly.  pg was trying to delete all of those files before doing its\nmerge work but failed because of the --ignored bug in git-ls-files;\nbut this is now fixed.  Still a possibility for confusion does exist.\n\nBut in at least one case my Porcelain is Eclipse and a Cygwin\nprompt.  In this case I want to view and edit everything in Eclipse.\nHaving all of the files in the same directory just makes it easier\nto view.  Random temporary names in the same directory as the tracked\nfile would be OK except if I had multiple conflicts in the same\ndirectory, in which case I need some easy way to tell them apart.\nAt which point we're starting to derive off the tracked file name\nand might as well always use well-known names.\n \n> If what you are trying is to reduce the number of checkout-index\n> calls by your Porcelain to extract conflicted stages, it _might_\n> make more sense to do something like this instead (I am thinking\n> aloud, so take this with a big grain of salt -- it may not make\n> sense at all):\n> \n>     checkout-index --stage=all checks out higher-order stages in\n>     made-up temporary filenames, just like git-merge-one-file\n>     does using git-unpack-file one-by-one, with a single\n>     invocation.\n> \n>     It reports the following to its standard output, one record\n>     per pathname in the index:\n> \n> \ttmp1 <SP> tmp2 <SP> tmp3 <TAB> pathname <RS>\n[...]\n\nThat's not a bad idea.  The only thing I don't like about that\nis that git-checkout-index won't build the directory tree for me;\nthe Porcelain must still be responsible for doing that before it\ncan rename the temporary files (if available) into the correct\nsubdirectory.\n\nMy plan with git-checkout-index though was originally to just have\nit fail if the file already exists, unless -f is given.  So if\na left-over foo.c#2 was still on disk and git-checkout-index was\ngoing to write to that name it would fail.\n\n\nI see a lot of benefit from the checkout to temporary file names\nand let the Porcelian rename (if it desires).\n\nSo I'm going to ask you to withdraw the --suffix patch from pu.\nI'll write up a new patch using the ideas you suggest above and\nsubmit that instead.\n\n-- \nShawn.\n"}]}