* Re: [PATCH/resent 0/9] Sparse checkout (first half)
From: Santi Béjar @ 2008-10-01 10:20 UTC (permalink / raw)
To: Nguyễn Thái Ngọc Duy; +Cc: git, Shawn O. Pearce
In-Reply-To: <1222833849-22129-1-git-send-email-pclouds@gmail.com>
Not in this half but I've seen that you added a --default-sparse flag
to "git clone". I think it is useless as mostly always the one given
in -sparse-checkout should be used.
Thanks
Santi
On Wed, Oct 1, 2008 at 6:04 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:
> This is the first half of the series, making git ready for sparse
> checkout. The only difference from the last (first half) sent
> series is safeguard bitmask fix in 1/9
>
> Nguyễn Thái Ngọc Duy (9):
> Extend index to save more flags
> Introduce CE_NO_CHECKOUT bit
> ls-files: add options to support sparse checkout
> update-index: refactor mark_valid() in preparation for new options
> update-index: add --checkout/--no-checkout to update CE_NO_CHECKOUT
> bit
> ls-files: Add tests for --sparse and friends
> Prevent diff machinery from examining worktree outside sparse
> checkout
> checkout_entry(): CE_NO_CHECKOUT on checked out entries.
> grep: skip files outside sparse checkout area
>
> .gitignore | 1 +
> Documentation/git-checkout.txt | 34 +++++++++++++++++
> Documentation/git-grep.txt | 4 +-
> Documentation/git-ls-files.txt | 24 +++++++++++-
> Documentation/git-update-index.txt | 13 ++++++
> Makefile | 2 +-
> builtin-grep.c | 7 +++-
> builtin-ls-files.c | 41 ++++++++++++++++++--
> builtin-update-index.c | 40 ++++++++++++-------
> cache.h | 66 +++++++++++++++++++++++++++++++--
> diff-lib.c | 5 +-
> diff.c | 4 +-
> entry.c | 1 +
> read-cache.c | 57 ++++++++++++++++++++++------
> t/t2104-update-index-no-checkout.sh | 36 ++++++++++++++++++
> t/t3004-ls-files-sparse.sh | 40 ++++++++++++++++++++
> t/t3004/cached.expected | 5 ++
> t/t3004/deleted.expected | 1 +
> t/t3004/everything.expected | 10 +++++
> t/t3004/modified.expected | 2 +
> t/t3004/no-checkout.expected | 2 +
> t/t3004/orphaned-no-checkout.expected | 3 +
> t/t3004/orphaned.expected | 1 +
> t/t3004/others.expected | 2 +
> t/t3004/sparse-cached.expected | 3 +
> t/t3004/sparse-everything.expected | 11 +++++
> test-index-version.c | 14 +++++++
> 27 files changed, 385 insertions(+), 44 deletions(-)
> create mode 100755 t/t2104-update-index-no-checkout.sh
> create mode 100755 t/t3004-ls-files-sparse.sh
> create mode 100644 t/t3004/cached.expected
> create mode 100644 t/t3004/deleted.expected
> create mode 100644 t/t3004/everything.expected
> create mode 100644 t/t3004/modified.expected
> create mode 100644 t/t3004/no-checkout.expected
> create mode 100644 t/t3004/orphaned-no-checkout.expected
> create mode 100644 t/t3004/orphaned.expected
> create mode 100644 t/t3004/others.expected
> create mode 100644 t/t3004/sparse-cached.expected
> create mode 100644 t/t3004/sparse-everything.expected
> create mode 100644 test-index-version.c
>
> --
> 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
>
^ permalink raw reply
* Re: [RFC PATCH] Documentation: add manpage about workflows
From: Santi Béjar @ 2008-10-01 9:54 UTC (permalink / raw)
To: Thomas Rast; +Cc: Dmitry Potapov, git, Junio C Hamano
In-Reply-To: <200809301805.30753.trast@student.ethz.ch>
On Tue, Sep 30, 2008 at 6:05 PM, Thomas Rast <trast@student.ethz.ch> wrote:
> As a quick status update, mostly to show that I haven't forgotten
> about this topic:
>
> Thanks Santi and Dmitry for your comments. You have raised some very
> good points, and I attempted to fix these issues.
Thanks for you document.
>
> Unfortunately, in some places I got stuck trying to work out good
> explanations for the workings of git.git, and some of the newer
> rearrangements left the lead of "Merging branches" in a dire state.
> I'll see if I can find a good solution myself, but suggestions would
> be welcome in any case. The WIP text is below, and I'll follow up
> with an interdiff to the last version.
>
> - Thomas
>
[...]
>
> SEPARATE CHANGES
> ----------------
>
> As a general rule, you should try to split your changes into small
> logical steps, and commit each of them. They should be consistent,
> working independently of any later commits, pass the test suite, etc.
> This makes the review process much easier, and the history much more
> useful for later inspection and analysis, for example with
> linkgit:git-blame[1] and linkgit:git-bisect[1].
>
> To achieve this, try to split your work into small steps from the very
> beginning. It is always easier to squash a few commits together than
> to split one big commit into several. Don't be afraid of making too
> small or imperfect steps along the way. You can always go back later
> and edit the commits with `git rebase \--interactive` before you
> publish them.
>
I know it is against the recommendation but I think it makes sense to
explain how you can split big patches testing them as is explained in
gitlink:git-stash.
[...]
> Graduation
> ~~~~~~~~~~
>
> As a given feature goes from experimental to stable, it also
> "graduates" between the corresponding branches of the software.
> `git.git` uses the following 'main branches':
>
> * 'master' tracks the commits that should go into the next release;
>
> * 'maint' tracks the commits that should go into the next "maintenance
> release", i.e., update of the last released stable version; and
The "logical" order would be 'maint', 'master', 'next', 'pu', each one
should fast-forward to the next one.
>
> * 'next' is intended as a testing branch for people who like to use
> more experimental stuff.
The key point is not "more experimental stuff", but 'master' material
but not stable enough.
[...]
> Integration branches
> ~~~~~~~~~~~~~~~~~~~~
>
> If you followed the last paragraph, you will now have many small topic
> branches, and occasionally wonder how they interact. Perhaps the
> result of merging them does not even work? But on the other hand, we
> want to avoid merging them anywhere "stable" because such merges
> cannot easily be undone.
>
> The solution, of course, is to make a merge that we can undo: merge
> into a throw-away branch.
>
> .Integration branches
> [caption="Rule: "]
> =====================================
> To test the interaction of several topics, merge them into a
> throw-away branch.
> =====================================
>
> If you make it (very) clear that this branch is going to be deleted
> right after the testing, you can even publish this branch, for example
> to give the testers a chance to work with it, or other developers a
> chance to see if their in-progress work will be compatible. `git.git`
> has such an official integration branch called 'pu'. You must never
> base any work on such a throw-away branch!
Maybe this last sentence should go in the "Rule:".
>
>
> SHARING WORK
> ------------
>
> After the last section, you should know how to manage topics. In
> general, you will not be the only person working on the project, so
> you will have to share your work.
Sharing work is explained in the tutorials, maybe this section should
be about "distributed workflows".
>
> Roughly speaking, there are two important workflows: push/pull and
> format-patch/am.
A more descriptive name could be the "merge workflow" and the "patch workflow".
> The important difference is that push/pull can
> propagate merges, while format-patch cannot.
Like I said in the other mail, the key is that one preserves the
history (including merges) and the other not. This is what makes
possible the push/pull workflow, that all the branches should
fast-forward (and this should be said somewhere)
> Medium to large projects
> will typically employ some mixture of the two:
s/:/./
Although I think it should be deleted. And what about litle projects?
Different roles do uses different workflows:
>
> * "Upstream" in the most general sense 'pushes' changes to the
> repositor(ies) holding the official history of the project.
> Everyone can 'fetch' from there to stay up to date.
s/pushes/publishes/
s/fetch/merge/
>
> * Frequent contributors, subsystem maintainers, etc. may push to a
> public repository to make their changes available to upstream.
s/push/publish/
Or:
* Frequent contributors, subsystem maintainers, etc. may publish to a
public repository to make their changes available to upstream, or to
their downstreams (acting as upstream to them)
>
> * The rest -- typically anyone more than one or two levels away from the
> main maintainer -- send patches by mail.
In the "distributed workflows" this would be:
* "Upstream" merges the branches from subsystem maintainers, applies
the 'patches' from others (including themselves) and publishes to the
main repository. See link:howto/maintain-git.txt to see how it is done
in git.git)
* "Subsystem maintainers" act as "upstream" but publishes to a
different repository/branch.
* Frequent contributors, etc, publish their changes in another repository.
* The rest ...
>
> None of these boundaries are sharp, so find out what works best for
> you.
>
>
> Push/pull
> ~~~~~~~~~
>
> There are three main tools that can be used for this:
Sorry, but I don't see the point explaining how to publish the
branches, or keep them up to date.
>
> If you are a maintainer and would like to merge other people's topic
> branches to the main branches, they will typically send a request to
> do so by mail. Such a request might say
>
> -------------------------------------
> Please pull from
> git://some.server.somewhere/random/repo.git mytopic
> -------------------------------------
>
> In that case, 'git-pull' can do the fetch and merge in one go, as
> follows.
Or:
Then, you can merge them with just:
> .Push/pull: Merging remote topics
> [caption="Recipe: "]
> =====================================
> `git pull <url> <branch>`
> =====================================
>
Use "<url> <branch>" or "git://some.server.somewhere/random/repo.git
mytopic" in the recipies, but not both.
[...]
>
> format-patch/am
> ~~~~~~~~~~~~~~~
s/.*/patch workflow/
>
> If you are a contributor that sends changes upstream in the form of
> emails, you should use topic branches as usual (see above). Then use
> linkgit:git-format-patch[1] to generate the corresponding emails
> (highly recommended over manually formatting them because it makes the
> maintainer's life easier).
>
> .format-patch/am: Publishing branches/topics
> [caption="Recipe: "]
> =====================================
> * `git format-patch -M upstream..topic` to turn them into preformatted
> patch files
> * `git send-email --to=<recipient> <patches>`
> =====================================
>
> See the linkgit:git-format-patch[1] and linkgit:git-send-email[1]
> manpages for further usage notes. Also you should be aware that the
> maintainer may impose further restrictions, such as "Signed-off-by"
> requirements.
The restrictions and the Signed-off-by also applies to the other workflows.
>
> If the maintainer tells you that your patch no longer applies to the
> current upstream, you will have to rebase your topic (you cannot use a
> merge because you cannot format-patch merges):
>
> .format-patch/am: Keeping topics up to date
> [caption="Recipe: "]
> =====================================
> `git pull --rebase <url> <branch>`
> =====================================
>
> You can then fix the conflicts during the rebase. Presumably you have
> not published your topic other than by mail, so rebasing it is not a
> problem.
>
> If you receive such a patch (as maintainer, or perhaps as a reader of
> the mailing list it was sent to), save the mail to a file and use
> 'git-am':
>
> .format-patch/am: Publishing branches/topics
> [caption="Recipe: "]
> =====================================
> `git am < patch`
> =====================================
>
> One feature worth pointing out is the three-way merge, which can help
> if you get conflicts: `git am -3` will use index information contained
> in patches to figure out the merge base. See linkgit:git-am[1] for
> other options.
>
>
> SEE ALSO
> --------
> linkgit:gittutorial[7],
> linkgit:git-push[1],
> linkgit:git-pull[1],
> linkgit:git-merge[1],
> linkgit:git-rebase[1],
> linkgit:git-format-patch[1],
> linkgit:git-send-email[1],
> linkgit:git-am[1]
>
> GIT
> ---
> Part of the linkgit:git[1] suite.
>
>
>
^ permalink raw reply
* Re: [RFC] gitweb wishlist and TODO list (profiling gitweb)
From: Jakub Narebski @ 2008-10-01 9:52 UTC (permalink / raw)
To: Ask Bjørn Hansen; +Cc: git, Petr Baudis
In-Reply-To: <1D35F972-DA47-4445-A667-B03F841CABC6@develooper.com>
On Wed, 1 Oct 2008, Ask Bjørn Hansen wrote:
> On Sep 25, 2008, at 3:30, Jakub Narebski wrote:
>
> > * Optional information about load stats
> >
> > Add an option to display information about how much time it took to
> > generate page, how many git commands were called, and possibly other
> > metric; if page was cached, write when it was generated, and how
> > much time till timeout. This probably would require additional perl
> > modules, and it should be conditional on those modules.
>
> Before spending too much time on this, be sure to have a look a
> Devel::NYTProf.
>
> http://search.cpan.org/~timb/Devel-NYTProf-2.03/lib/Devel/NYTProf.pm
>
> http://blog.timbunce.org/2008/07/15/nytprof-v2-a-major-advance-in-perl-profilers/
Thank you very much for the pointers.
However I'm not sure how much help would that be, as according to J.H.
(kernel.org admin) and Petr Baudis (repo.or.cz admin), gitweb
performance in real life settings is bound by I/O, not by CPU usage.
--
Jakub Narebski
Poland
^ permalink raw reply
* Re: [RFC] gitweb wishlist and TODO list
From: Ask Bjørn Hansen @ 2008-10-01 8:40 UTC (permalink / raw)
To: Jakub Narebski; +Cc: git, Petr Baudis
In-Reply-To: <200809251230.11342.jnareb@gmail.com>
On Sep 25, 2008, at 3:30, Jakub Narebski wrote:
> * Optional information about load stats
>
> Add an option to display information about how much time it took to
> generate page, how many git commands were called, and possibly other
> metric; if page was cached, write when it was generated, and how
> much time till timeout. This probably would require additional perl
> modules, and it should be conditional on those modules.
Before spending too much time on this, be sure to have a look a
Devel::NYTProf.
http://search.cpan.org/~timb/Devel-NYTProf-2.03/lib/Devel/NYTProf.pm
http://blog.timbunce.org/2008/07/15/nytprof-v2-a-major-advance-in-perl-profilers/
--
http://develooper.com/ - http://askask.com/
^ permalink raw reply
* Re: [PATCH] Builtin-commit: show on which branch a commit was added
From: Andreas Ericsson @ 2008-10-01 8:13 UTC (permalink / raw)
To: Jeff King
Cc: Wincent Colaiuta, Pieter de Bie, Junio C Hamano, Git Mailinglist
In-Reply-To: <20081001031400.GA24513@coredump.intra.peff.net>
Jeff King wrote:
> On Tue, Sep 30, 2008 at 11:59:25AM +0200, Andreas Ericsson wrote:
>
>> I agree. Obvious solution is to do
>>
>> subj_len = term_width - (strlen(cruft) + strlen(branch_name))
>
> I think the difficulty is that the printing is sometimes done by our
> printf and sometimes by log_tree_commit, and there isn't a convenient
> way to hook into log_tree_commit to postprocess the formatted output.
>
>> where strlen(cruft) is just 8 less if we drop 'commit ' from the
>> cases. See the patch I just sent though. I sort of like that one.
>
> I like it much better than what is on next (and I thought your commit
> message summed up the issue nicely), but...
>
Thanks. Feel free to recycle it :)
>> Another way would be to write
>> <branch>: Created <hash>: "subject line..."
>
> I think I like this even better.
Me too, but I thought it up after I sent out the first patch. The nicest
part is that the info that's always present will always end up in the
same place, while my patch moves the branch-name around depending on
the length of the subject line.
Let's agree here and now that the subject should be last and that "commit "
should be dropped, at least for the normal cases.
> My only concern is that many programs
> say "program: some error", so you could potentially have a confusing
> branch name. But I personally have never used a branch name that would
> cause such confusion.
>
A valid concern, certainly. We needn't use colons for the branch-name
though, but could instead use some other delimiter, like this:
[<branch>] Created <hash>: "subject line..."
although I do believe we're close to nitpicking this issue to death
now. It's not *that* important after all.
>> As <hash> will very, very rarely match anything the user would put
>> in his/her commit message themselves. Quoting the subject is probably
>> a nice touch, and it can make sense to put it last as it's the least
>> interesting of the things we print. Ah well. I'll just await commentary
>> on the patch I've already sent before I go ahead and do something like
>> that.
>
> Here is a patch for that format on top of next (the patch between this
> and what is in master is even more simple, since we are mostly removing
> Pieter's helper function).
>
I don't quite like the fact that you're removing the "detached" thingie.
I have coworkers that have been bitten by committing on detached head,
so I'd like to have some mention of it. I'll rework it to take that
into account. Otherwise, this looks good. Less code is always a good
thing, imo.
--
Andreas Ericsson andreas.ericsson@op5.se
OP5 AB www.op5.se
Tel: +46 8-230225 Fax: +46 8-230231
^ permalink raw reply
* Re: Git config not expanding user home directories
From: Andreas Ericsson @ 2008-10-01 7:52 UTC (permalink / raw)
To: Jeff King; +Cc: Jakub Narebski, Tom Lanyon, Karl Chen, Git Mailinglist
In-Reply-To: <20081001032246.GB24513@coredump.intra.peff.net>
Jeff King wrote:
> On Tue, Sep 30, 2008 at 04:38:46AM -0700, Jakub Narebski wrote:
>
>> There was a patch send to git mailing list adding basic '~' support
>> (I think via $ENV{HOME}), and IIRC even ~user support. I don't know
>> what happened to those patches (check mailing list archive), but
>> most probably it was not accepted because it didn't provide a way
>> for scripts to use this functionality, for example via --path option.
>
> There were several rounds, and I thought it was shaping up, but then
> no more rounds came. I assume that Karl lost interest (or perhaps we
> nitpicked him to death), but I thought at the end of the thread Junio
> laid out a plan for the next revision. I guess nobody cared enough about
> the feature to implement it after that (though I think I found the final
> version acceptable with a minor documentation tweak, I think Junio laid
> out a cleaner approach).
>
> The last patch is here, with one of the replies from Junio giving the
> aforementioned plan:
>
> http://mid.gmane.org/quack.20080829T0229.lthhc94rwyr_-_@roar.cs.berkeley.edu
>
That looks roughly like the way I'd have done it. I'll see if I can find
the time to polish it up a bit.
--
Andreas Ericsson andreas.ericsson@op5.se
OP5 AB www.op5.se
Tel: +46 8-230225 Fax: +46 8-230231
^ permalink raw reply
* Re: interactive rebase not rebasing
From: Andreas Ericsson @ 2008-10-01 7:50 UTC (permalink / raw)
To: Stephen Haberman; +Cc: git
In-Reply-To: <20081001010306.01cc34eb.stephen@exigencecorp.com>
Stephen Haberman wrote:
>>> # A --C------ <-- origin/stable
>>> # \ | \
>>> # B -- D -- E -- F <-- origin/topic2
>>> # \|
>>> # g -- h <-- topic2
>>>
>>> Nothing has changed. g & h haven't moved...I can keep executing this
>>> operation and the commits never make it on top of origin/topic2's F.
>>>
>>> Frustratingly, if I run non-interactive rebase, it works perfectly.
>> I can imagine. Since you don't want to preserve the merges in this
>> case, you shouldn't be using the -p flag.
>
> No, I do want to preserve most merges. This "most" qualification is
> because the merge "g", if rebased, would have been a no-op, so `rebase
> -i -p` correctly kept it out of the TODO file.
>
> Which is cool, except that later on, when rewriting the other TODO
> commits, some of which were children of "g", it did not remember that
> "g" had gone away, so did nothing to take "g" out of the rewritten
> children's parent list.
>
>> In fact, for this particular scenario (assuming "h" is really the only
>> commit on topic2), you probably want to just cherry-pick that commit
>> into origin/topic2:
>>
>> git checkout topic2
>> git reset --hard origin/topic2
>> git cherry-pick ORIG_HEAD
>
> Agreed. This makes a lot of sense for me, who has been hacking around in
> git-rebase--interactive fixing things, but I'd really like the other
> people on my team to just have to run `git rebase -i -p`.
>
>> I don't think you can have a single command that does all the things
>> you want, because the possible differences in input makes it very
>> nearly impossible to always do "the right thing".
>
> Ah, you are too pessimistic. :-)
>
Perhaps, although I think you're being overly optimistic if you think
rebase can do all of this intelligently while still retaining clear
semantics. I'd start with writing a separate tool for it, probably
based on git sequencer. When that works out ok, get it to do what
rebase does today and then incorporate the new tool as an option to
rebase and get ready to answer complex questions for the cases where
it doesn't do what the user wanted it to do.
Git is stupid very, very much by design. Linus constantly says that
he prefers tools that he can figure out why they did something stupid
over tools that try really hard to get it right, and I agree with him
100%, as do most of the core contributors (insofar as I've understood
it). What you're suggesting is that a git command should try hard to
dwim a lot of complexity about choosing tools away, and that goes
right against the KISS principle which serves git so well. I'm not
saying you shouldn't do it. Merely that you should think hard about
it and then make sure it doesn't break anything people are already
doing today with the current toolset.
--
Andreas Ericsson andreas.ericsson@op5.se
OP5 AB www.op5.se
Tel: +46 8-230225 Fax: +46 8-230231
^ permalink raw reply
* obscure platform autobuilders
From: Jeff King @ 2008-10-01 7:16 UTC (permalink / raw)
To: Mike Ralphson; +Cc: git
In-Reply-To: <e2b179460809290051q8ca76a4k7cf0af2748a5f0fc@mail.gmail.com>
On Mon, Sep 29, 2008 at 08:51:29AM +0100, Mike Ralphson wrote:
> Feel free to push changes to gitbuild.sh, including getting rid of
> anything which looks environment-specific.
I actually went a step further and revamped the architecture a bit.
Check out the "platform" branch in gitbuild.git. My goal was to try to
include more information in the gitbuild repository about exactly what
goes into the test setup for each platform.
I'm currently building, testing, and pushing FreeBSD 6.1 and Solaris 2.8
with it (you can see the copious tests I am skipping in
jk/solaris/config).
If you like this approach, please go ahead and add an "mr/aix" profile
with your setup. See the README for details, and let me know if you have
questions. The script is a mish-mash of yours, mine, and some extra
rewrites. I wouldn't be surprised if it needs a tweak or two. :)
-Peff
^ permalink raw reply
* Re: [QGit] [PATCH] Modify Highlight Color at File Context View.
From: Marco Costalba @ 2008-10-01 6:47 UTC (permalink / raw)
To: Li Frank-B20596; +Cc: git
In-Reply-To: <7FD1F85C96D70C4A89DA1DF7667EAE9605EA4E@zch01exm23.fsl.freescale.net>
On Mon, Sep 29, 2008 at 3:27 AM, Li Frank-B20596 <Frank.Li@freescale.com> wrote:
> Marco:
>
> I don't get my patch by git-pull.
> There are not my patch at
> http://git.kernel.org/?p=qgit/qgit4.git;a=summary.
>
> best regards
> Frank Li
> ________________________________
I have pushed to my local repo, I will be able to push to public repo
only this week end.
Marco
^ permalink raw reply
* Re: [PATCH] git grep: Add "-Z/--null" option as in GNU's grep.
From: Pierre Habouzit @ 2008-10-01 6:12 UTC (permalink / raw)
To: Raphael Zimmerer; +Cc: spearce, git
In-Reply-To: <1222816390-9141-1-git-send-email-killekulla@rdrz.de>
[-- Attachment #1: Type: text/plain, Size: 582 bytes --]
On Tue, Sep 30, 2008 at 11:13:10PM +0000, Raphael Zimmerer wrote:
> + printf("%s%c", name, opt->null_following_name ? 0 : '\n');
I know I'm nitpicking and I don't know what the git custom on this
really is, but I tend to prefer '\0' when in the context of a char.
There is no confusion here of course, but I believe it to be a sane
habit. (In the same vein that it's ugly to use 0 for NULL ;p).
--
·O· Pierre Habouzit
··O madcoder@debian.org
OOO http://www.madism.org
[-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --]
^ permalink raw reply
* [PATCH] Fix interactive rebase on dropped commits.
From: Stephen Haberman @ 2008-10-01 6:11 UTC (permalink / raw)
To: git; +Cc: ae, spearce
Interactive rebase got its rev-list of commits to keep by --left-right and
--cherry-pick. Adding --cherry-pick would throw out commits that were just
duplicating changes already in the rebase target.
Which is desirable, except the dropped commit has forgotten about when it came
to rewriting the parents of its descendents, so the descendents would get
cherry-picked as-in and essentially make the rebase a no-op.
This change adds a $DOTEST/dropped directory to remember dropped commits and
rewrite its children's parents as the children's (possibly rewritten)
grandparents.
Signed-off-by: Stephen Haberman <stephen@exigencecorp.com>
---
git-rebase--interactive.sh | 52 ++++++++++++---
t/t3409-rebase-interactive-cherry-picked.sh | 94 +++++++++++++++++++++++++++
2 files changed, 136 insertions(+), 10 deletions(-)
create mode 100644 t/t3409-rebase-interactive-cherry-picked.sh
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 929d681..2d62590 100755
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -37,6 +37,7 @@ DONE="$DOTEST"/done
MSG="$DOTEST"/message
SQUASH_MSG="$DOTEST"/message-squash
REWRITTEN="$DOTEST"/rewritten
+DROPPED="$DOTEST"/dropped
PRESERVE_MERGES=
STRATEGY=
ONTO=
@@ -146,15 +147,7 @@ pick_one () {
pick_one_preserving_merges () {
fast_forward=t
- case "$1" in
- -n)
- fast_forward=f
- sha1=$2
- ;;
- *)
- sha1=$1
- ;;
- esac
+ case "$1" in -n) fast_forward=f sha1=$2 ;; *) sha1=$1 ;; esac
sha1=$(git rev-parse $sha1)
if test -f "$DOTEST"/current-commit
@@ -183,7 +176,28 @@ pick_one_preserving_merges () {
;;
esac
else
- new_parents="$new_parents $p"
+ if test -f "$DROPPED"/$p
+ then
+ fast_forward=f
+ cat "$DROPPED"/$p | while read grandparent
+ do
+ if test -f "$REWRITTEN"/$grandparent
+ then
+ new_p=$(cat "$REWRITTEN"/$grandparent)
+ else
+ new_p=$grandparent
+ fi
+ case "$new_parents" in
+ *$new_p*)
+ ;; # do nothing; that parent is already there
+ *)
+ new_parents="$new_parents $new_p"
+ ;;
+ esac
+ done
+ else
+ new_parents="$new_parents $p"
+ fi
fi
done
case $fast_forward in
@@ -574,6 +588,24 @@ do
#
EOF
+ # Watch for commits that been dropped by --cherry-pick
+ if test t = "$PRESERVE_MERGES"
+ then
+ mkdir "$DROPPED"
+ # drop the --cherry-pick parameter this time
+ git rev-list $MERGES_OPTION --abbrev-commit \
+ --abbrev=7 $UPSTREAM...$HEAD --left-right | \
+ sed -n "s/^>//p" | while read rev
+ do
+ grep --quiet "$rev" "$TODO"
+ if [ $? -ne 0 ]
+ then
+ full=$(git rev-parse $rev)
+ git rev-list --parents -1 $rev | cut -d' ' -f2- | sed 's/ /\n/g' > "$DROPPED"/$full
+ fi
+ done
+ fi
+
has_action "$TODO" ||
die_abort "Nothing to do"
diff --git a/t/t3409-rebase-interactive-cherry-picked.sh b/t/t3409-rebase-interactive-cherry-picked.sh
new file mode 100644
index 0000000..3d20180
--- /dev/null
+++ b/t/t3409-rebase-interactive-cherry-picked.sh
@@ -0,0 +1,94 @@
+#!/bin/sh
+
+test_description='rebase interactive does not rebase'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+ echo "setup" >a &&
+ git add a &&
+ git commit -m "setup" &&
+ git clone ./. server &&
+ rm -fr server/.git/hooks &&
+ git remote add origin ./server &&
+ git config --add branch.master.remote origin &&
+ git config --add branch.master.merge refs/heads/master &&
+ git fetch &&
+
+ git checkout -b stable master &&
+ echo "setup.stable" >a &&
+ git commit -a -m "stable" &&
+ git push origin stable
+'
+#
+# A --C------ <-- origin/stable
+# \ | \
+# B -- D -- E -- F <-- origin/topic2
+# \| \
+# g -- h ------- i <-- topic2
+#
+# Trying to push F..i
+#
+# merge-base(F, h) has two options: B and C
+#
+test_expect_success 'merging in stable with tricky double baserev does not fool the script' '
+ # B: start our topic2 branch, and share it
+ git checkout -b topic2 origin/stable &&
+ git config --add branch.topic2.merge refs/heads/topic2 &&
+ echo "commit B" >a.topic2 &&
+ git add a.topic2 &&
+ git commit -m "commit B created topic2" &&
+ git push origin topic2 &&
+
+ # C: now, separately, move ahead stable, and share it
+ git checkout stable
+ echo "commit C" >a &&
+ git commit -a -m "commit C moved stable" &&
+ git push origin stable &&
+
+ # D: have another client commit (in this case, it is the server, but close enough) moves topic2
+ cd server &&
+ git checkout topic2 &&
+ echo "commit D continuing topic2" >a.client2 &&
+ git add a.client2 &&
+ git commit -m "commit D by client2" &&
+
+ # E: the same other client merges the moved stable
+ git merge stable &&
+
+ # F: the same other client moves topic2 again
+ echo "commit F" >a.client2 &&
+ git commit -a -m "commit F by client2" &&
+ F_hash=$(git rev-parse HEAD) &&
+ cd .. &&
+
+ # g: now locally merge in the moved stable (even though our topic2 is out of date)
+ git checkout topic2 &&
+ git merge stable &&
+ g_hash=$(git rev-parse HEAD) &&
+
+ # h: advance local topic2
+ echo "commit H" >a.topic2 &&
+ git commit -a -m "commit H continues local fork" &&
+ h_hash=$(git rev-parse HEAD) &&
+
+ # i: make a new merge commit
+ git pull --no-rebase &&
+ i_hash=$(git rev-parse HEAD) &&
+
+ # Watch merge rejected as something that should get rebased
+ # ! git push origin topic2
+ test "$i_hash $h_hash $F_hash" = "$(git rev-list --parents --no-walk HEAD)"
+
+ # Now fix it the merge by rebasing it
+ git reset --hard ORIG_HEAD &&
+ GIT_EDITOR=: git rebase -i -p origin/topic2 &&
+ h2_hash=$(git rev-parse HEAD) &&
+
+ # Previously $F_hash was dropped and it was the same $h_hash $g_hash
+ test "$h2_hash $F_hash" = "$(git rev-list --parents --no-walk HEAD)"
+'
+
+test_done
+
+
--
1.6.0.2
^ permalink raw reply related
* [PATCH 3/3] parse-opt: migrate builtin-merge-file.
From: Pierre Habouzit @ 2008-10-01 6:05 UTC (permalink / raw)
To: spearce; +Cc: git, gitster, Pierre Habouzit
In-Reply-To: <1222841106-26148-2-git-send-email-madcoder@debian.org>
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
---
builtin-merge-file.c | 68 +++++++++++++++++++++++++++----------------------
1 files changed, 37 insertions(+), 31 deletions(-)
diff --git a/builtin-merge-file.c b/builtin-merge-file.c
index 45c9853..7736fe8 100644
--- a/builtin-merge-file.c
+++ b/builtin-merge-file.c
@@ -2,21 +2,44 @@
#include "cache.h"
#include "xdiff/xdiff.h"
#include "xdiff-interface.h"
+#include "parse-options.h"
-static const char merge_file_usage[] =
-"git merge-file [-p | --stdout] [--diff3] [-q | --quiet] [-L name1 [-L orig [-L name2]]] file1 orig_file file2";
+static const char *const merge_file_usage[] = {
+ "git merge-file [options] [-L name1 [-L orig [-L name2]]] file1 orig_file file2",
+ NULL
+};
+
+static int label_cb(const struct option *opt, const char *arg, int unset)
+{
+ static int label_count = 0;
+ const char **names = (const char **)opt->value;
+
+ if (label_count >= 3)
+ return error("too many labels on the command like");
+ names[label_count++] = arg;
+ return 0;
+}
int cmd_merge_file(int argc, const char **argv, const char *prefix)
{
- const char *names[3];
+ const char *names[3] = { NULL, NULL, NULL };
mmfile_t mmfs[3];
mmbuffer_t result = {NULL, 0};
xpparam_t xpp = {XDF_NEED_MINIMAL};
int ret = 0, i = 0, to_stdout = 0;
int merge_level = XDL_MERGE_ZEALOUS_ALNUM;
- int merge_style = 0;
+ int merge_style = 0, quiet = 0;
int nongit;
+ struct option options[] = {
+ OPT_BOOLEAN('p', "stdout", &to_stdout, "send results to standard output"),
+ OPT_SET_INT(0, "diff3", &merge_style, "use a diff3 based merge", XDL_MERGE_DIFF3),
+ OPT__QUIET(&quiet),
+ OPT_CALLBACK('L', NULL, names, "name",
+ "set labels for file1/orig_file/file2", &label_cb),
+ OPT_END(),
+ };
+
prefix = setup_git_directory_gently(&nongit);
if (!nongit) {
/* Read the configuration file */
@@ -25,37 +48,20 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
merge_style = git_xmerge_style;
}
- while (argc > 4) {
- if (!strcmp(argv[1], "-L") && i < 3) {
- names[i++] = argv[2];
- argc--;
- argv++;
- } else if (!strcmp(argv[1], "-p") ||
- !strcmp(argv[1], "--stdout"))
- to_stdout = 1;
- else if (!strcmp(argv[1], "-q") ||
- !strcmp(argv[1], "--quiet"))
- freopen("/dev/null", "w", stderr);
- else if (!strcmp(argv[1], "--diff3"))
- merge_style = XDL_MERGE_DIFF3;
- else
- usage(merge_file_usage);
- argc--;
- argv++;
- }
-
- if (argc != 4)
- usage(merge_file_usage);
-
- for (; i < 3; i++)
- names[i] = argv[i + 1];
+ argc = parse_options(argc, argv, options, merge_file_usage, 0);
+ if (argc != 3)
+ usage_with_options(merge_file_usage, options);
+ if (quiet)
+ freopen("/dev/null", "w", stderr);
for (i = 0; i < 3; i++) {
- if (read_mmfile(mmfs + i, argv[i + 1]))
+ if (!names[i])
+ names[i] = argv[i];
+ if (read_mmfile(mmfs + i, argv[i]))
return -1;
if (buffer_is_binary(mmfs[i].ptr, mmfs[i].size))
return error("Cannot merge binary files: %s\n",
- argv[i + 1]);
+ argv[i]);
}
ret = xdl_merge(mmfs + 1, mmfs + 0, names[0], mmfs + 2, names[2],
@@ -65,7 +71,7 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
free(mmfs[i].ptr);
if (ret >= 0) {
- const char *filename = argv[1];
+ const char *filename = argv[0];
FILE *f = to_stdout ? stdout : fopen(filename, "wb");
if (!f)
--
1.6.0.2.415.g9800c0.dirty
^ permalink raw reply related
* [PATCH 1/3] parse-opt: migrate fmt-merge-msg.
From: Pierre Habouzit @ 2008-10-01 6:05 UTC (permalink / raw)
To: spearce; +Cc: git, gitster, Pierre Habouzit
In-Reply-To: <20080930224623.GQ21310@spearce.org>
Also fix an inefficient printf("%s", ...) where we can use write_in_full.
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
---
builtin-fmt-merge-msg.c | 52 +++++++++++++++++++++-------------------------
1 files changed, 24 insertions(+), 28 deletions(-)
> It may actually be a good idea to rebase this against master.
>
> Reading Junio's notes for sg/merge-options (the branch this conflict
> is coming out of) it sounds like we'd want to revert that anyway.
> Its been around since April and Junio was talking about it needing
> to be in a 1.7.0 release. Its not going to graduate anytime soon.
Fair enough, here it is.
diff --git a/builtin-fmt-merge-msg.c b/builtin-fmt-merge-msg.c
index df02ba7..78c04bf 100644
--- a/builtin-fmt-merge-msg.c
+++ b/builtin-fmt-merge-msg.c
@@ -5,8 +5,10 @@
#include "revision.h"
#include "tag.h"
-static const char *fmt_merge_msg_usage =
- "git fmt-merge-msg [--log] [--no-log] [--file <file>]";
+static const char * const fmt_merge_msg_usage[] = {
+ "git fmt-merge-msg [--log|--no-log] [--file <file>]",
+ NULL
+};
static int merge_summary;
@@ -347,38 +349,32 @@ int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) {
int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
{
+ const char *inpath = NULL;
+ struct option options[] = {
+ OPT_BOOLEAN(0, "log", &merge_summary, "populate log with the shortlog"),
+ OPT_BOOLEAN(0, "summary", &merge_summary, "alias for --log"),
+ OPT_STRING('F', "file", &inpath, "file", "file to read from"),
+ OPT_END()
+ };
+
FILE *in = stdin;
struct strbuf input, output;
int ret;
git_config(fmt_merge_msg_config, NULL);
-
- while (argc > 1) {
- if (!strcmp(argv[1], "--log") || !strcmp(argv[1], "--summary"))
- merge_summary = 1;
- else if (!strcmp(argv[1], "--no-log")
- || !strcmp(argv[1], "--no-summary"))
- merge_summary = 0;
- else if (!strcmp(argv[1], "-F") || !strcmp(argv[1], "--file")) {
- if (argc < 3)
- die ("Which file?");
- if (!strcmp(argv[2], "-"))
- in = stdin;
- else {
- fclose(in);
- in = fopen(argv[2], "r");
- if (!in)
- die("cannot open %s", argv[2]);
- }
- argc--; argv++;
- } else
- break;
- argc--; argv++;
+ argc = parse_options(argc, argv, options, fmt_merge_msg_usage, 0);
+ if (argc > 0)
+ usage_with_options(fmt_merge_msg_usage, options);
+
+ if (!inpath || strcmp(inpath, "-"))
+ in = stdin;
+ else {
+ fclose(in);
+ in = fopen(argv[2], "r");
+ if (!in)
+ die("cannot open %s", argv[2]);
}
- if (argc > 1)
- usage(fmt_merge_msg_usage);
-
strbuf_init(&input, 0);
if (strbuf_read(&input, fileno(in), 0) < 0)
die("could not read input file %s", strerror(errno));
@@ -387,6 +383,6 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
ret = fmt_merge_msg(merge_summary, &input, &output);
if (ret)
return ret;
- printf("%s", output.buf);
+ write_in_full(STDOUT_FILENO, output.buf, output.len);
return 0;
}
--
1.6.0.2.415.g9800c0.dirty
^ permalink raw reply related
* [PATCH 2/3] parse-opt: migrate git-merge-base.
From: Pierre Habouzit @ 2008-10-01 6:05 UTC (permalink / raw)
To: spearce; +Cc: git, gitster, Pierre Habouzit
In-Reply-To: <1222841106-26148-1-git-send-email-madcoder@debian.org>
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
---
builtin-merge-base.c | 37 ++++++++++++++++---------------------
1 files changed, 16 insertions(+), 21 deletions(-)
diff --git a/builtin-merge-base.c b/builtin-merge-base.c
index b08da51..03fc1c2 100644
--- a/builtin-merge-base.c
+++ b/builtin-merge-base.c
@@ -1,6 +1,7 @@
#include "builtin.h"
#include "cache.h"
#include "commit.h"
+#include "parse-options.h"
static int show_merge_base(struct commit **rev, int rev_nr, int show_all)
{
@@ -21,8 +22,10 @@ static int show_merge_base(struct commit **rev, int rev_nr, int show_all)
return 0;
}
-static const char merge_base_usage[] =
-"git merge-base [--all] <commit-id> <commit-id>...";
+static const char * const merge_base_usage[] = {
+ "git merge-base [--all] <commit-id> <commit-id>...",
+ NULL
+};
static struct commit *get_commit_reference(const char *arg)
{
@@ -44,25 +47,17 @@ int cmd_merge_base(int argc, const char **argv, const char *prefix)
int rev_nr = 0;
int show_all = 0;
- git_config(git_default_config, NULL);
-
- while (1 < argc && argv[1][0] == '-') {
- const char *arg = argv[1];
- if (!strcmp(arg, "-a") || !strcmp(arg, "--all"))
- show_all = 1;
- else
- usage(merge_base_usage);
- argc--; argv++;
- }
- if (argc < 3)
- usage(merge_base_usage);
-
- rev = xmalloc((argc - 1) * sizeof(*rev));
-
- do {
- rev[rev_nr++] = get_commit_reference(argv[1]);
- argc--; argv++;
- } while (argc > 1);
+ struct option options[] = {
+ OPT_BOOLEAN('a', "all", &show_all, "outputs all common ancestors"),
+ OPT_END()
+ };
+ git_config(git_default_config, NULL);
+ argc = parse_options(argc, argv, options, merge_base_usage, 0);
+ if (argc < 2)
+ usage_with_options(merge_base_usage, options);
+ rev = xmalloc(argc * sizeof(*rev));
+ while (argc-- > 0)
+ rev[rev_nr++] = get_commit_reference(*argv++);
return show_merge_base(rev, rev_nr, show_all);
}
--
1.6.0.2.415.g9800c0.dirty
^ permalink raw reply related
* Re: interactive rebase not rebasing
From: Stephen Haberman @ 2008-10-01 6:03 UTC (permalink / raw)
To: Andreas Ericsson; +Cc: git
In-Reply-To: <48E078BF.5030806@op5.se>
> > # A --C------ <-- origin/stable
> > # \ | \
> > # B -- D -- E -- F <-- origin/topic2
> > # \|
> > # g -- h <-- topic2
> >
> > Nothing has changed. g & h haven't moved...I can keep executing this
> > operation and the commits never make it on top of origin/topic2's F.
> >
> > Frustratingly, if I run non-interactive rebase, it works perfectly.
>
> I can imagine. Since you don't want to preserve the merges in this
> case, you shouldn't be using the -p flag.
No, I do want to preserve most merges. This "most" qualification is
because the merge "g", if rebased, would have been a no-op, so `rebase
-i -p` correctly kept it out of the TODO file.
Which is cool, except that later on, when rewriting the other TODO
commits, some of which were children of "g", it did not remember that
"g" had gone away, so did nothing to take "g" out of the rewritten
children's parent list.
> In fact, for this particular scenario (assuming "h" is really the only
> commit on topic2), you probably want to just cherry-pick that commit
> into origin/topic2:
>
> git checkout topic2
> git reset --hard origin/topic2
> git cherry-pick ORIG_HEAD
Agreed. This makes a lot of sense for me, who has been hacking around in
git-rebase--interactive fixing things, but I'd really like the other
people on my team to just have to run `git rebase -i -p`.
> I don't think you can have a single command that does all the things
> you want, because the possible differences in input makes it very
> nearly impossible to always do "the right thing".
Ah, you are too pessimistic. :-)
> Assuming you're passing a correct input file to rebase -i; yes. At the
> very least, "h" should be moved to the tip of origin/topic2.
Cool, agreed. I've got a patch that gets `rebase -i -p` to do this. I'll
send it to the list soon.
- Stephen
^ permalink raw reply
* [PATCH 9/9] grep: skip files outside sparse checkout area
From: Nguyễn Thái Ngọc Duy @ 2008-10-01 4:04 UTC (permalink / raw)
To: git, Shawn O. Pearce; +Cc: Nguyễn Thái Ngọc Duy
In-Reply-To: <1222833849-22129-9-git-send-email-pclouds@gmail.com>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
Documentation/git-grep.txt | 4 +++-
builtin-grep.c | 7 ++++++-
2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt
index fa4d133..ee359c9 100644
--- a/Documentation/git-grep.txt
+++ b/Documentation/git-grep.txt
@@ -24,7 +24,9 @@ SYNOPSIS
DESCRIPTION
-----------
Look for specified patterns in the working tree files, blobs
-registered in the index file, or given tree objects.
+registered in the index file, or given tree objects. By default
+it will search in the working tree files. When in sparse checkout
+mode, it only searches checked-out files.
OPTIONS
diff --git a/builtin-grep.c b/builtin-grep.c
index 3a51662..d5507d7 100644
--- a/builtin-grep.c
+++ b/builtin-grep.c
@@ -343,6 +343,8 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached)
continue;
if (!pathspec_matches(paths, ce->name))
continue;
+ if (ce_no_checkout(ce))
+ continue;
name = ce->name;
if (name[0] == '-') {
int len = ce_namelen(ce);
@@ -404,8 +406,11 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached)
continue;
hit |= grep_sha1(opt, ce->sha1, ce->name, 0);
}
- else
+ else {
+ if (ce_no_checkout(ce))
+ continue;
hit |= grep_file(opt, ce->name);
+ }
if (ce_stage(ce)) {
do {
nr++;
--
1.6.0.2.488.gf604a
^ permalink raw reply related
* [PATCH 8/9] checkout_entry(): CE_NO_CHECKOUT on checked out entries.
From: Nguyễn Thái Ngọc Duy @ 2008-10-01 4:04 UTC (permalink / raw)
To: git, Shawn O. Pearce; +Cc: Nguyễn Thái Ngọc Duy
In-Reply-To: <1222833849-22129-8-git-send-email-pclouds@gmail.com>
With this you can just do "git checkout some-files" to
widen your checkout. One caveat though: caller must save
the index.
For all of its callers (unpack_trees(), checkout-index, checkout
and apply), only "git apply" does not write index back.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
entry.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/entry.c b/entry.c
index aa2ee46..305f8d3 100644
--- a/entry.c
+++ b/entry.c
@@ -230,5 +230,6 @@ int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *t
} else if (state->not_new)
return 0;
create_directories(path, state);
+ ce_mark_checkout(ce);
return write_entry(ce, path, state, 0);
}
--
1.6.0.2.488.gf604a
^ permalink raw reply related
* [PATCH 7/9] Prevent diff machinery from examining worktree outside sparse checkout
From: Nguyễn Thái Ngọc Duy @ 2008-10-01 4:04 UTC (permalink / raw)
To: git, Shawn O. Pearce; +Cc: Nguyễn Thái Ngọc Duy
In-Reply-To: <1222833849-22129-7-git-send-email-pclouds@gmail.com>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
diff-lib.c | 5 +++--
diff.c | 4 +++-
2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/diff-lib.c b/diff-lib.c
index ae96c64..992280b 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -161,7 +161,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
continue;
}
- if (ce_uptodate(ce))
+ if (ce_uptodate(ce) || ce_no_checkout(ce))
continue;
changed = check_removed(ce, &st);
@@ -348,6 +348,8 @@ static void do_oneway_diff(struct unpack_trees_options *o,
struct rev_info *revs = cbdata->revs;
int match_missing, cached;
+ /* if the entry is not checked out, don't examine work tree */
+ cached = o->index_only || (idx && ce_no_checkout(idx));
/*
* Backward compatibility wart - "diff-index -m" does
* not mean "do not ignore merges", but "match_missing".
@@ -355,7 +357,6 @@ static void do_oneway_diff(struct unpack_trees_options *o,
* But with the revision flag parsing, that's found in
* "!revs->ignore_merges".
*/
- cached = o->index_only;
match_missing = !revs->ignore_merges;
if (cached && idx && ce_stage(idx)) {
diff --git a/diff.c b/diff.c
index b001d7b..c001e2c 100644
--- a/diff.c
+++ b/diff.c
@@ -1798,8 +1798,10 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int
/*
* If ce matches the file in the work tree, we can reuse it.
+ * For sparse checkout case, ce_uptodate() may be true although
+ * the file may or may not exist in the work tree.
*/
- if (ce_uptodate(ce) ||
+ if ((ce_uptodate(ce) && ce_checkout(ce)) ||
(!lstat(name, &st) && !ce_match_stat(ce, &st, 0)))
return 1;
--
1.6.0.2.488.gf604a
^ permalink raw reply related
* [PATCH 6/9] ls-files: Add tests for --sparse and friends
From: Nguyễn Thái Ngọc Duy @ 2008-10-01 4:04 UTC (permalink / raw)
To: git, Shawn O. Pearce; +Cc: Nguyễn Thái Ngọc Duy
In-Reply-To: <1222833849-22129-6-git-send-email-pclouds@gmail.com>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
t/t3004-ls-files-sparse.sh | 40 +++++++++++++++++++++++++++++++++
t/t3004/cached.expected | 5 ++++
t/t3004/deleted.expected | 1 +
t/t3004/everything.expected | 10 ++++++++
t/t3004/modified.expected | 2 +
t/t3004/no-checkout.expected | 2 +
t/t3004/orphaned-no-checkout.expected | 3 ++
t/t3004/orphaned.expected | 1 +
t/t3004/others.expected | 2 +
t/t3004/sparse-cached.expected | 3 ++
t/t3004/sparse-everything.expected | 11 +++++++++
11 files changed, 80 insertions(+), 0 deletions(-)
create mode 100755 t/t3004-ls-files-sparse.sh
create mode 100644 t/t3004/cached.expected
create mode 100644 t/t3004/deleted.expected
create mode 100644 t/t3004/everything.expected
create mode 100644 t/t3004/modified.expected
create mode 100644 t/t3004/no-checkout.expected
create mode 100644 t/t3004/orphaned-no-checkout.expected
create mode 100644 t/t3004/orphaned.expected
create mode 100644 t/t3004/others.expected
create mode 100644 t/t3004/sparse-cached.expected
create mode 100644 t/t3004/sparse-everything.expected
diff --git a/t/t3004-ls-files-sparse.sh b/t/t3004-ls-files-sparse.sh
new file mode 100755
index 0000000..ec2c869
--- /dev/null
+++ b/t/t3004-ls-files-sparse.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+test_description="test ls-files in --sparse mode"
+
+. test-lib.sh
+
+test_ls_files() {
+ T=../t3004/$1.expected
+ shift
+ test_expect_success "ls-files $*" "git ls-files $* > result && test_cmp $T result"
+}
+
+test_expect_success 'setup' '
+ touch other orphaned no-checkout cached modified deleted &&
+ git add orphaned no-checkout cached modified deleted &&
+ git update-index --no-checkout orphaned no-checkout &&
+ echo modified >> modified &&
+ rm no-checkout deleted
+'
+
+test_ls_files cached
+test_ls_files cached --cached
+test_ls_files sparse-cached --sparse
+test_ls_files sparse-cached --sparse --cached
+test_ls_files no-checkout --no-checkout
+test_ls_files no-checkout --sparse --no-checkout
+test_ls_files orphaned --orphaned
+test_ls_files orphaned --sparse --orphaned
+test_ls_files orphaned-no-checkout -v --no-checkout --orphaned
+test_ls_files orphaned-no-checkout -v --sparse --no-checkout --orphaned
+test_ls_files deleted --deleted
+test_ls_files deleted --sparse --deleted
+test_ls_files modified --modified
+test_ls_files modified --sparse --modified
+test_ls_files others --others
+test_ls_files others --sparse --others
+test_ls_files everything -v --cached --deleted --modified --others
+test_ls_files sparse-everything -v --cached --no-checkout --orphaned --deleted --modified --others
+
+test_done
\ No newline at end of file
diff --git a/t/t3004/cached.expected b/t/t3004/cached.expected
new file mode 100644
index 0000000..6fd0c78
--- /dev/null
+++ b/t/t3004/cached.expected
@@ -0,0 +1,5 @@
+cached
+deleted
+modified
+no-checkout
+orphaned
diff --git a/t/t3004/deleted.expected b/t/t3004/deleted.expected
new file mode 100644
index 0000000..71779d2
--- /dev/null
+++ b/t/t3004/deleted.expected
@@ -0,0 +1 @@
+deleted
diff --git a/t/t3004/everything.expected b/t/t3004/everything.expected
new file mode 100644
index 0000000..6000328
--- /dev/null
+++ b/t/t3004/everything.expected
@@ -0,0 +1,10 @@
+? other
+? result
+H cached
+H deleted
+H modified
+H no-checkout
+H orphaned
+R deleted
+C deleted
+C modified
diff --git a/t/t3004/modified.expected b/t/t3004/modified.expected
new file mode 100644
index 0000000..644a96e
--- /dev/null
+++ b/t/t3004/modified.expected
@@ -0,0 +1,2 @@
+deleted
+modified
diff --git a/t/t3004/no-checkout.expected b/t/t3004/no-checkout.expected
new file mode 100644
index 0000000..b2a429f
--- /dev/null
+++ b/t/t3004/no-checkout.expected
@@ -0,0 +1,2 @@
+no-checkout
+orphaned
diff --git a/t/t3004/orphaned-no-checkout.expected b/t/t3004/orphaned-no-checkout.expected
new file mode 100644
index 0000000..d687ef0
--- /dev/null
+++ b/t/t3004/orphaned-no-checkout.expected
@@ -0,0 +1,3 @@
+- no-checkout
+- orphaned
+O orphaned
diff --git a/t/t3004/orphaned.expected b/t/t3004/orphaned.expected
new file mode 100644
index 0000000..571b267
--- /dev/null
+++ b/t/t3004/orphaned.expected
@@ -0,0 +1 @@
+orphaned
diff --git a/t/t3004/others.expected b/t/t3004/others.expected
new file mode 100644
index 0000000..bf5bf2b
--- /dev/null
+++ b/t/t3004/others.expected
@@ -0,0 +1,2 @@
+other
+result
diff --git a/t/t3004/sparse-cached.expected b/t/t3004/sparse-cached.expected
new file mode 100644
index 0000000..3453483
--- /dev/null
+++ b/t/t3004/sparse-cached.expected
@@ -0,0 +1,3 @@
+cached
+deleted
+modified
diff --git a/t/t3004/sparse-everything.expected b/t/t3004/sparse-everything.expected
new file mode 100644
index 0000000..5df0599
--- /dev/null
+++ b/t/t3004/sparse-everything.expected
@@ -0,0 +1,11 @@
+? other
+? result
+H cached
+H deleted
+H modified
+- no-checkout
+- orphaned
+O orphaned
+R deleted
+C deleted
+C modified
--
1.6.0.2.488.gf604a
^ permalink raw reply related
* [PATCH 5/9] update-index: add --checkout/--no-checkout to update CE_NO_CHECKOUT bit
From: Nguyễn Thái Ngọc Duy @ 2008-10-01 4:04 UTC (permalink / raw)
To: git, Shawn O. Pearce; +Cc: Nguyễn Thái Ngọc Duy
In-Reply-To: <1222833849-22129-5-git-send-email-pclouds@gmail.com>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
.gitignore | 1 +
Documentation/git-checkout.txt | 3 +-
Documentation/git-update-index.txt | 13 ++++++++++++
Makefile | 2 +-
builtin-update-index.c | 16 ++++++++++++++-
t/t2104-update-index-no-checkout.sh | 36 +++++++++++++++++++++++++++++++++++
test-index-version.c | 14 +++++++++++++
7 files changed, 82 insertions(+), 3 deletions(-)
create mode 100755 t/t2104-update-index-no-checkout.sh
create mode 100644 test-index-version.c
diff --git a/.gitignore b/.gitignore
index bbaf9de..0c35577 100644
--- a/.gitignore
+++ b/.gitignore
@@ -147,6 +147,7 @@ test-date
test-delta
test-dump-cache-tree
test-genrandom
+test-index-version
test-match-trees
test-parse-options
test-path-utils
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index 4bd9eba..2b344e1 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -196,7 +196,8 @@ to index, it will be marked "checkout" unless sparse patterns are
applied. Unmerged files are always "checkout". When you checkout new
files using "git checkout <file>" they will be automatically marked
"checkout". Other commands such as "git apply" can also checkout new
-files if they are needed.
+files if they are needed. linkgit:git-update-index[1] can be used to
+update "checkout/no-checkout" status in index.
"No-checkout" status is very similar to "assume-unchanged bit"
(see linkgit:git-update-index[1]). The main difference between them
diff --git a/Documentation/git-update-index.txt b/Documentation/git-update-index.txt
index 1d9d81a..ec03e05 100644
--- a/Documentation/git-update-index.txt
+++ b/Documentation/git-update-index.txt
@@ -15,6 +15,7 @@ SYNOPSIS
[--cacheinfo <mode> <object> <file>]\*
[--chmod=(+|-)x]
[--assume-unchanged | --no-assume-unchanged]
+ [--checkout | --no-checkout]
[--ignore-submodules]
[--really-refresh] [--unresolve] [--again | -g]
[--info-only] [--index-info]
@@ -99,6 +100,18 @@ in the index e.g. when merging in a commit;
thus, in case the assumed-untracked file is changed upstream,
you will need to handle the situation manually.
+--checkout::
+--no-checkout::
+ When one of these flags is specified, the object name recorded
+ for the paths are not updated. Instead, these options
+ set and unset the "no-checkout" bit for the paths. This
+ bit is used for marking files for sparse checkout. If
+ a path is marked "no-checkout", then it should not be
+ checked out unless requested by user or needed for a git
+ command to function.
+ See linkgit:git-checkout[1] for more information about
+ sparse checkout.
+
-g::
--again::
Runs 'git-update-index' itself on the paths whose index
diff --git a/Makefile b/Makefile
index e0c03c3..edb33cb 100644
--- a/Makefile
+++ b/Makefile
@@ -1327,7 +1327,7 @@ endif
### Testing rules
-TEST_PROGRAMS = test-chmtime$X test-genrandom$X test-date$X test-delta$X test-sha1$X test-match-trees$X test-parse-options$X test-path-utils$X
+TEST_PROGRAMS = test-chmtime$X test-genrandom$X test-date$X test-delta$X test-sha1$X test-match-trees$X test-parse-options$X test-path-utils$X test-index-version$X
all:: $(TEST_PROGRAMS)
diff --git a/builtin-update-index.c b/builtin-update-index.c
index ae94739..7514aff 100644
--- a/builtin-update-index.c
+++ b/builtin-update-index.c
@@ -24,6 +24,7 @@ static int info_only;
static int force_remove;
static int verbose;
static int mark_valid_only;
+static int mark_no_checkout_only;
#define MARK_FLAG 1
#define UNMARK_FLAG 2
@@ -276,6 +277,11 @@ static void update_one(const char *path, const char *prefix, int prefix_length)
die("Unable to mark file %s", path);
goto free_return;
}
+ if (mark_no_checkout_only) {
+ if (mark_ce_flags(p, CE_NO_CHECKOUT, mark_no_checkout_only == MARK_FLAG))
+ die("Unable to mark file %s", path);
+ goto free_return;
+ }
if (force_remove) {
if (remove_file_from_cache(p))
@@ -386,7 +392,7 @@ static void read_index_info(int line_termination)
}
static const char update_index_usage[] =
-"git update-index [-q] [--add] [--replace] [--remove] [--unmerged] [--refresh] [--really-refresh] [--cacheinfo] [--chmod=(+|-)x] [--assume-unchanged] [--info-only] [--force-remove] [--stdin] [--index-info] [--unresolve] [--again | -g] [--ignore-missing] [-z] [--verbose] [--] <file>...";
+"git update-index [-q] [--add] [--replace] [--remove] [--unmerged] [--refresh] [--really-refresh] [--cacheinfo] [--chmod=(+|-)x] [--assume-unchanged] [--checkout|--no-checkout] [--info-only] [--force-remove] [--stdin] [--index-info] [--unresolve] [--again | -g] [--ignore-missing] [-z] [--verbose] [--] <file>...";
static unsigned char head_sha1[20];
static unsigned char merge_head_sha1[20];
@@ -652,6 +658,14 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
mark_valid_only = UNMARK_FLAG;
continue;
}
+ if (!strcmp(path, "--checkout")) {
+ mark_no_checkout_only = UNMARK_FLAG;
+ continue;
+ }
+ if (!strcmp(path, "--no-checkout")) {
+ mark_no_checkout_only = MARK_FLAG;
+ continue;
+ }
if (!strcmp(path, "--info-only")) {
info_only = 1;
continue;
diff --git a/t/t2104-update-index-no-checkout.sh b/t/t2104-update-index-no-checkout.sh
new file mode 100755
index 0000000..be9f913
--- /dev/null
+++ b/t/t2104-update-index-no-checkout.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+#
+# Copyright (c) 2008 Nguyễn Thái Ngọc Duy
+#
+
+test_description='git update-index no-checkout bits (a.k.a sparse checkout)'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+ mkdir sub &&
+ touch 1 2 sub/1 sub/2 &&
+ git add 1 2 sub/1 sub/2
+'
+
+test_expect_success 'index is at version 2' '
+ test "$(test-index-version < .git/index)" = 2
+'
+
+test_expect_success 'update-index --no-checkout' '
+ git update-index --no-checkout 1 sub/1 &&
+ test -z "$(git ls-files --sparse|grep 1)"'
+
+test_expect_success 'index is at version 3 after having some no-checkout entries' '
+ test "$(test-index-version < .git/index)" = 3
+'
+
+test_expect_success 'update-index --checkout' '
+ git update-index --checkout 1 sub/1 &&
+ test "$(git ls-files)" = "$(git ls-files --sparse)"'
+
+test_expect_success 'index version is back to 2 when there is no no-checkout entry' '
+ test "$(test-index-version < .git/index)" = 2
+'
+
+test_done
diff --git a/test-index-version.c b/test-index-version.c
new file mode 100644
index 0000000..bfaad9e
--- /dev/null
+++ b/test-index-version.c
@@ -0,0 +1,14 @@
+#include "cache.h"
+
+int main(int argc, const char **argv)
+{
+ struct cache_header hdr;
+ int version;
+
+ memset(&hdr,0,sizeof(hdr));
+ if (read(0, &hdr, sizeof(hdr)) != sizeof(hdr))
+ return 0;
+ version = ntohl(hdr.hdr_version);
+ printf("%d\n", version);
+ return 0;
+}
--
1.6.0.2.488.gf604a
^ permalink raw reply related
* [PATCH 4/9] update-index: refactor mark_valid() in preparation for new options
From: Nguyễn Thái Ngọc Duy @ 2008-10-01 4:04 UTC (permalink / raw)
To: git, Shawn O. Pearce; +Cc: Nguyễn Thái Ngọc Duy
In-Reply-To: <1222833849-22129-4-git-send-email-pclouds@gmail.com>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
builtin-update-index.c | 24 ++++++++++--------------
1 files changed, 10 insertions(+), 14 deletions(-)
diff --git a/builtin-update-index.c b/builtin-update-index.c
index 417f972..ae94739 100644
--- a/builtin-update-index.c
+++ b/builtin-update-index.c
@@ -24,8 +24,8 @@ static int info_only;
static int force_remove;
static int verbose;
static int mark_valid_only;
-#define MARK_VALID 1
-#define UNMARK_VALID 2
+#define MARK_FLAG 1
+#define UNMARK_FLAG 2
static void report(const char *fmt, ...)
{
@@ -40,19 +40,15 @@ static void report(const char *fmt, ...)
va_end(vp);
}
-static int mark_valid(const char *path)
+static int mark_ce_flags(const char *path, int flag, int mark)
{
int namelen = strlen(path);
int pos = cache_name_pos(path, namelen);
if (0 <= pos) {
- switch (mark_valid_only) {
- case MARK_VALID:
- active_cache[pos]->ce_flags |= CE_VALID;
- break;
- case UNMARK_VALID:
- active_cache[pos]->ce_flags &= ~CE_VALID;
- break;
- }
+ if (mark)
+ active_cache[pos]->ce_flags |= flag;
+ else
+ active_cache[pos]->ce_flags &= ~flag;
cache_tree_invalidate_path(active_cache_tree, path);
active_cache_changed = 1;
return 0;
@@ -276,7 +272,7 @@ static void update_one(const char *path, const char *prefix, int prefix_length)
goto free_return;
}
if (mark_valid_only) {
- if (mark_valid(p))
+ if (mark_ce_flags(p, CE_VALID, mark_valid_only == MARK_FLAG))
die("Unable to mark file %s", path);
goto free_return;
}
@@ -649,11 +645,11 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
continue;
}
if (!strcmp(path, "--assume-unchanged")) {
- mark_valid_only = MARK_VALID;
+ mark_valid_only = MARK_FLAG;
continue;
}
if (!strcmp(path, "--no-assume-unchanged")) {
- mark_valid_only = UNMARK_VALID;
+ mark_valid_only = UNMARK_FLAG;
continue;
}
if (!strcmp(path, "--info-only")) {
--
1.6.0.2.488.gf604a
^ permalink raw reply related
* [PATCH 3/9] ls-files: add options to support sparse checkout
From: Nguyễn Thái Ngọc Duy @ 2008-10-01 4:04 UTC (permalink / raw)
To: git, Shawn O. Pearce; +Cc: Nguyễn Thái Ngọc Duy
In-Reply-To: <1222833849-22129-3-git-send-email-pclouds@gmail.com>
The first option to be introduced is --sparse, which puts ls-files
in "sparse mode". In this mode, cached entries are divided into
- checkout entries: shown by --cached (new behavior with --sparse)
- no-checkout entries: show by --no-checkout (new option)
- orphaned entries: shown by --orphaned (new option)
Orphaned entries are themselves no-checkout ones but for some reasons
still be present in working directory.
While at it, fix "--deleted" running out of checkout area.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
Documentation/git-ls-files.txt | 24 +++++++++++++++++++++-
builtin-ls-files.c | 41 ++++++++++++++++++++++++++++++++++++---
2 files changed, 59 insertions(+), 6 deletions(-)
diff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt
index 9f85d60..1de68e2 100644
--- a/Documentation/git-ls-files.txt
+++ b/Documentation/git-ls-files.txt
@@ -10,8 +10,9 @@ SYNOPSIS
--------
[verse]
'git ls-files' [-z] [-t] [-v]
- (--[cached|deleted|others|ignored|stage|unmerged|killed|modified])\*
+ (--[cached|deleted|others|ignored|stage|unmerged|killed|modified|orphaned|no-checkout])\*
(-[c|d|o|i|s|u|k|m])\*
+ [--sparse]
[-x <pattern>|--exclude=<pattern>]
[-X <file>|--exclude-from=<file>]
[--exclude-per-directory=<file>]
@@ -32,7 +33,9 @@ OPTIONS
-------
-c::
--cached::
- Show cached files in the output (default)
+ Show cached files in the output (default). When used with --sparse,
+ show only cached files that are marked "checkout", no-checkout
+ entries will be excluded.
-d::
--deleted::
@@ -72,6 +75,21 @@ OPTIONS
to file/directory conflicts for checkout-index to
succeed.
+--no-checkout::
+ Show no-checkout entries. This option implies --sparse.
+
+--orphaned::
+ Show orphaned entries. Orphaned entries are no-checkout
+ entries that are present in working directory. This option
+ implies --sparse.
+
+--sparse::
+ When --sparse is passed, cached files will be divided into two
+ parts: checkout entries and no-checkout entries.
+ --cached will only show checkout entries.
+ No-checkout entries can be shown using --orphaned or
+ --no-checkout (or both).
+
-z::
\0 line termination on output.
@@ -107,6 +125,8 @@ OPTIONS
Identify the file status with the following tags (followed by
a space) at the start of each line:
H:: cached
+ -:: no-checkout entries
+ O:: orphaned entries
M:: unmerged
R:: removed/deleted
C:: modified/changed
diff --git a/builtin-ls-files.c b/builtin-ls-files.c
index 068f424..873de15 100644
--- a/builtin-ls-files.c
+++ b/builtin-ls-files.c
@@ -20,6 +20,9 @@ static int show_unmerged;
static int show_modified;
static int show_killed;
static int show_valid_bit;
+static int show_orphaned;
+static int show_no_checkout;
+static int sparse_checkout;
static int line_terminator = '\n';
static int prefix_len;
@@ -35,6 +38,8 @@ static const char *tag_removed = "";
static const char *tag_other = "";
static const char *tag_killed = "";
static const char *tag_modified = "";
+static const char *tag_orphaned = "";
+static const char *tag_no_checkout = "";
/*
@@ -235,7 +240,7 @@ static void show_files(struct dir_struct *dir, const char *prefix)
if (show_killed)
show_killed_files(dir);
}
- if (show_cached | show_stage) {
+ if (show_cached | show_stage | show_orphaned | show_no_checkout) {
for (i = 0; i < active_nr; i++) {
struct cache_entry *ce = active_cache[i];
int dtype = ce_to_dtype(ce);
@@ -245,6 +250,16 @@ static void show_files(struct dir_struct *dir, const char *prefix)
continue;
if (ce->ce_flags & CE_UPDATE)
continue;
+ if (sparse_checkout && ce_no_checkout(ce)) {
+ struct stat st;
+ if (show_no_checkout)
+ show_ce_entry(tag_no_checkout, ce);
+ if (show_orphaned && !lstat(ce->name, &st))
+ show_ce_entry(tag_orphaned, ce);
+ continue;
+ }
+ if (!(show_cached | show_stage))
+ continue;
show_ce_entry(ce_stage(ce) ? tag_unmerged : tag_cached, ce);
}
}
@@ -257,7 +272,7 @@ static void show_files(struct dir_struct *dir, const char *prefix)
if (excluded(dir, ce->name, &dtype) != dir->show_ignored)
continue;
err = lstat(ce->name, &st);
- if (show_deleted && err)
+ if (show_deleted && err && ce_checkout(ce))
show_ce_entry(tag_removed, ce);
if (show_modified && ce_modified(ce, &st, 0))
show_ce_entry(tag_modified, ce);
@@ -423,7 +438,8 @@ int report_path_error(const char *ps_matched, const char **pathspec, int prefix_
}
static const char ls_files_usage[] =
- "git ls-files [-z] [-t] [-v] (--[cached|deleted|others|stage|unmerged|killed|modified])* "
+ "git ls-files [-z] [-t] [-v] (--[cached|deleted|others|stage|unmerged|killed|modified|orphaned|no-checkout])* "
+ "[ --sparse ] "
"[ --ignored ] [--exclude=<pattern>] [--exclude-from=<file>] "
"[ --exclude-per-directory=<filename> ] [--exclude-standard] "
"[--full-name] [--abbrev] [--] [<file>]*";
@@ -457,6 +473,8 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
tag_modified = "C ";
tag_other = "? ";
tag_killed = "K ";
+ tag_orphaned = "O ";
+ tag_no_checkout = "- ";
if (arg[1] == 'v')
show_valid_bit = 1;
continue;
@@ -465,6 +483,21 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
show_cached = 1;
continue;
}
+ if (!strcmp(arg, "--sparse")) {
+ sparse_checkout = 1;
+ continue;
+ }
+ if (!strcmp(arg, "--orphaned")) {
+ show_orphaned = 1;
+ sparse_checkout = 1;
+ require_work_tree = 1;
+ continue;
+ }
+ if (!strcmp(arg, "--no-checkout")) {
+ show_no_checkout = 1;
+ sparse_checkout = 1;
+ continue;
+ }
if (!strcmp(arg, "-d") || !strcmp(arg, "--deleted")) {
show_deleted = 1;
continue;
@@ -593,7 +626,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
/* With no flags, we default to showing the cached files */
if (!(show_stage | show_deleted | show_others | show_unmerged |
- show_killed | show_modified))
+ show_killed | show_modified | show_orphaned | show_no_checkout))
show_cached = 1;
read_cache();
--
1.6.0.2.488.gf604a
^ permalink raw reply related
* [PATCH 2/9] Introduce CE_NO_CHECKOUT bit
From: Nguyễn Thái Ngọc Duy @ 2008-10-01 4:04 UTC (permalink / raw)
To: git, Shawn O. Pearce; +Cc: Nguyễn Thái Ngọc Duy
In-Reply-To: <1222833849-22129-2-git-send-email-pclouds@gmail.com>
This bit is the basis of sparse checkout. If this bit is on, the entry
is outside sparse checkout and therefore should be ignored (similar
to CE_VALID)
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
Documentation/git-checkout.txt | 33 +++++++++++++++++++++++++++++++++
cache.h | 10 +++++++++-
read-cache.c | 6 +++---
3 files changed, 45 insertions(+), 4 deletions(-)
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index 82e154d..4bd9eba 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -171,6 +171,39 @@ the reflog for HEAD where you were, e.g.
$ git log -g -2 HEAD
------------
+Sparse checkout
+---------------
+
+Normally when you checkout a branch, your working directory
+will be fully populated. In some situations, you just need to
+work on certain files, no full checkout is needed. Sparse
+checkout is a mode that limits the checkout area according to your
+needs. With sparse checkout, you can work on a single file, a
+collection of files, a subdirectory or a collection of separated
+subdirectories.
+
+Because sparse checkout uses a new index format, it will be
+incompatible with git prior to 1.6.0 regarding worktree operations.
+Operations that only need access to the repository itself, such as
+clone, push, or pull/fetch from another (normal) repository... should
+not be affected by sparse checkout.
+
+In sparse checkout mode, checkout status of every files in your
+working directory will be recorded in index. If a file is marked
+"no-checkout", it means that file is not needed to be present in
+working directory by user or any git command. When a new file is added
+to index, it will be marked "checkout" unless sparse patterns are
+applied. Unmerged files are always "checkout". When you checkout new
+files using "git checkout <file>" they will be automatically marked
+"checkout". Other commands such as "git apply" can also checkout new
+files if they are needed.
+
+"No-checkout" status is very similar to "assume-unchanged bit"
+(see linkgit:git-update-index[1]). The main difference between them
+is "assume unchanged" bit just ignores corresponding files in working
+directory while sparse checkout goes a bit farther, remove those files
+when it is safe to do so.
+
EXAMPLES
--------
diff --git a/cache.h b/cache.h
index 5180879..f13ddbc 100644
--- a/cache.h
+++ b/cache.h
@@ -170,10 +170,11 @@ struct cache_entry {
/*
* Extended on-disk flags
*/
+#define CE_NO_CHECKOUT 0x40000000
/* CE_EXTENDED2 is for future extension */
#define CE_EXTENDED2 0x80000000
-#define CE_EXTENDED_FLAGS (0)
+#define CE_EXTENDED_FLAGS (CE_NO_CHECKOUT)
/*
* Safeguard to avoid saving wrong flags:
@@ -185,6 +186,9 @@ struct cache_entry {
#error "CE_EXTENDED_FLAGS out of range"
#endif
+/* "Assume unchanged" mask */
+#define CE_VALID_MASK (CE_VALID | CE_NO_CHECKOUT)
+
/*
* Copy the sha1 and stat state of a cache entry from one to
* another. But we never change the name, or the hash state!
@@ -222,6 +226,10 @@ static inline size_t ce_namelen(const struct cache_entry *ce)
ondisk_cache_entry_size(ce_namelen(ce)))
#define ce_stage(ce) ((CE_STAGEMASK & (ce)->ce_flags) >> CE_STAGESHIFT)
#define ce_uptodate(ce) ((ce)->ce_flags & CE_UPTODATE)
+#define ce_no_checkout(ce) ((ce)->ce_flags & CE_NO_CHECKOUT)
+#define ce_checkout(ce) (!ce_no_checkout(ce))
+#define ce_mark_no_checkout(ce) ((ce)->ce_flags |= CE_NO_CHECKOUT)
+#define ce_mark_checkout(ce) ((ce)->ce_flags &= ~CE_NO_CHECKOUT)
#define ce_mark_uptodate(ce) ((ce)->ce_flags |= CE_UPTODATE)
#define ce_permissions(mode) (((mode) & 0100) ? 0755 : 0644)
diff --git a/read-cache.c b/read-cache.c
index 667c36b..e965a4c 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -254,7 +254,7 @@ int ie_match_stat(const struct index_state *istate,
* If it's marked as always valid in the index, it's
* valid whatever the checked-out copy says.
*/
- if (!ignore_valid && (ce->ce_flags & CE_VALID))
+ if (!ignore_valid && (ce->ce_flags & CE_VALID_MASK))
return 0;
changed = ce_match_stat_basic(ce, st);
@@ -962,10 +962,10 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,
return ce;
/*
- * CE_VALID means the user promised us that the change to
+ * CE_VALID_MASK means the user promised us that the change to
* the work tree does not matter and told us not to worry.
*/
- if (!ignore_valid && (ce->ce_flags & CE_VALID)) {
+ if (!ignore_valid && (ce->ce_flags & CE_VALID_MASK)) {
ce_mark_uptodate(ce);
return ce;
}
--
1.6.0.2.488.gf604a
^ permalink raw reply related
* [PATCH 1/9] Extend index to save more flags
From: Nguyễn Thái Ngọc Duy @ 2008-10-01 4:04 UTC (permalink / raw)
To: git, Shawn O. Pearce; +Cc: Nguyễn Thái Ngọc Duy
In-Reply-To: <1222833849-22129-1-git-send-email-pclouds@gmail.com>
The on-disk format of index only saves 16 bit flags, nearly all have
been used. The last bit (CE_EXTENDED) is used to for future extension.
This patch extends index entry format to save more flags in future.
The new entry format will be used when CE_EXTENDED bit is 1.
Because older implementation may not understand CE_EXTENDED bit and
misread the new format, if there is any extended entry in index, index
header version will turn 3, which makes it incompatible for older git.
If there is none, header version will return to 2 again.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
cache.h | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----
read-cache.c | 51 +++++++++++++++++++++++++++++++++++++++++----------
2 files changed, 95 insertions(+), 14 deletions(-)
diff --git a/cache.h b/cache.h
index f4b8ddf..5180879 100644
--- a/cache.h
+++ b/cache.h
@@ -109,6 +109,26 @@ struct ondisk_cache_entry {
char name[FLEX_ARRAY]; /* more */
};
+/*
+ * This struct is used when CE_EXTENDED bit is 1
+ * The struct must match ondisk_cache_entry exactly from
+ * ctime till flags
+ */
+struct ondisk_cache_entry_extended {
+ struct cache_time ctime;
+ struct cache_time mtime;
+ unsigned int dev;
+ unsigned int ino;
+ unsigned int mode;
+ unsigned int uid;
+ unsigned int gid;
+ unsigned int size;
+ unsigned char sha1[20];
+ unsigned short flags;
+ unsigned short flags2;
+ char name[FLEX_ARRAY]; /* more */
+};
+
struct cache_entry {
unsigned int ce_ctime;
unsigned int ce_mtime;
@@ -130,7 +150,15 @@ struct cache_entry {
#define CE_VALID (0x8000)
#define CE_STAGESHIFT 12
-/* In-memory only */
+/*
+ * Range 0xFFFF0000 in ce_flags is divided into
+ * two parts: in-memory flags and on-disk ones.
+ * Flags in CE_EXTENDED_FLAGS will get saved on-disk
+ * if you want to save a new flag, add it in
+ * CE_EXTENDED_FLAGS
+ *
+ * In-memory only flags
+ */
#define CE_UPDATE (0x10000)
#define CE_REMOVE (0x20000)
#define CE_UPTODATE (0x40000)
@@ -140,6 +168,24 @@ struct cache_entry {
#define CE_UNHASHED (0x200000)
/*
+ * Extended on-disk flags
+ */
+/* CE_EXTENDED2 is for future extension */
+#define CE_EXTENDED2 0x80000000
+
+#define CE_EXTENDED_FLAGS (0)
+
+/*
+ * Safeguard to avoid saving wrong flags:
+ * - CE_EXTENDED2 won't get saved until its semantic is known
+ * - Bits in 0x0000FFFF have been saved in ce_flags already
+ * - Bits in 0x003F0000 are currently in-memory flags
+ */
+#if CE_EXTENDED_FLAGS & 0x803FFFFF
+#error "CE_EXTENDED_FLAGS out of range"
+#endif
+
+/*
* Copy the sha1 and stat state of a cache entry from one to
* another. But we never change the name, or the hash state!
*/
@@ -171,7 +217,9 @@ static inline size_t ce_namelen(const struct cache_entry *ce)
}
#define ce_size(ce) cache_entry_size(ce_namelen(ce))
-#define ondisk_ce_size(ce) ondisk_cache_entry_size(ce_namelen(ce))
+#define ondisk_ce_size(ce) (((ce)->ce_flags & CE_EXTENDED) ? \
+ ondisk_cache_entry_extended_size(ce_namelen(ce)) : \
+ ondisk_cache_entry_size(ce_namelen(ce)))
#define ce_stage(ce) ((CE_STAGEMASK & (ce)->ce_flags) >> CE_STAGESHIFT)
#define ce_uptodate(ce) ((ce)->ce_flags & CE_UPTODATE)
#define ce_mark_uptodate(ce) ((ce)->ce_flags |= CE_UPTODATE)
@@ -214,8 +262,10 @@ static inline int ce_to_dtype(const struct cache_entry *ce)
(S_ISREG(mode) ? (S_IFREG | ce_permissions(mode)) : \
S_ISLNK(mode) ? S_IFLNK : S_ISDIR(mode) ? S_IFDIR : S_IFGITLINK)
-#define cache_entry_size(len) ((offsetof(struct cache_entry,name) + (len) + 8) & ~7)
-#define ondisk_cache_entry_size(len) ((offsetof(struct ondisk_cache_entry,name) + (len) + 8) & ~7)
+#define flexible_size(STRUCT,len) ((offsetof(struct STRUCT,name) + (len) + 8) & ~7)
+#define cache_entry_size(len) flexible_size(cache_entry,len)
+#define ondisk_cache_entry_size(len) flexible_size(ondisk_cache_entry,len)
+#define ondisk_cache_entry_extended_size(len) flexible_size(ondisk_cache_entry_extended,len)
struct index_state {
struct cache_entry **cache;
diff --git a/read-cache.c b/read-cache.c
index c5a8659..667c36b 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -1096,7 +1096,7 @@ static int verify_hdr(struct cache_header *hdr, unsigned long size)
if (hdr->hdr_signature != htonl(CACHE_SIGNATURE))
return error("bad signature");
- if (hdr->hdr_version != htonl(2))
+ if (hdr->hdr_version != htonl(2) && hdr->hdr_version != htonl(3))
return error("bad index version");
SHA1_Init(&c);
SHA1_Update(&c, hdr, size - 20);
@@ -1131,6 +1131,7 @@ int read_index(struct index_state *istate)
static void convert_from_disk(struct ondisk_cache_entry *ondisk, struct cache_entry *ce)
{
size_t len;
+ const char *name;
ce->ce_ctime = ntohl(ondisk->ctime.sec);
ce->ce_mtime = ntohl(ondisk->mtime.sec);
@@ -1143,19 +1144,31 @@ static void convert_from_disk(struct ondisk_cache_entry *ondisk, struct cache_en
/* On-disk flags are just 16 bits */
ce->ce_flags = ntohs(ondisk->flags);
- /* For future extension: we do not understand this entry yet */
- if (ce->ce_flags & CE_EXTENDED)
- die("Unknown index entry format");
hashcpy(ce->sha1, ondisk->sha1);
len = ce->ce_flags & CE_NAMEMASK;
+
+ if (ce->ce_flags & CE_EXTENDED) {
+ struct ondisk_cache_entry_extended *ondisk2;
+ int extended_flags;
+ ondisk2 = (struct ondisk_cache_entry_extended *)ondisk;
+ extended_flags = ntohs(ondisk2->flags2) << 16;
+ /* We do not yet understand any bit out of CE_EXTENDED_FLAGS */
+ if (extended_flags & ~CE_EXTENDED_FLAGS)
+ die("Unknown index entry format %08x", extended_flags);
+ ce->ce_flags |= extended_flags;
+ name = ondisk2->name;
+ }
+ else
+ name = ondisk->name;
+
if (len == CE_NAMEMASK)
- len = strlen(ondisk->name);
+ len = strlen(name);
/*
* NEEDSWORK: If the original index is crafted, this copy could
* go unchecked.
*/
- memcpy(ce->name, ondisk->name, len + 1);
+ memcpy(ce->name, name, len + 1);
}
static inline size_t estimate_cache_size(size_t ondisk_size, unsigned int entries)
@@ -1415,6 +1428,7 @@ static int ce_write_entry(SHA_CTX *c, int fd, struct cache_entry *ce)
{
int size = ondisk_ce_size(ce);
struct ondisk_cache_entry *ondisk = xcalloc(1, size);
+ char *name;
ondisk->ctime.sec = htonl(ce->ce_ctime);
ondisk->ctime.nsec = 0;
@@ -1428,7 +1442,15 @@ static int ce_write_entry(SHA_CTX *c, int fd, struct cache_entry *ce)
ondisk->size = htonl(ce->ce_size);
hashcpy(ondisk->sha1, ce->sha1);
ondisk->flags = htons(ce->ce_flags);
- memcpy(ondisk->name, ce->name, ce_namelen(ce));
+ if (ce->ce_flags & CE_EXTENDED) {
+ struct ondisk_cache_entry_extended *ondisk2;
+ ondisk2 = (struct ondisk_cache_entry_extended *)ondisk;
+ ondisk2->flags2 = htons((ce->ce_flags & CE_EXTENDED_FLAGS) >> 16);
+ name = ondisk2->name;
+ }
+ else
+ name = ondisk->name;
+ memcpy(name, ce->name, ce_namelen(ce));
return ce_write(c, fd, ondisk, size);
}
@@ -1437,16 +1459,25 @@ int write_index(const struct index_state *istate, int newfd)
{
SHA_CTX c;
struct cache_header hdr;
- int i, err, removed;
+ int i, err, removed, extended;
struct cache_entry **cache = istate->cache;
int entries = istate->cache_nr;
- for (i = removed = 0; i < entries; i++)
+ for (i = removed = extended = 0; i < entries; i++) {
if (cache[i]->ce_flags & CE_REMOVE)
removed++;
+ /* reduce extended entries if possible */
+ cache[i]->ce_flags &= ~CE_EXTENDED;
+ if (cache[i]->ce_flags & CE_EXTENDED_FLAGS) {
+ extended++;
+ cache[i]->ce_flags |= CE_EXTENDED;
+ }
+ }
+
hdr.hdr_signature = htonl(CACHE_SIGNATURE);
- hdr.hdr_version = htonl(2);
+ /* for extended format, increase version so older git won't try to read it */
+ hdr.hdr_version = htonl(extended ? 3 : 2);
hdr.hdr_entries = htonl(entries - removed);
SHA1_Init(&c);
--
1.6.0.2.488.gf604a
^ permalink raw reply related
* [PATCH/resent 0/9] Sparse checkout (first half)
From: Nguyễn Thái Ngọc Duy @ 2008-10-01 4:04 UTC (permalink / raw)
To: git, Shawn O. Pearce; +Cc: Nguyễn Thái Ngọc Duy
This is the first half of the series, making git ready for sparse
checkout. The only difference from the last (first half) sent
series is safeguard bitmask fix in 1/9
Nguyá»
n Thái Ngá»c Duy (9):
Extend index to save more flags
Introduce CE_NO_CHECKOUT bit
ls-files: add options to support sparse checkout
update-index: refactor mark_valid() in preparation for new options
update-index: add --checkout/--no-checkout to update CE_NO_CHECKOUT
bit
ls-files: Add tests for --sparse and friends
Prevent diff machinery from examining worktree outside sparse
checkout
checkout_entry(): CE_NO_CHECKOUT on checked out entries.
grep: skip files outside sparse checkout area
.gitignore | 1 +
Documentation/git-checkout.txt | 34 +++++++++++++++++
Documentation/git-grep.txt | 4 +-
Documentation/git-ls-files.txt | 24 +++++++++++-
Documentation/git-update-index.txt | 13 ++++++
Makefile | 2 +-
builtin-grep.c | 7 +++-
builtin-ls-files.c | 41 ++++++++++++++++++--
builtin-update-index.c | 40 ++++++++++++-------
cache.h | 66 +++++++++++++++++++++++++++++++--
diff-lib.c | 5 +-
diff.c | 4 +-
entry.c | 1 +
read-cache.c | 57 ++++++++++++++++++++++------
t/t2104-update-index-no-checkout.sh | 36 ++++++++++++++++++
t/t3004-ls-files-sparse.sh | 40 ++++++++++++++++++++
t/t3004/cached.expected | 5 ++
t/t3004/deleted.expected | 1 +
t/t3004/everything.expected | 10 +++++
t/t3004/modified.expected | 2 +
t/t3004/no-checkout.expected | 2 +
t/t3004/orphaned-no-checkout.expected | 3 +
t/t3004/orphaned.expected | 1 +
t/t3004/others.expected | 2 +
t/t3004/sparse-cached.expected | 3 +
t/t3004/sparse-everything.expected | 11 +++++
test-index-version.c | 14 +++++++
27 files changed, 385 insertions(+), 44 deletions(-)
create mode 100755 t/t2104-update-index-no-checkout.sh
create mode 100755 t/t3004-ls-files-sparse.sh
create mode 100644 t/t3004/cached.expected
create mode 100644 t/t3004/deleted.expected
create mode 100644 t/t3004/everything.expected
create mode 100644 t/t3004/modified.expected
create mode 100644 t/t3004/no-checkout.expected
create mode 100644 t/t3004/orphaned-no-checkout.expected
create mode 100644 t/t3004/orphaned.expected
create mode 100644 t/t3004/others.expected
create mode 100644 t/t3004/sparse-cached.expected
create mode 100644 t/t3004/sparse-everything.expected
create mode 100644 test-index-version.c
^ 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