# Re: Missing features in git

12 messages from 2006-11-14 to 2006-11-14. Participants: Karl Hasselström, linux@horizon.com, Jakub Narebski, Shawn Pearce, Junio C Hamano, Petr Baudis, Linus Torvalds.
Thread: https://gitlist.dev/t/43317

## linux@horizon.com, 2006-11-14 13:49

Subject: Missing features in git
Message-ID: <20061114134958.5326.qmail@science.horizon.com>
URL: https://gitlist.dev/e/20061114134958.5326.qmail%40science.horizon.com

```
I've been writing some more git docs, and I came across a few
things git does that I'm not sure are desirable.


One thing I noticed is that with ref logs, you've just re-invented the
CVS problem of associating history with a name.  If you want to rename
a branch (say, from "mischacks" to something suitable for publication),
do you rename the log or not?  It's a less virulent form, but it seems
like the same disease.

Another minor quibble: AFAICT, "git checkout -f -m" is meaningless (-f
overrides -m), but doesn't complain.


One feature that I noticed is missing, is that there's no easy way to do a
"git reset --hard" while doing a "git checkout" style merge.

An example of when you'd want to do this is performing a "git bisect"
with a local "#define DEBUG 1" change.  Particularly if you
hit a non-compiling version and need to back up.

  
The only way to do this currently is somethig like:
        git checkout -b temp HEAD^
        git branch -f bisect temp
        git checkout bisect
        git branch -d temp

or the way git-bisect does it
  
        echo "$rev" > "$GIT_DIR/refs/heads/new-bisect"
        git checkout new-bisect || exit
        mv "$GIT_DIR/refs/heads/new-bisect" "$GIT_DIR/refs/heads/bisect" &&
        GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD refs/heads/bisect
  
Either way, it reserves a second branch name, and seems like a bit of
a hack.  I'm already a bit annoyed that "bisect" is reserved but not
clearly documented as such, and note that the branch name "new-bisect",
which we are switched to temporarily, does not match the pattern
"refs/heads/bisect*" that bisect_start checks for.

The only thing I don't know is if this should be a git-checkout
option or a git-reset option.  The former shares far more code,
but the latter might make more logical sense.

  
Personally, I'd prefer if the requirement that HEAD point to
refs/heads were enforced when checking in rather than checking out.
  
Then you could check out an arbitrary version without any of the annoyance
above; I could "git checkout tags/foo" or even "git checkout deadbeef~3".
I wouldn't be on a current branch (which would necessitate changing
"git branch" output), so HEAD would simply contain an object ID directly
rather than being a symlink/symref.

It's a bit of a PITA auditing the code base to find everywhere affected
by changing this invariant, but it doesn't conceptually difficult.
Is there anything fundamental that this would break?


The above would make a "-b <newbranch>" option to git-commit more useful,
but it's not a half-bad idea as it is.  It's just one extra command
(git checkout -b newbranch; git commit), but it takes a bit of
thinking to realize that "git checkout", which normally modifies the
working directory, won't touch your ready-to-be-committed changes in

```

## Jakub Narebski, 2006-11-14 14:53

Subject: Re: Missing features in git
Message-ID: <ejcl6l$bo0$1@sea.gmane.org>
URL: https://gitlist.dev/e/ejcl6l%24bo0%241%40sea.gmane.org
In-Reply-To: <20061114134958.5326.qmail@science.horizon.com>

```
linux@horizon.com wrote:

> One thing I noticed is that with ref logs, you've just re-invented the
> CVS problem of associating history with a name.  If you want to rename
> a branch (say, from "mischacks" to something suitable for publication),
> do you rename the log or not?  It's a less virulent form, but it seems
> like the same disease.

Well, it would be nice to have command to rename branches (with its reflog)
and to rename tags (even in their packed format).

[...] 
> Then you could check out an arbitrary version without any of the annoyance
> above; I could "git checkout tags/foo" or even "git checkout deadbeef~3".
> I wouldn't be on a current branch (which would necessitate changing
> "git branch" output), so HEAD would simply contain an object ID directly
> rather than being a symlink/symref.

And what would happen if you want to checkout other branch? Where the ID
in the HEAD would go to? HEAD just _has_ to be reference to _branch_.
 
-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git


```

## Karl Hasselström, 2006-11-14 15:39

Subject: Re: Missing features in git
Message-ID: <20061114153922.GA5453@diana.vm.bytemark.co.uk>
URL: https://gitlist.dev/e/20061114153922.GA5453%40diana.vm.bytemark.co.uk
In-Reply-To: <20061114134958.5326.qmail@science.horizon.com>

```
On 2006-11-14 08:49:58 -0500, linux@horizon.com wrote:

> One feature that I noticed is missing, is that there's no easy way
> to do a "git reset --hard" while doing a "git checkout" style merge.
>
> An example of when you'd want to do this is performing a "git
> bisect" with a local "#define DEBUG 1" change. Particularly if you
> hit a non-compiling version and need to back up.

Yes, this feature would be good to have. StGIT makes it a little less
painful to hack around this limitation, but you still have to remember
popping your patches before running "git bisect good|bad".

Then again, in StGIT's case this could be solved by creating an "stg
bisect" command that takes care of this for you. But I still agree
with you that it would be a win if regular git could do as you
describe.

-- 
Karl Hasselström, kha@treskal.com

```

## Karl Hasselström, 2006-11-14 15:47

Subject: Re: Missing features in git
Message-ID: <20061114154739.GB5453@diana.vm.bytemark.co.uk>
URL: https://gitlist.dev/e/20061114154739.GB5453%40diana.vm.bytemark.co.uk
In-Reply-To: <ejcl6l$bo0$1@sea.gmane.org>

```
On 2006-11-14 15:53:18 +0100, Jakub Narebski wrote:

> linux@horizon.com wrote:
>
> > Then you could check out an arbitrary version without any of the
> > annoyance above; I could "git checkout tags/foo" or even "git
> > checkout deadbeef~3". I wouldn't be on a current branch (which
> > would necessitate changing "git branch" output), so HEAD would
> > simply contain an object ID directly rather than being a
> > symlink/symref.
>
> And what would happen if you want to checkout other branch? Where
> the ID in the HEAD would go to? HEAD just _has_ to be reference to
> _branch_.

The id that used to be HEAD would not be saved anywhere. It would
still be reachable from your refs, presumably, just like before you
checked it out. (It would not be the case that you had made commits on
an unnamed branch that would now get lost, because the tool would
refuse to commit until you had created a name for the branch.)

-- 
Karl Hasselström, kha@treskal.com

```

## Jakub Narebski, 2006-11-14 17:15

Subject: Re: Missing features in git
Message-ID: <200611141815.24236.jnareb@gmail.com>
URL: https://gitlist.dev/e/200611141815.24236.jnareb%40gmail.com
In-Reply-To: <20061114154739.GB5453@diana.vm.bytemark.co.uk>

```
Karl Hasselström wrote:
> On 2006-11-14 15:53:18 +0100, Jakub Narebski wrote:
> 
>> linux@horizon.com wrote:
>>
>>> Then you could check out an arbitrary version without any of the
>>> annoyance above; I could "git checkout tags/foo" or even "git
>>> checkout deadbeef~3". I wouldn't be on a current branch (which
>>> would necessitate changing "git branch" output), so HEAD would
>>> simply contain an object ID directly rather than being a
>>> symlink/symref.
>>
>> And what would happen if you want to checkout other branch? Where
>> the ID in the HEAD would go to? HEAD just _has_ to be reference to
>> _branch_.
> 
> The id that used to be HEAD would not be saved anywhere. It would
> still be reachable from your refs, presumably, just like before you
> checked it out. (It would not be the case that you had made commits on
> an unnamed branch that would now get lost, because the tool would
> refuse to commit until you had created a name for the branch.)

If HEAD would contain an commit ID directly, then you shouldn't be able
to commit at all. Not very useful, it is.
-- 
Jakub Narebski

```

## Karl Hasselström, 2006-11-14 17:36

Subject: Re: Missing features in git
Message-ID: <20061114173657.GC5453@diana.vm.bytemark.co.uk>
URL: https://gitlist.dev/e/20061114173657.GC5453%40diana.vm.bytemark.co.uk
In-Reply-To: <200611141815.24236.jnareb@gmail.com>

```
On 2006-11-14 18:15:23 +0100, Jakub Narebski wrote:

> Karl Hasselström wrote:

> > On 2006-11-14 15:53:18 +0100, Jakub Narebski wrote:
>
> > > And what would happen if you want to checkout other branch?
> > > Where the ID in the HEAD would go to? HEAD just _has_ to be
> > > reference to _branch_.
> >
> > The id that used to be HEAD would not be saved anywhere. It would
> > still be reachable from your refs, presumably, just like before
> > you checked it out. (It would not be the case that you had made
> > commits on an unnamed branch that would now get lost, because the
> > tool would refuse to commit until you had created a name for the
> > branch.)
>
> If HEAD would contain an commit ID directly, then you shouldn't be
> able to commit at all.

I agree. You aren't on a branch, so you can't commit. (Of course,
creating a branch for the commit you're on is trivial: "git checkout
-b <branchname>".)

> Not very useful, it is.

Well, as long as you only want to visit the past, not change it, it
can be useful. For example, we could skip the "bisect" branch, since
you aren't supposed to commit to that anyway.

-- 
Karl Hasselström, kha@treskal.com

```

## Jakub Narebski, 2006-11-14 17:45

Subject: Re: Missing features in git
Message-ID: <200611141845.18930.jnareb@gmail.com>
URL: https://gitlist.dev/e/200611141845.18930.jnareb%40gmail.com
In-Reply-To: <20061114173657.GC5453@diana.vm.bytemark.co.uk>

```
Dnia wtorek 14. listopada 2006 18:36, Karl Hasselström napisał:
>
> For example, we could skip the "bisect" branch, since
> you aren't supposed to commit to that anyway.

Well, to have "branch" to which you could not commit, just put ref
outside refs/heads. 

Another solution would be to be able to put non-head ref in HEAD,
but allow to commit only if the prefix is refs/heads/
-- 
Jakub Narebski

```

## Shawn Pearce, 2006-11-14 17:49

Subject: Re: Missing features in git
Message-ID: <20061114174939.GB4299@spearce.org>
URL: https://gitlist.dev/e/20061114174939.GB4299%40spearce.org
In-Reply-To: <200611141845.18930.jnareb@gmail.com>

```
Jakub Narebski <jnareb@gmail.com> wrote:
> Dnia wtorek 14. listopada 2006 18:36, Karl Hasselström napisa?:
> >
> > For example, we could skip the "bisect" branch, since
> > you aren't supposed to commit to that anyway.
> 
> Well, to have "branch" to which you could not commit, just put ref
> outside refs/heads. 
> 
> Another solution would be to be able to put non-head ref in HEAD,
> but allow to commit only if the prefix is refs/heads/

That's not a bad idea.  Then you can checkout a tag and have
'ref: refs/tags/v1.11' in HEAD, which means anyone who puts
$(git-symbolic-ref) calls into their PS1 will see "refs/tags/v1.11"
as their current branch, reminding them they are looking at the past.

Doing bisect branch in refs/bisect rather than refs/heads/bisect
would then likewise remind the user that they are bisecting, and
since neither matches refs/heads/* you cannot commit.

-- 

```

## Linus Torvalds, 2006-11-14 18:40

Subject: Re: Missing features in git
Message-ID: <Pine.LNX.4.64.0611141037120.3327@woody.osdl.org>
URL: https://gitlist.dev/e/Pine.LNX.4.64.0611141037120.3327%40woody.osdl.org
In-Reply-To: <20061114174939.GB4299@spearce.org>

```


On Tue, 14 Nov 2006, Shawn Pearce wrote:

> Jakub Narebski <jnareb@gmail.com> wrote:
> > Dnia wtorek 14. listopada 2006 18:36, Karl Hasselström napisa?:
> > >
> > > For example, we could skip the "bisect" branch, since
> > > you aren't supposed to commit to that anyway.
> > 
> > Well, to have "branch" to which you could not commit, just put ref
> > outside refs/heads. 
> > 
> > Another solution would be to be able to put non-head ref in HEAD,
> > but allow to commit only if the prefix is refs/heads/
> 
> That's not a bad idea.  Then you can checkout a tag and have
> 'ref: refs/tags/v1.11' in HEAD, which means anyone who puts
> $(git-symbolic-ref) calls into their PS1 will see "refs/tags/v1.11"
> as their current branch, reminding them they are looking at the past.

I agree. This would probably be a good way to do "read-only branches".

Allowing people to do a "git checkout" on anything committish, but then 
not allowing them to commit to that, is probably the right thing to do.

Together with a nice readable error message from "git commit" (and merge, 
and pull - although you might well allow "fetch" to update the thing that 
current HEAD points to, though), this would be a lot easier to use for 
people who just follow somebody elses branch.

Junio, what do you think? It wouldn't even be backwards incompatible, 
because we're strictly allowing a superset of what we used to..

			Linus
```

## Petr Baudis, 2006-11-14 19:37

Subject: Re: Missing features in git
Message-ID: <20061114193726.GG7201@pasky.or.cz>
URL: https://gitlist.dev/e/20061114193726.GG7201%40pasky.or.cz
In-Reply-To: <Pine.LNX.4.64.0611141037120.3327@woody.osdl.org>

```
On Tue, Nov 14, 2006 at 07:40:30PM CET, Linus Torvalds wrote:
> On Tue, 14 Nov 2006, Shawn Pearce wrote:
> 
> > Jakub Narebski <jnareb@gmail.com> wrote:
> > > Dnia wtorek 14. listopada 2006 18:36, Karl Hasselström napisa?:
> > > >
> > > > For example, we could skip the "bisect" branch, since
> > > > you aren't supposed to commit to that anyway.
> > > 
> > > Well, to have "branch" to which you could not commit, just put ref
> > > outside refs/heads. 
> > > 
> > > Another solution would be to be able to put non-head ref in HEAD,
> > > but allow to commit only if the prefix is refs/heads/
> > 
> > That's not a bad idea.  Then you can checkout a tag and have
> > 'ref: refs/tags/v1.11' in HEAD, which means anyone who puts
> > $(git-symbolic-ref) calls into their PS1 will see "refs/tags/v1.11"
> > as their current branch, reminding them they are looking at the past.

  There's been a brief discussion on a related topic in

	http://news.gmane.org/find-root.php?message_id=%3cPine.LNX.4.58.0507120938240.17536%40g5.osdl.org%3e

(apparently the Linus-has-another-totally-awesome-idea kind (no irony
(*))).  Before, Cogito did basically what's proposed above to permit
again: storing a random sha1 in the HEAD when it is seeked away to some
historical commit. It switched to using a temporary branch for this
purpose, but I'm not sure about the Linus' reasoning that

	"in order for a "git checkout" to not get confused and possibly
	throwing a cogito temporary head away ..."

which has been apparently clear to me back then. :-(

> I agree. This would probably be a good way to do "read-only branches".
> 
> Allowing people to do a "git checkout" on anything committish, but then 
> not allowing them to commit to that, is probably the right thing to do.

  So, the basic relaxation is that "again after a year, HEAD does not
have to be a ref at all".

> Together with a nice readable error message from "git commit" (and merge, 
> and pull - although you might well allow "fetch" to update the thing that 
> current HEAD points to, though), this would be a lot easier to use for 
> people who just follow somebody elses branch.

  Hmm, so that there would be something like refs/tracking/master as an
alternative to refs/heads/master? I'm not really sure if it is a good
idea. On one hand, you can relax my favorite fastforward restrictions on
those tracking branches, but I think the net worth is negative since you
will have to burden new users with yet another concept of "readonly
branches", tell them things like "either do git clone --no-tracking or
the first time you will want to commit something locally, create a
'head' using git checkout -b master HEAD" (you are already on a "master"
branch but it's a different "master", you know?) etc.


  (*) You never are ironical about Linus, the Chuck Norris of CS. (And a
hero, too!)

-- 
				Petr "Pasky the Wow Pruit Igoe is
					Awesome Too!" Baudis
Stuff: http://pasky.or.cz/
#!/bin/perl -sp0777i<X+d*lMLa^*lN%0]dsXx++lMlN/dsM0<j]dsj
$/=unpack('H*',$_);$_=`echo 16dio\U$k"SK$/SM$n\EsN0p[lN*1

```

## Junio C Hamano, 2006-11-14 22:09

Subject: Re: Missing features in git
Message-ID: <7v64dhznmx.fsf@assigned-by-dhcp.cox.net>
URL: https://gitlist.dev/e/7v64dhznmx.fsf%40assigned-by-dhcp.cox.net
In-Reply-To: <Pine.LNX.4.64.0611141037120.3327@woody.osdl.org>

```
Linus Torvalds <torvalds@osdl.org> writes:

> On Tue, 14 Nov 2006, Shawn Pearce wrote:
>> That's not a bad idea.  Then you can checkout a tag and have
>> 'ref: refs/tags/v1.11' in HEAD, which means anyone who puts
>> $(git-symbolic-ref) calls into their PS1 will see "refs/tags/v1.11"
>> as their current branch, reminding them they are looking at the past.
>
> I agree. This would probably be a good way to do "read-only branches".
> ...
> Junio, what do you think? It wouldn't even be backwards incompatible, 
> because we're strictly allowing a superset of what we used to..

(late reply -- just came back from a clinic)

I do not see any fundamental reason not to allow HEAD to be a
commit that you cannot commit on top of because you are not on
any branch, and I agree it is the right way to go.

I am not sure how much pain we are talking about yet though.

```

## Junio C Hamano, 2006-11-14 22:13

Subject: Re: Missing features in git
Message-ID: <7vy7qdy8vb.fsf@assigned-by-dhcp.cox.net>
URL: https://gitlist.dev/e/7vy7qdy8vb.fsf%40assigned-by-dhcp.cox.net
In-Reply-To: <20061114134958.5326.qmail@science.horizon.com>

```
linux@horizon.com writes:

> One thing I noticed is that with ref logs, you've just re-invented the
> CVS problem of associating history with a name.  If you want to rename
> a branch (say, from "mischacks" to something suitable for publication),
> do you rename the log or not?  It's a less virulent form, but it seems
> like the same disease.

I do not think we currently rename the log but it is probably a
bug.  Renaming tag should also be made easier.

> Another minor quibble: AFAICT, "git checkout -f -m" is meaningless (-f
> overrides -m), but doesn't complain.

It should be made to complain.

> An example of when you'd want to do this is performing a "git bisect"
> with a local "#define DEBUG 1" change.  Particularly if you
> hit a non-compiling version and need to back up.
> or the way git-bisect does it
>   
>         echo "$rev" > "$GIT_DIR/refs/heads/new-bisect"
>         git checkout new-bisect || exit
>         mv "$GIT_DIR/refs/heads/new-bisect" "$GIT_DIR/refs/heads/bisect" &&
>         GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD refs/heads/bisect

The name new-bisect is really temporary the code just shows it
punts on a situation it does not expect (it essentially expects
a clean tree and working with a local change is by accident) and
being ony half helpful to the user while recovering from that
unexpected situation.  In other words, that's a room for
improvement.  We should be rewrite the above with something like
what we have in the else clause in git-checkout around line 150.
It might make sense to make it a shell function and sharable
between checkout and bisect (perhaps there are other uses).
Then we do not need the temporary branch.

> Either way, it reserves a second branch name, and seems like a bit of
> a hack.

You are correct to call it a hack.  git-bisect started as a
technology demonstration of the underlying rev-list --bisect
feature.  The thing is that the technology was so nice and
useful that we started using it before cleaning up these
implementation details.  I think instead of documenting the duct
tape that holds git-bisect together ("rev-list --bisect" is
great, and what "git-bisect" does is basically great but with
minor glitches like you noticed and with hacky implementation
details; I am calling the latter "duct tape"), we should redo
the hackish part.

Enough with bisect.  And jumping the head while forward/back
porting the local change would also involve the same kind of
change, so "git reset --merge-local-change" might be a good
addition, but I am not sure about the details yet.

```
