# index manipulation -- how?

7 messages from 2005-11-22 to 2005-11-22. Participants: Luben Tuikov, Junio C Hamano, Linus Torvalds.
Thread: https://gitlist.dev/t/2646

## Luben Tuikov, 2005-11-22 05:03

Subject: index manipulation -- how?
Message-ID: <20051122050337.46450.qmail@web31808.mail.mud.yahoo.com>
URL: https://gitlist.dev/e/20051122050337.46450.qmail%40web31808.mail.mud.yahoo.com

```
I've a question:

Suppose I've updated the index and there is
several updates pending in it: several new
files, and several updates, etc.

That is a sequence of:
git-update-index [options] <file>
...

My question is:
How do I reverse a _single_ "git-update-index" operation?
Be it --add or just an update.

Thanks,
    Luben

```

## Linus Torvalds, 2005-11-22 05:23

Subject: Re: index manipulation -- how?
Message-ID: <Pine.LNX.4.64.0511212113080.13959@g5.osdl.org>
URL: https://gitlist.dev/e/Pine.LNX.4.64.0511212113080.13959%40g5.osdl.org
In-Reply-To: <20051122050337.46450.qmail@web31808.mail.mud.yahoo.com>

```


On Mon, 21 Nov 2005, Luben Tuikov wrote:
> 
> How do I reverse a _single_ "git-update-index" operation?
> Be it --add or just an update.

An "add" is easy enough to undo: just do a

	git-update-index --force-remove filename

which will remove the entry from the index even if the file on your 
filesystem still remains (so you can "git add" it later when you do want 
to commit it).

For a file that you had in your old index, but you've updated (either mode 
or SHA1), you need to figure out what the old mode/sha1 was. USUALLY this 
would be just the state that you still have in your HEAD tree, but if 
you want to go back to something else, you'd need to figure out what that 
was.

If it's the "last commit" state (ie just your HEAD state), then do

	git-ls-tree HEAD filename

which will show you the info, and then you do

	git-update-index --cacheinfo <mode> <sha1> filename

from that state.

You could obviously script something like "git-downdate-index":

	#!/bin/sh
	filename="$1"
	tree_info=$(git-ls-tree HEAD -- "$filename")
	if [ -z "$tree_info" ]; then
		git-update-index --force-remove -- "$filename"
	else
		echo "$tree_info" | while read mode type sha1 name; do
			git-update-index --cacheinfo "$mode" "$sha1" "$filename"
		done
	fi

but the above is totally untested, and "git-downdate-index" is a really 
sucky name too, so you'd need to rename it and test whether it does what 
you want.

Hmm?

		Linus

```

## Junio C Hamano, 2005-11-22 05:24

Subject: Re: index manipulation -- how?
Message-ID: <7v8xvhi7bi.fsf@assigned-by-dhcp.cox.net>
URL: https://gitlist.dev/e/7v8xvhi7bi.fsf%40assigned-by-dhcp.cox.net
In-Reply-To: <20051122050337.46450.qmail@web31808.mail.mud.yahoo.com>

```
Luben Tuikov <ltuikov@yahoo.com> writes:

> How do I reverse a _single_ "git-update-index" operation?
> Be it --add or just an update.

Reverting working tree files are "git checkout HEAD the-file"
(both index and working tree file from the head commit) or "git
checkout -- the-file" (working tree file from the index), but I
do not think there is a prepackaged way to revert only a single
index path offhand.

        git-ls-tree HEAD the-file |
        sed -e 's/^\([0-7]*\) [^ ]* \(.*\)/\1 \2/' |
        git-update-index --index-info

should work.

I think changing update-index --index-info so that you can lose
the sed in between without breaking its other usage (it reads
from git-apply --index-info, which does not say " blob " which
is what the sed is stripping out) is a worthwhile thing to do.

```

## Junio C Hamano, 2005-11-22 05:36

Subject: Re: index manipulation -- how?
Message-ID: <7v3blpi6r7.fsf@assigned-by-dhcp.cox.net>
URL: https://gitlist.dev/e/7v3blpi6r7.fsf%40assigned-by-dhcp.cox.net
In-Reply-To: <7v8xvhi7bi.fsf@assigned-by-dhcp.cox.net>

```
Junio C Hamano <junkio@cox.net> writes:

> Luben Tuikov <ltuikov@yahoo.com> writes:
>
>> How do I reverse a _single_ "git-update-index" operation?
>> Be it --add or just an update.
>
> Reverting working tree files are "git checkout HEAD the-file"
> (both index and working tree file from the head commit) or "git
> checkout -- the-file" (working tree file from the index), but I
> do not think there is a prepackaged way to revert only a single
> index path offhand.
>
>         git-ls-tree HEAD the-file |
>         sed -e 's/^\([0-7]*\) [^ ]* \(.*\)/\1 \2/' |
>         git-update-index --index-info
>
> should work.
>
> I think changing update-index --index-info so that you can lose
> the sed in between without breaking its other usage (it reads
> from git-apply --index-info, which does not say " blob " which
> is what the sed is stripping out) is a worthwhile thing to do.

And here is the patch to let you say:

	git-ls-tree HEAD the-file | git-update-index --index-info


---

diff --git a/update-index.c b/update-index.c
index 5bbc3de..11b7f6a 100644
--- a/update-index.c
+++ b/update-index.c
@@ -338,7 +338,7 @@ static void read_index_info(int line_ter
 	struct strbuf buf;
 	strbuf_init(&buf);
 	while (1) {
-		char *ptr;
+		char *ptr, *tab;
 		char *path_name;
 		unsigned char sha1[20];
 		unsigned int mode;
@@ -348,12 +348,15 @@ static void read_index_info(int line_ter
 			break;
 
 		mode = strtoul(buf.buf, &ptr, 8);
-		if (ptr == buf.buf || *ptr != ' ' ||
-		    get_sha1_hex(ptr + 1, sha1) ||
-		    ptr[41] != '\t')
+		if (ptr == buf.buf || *ptr != ' ')
 			goto bad_line;
 
-		ptr += 42;
+		tab = strchr(ptr, '\t');
+		if (!tab || tab - ptr < 41)
+			goto bad_line;
+		if (get_sha1_hex(tab - 40, sha1) || tab[-41] != ' ')
+			goto bad_line;
+		ptr = tab + 1;
 
 		if (line_termination && ptr[0] == '"')
 			path_name = unquote_c_style(ptr, NULL);

```

## Luben Tuikov, 2005-11-22 06:20

Subject: Re: index manipulation -- how?
Message-ID: <20051122062048.8891.qmail@web31805.mail.mud.yahoo.com>
URL: https://gitlist.dev/e/20051122062048.8891.qmail%40web31805.mail.mud.yahoo.com
In-Reply-To: <7v3blpi6r7.fsf@assigned-by-dhcp.cox.net>

```
--- Junio C Hamano <junkio@cox.net> wrote:

> Junio C Hamano <junkio@cox.net> writes:
> 
> > Luben Tuikov <ltuikov@yahoo.com> writes:
> >
> >> How do I reverse a _single_ "git-update-index" operation?
> >> Be it --add or just an update.
> >
> > Reverting working tree files are "git checkout HEAD the-file"
> > (both index and working tree file from the head commit) or "git
> > checkout -- the-file" (working tree file from the index), but I
> > do not think there is a prepackaged way to revert only a single
> > index path offhand.
> >
> >         git-ls-tree HEAD the-file |
> >         sed -e 's/^\([0-7]*\) [^ ]* \(.*\)/\1 \2/' |
> >         git-update-index --index-info

Ok.
(There is a very similar construct in git-checkout.sh.
So if you apply the patch below, please make sure
git-checkout.sh doesn't break.)

Question: so in effect, more generally:
  git checkout <tree-ish> <file>

would do the right thing: update index and the working
tree as the file <file> looked as it was at <tree-ish>?

Is that correct?  Can someone confirm/deny?

   Luben
P.S. So both methods as mentioned by Linus and Junio
do what I asked about.

> >
> > should work.
> >
> > I think changing update-index --index-info so that you can lose
> > the sed in between without breaking its other usage (it reads
> > from git-apply --index-info, which does not say " blob " which
> > is what the sed is stripping out) is a worthwhile thing to do.
> 
> And here is the patch to let you say:
> 
> 	git-ls-tree HEAD the-file | git-update-index --index-info
> 
> 
> ---
> 
> diff --git a/update-index.c b/update-index.c
> index 5bbc3de..11b7f6a 100644
> --- a/update-index.c
> +++ b/update-index.c
> @@ -338,7 +338,7 @@ static void read_index_info(int line_ter
>  	struct strbuf buf;
>  	strbuf_init(&buf);
>  	while (1) {
> -		char *ptr;
> +		char *ptr, *tab;
>  		char *path_name;
>  		unsigned char sha1[20];
>  		unsigned int mode;
> @@ -348,12 +348,15 @@ static void read_index_info(int line_ter
>  			break;
>  
>  		mode = strtoul(buf.buf, &ptr, 8);
> -		if (ptr == buf.buf || *ptr != ' ' ||
> -		    get_sha1_hex(ptr + 1, sha1) ||
> -		    ptr[41] != '\t')
> +		if (ptr == buf.buf || *ptr != ' ')
>  			goto bad_line;
>  
> -		ptr += 42;
> +		tab = strchr(ptr, '\t');
> +		if (!tab || tab - ptr < 41)
> +			goto bad_line;
> +		if (get_sha1_hex(tab - 40, sha1) || tab[-41] != ' ')
> +			goto bad_line;
> +		ptr = tab + 1;
>  
>  		if (line_termination && ptr[0] == '"')
>  			path_name = unquote_c_style(ptr, NULL);
> 
> 
> -
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

```

## Junio C Hamano, 2005-11-22 07:05

Subject: Re: index manipulation -- how?
Message-ID: <7vbr0dgo1f.fsf@assigned-by-dhcp.cox.net>
URL: https://gitlist.dev/e/7vbr0dgo1f.fsf%40assigned-by-dhcp.cox.net
In-Reply-To: <20051122062048.8891.qmail@web31805.mail.mud.yahoo.com>

```
Luben Tuikov <ltuikov@yahoo.com> writes:

> (There is a very similar construct in git-checkout.sh.
> So if you apply the patch below, please make sure
> git-checkout.sh doesn't break.)

Thanks.

> Question: so in effect, more generally:
>   git checkout <tree-ish> <file>
>
> would do the right thing: update index and the working
> tree as the file <file> looked as it was at <tree-ish>?

Yes that is correct.  Also by omitting <tree-ish> you can
checkout from the index.

I thought what you originally wanted to do was revert only index
without losing your changes from the working tree, so just to
make sure, the above does _not_ do it --- the named file in the
working tree is also reverted to the one from <tree-ish>.

```

## Luben Tuikov, 2005-11-22 07:35

Subject: Re: index manipulation -- how?
Message-ID: <20051122073538.4708.qmail@web31806.mail.mud.yahoo.com>
URL: https://gitlist.dev/e/20051122073538.4708.qmail%40web31806.mail.mud.yahoo.com
In-Reply-To: <7vbr0dgo1f.fsf@assigned-by-dhcp.cox.net>

```
--- Junio C Hamano <junkio@cox.net> wrote:
> 
> I thought what you originally wanted to do was revert only index
> without losing your changes from the working tree, so just to
> make sure, the above does _not_ do it --- the named file in the
> working tree is also reverted to the one from <tree-ish>.

Exactly what I want.

Thanks,
   Luben
P.S. I figured this one out in three stages:
Since checked out files are in rw- mode, but unchecked
files simply do not exist, first I want to "revert"
a changed file in the working tree -- this one is easy.
Then the second stage is if also the index is updated
(but no commit), and the last stage is if also
there is a commit, for which I think I know what to use.

```
