* Re: Git is not scalable with too many refs/*
From: René Scharfe @ 2011-09-30 9:12 UTC (permalink / raw)
To: Martin Fick
Cc: Julian Phillips, Christian Couder, git, Christian Couder,
Thomas Rast, Junio C Hamano
In-Reply-To: <201109291411.06733.mfick@codeaurora.org>
Hi Martin,
Am 29.09.2011 22:11, schrieb Martin Fick:
> Your patch works well for me. It achieves about the same
> gains as Julian's patch. Thanks!
OK, and what happens if you apply the following patch on top of my first
one? It avoids going through all the refs a second time during cleanup,
at the cost of going through the list of all known objects. I wonder if
that's any faster in your case.
Thanks,
René
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 84e0cdc..a4b1003 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -596,15 +596,14 @@ static int add_pending_uninteresting_ref(const char *refname,
return 0;
}
-static int clear_commit_marks_from_one_ref(const char *refname,
- const unsigned char *sha1,
- int flags,
- void *cb_data)
+static void clear_commit_marks_for_all(unsigned int mark)
{
- struct commit *commit = lookup_commit_reference_gently(sha1, 1);
- if (commit)
- clear_commit_marks(commit, -1);
- return 0;
+ unsigned int i, max = get_max_object_index();
+ for (i = 0; i < max; i++) {
+ struct object *object = get_indexed_object(i);
+ if (object && object->type == OBJ_COMMIT)
+ object->flags &= ~mark;
+ }
}
static void describe_one_orphan(struct strbuf *sb, struct commit *commit)
@@ -690,8 +689,7 @@ static void orphaned_commit_warning(struct commit *commit)
else
describe_detached_head(_("Previous HEAD position was"), commit);
- clear_commit_marks(commit, -1);
- for_each_ref(clear_commit_marks_from_one_ref, NULL);
+ clear_commit_marks_for_all(ALL_REV_FLAGS);
}
static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
^ permalink raw reply related
* Re: [RFC/PATCHv2] git-p4: handle files with shell metacharacters
From: Luke Diamand @ 2011-09-30 9:06 UTC (permalink / raw)
To: Pete Wyckoff; +Cc: git
In-Reply-To: <20110927130334.GA24327@arf.padd.com>
On 27/09/11 14:03, Pete Wyckoff wrote:
<snip>
>
> If you don't mind, I'll just queue it up with the utf16 and
> test-refactor stuff I have, and send it all to Junio post-1.7.7.
> Here's how I plan to adjust your tests, given the feedback that
> Junio gave earlier and from reading other tests in t/.
>
> -- Pete
Pete - I've just noticed that t9803 sets P4EDITOR up for the wrong commit.
It works fine for me in my the setup I've got at home but on another
setup hangs trying to run vi from within the test.
It looks like two or possibly three bugs combine with each other.
(a) my misplacement of P4EDITOR
(b) git-p4 doesn't check the return code from system(editor + fileName)
at around 1018, so it just carries blithely on.
(c) "git var GIT_EDITOR" called from within the test harness gives
differing results. In one setup I get "vi", in another, nothing. The
tests pass in the latter case.
I'll submit a new patch series to fix (a) and (b). I'm not sure if (c)
is a bug or a feature. If I get very keen I might also include a tidied
up version of the recent patch for turning off the editor explicitly.
Luke
^ permalink raw reply
* Re: [PATCH] Clarify that '--tags' fetches tags only
From: Jakub Narebski @ 2011-09-30 8:44 UTC (permalink / raw)
To: Peter Shenkin; +Cc: git
In-Reply-To: <loom.20110930T041939-332@post.gmane.org>
Peter Shenkin <shenkin@gmail.com> writes:
[...]
> Now I have a related question. I always want to retrieve all
> tags from tracking branches when I do a "git pull". Right now,
> if I want to do this, it seem (unless I am missing something)
> that I have to do "git fetch --tags; git fetch; git merge". Is
> there a way I can put something into my .git/config file so
> that I get this effect simply by doing a "git pull"? That's
> what I was trying to do when I added "tagopt = --tags".
Actually fetching of branches on remote into remote-tracking branches
would also fetch all tags that point to commits on fetched branches
(so called "autofollow" feature).
If you want to fetch _all_ tags, you need to configure fetched
branches (e.g. via glob refspec). I think that then "tagopt = --tags"
works as expected then, as it is in addition to refspec not as the
only refspec; "fetch = +refs/tags/*:refs/tags/*" should work as well.
HTH
--
Jakub Narębski
^ permalink raw reply
* Re: RFC: reverse bisect
From: Michal Vyskocil @ 2011-09-30 8:29 UTC (permalink / raw)
To: git
In-Reply-To: <4E849C5B.7050201@kdbg.org>
[-- Attachment #1: Type: text/plain, Size: 829 bytes --]
On Thu, Sep 29, 2011 at 06:27:07PM +0200, Johannes Sixt wrote:
> Am 29.09.2011 16:20, schrieb Michal Vyskocil:
> > git bisect start --reverse HEAD~999 HEAD
>
> With the regular meaning of the start subcommand, the revs given are
> ordered: bad good good...
>
> With the reversed meaning, this would have to become: good bad bad...
>
> This would have to be mentioned clearly in the documentation.
>
> > git bisect good/bad/skip/run
>
> Last time this came up on the list I suggested to add the following
> commands:
>
> git bisect regression # a synonym for git bisect start
> git bisect improvement # your --reverse
Good point! As you mentioned, the --switch already reverse the meanings
of arguments as you mentioned. Using a new command will be less
confusing for users.
Michal Vyskocil
[-- Attachment #2: Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply
* fatal: index-pack failed
From: Matti Linnanvuori @ 2011-09-30 8:11 UTC (permalink / raw)
To: git
Jenkins got an error:
Error performing command: git fetch -t ssh://iac-builder@sorsa.portalify.com/p/git/.git+refs/heads/*:refs/
Command "git fetch -t ssh://iac-builder@sorsa.portalify.com/p/git/.git+refs/heads/*:refs/remotes/origin/*" returned status code 128: error: refs/remotes/origin/HEAD does not point to a valid object!
error: refs/remotes/origin/master does not point to a valid object!
error: refs/tags/jenkins-iac-orm-snapshot-889 does not point to a valid object!
error: refs/remotes/origin/HEAD does not point to a valid object!
error: refs/remotes/origin/master does not point to a valid object!
error: refs/tags/jenkins-iac-orm-snapshot-889 does not point to a valid object!
error: Could not read 49f273234b582edb44bbdbda29193719e5054cb7
error: refs/remotes/origin/HEAD does not point to a valid object!
error: refs/remotes/origin/master does not point to a valid object!
error: missing object referenced by 'refs/tags/iac-1.4.13'
error: refs/tags/jenkins-iac-orm-snapshot-889 does not point to a valid object!
error: Could not read 49f273234b582edb44bbdbda29193719e5054cb7
fatal: pack has 26 unresolved deltas
fatal: index-pack failed
git fsck --full
error: refs/remotes/origin/HEAD does not point to a valid object!
error: refs/remotes/origin/master does not point to a valid object!
error: refs/tags/jenkins-iac-orm-snapshot-889 does not point to a valid object!
broken link from commit 5d4e8989e0b84546cd85fc5e1da12f68e4d38972
to tree 54e146b9fca023bbde2b311629d82601fa1e89a0
broken link from commit 5d4e8989e0b84546cd85fc5e1da12f68e4d38972
to commit 49f273234b582edb44bbdbda29193719e5054cb7
dangling tree ec3b83770e89242fccda40b5194dd450122e49ed
dangling tree dd51bc467f3f36c89b8064e550298f91d15bf28d
dangling blob 1756f72adc8a8292e6fadeb306823f1d26feeb7b
dangling tree 5e58d68ae6f5d5f554fbeb80f14c49bbf097a44c
dangling blob 0f67ad10d3ad05b33b4689f3859cf2455bc0c292
dangling tree 72818c927d476f0d56846d82062afe2648f9b554
dangling blob 07969328481717f171624066c43948b8d69b4933
dangling tree c49ef6d9a7a248c726327fb9e00bffa365f84dcb
dangling tree 66b64e2a6ba858d357baa65887e8e117b368e771
dangling blob 18c48a80fde2c5e1c9e696c055852af723eec01c
dangling blob 4dcf4f005cc2e57f0f2720a937fa53740504ebf8
dangling tree add32288c58a090c3746f7286bfaefd5f5fb24a4
missing tree 54e146b9fca023bbde2b311629d82601fa1e89a0
missing commit 49f273234b582edb44bbdbda29193719e5054cb7
git --version
git version 1.7.2.5
Debian GNU/Linux 6.0
Matti Linnanvuori
^ permalink raw reply
* Re: [PATCH v3] refs: Use binary search to lookup refs faster
From: Julian Phillips @ 2011-09-30 8:04 UTC (permalink / raw)
To: Junio C Hamano
Cc: Martin Fick, Christian Couder, git, Christian Couder, Thomas Rast
In-Reply-To: <7vwrcqpuc7.fsf@alter.siamese.dyndns.org>
On Thu, 29 Sep 2011 20:44:40 -0700, Junio C Hamano wrote:
> Martin Fick <mfick@codeaurora.org> writes:
>
>> This works for me, however unfortunately, I cannot find any
>> scenarios where it improves anything over the previous fix
>> by René. :(
>
> Nevertheless, I would appreciate it if you can try this _without_
> René's
> patch. This attempts to make resolve_ref() cheap for _any_ caller.
> René's
> patch avoids calling it in one specific callchain.
>
> They address different issues. René's patch is probably an
> independently
> good change (I haven't thought about the interactions with the topics
> in
> flight and its implications on the future direction), but would not
> help
> other/new callers that make many calls to resolve_ref().
It certainly helps with my test repo (~140k refs, of which ~40k are
branches). User times for checkout starting from an orphaned commit
are:
No fix : ~16m8s
+ Binary Search : ~4s
+ René's patch : ~2s
(The 2s includes both patches, though the timing is the same for René's
patch alone)
--
Julian
^ permalink raw reply
* Updated tag 'junio-gpg-pub' ?
From: Stefan Näwe @ 2011-09-30 6:49 UTC (permalink / raw)
To: Junio C. Hamano; +Cc: Git List
Junio,
I haven't seen any announcement of this:
> Fetching origin
> >From http://github.com/gitster/git
> - [tag update] junio-gpg-pub -> junio-gpg-pub
Did you update your GPG key ?
Greetings,
Stefan
--
----------------------------------------------------------------
/dev/random says: Bullets speak louder than reason.
python -c "print '73746566616e2e6e616577654061746c61732d656c656b74726f6e696b2e636f6d'.decode('hex')"
^ permalink raw reply
* [ANNOUNCE] Gitolite v2.1 and mirroring features
From: Sitaram Chamarty @ 2011-09-30 6:44 UTC (permalink / raw)
To: Git Mailing List
Hello all,
I've kinda stopped sending "announce" emails for all the little
features and enhancements that happen to gitolite, but this one seemed
big enough and important enough to send one out to this list.
Gitolite v2.1 now does mirroring much more flexibly and powerfully
than the old, rather naive, setup.
Most of the impetus for these changes came from a rather large product
development group within TCS, the company I work for -- many cities,
offices, servers, repos, and developers.
Here are the highlights:
(1) the "NUMA" thing: Different repos can now be mastered on different
servers, depending on which city/office has the most developers for
*that* project.
This was the single biggest motivator for the new mirroring code; the
rest of the cool stuff just happened along.
(2) almost as good as "active-active" mirroring: If the "master"
server trusts the authentication performed by the "slave" server, you
can have the slave internally redirect a "git push" to the correct
master.
With this, developers don't have to remember which repo is mastered
where, use different 'pushurl's, etc. They just do *everything* with
their local mirror and let the system deal with it. (You can even
change which server is "master" and people don't even need to know it
has changed!)
(3) partial mirrors and local repos: A server doesn't have to carry
*all* the repos in the system -- it can choose to carry only some.
In our case it was often because there were no developers for that
project in that office, but there could be other reasons. Server
load/resource constraints, legal/jurisdictional issues, server in a
non-free country and repo has crypto code ;-) etc.
Similarly, a server can have repos that it wants to keep purely local
-- not to be mirrored at all.
(4) laggy mirrors: If daytime bandwidth is an issue, and you're ok
with the lag, you can postpone mirroring to night times instead of
with every push. The actual mirroring is triggered with a simple
command -- you can write your cron jobs around that quite easily.
(5) autonomous mirrors: Your mirrors don't all have to be under your
control. They can be owned by someone else and you negotiate what
repos you'll mirror for each other. For example, an open source
project may find a "donor" that is willing to mirror a few
highly-trafficked repos and make them available via git:// or http://
----
We use all these features (except the last one; it's not pertinent to
our setup), and things have been humming along for a few weeks now.
If you have any questions not answered by the documentation[1], feel
free to email me.
[1]: http://sitaramc.github.com/gitolite/doc/mirroring.html
--
Sitaram
^ permalink raw reply
* Re: RFC: reverse bisect
From: Frans Klaver @ 2011-09-30 5:31 UTC (permalink / raw)
To: git
In-Reply-To: <20110930040924.GA28724@sigill.intra.peff.net>
On Fri, 30 Sep 2011 06:09:24 +0200, Jeff King <peff@peff.net> wrote:
> One catch is that the run command assumes a successful exit is "good",
> and anything else is "bad". Which makes:
>
> git bisect run make test
>
> good for finding regressions, but is a little counterintuitive for the
> yes/no thing (a successful exit means "no").
Then you would require a script that inverts the result, no? From my
point of view it's either that or add an option telling bisect run how
to interpret the results. In the latter case you could still consider
adding the regression/improvement qualification to bisect start. It might
help getting the mind set right.
Frans
^ permalink raw reply
* Re: RFC: reverse bisect
From: Jeff King @ 2011-09-30 4:09 UTC (permalink / raw)
To: Johannes Sixt; +Cc: Michal Vyskocil, git
In-Reply-To: <4E849C5B.7050201@kdbg.org>
On Thu, Sep 29, 2011 at 06:27:07PM +0200, Johannes Sixt wrote:
> > git bisect good/bad/skip/run
>
> Last time this came up on the list I suggested to add the following
> commands:
>
> git bisect regression # a synonym for git bisect start
> git bisect improvement # your --reverse
That makes some sense to me. But I do wonder if you could simply get rid
of the connotations of "good" and "bad" entirely, by thinking of it as
simply looking for a commit that introduced some property. Like:
# find a bug
git bisect start
git bisect yes ;# has the bug
git bisect no ;# does not have the bug
git bisect skip ;# no idea
# find a feature being implemented
git bisect start
git bisect yes ;# has the feature
git bisect no ;# does not have the feature
git bisect skip ;# no idea
IOW, I feel like we are having to handle this weird negation only
because we have assigned a value judgement to the tests. That instead of
saying "yes, we have this bug", we say "bad", which only makes sense if
you are looking for a bad thing.
You can still produce a negation in your mind, of course, by asking
"when did this property go away". But that is usually about a bug being
fixed, so the right answer is generally not a set of command line
options, but to stop asking "when did bug X go away", and instead ask
"when did the fix for bug X appear".
One catch is that the run command assumes a successful exit is "good",
and anything else is "bad". Which makes:
git bisect run make test
good for finding regressions, but is a little counterintuitive for the
yes/no thing (a successful exit means "no").
-Peff
^ permalink raw reply
* Re: [PATCH v3] refs: Use binary search to lookup refs faster
From: Junio C Hamano @ 2011-09-30 3:44 UTC (permalink / raw)
To: Martin Fick
Cc: Julian Phillips, Christian Couder, git, Christian Couder,
Thomas Rast
In-Reply-To: <201109291913.34196.mfick@codeaurora.org>
Martin Fick <mfick@codeaurora.org> writes:
> This works for me, however unfortunately, I cannot find any
> scenarios where it improves anything over the previous fix
> by René. :(
Nevertheless, I would appreciate it if you can try this _without_ René's
patch. This attempts to make resolve_ref() cheap for _any_ caller. René's
patch avoids calling it in one specific callchain.
They address different issues. René's patch is probably an independently
good change (I haven't thought about the interactions with the topics in
flight and its implications on the future direction), but would not help
other/new callers that make many calls to resolve_ref().
^ permalink raw reply
* Re: [PATCH] Clarify that '--tags' fetches tags only
From: Peter Shenkin @ 2011-09-30 2:51 UTC (permalink / raw)
To: git
In-Reply-To: <119711285.RuumktFLOq@hyperion>
Hi,
I just searched the List to see if there were any postings on
"fetch --tags", because I was recently thrown for a loop by
the fact the this command retrieves only tags (and commits
needed to fulfill them). So I was very happy to find this
discussion. I was actually trying to figure out whether the
observed behavior is a bug, given that there is no mention of
it in the documentation.
Perhaps it will be useful to say what would have been most
helpful for me. In the current documentation for "fetch
--tags", one sentence reads, "This flag lets all tags and
their associated objects be downloaded." The following small
modification would, IMO, be sufficient: "This flag causes all
tags and their associated objects (only) to be downloaded."
Now I have a related question. I always want to retrieve all
tags from tracking branches when I do a "git pull". Right now,
if I want to do this, it seem (unless I am missing something)
that I have to do "git fetch --tags; git fetch; git merge". Is
there a way I can put something into my .git/config file so
that I get this effect simply by doing a "git pull"? That's
what I was trying to do when I added "tagopt = --tags".
Thanks,
-P.
^ permalink raw reply
* Re: In favor of "git commit --no-parent"
From: Junio C Hamano @ 2011-09-30 2:28 UTC (permalink / raw)
To: Michael Witten
Cc: Phil Hord, Carlos Martín Nieto, vra5107, Michael J Gruber,
Matthieu Moy, Eric Raible, Philip Oakley, Jeff King, Jay Soffian,
git
In-Reply-To: <CAMOZ1BuUvuyrf3Tio+9EZR_-b3zy-RWpq36+0rmDO+QKWaVmxQ@mail.gmail.com>
Michael Witten <mfwitten@gmail.com> writes:
> The main issue with "git commit --no-parent" is [supposedly] safety, but it
> can be made pretty safe:
>
> $ cd repo
> $ # Hack away as usual or not
> $ git status # As with any other commit.
> $ git commit --no-parent
> Error! There must be another branch head directly referencing the
> same commit that is directly referenced by the current branch head!
That safety indeed will work, and I kind of like it. I think this is in
line with what we try to do when you come back from a detached HEAD state.
You may also want to allow this when HEAD is detached already (I am just
thinking aloud here). One possible workflow may be to start from somewhere
random, such as the last customer release point:
git checkout rel-2011-09-01
# strip proprietary stuff away
# make sure the result is satisfactory
git commit --no-parent
git checkout -b opensource
By the way, I am not convinced enough with the "git status" argument,
though.
The output from "status" and "diff" will show what you changed, but in the
"strip proprietary stuff" scenario, what you care much more about is what
you forgot to remove.
If my current source is littered with a confidencial name of an unreleased
device that I need to remove, I am more likely to use "git grep" on the
_remaining_ files, and this does not make a difference between "checkout
--orphan" or "commit --no-parent".
But I would imagine I would not _know_ what I am looking for until I see
it. There may be the name of another confidential device in the source
that I need to sanitize, too.
In a "strip" scenario, I suspect that the most natural way to verify would
be to run "git diff" between what is about to be committed and an empty
tree and inspect the output. That would be what I would do if I were
starting from an empty repository, populating the working tree and the
index with what I think is releaseable.
Another an advantage of "commit --no-parent" is that we do not have to
worry about a corner case like this:
git checkout --orphan xyzzy
# time passes, you do many things
git checkout foo
git branch | grep xyzzy ;# not found -- what happened to the branch?
^ permalink raw reply
* Re: [PATCH] contrib: add a pair of credential helpers for Mac OS X's keychain
From: John Szakmeister @ 2011-09-30 1:17 UTC (permalink / raw)
To: Jeff King; +Cc: Jay Soffian, git, Junio C Hamano
In-Reply-To: <CAEBDL5WhpVg17aPuRqrE5=2Q293kVD4fYtxGqRzx_K=87t-jgw@mail.gmail.com>
On Thu, Sep 29, 2011 at 6:03 AM, John Szakmeister <john@szakmeister.net> wrote:
[snip]
> Yep, I agree. And it's worse when using the security command line
> tool... when you grant security access to the key, then any app could
> technically gain access to the item via the security tool. That's one
> of the reasons I didn't pursue that route early on.
Thinking about this a little more, git-credential-anything has the
same problem. I can run it, and it'll dump out my password for
anybody. I'd rather it didn't do that. I think it would be more
satisfying to have the mechanisms built into git itself, without a
separate application. I'm not sure how practical that is though.
-John
^ permalink raw reply
* Re: [PATCH v3] refs: Use binary search to lookup refs faster
From: Martin Fick @ 2011-09-30 1:13 UTC (permalink / raw)
To: Julian Phillips
Cc: Junio C Hamano, Christian Couder, git, Christian Couder,
Thomas Rast
In-Reply-To: <20110929221143.23806.25666.julian@quantumfyre.co.uk>
On Thursday, September 29, 2011 04:11:42 pm Julian Phillips
wrote:
> Currently we linearly search through lists of refs when
> we need to find a specific ref. This can be very slow
> if we need to lookup a large number of refs. By
> changing to a binary search we can make this faster.
>
> In order to be able to use a binary search we need to
> change from using linked lists to arrays, which we can
> manage using ALLOC_GROW.
>
> We can now also use the standard library qsort function
> to sort the refs arrays.
>
This works for me, however unfortunately, I cannot find any
scenarios where it improves anything over the previous fix
by René. :(
I tested many things, clones, fetches, fetch noops,
checkouts, garbage collection. I am a bit surprised,
because I thought that my hack of a hash map did improve
still on checkouts on packed refs, but it could just be that
my hack was buggy and did not actually do a full orphan
check.
Thanks,
-Martin
^ permalink raw reply
* Re: [RFC/PATCH] git checkout $tree path
From: John Szakmeister @ 2011-09-30 1:02 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7vk48rq854.fsf@alter.siamese.dyndns.org>
On Thu, Sep 29, 2011 at 6:46 PM, Junio C Hamano <gitster@pobox.com> wrote:
[snip]
> According to that definition, because "master" has dir/file1, and the
> index is unchanged since "next", we would add dir/file1 to the index, and
> then check dir/file1 and dir/file3 out of the index. Hence, we end up
> resurrecting dir/file3 out of the index, even though "master" does not
> have that path.
>
> This is somewhat surprising.
That is surprising! It explains something I saw just yesterday which
closely mirrors your recipe.
> It may make sense to tweak the semantics a little bit. We can grab the
> paths out of the named tree ("master" in this case), update the index, and
> update the working tree with only with these paths we grabbed from the
> named tree. By doing so, we will keep the local modification to dir/file3
> (in this case, the modification is to "delete", but the above observation
> hold equally true if dir/file3 were modified).
That seems sane.
> An alternative semantics could be to first remove paths that match the
> given pathspec from the index, then update the index with paths taken from
> the named tree, and update the working tree. "git checkout master dir"
> would then mean "replace anything currently in dir with whatever is in dir
> in master". It is more dangerous, and it can easily emulated by doing:
This is equally sane, but is probably closer to my expectation.
[snip]
> * This is a behaviour change, but it may qualify as a bugfix. I dunno.
Personally, I lean towards it being a bugfix.
-John
^ permalink raw reply
* Re: In favor of "git commit --no-parent"
From: Michael Witten @ 2011-09-30 0:51 UTC (permalink / raw)
To: Junio C Hamano
Cc: Phil Hord, Carlos Martín Nieto, vra5107, Michael J Gruber,
Matthieu Moy, Eric Raible, Philip Oakley, Jeff King, Jay Soffian,
git
In-Reply-To: <7vd3ejq74z.fsf@alter.siamese.dyndns.org>
On Thu, Sep 29, 2011 at 23:08, Junio C Hamano <gitster@pobox.com> wrote:
> The branch switching semantics of Git is designed to work well when all
> the branches you check out in the working tree are somewhat related
> content-wise. You create a new file, or make modifications to an existing
> file, realize that the change wants to go to a branch different from the
> current one. You _can_ switch to the branch the change should belong to,
> because the contents in the working tree is defined to be not tied to any
> branch, but is floating on top of the current branch.
That's exactly why "git commit --no-parent" is so useful.
Look at the difference:
Creating a Hidden History (git commit --no-parent)
$ cd repo
$ git checkout -b hidden-history
$ # Hack away as usual or not
$ git status # As with any other commit.
$ git commit --no-parent
Creating a Hidden History (git checkout --orphan):
$ cd repo
$ git checkout --orphan hidden-history
$ # Hack away as usual or not
$ git status # lots of "new file" notifications obscuring my changes
$ git commit
The main issue with "git commit --no-parent" is [supposedly] safety, but it
can be made pretty safe:
$ cd repo
$ # Hack away as usual or not
$ git status # As with any other commit.
$ git commit --no-parent
Error! There must be another branch head directly referencing the
same commit that is directly referenced by the current branch head!
$ git checkout -b hidden-history
$ git commit --no-parent
In the vast majority of cases, that rule will prevent people from
losing history inadvertantly, and no extra "--force" is required.
^ permalink raw reply
* Re: [PATCH v3] refs: Use binary search to lookup refs faster
From: Junio C Hamano @ 2011-09-29 23:48 UTC (permalink / raw)
To: Julian Phillips
Cc: Michael Haggerty, Martin Fick, Christian Couder, git,
Christian Couder, Thomas Rast
In-Reply-To: <20110929221143.23806.25666.julian@quantumfyre.co.uk>
This version looks sane, although I have a suspicion that it may have
some interaction with what Michael may be working on.
Thanks.
^ permalink raw reply
* Re: In favor of "git commit --no-parent"
From: Junio C Hamano @ 2011-09-29 23:08 UTC (permalink / raw)
To: Phil Hord
Cc: Michael Witten, Carlos Martín Nieto, vra5107,
Michael J Gruber, Matthieu Moy, Eric Raible, Philip Oakley,
Jeff King, Jay Soffian, git
In-Reply-To: <CABURp0rjBdx+=_8R5g16fNKWis3=GgJw9SQ9D53H6xu_-Tq3Uw@mail.gmail.com>
Phil Hord <phil.hord@gmail.com> writes:
>> I am saying that "separate history" has no place in git workflow, if these
>> multiple roots _originate_ in the same single repository with a working
>> tree.
>
> No place in *your* workflow. Oh, wait. Except it has, and you use it
> in the git tree. So, um... I'm confused.
No, no place in anybody's workflow.
I do carry non source html/man branches in the same distribution point
repository, but I did not create and I do not have these unrelated
branches in my development repository. Possibility to run "git checkout
html" in my development repository is just insane.
The branch switching semantics of Git is designed to work well when all
the branches you check out in the working tree are somewhat related
content-wise. You create a new file, or make modifications to an existing
file, realize that the change wants to go to a branch different from the
current one. You _can_ switch to the branch the change should belong to,
because the contents in the working tree is defined to be not tied to any
branch, but is floating on top of the current branch.
We often see new people who do not understand this (yet) wonder "I
modified a file, switched to another branch, but the modification is still
there. Why?" It is because the local changes in the working tree do not
belong to a specific branch, and local changes could be committed to any
branch.
What would happen if I were crazy enough to have the html branch in my
development repository and checked it out? In addition to the previous
build artifacts *.o files, new source files *.[ch] and documentation
sources Documentation/*.txt will stay and will be mixed in the checkout of
the html branch, where we all know there is no reason for them to be
committed on.
A sane way to use Git is to have a separate repository to keep track of
changes in the other unrelated material, and I have separate repositories
with checkouts for html and man. Of course I do not edit them manually;
these repositories are targets of "make install-doc" from the source
repository.
They happen to be pushed into the same distribution point repository, but
that is a mere historical artifact. It only started because at k.org I
only had a write access to /pub/scm/git/git.git but not to /pub/scm/git/
directory itself; I may have used /pub/scm/git/html and /pub/scm/git/man
repositories otherwise.
And cloners are advised to "tar-tree" these out and extract them to
somewhere else, if they do not want to format the documentation themselves
but still want to look at them. Of course, they could "checkout", but you
would not edit these generated files in the working tree or commit to
these branches. So in that sense, yes they could "checkout", but that is
like saying they can run "rm -fr .git" too---they can do useful things and
not so useful things just alike.
I suspect that people often see those html/man branches in the
distribution point repository and get a wrong idea that having these
unrelated histories somehow add their coolness factor. It doesn't.
>> I have no trouble in a single repository with multiple roots if that is
>> done in a distribution point, which by definition does not need and
>> typically does not have any working tree. Options to "checkout/commit"
>> would not help as they need a working tree.
> ...
>> The way to do it is to work in multiple repositories, one for each of
>> these roots, and push into a single repository from them.
>
> That's one way to do it.
And I have been trying to teach why the other way is a wrong thing to do,
but there is no point in teaching a better practice if the listener is not
willing to learn. My time is better spent on other topics.
^ permalink raw reply
* [RFC/PATCH] git checkout $tree path
From: Junio C Hamano @ 2011-09-29 22:46 UTC (permalink / raw)
To: git
Suppose you have two branches, "master" with dir/file1 and file2, and
"next" with dir/file3 and file4. You are currently on "next" branch.
$ rm dir/file3
$ git status -suno
D dir/file3
Now, what should "git checkout master dir" do?
Checking paths out of a tree is (currently) defined to:
- Grab the paths from the named tree that match the given pathspec,
and add them to the index; and then
- Check out the contents from the index for paths that match the
pathspec to the working tree;
- While at it, if the given pathspec did not match anything, suspect
a typo from the command line and error out without updating the index
nor the working tree.
According to that definition, because "master" has dir/file1, and the
index is unchanged since "next", we would add dir/file1 to the index, and
then check dir/file1 and dir/file3 out of the index. Hence, we end up
resurrecting dir/file3 out of the index, even though "master" does not
have that path.
This is somewhat surprising.
It may make sense to tweak the semantics a little bit. We can grab the
paths out of the named tree ("master" in this case), update the index, and
update the working tree with only with these paths we grabbed from the
named tree. By doing so, we will keep the local modification to dir/file3
(in this case, the modification is to "delete", but the above observation
hold equally true if dir/file3 were modified).
An alternative semantics could be to first remove paths that match the
given pathspec from the index, then update the index with paths taken from
the named tree, and update the working tree. "git checkout master dir"
would then mean "replace anything currently in dir with whatever is in dir
in master". It is more dangerous, and it can easily emulated by doing:
$ git rm -rf dir
$ git checkout master dir
so I did not go that far with this patch.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
* This is a behaviour change, but it may qualify as a bugfix. I dunno.
builtin/checkout.c | 6 +++++-
1 files changed, 5 insertions(+), 1 deletions(-)
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 5e356a6..75dbe76 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -71,7 +71,7 @@ static int update_some(const unsigned char *sha1, const char *base, int baselen,
hashcpy(ce->sha1, sha1);
memcpy(ce->name, base, baselen);
memcpy(ce->name + baselen, pathname, len - baselen);
- ce->ce_flags = create_ce_flags(len, 0);
+ ce->ce_flags = create_ce_flags(len, 0) | CE_UPDATE;
ce->ce_mode = create_ce_mode(mode);
add_cache_entry(ce, ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
return 0;
@@ -228,6 +228,8 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec,
for (pos = 0; pos < active_nr; pos++) {
struct cache_entry *ce = active_cache[pos];
+ if (source_tree && !(ce->ce_flags & CE_UPDATE))
+ continue;
match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, ps_matched);
}
@@ -266,6 +268,8 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec,
state.refresh_cache = 1;
for (pos = 0; pos < active_nr; pos++) {
struct cache_entry *ce = active_cache[pos];
+ if (source_tree && !(ce->ce_flags & CE_UPDATE))
+ continue;
if (match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, NULL)) {
if (!ce_stage(ce)) {
errs |= checkout_entry(ce, &state, NULL);
^ permalink raw reply related
* Re: In favor of "git commit --no-parent"
From: Michael Witten @ 2011-09-29 22:32 UTC (permalink / raw)
To: Phil Hord
Cc: Junio C Hamano, Carlos Martín Nieto, vra5107,
Michael J Gruber, Matthieu Moy, Eric Raible, Philip Oakley,
Jeff King, Jay Soffian, git
In-Reply-To: <CAMOZ1Bspiz-J4Z7d8t7+jA_rKmzKcjhxuUpUSv7BrjJ=kCBfBQ@mail.gmail.com>
On Thu, Sep 29, 2011 at 22:29, Michael Witten <mfwitten@gmail.com> wrote:
> Consider trying the "Hidden History" scenario with the current
> approach, which only allows for "git checkout --orphan":
>
> $ cd repo
> $ git checkout --orphan separate-history
> $ # Hack away as usual or not
> $ git status # lots of "new file" notifications obscuring my changes
> $ git commit
To avoid confusion, please note that the line:
$ git checkout --orphan separate-history
was meant to read:
$ git checkout --orphan hidden-history
^ permalink raw reply
* Re: In favor of "git commit --no-parent"
From: Michael Witten @ 2011-09-29 22:29 UTC (permalink / raw)
To: Phil Hord
Cc: Junio C Hamano, Carlos Martín Nieto, vra5107,
Michael J Gruber, Matthieu Moy, Eric Raible, Philip Oakley,
Jeff King, Jay Soffian, git
In-Reply-To: <CABURp0rjBdx+=_8R5g16fNKWis3=GgJw9SQ9D53H6xu_-Tq3Uw@mail.gmail.com>
On Thu, Sep 29, 2011 at 22:07, Phil Hord <phil.hord@gmail.com> wrote:
> If I understand right, the mechanics of the initial creation is what
> bothers you. Is that right? If so, we're on the same page here,
> because it bothers me too. The commit or checkout alternatives seem
> like two halves of a turd sandwich. Both ends are wrong somehow, and
> it's because of the state of the working directory in the interim.
Creating a Hidden History (Junio is OK with this usage):
$ cd repo
$ git checkout -b hidden-history
$ # Hack away as usual or not
$ git status # As with any other commit.
$ git commit --no-parent
Creating a completely Separate History (Junio doesn't like this):
$ cd repo
$ git checkout --orphan separate-history
$ git rm -rf . # This SHOULD be automatic.
$ # add files as with an empty repo.
$ git status # As with an empty new repo; lots of "new file"
$ git commit
Those are the 2 halves, and they are correct for their purposes;
however, I would agree that "git init" is better instead of
"git checkout", especially when there should be an automatic
use of "git rm -rf .".
Consider trying the "Hidden History" scenario with the current
approach, which only allows for "git checkout --orphan":
$ cd repo
$ git checkout --orphan separate-history
$ # Hack away as usual or not
$ git status # lots of "new file" notifications obscuring my changes
$ git commit
The main issue with "git commit --no-parent" is [supposedly] safety, but it
can be made pretty safe:
$ cd repo
$ # Hack away as usual or not
$ git status # As with any other commit.
$ git commit --no-parent
Error! There must be another branch head directly referencing the
same commit that is directly referenced by the current branch head!
$ git checkout -b hidden-history
$ git commit --no-parent
In the vast majority of cases, that rule will prevent people from
losing history inadvertantly, and no extra "--force" is required.
^ permalink raw reply
* [PATCH v3] refs: Use binary search to lookup refs faster
From: Julian Phillips @ 2011-09-29 22:11 UTC (permalink / raw)
To: Junio C Hamano
Cc: Martin Fick, Christian Couder, git, Christian Couder, Thomas Rast
In-Reply-To: <7vvcsbqa0k.fsf@alter.siamese.dyndns.org>
Currently we linearly search through lists of refs when we need to
find a specific ref. This can be very slow if we need to lookup a
large number of refs. By changing to a binary search we can make this
faster.
In order to be able to use a binary search we need to change from
using linked lists to arrays, which we can manage using ALLOC_GROW.
We can now also use the standard library qsort function to sort the
refs arrays.
Signed-off-by: Julian Phillips <julian@quantumfyre.co.uk>
---
On Thu, 29 Sep 2011 15:06:03 -0700, Junio C Hamano wrote:
> Julian Phillips <julian@quantumfyre.co.uk> writes:
>
>> +static void add_ref(const char *name, const unsigned char *sha1,
>> + int flag, struct ref_array *refs,
>> + struct ref_entry **new_entry)
>> {
>> int len;
>> - struct ref_list *entry;
>> + struct ref_entry *entry;
>>
>> /* Allocate it and add it in.. */
>> len = strlen(name) + 1;
>> - entry = xmalloc(sizeof(struct ref_list) + len);
>> + entry = xmalloc(sizeof(struct ref) + len);
>
> This should be sizeof(struct ref_entry), no? There is another such
> misallocation in search_ref_array() where it prepares a temporary.
Indeed, thanks.
Looks like two instances of not noticing that "struct ref" already existed
managed to survive. Drat. Of course since "struct ref" is bigger than "struct
ref_entry", everthing worked fine ... so no failed tests to tip me off.
refs.c | 329 ++++++++++++++++++++++++++--------------------------------------
1 files changed, 133 insertions(+), 196 deletions(-)
diff --git a/refs.c b/refs.c
index a49ff74..4c01d79 100644
--- a/refs.c
+++ b/refs.c
@@ -8,14 +8,18 @@
#define REF_KNOWS_PEELED 04
#define REF_BROKEN 010
-struct ref_list {
- struct ref_list *next;
+struct ref_entry {
unsigned char flag; /* ISSYMREF? ISPACKED? */
unsigned char sha1[20];
unsigned char peeled[20];
char name[FLEX_ARRAY];
};
+struct ref_array {
+ int nr, alloc;
+ struct ref_entry **refs;
+};
+
static const char *parse_ref_line(char *line, unsigned char *sha1)
{
/*
@@ -44,108 +48,58 @@ static const char *parse_ref_line(char *line, unsigned char *sha1)
return line;
}
-static struct ref_list *add_ref(const char *name, const unsigned char *sha1,
- int flag, struct ref_list *list,
- struct ref_list **new_entry)
+static void add_ref(const char *name, const unsigned char *sha1,
+ int flag, struct ref_array *refs,
+ struct ref_entry **new_entry)
{
int len;
- struct ref_list *entry;
+ struct ref_entry *entry;
/* Allocate it and add it in.. */
len = strlen(name) + 1;
- entry = xmalloc(sizeof(struct ref_list) + len);
+ entry = xmalloc(sizeof(struct ref_entry) + len);
hashcpy(entry->sha1, sha1);
hashclr(entry->peeled);
memcpy(entry->name, name, len);
entry->flag = flag;
- entry->next = list;
if (new_entry)
*new_entry = entry;
- return entry;
+ ALLOC_GROW(refs->refs, refs->nr + 1, refs->alloc);
+ refs->refs[refs->nr++] = entry;
}
-/* merge sort the ref list */
-static struct ref_list *sort_ref_list(struct ref_list *list)
+static int ref_entry_cmp(const void *a, const void *b)
{
- int psize, qsize, last_merge_count, cmp;
- struct ref_list *p, *q, *l, *e;
- struct ref_list *new_list = list;
- int k = 1;
- int merge_count = 0;
-
- if (!list)
- return list;
-
- do {
- last_merge_count = merge_count;
- merge_count = 0;
-
- psize = 0;
+ struct ref_entry *one = *(struct ref_entry **)a;
+ struct ref_entry *two = *(struct ref_entry **)b;
+ return strcmp(one->name, two->name);
+}
- p = new_list;
- q = new_list;
- new_list = NULL;
- l = NULL;
+static void sort_ref_array(struct ref_array *array)
+{
+ qsort(array->refs, array->nr, sizeof(*array->refs), ref_entry_cmp);
+}
- while (p) {
- merge_count++;
+static struct ref_entry *search_ref_array(struct ref_array *array, const char *name)
+{
+ struct ref_entry *e, **r;
+ int len;
- while (psize < k && q->next) {
- q = q->next;
- psize++;
- }
- qsize = k;
-
- while ((psize > 0) || (qsize > 0 && q)) {
- if (qsize == 0 || !q) {
- e = p;
- p = p->next;
- psize--;
- } else if (psize == 0) {
- e = q;
- q = q->next;
- qsize--;
- } else {
- cmp = strcmp(q->name, p->name);
- if (cmp < 0) {
- e = q;
- q = q->next;
- qsize--;
- } else if (cmp > 0) {
- e = p;
- p = p->next;
- psize--;
- } else {
- if (hashcmp(q->sha1, p->sha1))
- die("Duplicated ref, and SHA1s don't match: %s",
- q->name);
- warning("Duplicated ref: %s", q->name);
- e = q;
- q = q->next;
- qsize--;
- free(e);
- e = p;
- p = p->next;
- psize--;
- }
- }
+ if (name == NULL)
+ return NULL;
- e->next = NULL;
+ len = strlen(name) + 1;
+ e = xmalloc(sizeof(struct ref_entry) + len);
+ memcpy(e->name, name, len);
- if (l)
- l->next = e;
- if (!new_list)
- new_list = e;
- l = e;
- }
+ r = bsearch(&e, array->refs, array->nr, sizeof(*array->refs), ref_entry_cmp);
- p = q;
- };
+ free(e);
- k = k * 2;
- } while ((last_merge_count != merge_count) || (last_merge_count != 1));
+ if (r == NULL)
+ return NULL;
- return new_list;
+ return *r;
}
/*
@@ -155,38 +109,37 @@ static struct ref_list *sort_ref_list(struct ref_list *list)
static struct cached_refs {
char did_loose;
char did_packed;
- struct ref_list *loose;
- struct ref_list *packed;
+ struct ref_array loose;
+ struct ref_array packed;
} cached_refs, submodule_refs;
-static struct ref_list *current_ref;
+static struct ref_entry *current_ref;
-static struct ref_list *extra_refs;
+static struct ref_array extra_refs;
-static void free_ref_list(struct ref_list *list)
+static void free_ref_array(struct ref_array *array)
{
- struct ref_list *next;
- for ( ; list; list = next) {
- next = list->next;
- free(list);
- }
+ int i;
+ for (i = 0; i < array->nr; i++)
+ free(array->refs[i]);
+ free(array->refs);
+ array->nr = array->alloc = 0;
+ array->refs = NULL;
}
static void invalidate_cached_refs(void)
{
struct cached_refs *ca = &cached_refs;
- if (ca->did_loose && ca->loose)
- free_ref_list(ca->loose);
- if (ca->did_packed && ca->packed)
- free_ref_list(ca->packed);
- ca->loose = ca->packed = NULL;
+ if (ca->did_loose)
+ free_ref_array(&ca->loose);
+ if (ca->did_packed)
+ free_ref_array(&ca->packed);
ca->did_loose = ca->did_packed = 0;
}
static void read_packed_refs(FILE *f, struct cached_refs *cached_refs)
{
- struct ref_list *list = NULL;
- struct ref_list *last = NULL;
+ struct ref_entry *last = NULL;
char refline[PATH_MAX];
int flag = REF_ISPACKED;
@@ -205,7 +158,7 @@ static void read_packed_refs(FILE *f, struct cached_refs *cached_refs)
name = parse_ref_line(refline, sha1);
if (name) {
- list = add_ref(name, sha1, flag, list, &last);
+ add_ref(name, sha1, flag, &cached_refs->packed, &last);
continue;
}
if (last &&
@@ -215,21 +168,20 @@ static void read_packed_refs(FILE *f, struct cached_refs *cached_refs)
!get_sha1_hex(refline + 1, sha1))
hashcpy(last->peeled, sha1);
}
- cached_refs->packed = sort_ref_list(list);
+ sort_ref_array(&cached_refs->packed);
}
void add_extra_ref(const char *name, const unsigned char *sha1, int flag)
{
- extra_refs = add_ref(name, sha1, flag, extra_refs, NULL);
+ add_ref(name, sha1, flag, &extra_refs, NULL);
}
void clear_extra_refs(void)
{
- free_ref_list(extra_refs);
- extra_refs = NULL;
+ free_ref_array(&extra_refs);
}
-static struct ref_list *get_packed_refs(const char *submodule)
+static struct ref_array *get_packed_refs(const char *submodule)
{
const char *packed_refs_file;
struct cached_refs *refs;
@@ -237,7 +189,7 @@ static struct ref_list *get_packed_refs(const char *submodule)
if (submodule) {
packed_refs_file = git_path_submodule(submodule, "packed-refs");
refs = &submodule_refs;
- free_ref_list(refs->packed);
+ free_ref_array(&refs->packed);
} else {
packed_refs_file = git_path("packed-refs");
refs = &cached_refs;
@@ -245,18 +197,17 @@ static struct ref_list *get_packed_refs(const char *submodule)
if (!refs->did_packed || submodule) {
FILE *f = fopen(packed_refs_file, "r");
- refs->packed = NULL;
if (f) {
read_packed_refs(f, refs);
fclose(f);
}
refs->did_packed = 1;
}
- return refs->packed;
+ return &refs->packed;
}
-static struct ref_list *get_ref_dir(const char *submodule, const char *base,
- struct ref_list *list)
+static void get_ref_dir(const char *submodule, const char *base,
+ struct ref_array *array)
{
DIR *dir;
const char *path;
@@ -299,7 +250,7 @@ static struct ref_list *get_ref_dir(const char *submodule, const char *base,
if (stat(refdir, &st) < 0)
continue;
if (S_ISDIR(st.st_mode)) {
- list = get_ref_dir(submodule, ref, list);
+ get_ref_dir(submodule, ref, array);
continue;
}
if (submodule) {
@@ -314,12 +265,11 @@ static struct ref_list *get_ref_dir(const char *submodule, const char *base,
hashclr(sha1);
flag |= REF_BROKEN;
}
- list = add_ref(ref, sha1, flag, list, NULL);
+ add_ref(ref, sha1, flag, array, NULL);
}
free(ref);
closedir(dir);
}
- return list;
}
struct warn_if_dangling_data {
@@ -356,21 +306,21 @@ void warn_dangling_symref(FILE *fp, const char *msg_fmt, const char *refname)
for_each_rawref(warn_if_dangling_symref, &data);
}
-static struct ref_list *get_loose_refs(const char *submodule)
+static struct ref_array *get_loose_refs(const char *submodule)
{
if (submodule) {
- free_ref_list(submodule_refs.loose);
- submodule_refs.loose = get_ref_dir(submodule, "refs", NULL);
- submodule_refs.loose = sort_ref_list(submodule_refs.loose);
- return submodule_refs.loose;
+ free_ref_array(&submodule_refs.loose);
+ get_ref_dir(submodule, "refs", &submodule_refs.loose);
+ sort_ref_array(&submodule_refs.loose);
+ return &submodule_refs.loose;
}
if (!cached_refs.did_loose) {
- cached_refs.loose = get_ref_dir(NULL, "refs", NULL);
- cached_refs.loose = sort_ref_list(cached_refs.loose);
+ get_ref_dir(NULL, "refs", &cached_refs.loose);
+ sort_ref_array(&cached_refs.loose);
cached_refs.did_loose = 1;
}
- return cached_refs.loose;
+ return &cached_refs.loose;
}
/* We allow "recursive" symbolic refs. Only within reason, though */
@@ -381,8 +331,8 @@ static int resolve_gitlink_packed_ref(char *name, int pathlen, const char *refna
{
FILE *f;
struct cached_refs refs;
- struct ref_list *ref;
- int retval;
+ struct ref_entry *ref;
+ int retval = -1;
strcpy(name + pathlen, "packed-refs");
f = fopen(name, "r");
@@ -390,17 +340,12 @@ static int resolve_gitlink_packed_ref(char *name, int pathlen, const char *refna
return -1;
read_packed_refs(f, &refs);
fclose(f);
- ref = refs.packed;
- retval = -1;
- while (ref) {
- if (!strcmp(ref->name, refname)) {
- retval = 0;
- memcpy(result, ref->sha1, 20);
- break;
- }
- ref = ref->next;
+ ref = search_ref_array(&refs.packed, refname);
+ if (ref != NULL) {
+ memcpy(result, ref->sha1, 20);
+ retval = 0;
}
- free_ref_list(refs.packed);
+ free_ref_array(&refs.packed);
return retval;
}
@@ -501,15 +446,13 @@ const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *
git_snpath(path, sizeof(path), "%s", ref);
/* Special case: non-existing file. */
if (lstat(path, &st) < 0) {
- struct ref_list *list = get_packed_refs(NULL);
- while (list) {
- if (!strcmp(ref, list->name)) {
- hashcpy(sha1, list->sha1);
- if (flag)
- *flag |= REF_ISPACKED;
- return ref;
- }
- list = list->next;
+ struct ref_array *packed = get_packed_refs(NULL);
+ struct ref_entry *r = search_ref_array(packed, ref);
+ if (r != NULL) {
+ hashcpy(sha1, r->sha1);
+ if (flag)
+ *flag |= REF_ISPACKED;
+ return ref;
}
if (reading || errno != ENOENT)
return NULL;
@@ -584,7 +527,7 @@ int read_ref(const char *ref, unsigned char *sha1)
#define DO_FOR_EACH_INCLUDE_BROKEN 01
static int do_one_ref(const char *base, each_ref_fn fn, int trim,
- int flags, void *cb_data, struct ref_list *entry)
+ int flags, void *cb_data, struct ref_entry *entry)
{
if (prefixcmp(entry->name, base))
return 0;
@@ -630,18 +573,12 @@ int peel_ref(const char *ref, unsigned char *sha1)
return -1;
if ((flag & REF_ISPACKED)) {
- struct ref_list *list = get_packed_refs(NULL);
+ struct ref_array *array = get_packed_refs(NULL);
+ struct ref_entry *r = search_ref_array(array, ref);
- while (list) {
- if (!strcmp(list->name, ref)) {
- if (list->flag & REF_KNOWS_PEELED) {
- hashcpy(sha1, list->peeled);
- return 0;
- }
- /* older pack-refs did not leave peeled ones */
- break;
- }
- list = list->next;
+ if (r != NULL && r->flag & REF_KNOWS_PEELED) {
+ hashcpy(sha1, r->peeled);
+ return 0;
}
}
@@ -660,36 +597,39 @@ fallback:
static int do_for_each_ref(const char *submodule, const char *base, each_ref_fn fn,
int trim, int flags, void *cb_data)
{
- int retval = 0;
- struct ref_list *packed = get_packed_refs(submodule);
- struct ref_list *loose = get_loose_refs(submodule);
+ int retval = 0, i, p = 0, l = 0;
+ struct ref_array *packed = get_packed_refs(submodule);
+ struct ref_array *loose = get_loose_refs(submodule);
- struct ref_list *extra;
+ struct ref_array *extra = &extra_refs;
- for (extra = extra_refs; extra; extra = extra->next)
- retval = do_one_ref(base, fn, trim, flags, cb_data, extra);
+ for (i = 0; i < extra->nr; i++)
+ retval = do_one_ref(base, fn, trim, flags, cb_data, extra->refs[i]);
- while (packed && loose) {
- struct ref_list *entry;
- int cmp = strcmp(packed->name, loose->name);
+ while (p < packed->nr && l < loose->nr) {
+ struct ref_entry *entry;
+ int cmp = strcmp(packed->refs[p]->name, loose->refs[l]->name);
if (!cmp) {
- packed = packed->next;
+ p++;
continue;
}
if (cmp > 0) {
- entry = loose;
- loose = loose->next;
+ entry = loose->refs[l++];
} else {
- entry = packed;
- packed = packed->next;
+ entry = packed->refs[p++];
}
retval = do_one_ref(base, fn, trim, flags, cb_data, entry);
if (retval)
goto end_each;
}
- for (packed = packed ? packed : loose; packed; packed = packed->next) {
- retval = do_one_ref(base, fn, trim, flags, cb_data, packed);
+ if (l < loose->nr) {
+ p = l;
+ packed = loose;
+ }
+
+ for (; p < packed->nr; p++) {
+ retval = do_one_ref(base, fn, trim, flags, cb_data, packed->refs[p]);
if (retval)
goto end_each;
}
@@ -1005,24 +945,24 @@ static int remove_empty_directories(const char *file)
}
static int is_refname_available(const char *ref, const char *oldref,
- struct ref_list *list, int quiet)
-{
- int namlen = strlen(ref); /* e.g. 'foo/bar' */
- while (list) {
- /* list->name could be 'foo' or 'foo/bar/baz' */
- if (!oldref || strcmp(oldref, list->name)) {
- int len = strlen(list->name);
+ struct ref_array *array, int quiet)
+{
+ int i, namlen = strlen(ref); /* e.g. 'foo/bar' */
+ for (i = 0; i < array->nr; i++ ) {
+ struct ref_entry *entry = array->refs[i];
+ /* entry->name could be 'foo' or 'foo/bar/baz' */
+ if (!oldref || strcmp(oldref, entry->name)) {
+ int len = strlen(entry->name);
int cmplen = (namlen < len) ? namlen : len;
- const char *lead = (namlen < len) ? list->name : ref;
- if (!strncmp(ref, list->name, cmplen) &&
+ const char *lead = (namlen < len) ? entry->name : ref;
+ if (!strncmp(ref, entry->name, cmplen) &&
lead[cmplen] == '/') {
if (!quiet)
error("'%s' exists; cannot create '%s'",
- list->name, ref);
+ entry->name, ref);
return 0;
}
}
- list = list->next;
}
return 1;
}
@@ -1129,18 +1069,13 @@ static struct lock_file packlock;
static int repack_without_ref(const char *refname)
{
- struct ref_list *list, *packed_ref_list;
- int fd;
- int found = 0;
+ struct ref_array *packed;
+ struct ref_entry *ref;
+ int fd, i;
- packed_ref_list = get_packed_refs(NULL);
- for (list = packed_ref_list; list; list = list->next) {
- if (!strcmp(refname, list->name)) {
- found = 1;
- break;
- }
- }
- if (!found)
+ packed = get_packed_refs(NULL);
+ ref = search_ref_array(packed, refname);
+ if (ref == NULL)
return 0;
fd = hold_lock_file_for_update(&packlock, git_path("packed-refs"), 0);
if (fd < 0) {
@@ -1148,17 +1083,19 @@ static int repack_without_ref(const char *refname)
return error("cannot delete '%s' from packed refs", refname);
}
- for (list = packed_ref_list; list; list = list->next) {
+ for (i = 0; i < packed->nr; i++) {
char line[PATH_MAX + 100];
int len;
- if (!strcmp(refname, list->name))
+ ref = packed->refs[i];
+
+ if (!strcmp(refname, ref->name))
continue;
len = snprintf(line, sizeof(line), "%s %s\n",
- sha1_to_hex(list->sha1), list->name);
+ sha1_to_hex(ref->sha1), ref->name);
/* this should not happen but just being defensive */
if (len > sizeof(line))
- die("too long a refname '%s'", list->name);
+ die("too long a refname '%s'", ref->name);
write_or_die(fd, line, len);
}
return commit_lock_file(&packlock);
--
1.7.6.1
^ permalink raw reply related
* Re: In favor of "git commit --no-parent"
From: Michael Witten @ 2011-09-29 22:07 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7v4nzvrp3k.fsf@alter.siamese.dyndns.org>
On Thu, Sep 29, 2011 at 21:54, Junio C Hamano <gitster@pobox.com> wrote:
> I am saying that "separate history" has no place in git workflow, if these
> multiple roots _originate_ in the same single repository with a working
> tree. And all of "git checkout --orphan", "git commit --root" and your
> "git init --root" are solutions to make multiple roots _originate_ in the
> same single repository with a working tree.
Why do you keep repeating this?
The "git commit --no-parent" is the CORRECT solution for
"HIDDEN history", NOT the "separate history" that you so loathe.
The existing "git checkout --orphan" is the CORRECT solution for
the "SEPARATE history" that you so loathe, NOT the "hidden history".
^ permalink raw reply
* Re: In favor of "git commit --no-parent"
From: Phil Hord @ 2011-09-29 22:07 UTC (permalink / raw)
To: Junio C Hamano
Cc: Michael Witten, Carlos Martín Nieto, vra5107,
Michael J Gruber, Matthieu Moy, Eric Raible, Philip Oakley,
Jeff King, Jay Soffian, git
In-Reply-To: <7v4nzvrp3k.fsf@alter.siamese.dyndns.org>
Junio C Hamano <gitster@pobox.com> writes:
> Phil Hord <phil.hord@gmail.com> writes:
>
>> I think a user looking for this functionality -- either a new git user
>> or a user who seldom uses the "create secondary root commit" command
>> -- would first try 'git help init'. It seems logical to me that I
>> should be able to do this:
>>
>> cd my-git-repo
>> git init --root=<newbranch> .
>>
>> This feels natural to me for this operation.
>
> Hmm, this does not feel very natural to me; unless "git init --root=work"
> uses 'work' branch instead of 'master' when creating a new repository,
> that is. But it is attractive that init is much less often used than
> checkout/commit and everybody knows it is somewhat a _special_ operation.
That's what I meant. Sorry my example wasn't more clear about that.
I also considered "--new-branch" and "--new-root". I like the latter
more, but I didn't like the extra hyphen. Considering the rarity and
the prior art, I guess either one is more clear here.
>>> That leaves "Hidden History" the only useful use case. IOW, the answer to
>>> the first question above is not "Separate or Hidden History", but is
>>> "Hidden History and nothing else".
>>
>> I think you're saying that the "hidden history" scenario is more
>> special than the "separate history" one because of these reasons:
>
> Not at all.
>
> I am saying that "separate history" has no place in git workflow, if these
> multiple roots _originate_ in the same single repository with a working
> tree.
No place in *your* workflow. Oh, wait. Except it has, and you use it
in the git tree. So, um... I'm confused.
> And all of "git checkout --orphan", "git commit --root" and your
> "git init --root" are solutions to make multiple roots _originate_ in the
> same single repository with a working tree.
>
> I have no trouble in a single repository with multiple roots if that is
> done in a distribution point, which by definition does not need and
> typically does not have any working tree. Options to "checkout/commit"
> would not help as they need a working tree.
I'm not sure where you're going with the "working tree" objection.
Are you saying that it's ok to _create_ "separate histories" in a bare
repository but wrong to do so in a non-bare one? But surely this
means it is ok to _have_ "separate histories" in a non-bare
repository, since that is what I will get when I do a simple git-clone
of the bare one.
If I understand right, the mechanics of the initial creation is what
bothers you. Is that right? If so, we're on the same page here,
because it bothers me too. The commit or checkout alternatives seem
like two halves of a turd sandwich. Both ends are wrong somehow, and
it's because of the state of the working directory in the interim.
If I don't understand you right, ignore the sandwich metaphor and
please explain.
> The way to do it is to work in multiple repositories, one for each of
> these roots, and push into a single repository from them.
That's one way to do it.
>>> And a half of the the answer to the second question is "checkout --orphan"
>>> (and the other half would be "filter-branch"). "checkout --orphan" does
>>> have major safety advantage than introducing "commit --no-parent", as Peff
>>> pointed out earlier (to which I agreed).
>>
>> The thing I don't understand about "checkout --orphan" is exactly what
>> you're getting when you do this. I assume you get a populated index
>> and a non-existent HEAD. This seems a lot like "git init" to me,
>> especially in the non-existent HEAD area.
>
> It is "HEAD pointing at a branch that does not yet exist", but I find it
> strangely attractive ;-)
>
>> I didn't think git init would be much use for this scenario before,
>> but now I've changed my mind.
>>
>> git init --root=<newbranch> --keep-index
>>
>> Again, this avoids complicating the common commands. But maybe it
>> does overload init with extra baggage.
>
> I do not think you would even need --keep-index there (running "git init"
> in an existing repository to see what it does. It does not touch the index
> nor HEAD).
In my imagined extension, the "separate history" action needs a clean
index. I guess 'git rm -fr *' will suffice, but I think an in-line
switch would be more useful... for this "non-git workflow". :-)
> I am not sure if "--root" is the right name but if "git init --root=work"
> that is run to create (not re-init) a new repository points HEAD at a yet
> to be created 'work' branch instead of 'master', I think it would be a
> reasonable alternative.
That's what I meant. How about this?
git init --new-root-branch=<new-branch-name>
> By the way, why did you drop the mailing list?
Clicked the wrong button. Not used to gmail yet for this. Sorry about that.
Phil
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox