* [PATCH 3/3] Documentation: add manpage about workflows
From: Thomas Rast @ 2008-09-13 16:11 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano
In-Reply-To: <1221322263-25291-3-git-send-email-trast@student.ethz.ch>
This attempts to make a manpage about workflows that is both handy to
point people at it and as a beginner's introduction.
Signed-off-by: Thomas Rast <trast@student.ethz.ch>
---
Interdiff follows. The important change is that the format-patch
recipe says to use send-email, hopefully keeping people from damaging
their patches via cut&paste.
Unfortunately I still don't know how to make the blocks look right in
manpage format.
Documentation/Makefile | 2 +-
Documentation/gitworkflows.txt | 330 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 331 insertions(+), 1 deletions(-)
create mode 100644 Documentation/gitworkflows.txt
diff --git a/Documentation/Makefile b/Documentation/Makefile
index ded0e40..e33ddcb 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -6,7 +6,7 @@ MAN5_TXT=gitattributes.txt gitignore.txt gitmodules.txt githooks.txt \
gitrepository-layout.txt
MAN7_TXT=gitcli.txt gittutorial.txt gittutorial-2.txt \
gitcvs-migration.txt gitcore-tutorial.txt gitglossary.txt \
- gitdiffcore.txt
+ gitdiffcore.txt gitworkflows.txt
MAN_TXT = $(MAN1_TXT) $(MAN5_TXT) $(MAN7_TXT)
MAN_XML=$(patsubst %.txt,%.xml,$(MAN_TXT))
diff --git a/Documentation/gitworkflows.txt b/Documentation/gitworkflows.txt
new file mode 100644
index 0000000..b4b43da
--- /dev/null
+++ b/Documentation/gitworkflows.txt
@@ -0,0 +1,330 @@
+gitworkflows(7)
+===============
+
+NAME
+----
+gitworkflows - An overview of recommended workflows with git
+
+SYNOPSIS
+--------
+git *
+
+
+DESCRIPTION
+-----------
+
+This tutorial gives a brief overview of workflows recommended to
+use, and collaborate with, Git.
+
+While the prose tries to motivate each of them, we formulate a set of
+'rules' for quick reference. Do not always take them literally; you
+should value good reasons higher than following a random manpage to
+the letter.
+
+
+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.
+
+To achieve this, try to commit your new work at least every couple
+hours. You can always go back and edit the commits with `git rebase
+--interactive` to further improve the history before you publish it.
+
+
+MANAGING BRANCHES
+-----------------
+
+In the following, we will assume there are 'developers', 'testers' and
+'users'. Even if the "Testers" are actually an automated test suite
+and all "Users" are developers themselves, try to think in these terms
+as you follow a software change through its life cycle.
+
+Usually a change evolves in a few steps:
+
+* The developers implement a few iterations until it "seems to work".
+
+* The testers play with it, report bugs, test the fixes, eventually
+ clearing the change for stable releases.
+
+* As the users work with the new feature, they report bugs which will
+ have to be fixed.
+
+In the following sections we discuss some problems that arise from
+such a "change flow", and how to solve them with Git.
+
+We consider a fictional project with (supported) stable branch
+'maint', main testing/development branch 'master' and "bleeding edge"
+branch 'next'. We collectively call these three branches 'main
+branches'.
+
+
+Merging upwards
+~~~~~~~~~~~~~~~
+
+Since Git is quite good at merges, one should try to use them to
+propagate changes. For example, if a bug is fixed, you would want to
+apply the corresponding fix to all main branches.
+
+A quick moment of thought reveals that you cannot do this by merging
+"downwards" to older releases, since that would merge 'all' changes.
+Hence the following:
+
+.Merge upwards
+[caption="Rule: "]
+=====================================
+Always commit your fixes to the oldest supported branch that require
+them. Then (periodically) merge the main branches upwards into each
+other.
+=====================================
+
+This gives a very controlled flow of fixes. If you notice that you
+have applied a fix to e.g. 'master' that is also required in 'maint',
+you will need to cherry-pick it (using linkgit:git-cherry-pick[1])
+downwards. This will happen a few times and is nothing to worry about
+unless you do it all the time.
+
+
+Topic branches
+~~~~~~~~~~~~~~
+
+Any nontrivial feature will require several patches to implement, and
+may get extra bugfixes or improvements during its lifetime. If all
+such commits were in one long linear history chain (e.g., if they were
+all committed directly to 'master'), it becomes very hard to see how
+they belong together.
+
+The key concept here is "topic branches". The name is pretty self
+explanatory, with a minor caveat that comes from the "merge upwards"
+rule above:
+
+.Topic branches
+[caption="Rule: "]
+=====================================
+Make a side branch for every topic. Fork it off at the oldest main
+branch that you will eventually want to merge it into.
+=====================================
+
+Many things can then be done very naturally:
+
+* To get the feature/bugfix into a main branch, simply merge it. If
+ the topic has evolved further in the meantime, merge again.
+
+* If you find you need new features from an 'other' branch to continue
+ working on your topic, merge 'other' to 'topic'. (However, do not
+ do this "just habitually", see below.)
+
+* If you find you forked off the wrong branch and want to move it
+ "back in time", use linkgit:git-rebase[1].
+
+Note that the last two points clash: a topic that has been merged
+elsewhere should not be rebased. See the section on RECOVERING FROM
+UPSTREAM REBASE in linkgit:git-rebase[1].
+
+We should point out that "habitually" (regularly for no real reason)
+merging a main branch into your topics -- and by extension, merging
+anything upstream into anything downstream on a regular basis -- is
+frowned upon:
+
+.Merge to downstream only at well-defined points
+[caption="Rule: "]
+=====================================
+Do not merge to downstream except:
+
+* with a good reason (such as upstream API changes that affect you), or
+
+* at well-defined points such as when an upstream release has been tagged.
+=====================================
+
+Otherwise, the many resulting small merges will greatly clutter up
+history. Anyone who later investigates the history of a file will
+have to find out whether that merge affected the topic in
+development. Linus hates it. An upstream might even inadvertently be
+merged into a "more stable" branch. And so on.
+
+
+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.
+
+
+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.
+
+Roughly speaking, there are two important workflows. Their
+distinguishing mark is whether they can be used to propagate merges.
+Medium to large projects will typically employ some mixture of the
+two:
+
+* "Upstream" in the most general sense 'pushes' changes to the
+ repositor(ies) holding the main history. Everyone can 'pull' from
+ there to stay up to date.
+
+* Frequent contributors, subsystem maintainers, etc. may use push/pull
+ to send their changes upstream.
+
+* The rest -- typically anyone more than one or two levels away from the
+ main maintainer -- send patches by mail.
+
+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:
+
+* linkgit:git-push[1] copies your branches to a remote repository,
+ usually to one that can be read by all involved parties;
+
+* linkgit:git-fetch[1] that copies remote branches to your repository;
+ and
+
+* linkgit:git-pull[1] that does fetch and merge in one go.
+
+Note the last point. Do 'not' use 'git-pull' unless you actually want
+to merge the remote branch.
+
+Getting changes out is easy:
+
+.Push/pull: Publishing branches/topics
+[caption="Recipe: "]
+=====================================
+`git push <remote> <branch>` and tell everyone where they can fetch
+from.
+=====================================
+
+You will still have to tell people by other means, such as mail. (Git
+provides the linkgit:request-pull[1] to send preformatted pull
+requests to upstream maintainers to simplify this task.)
+
+If you just want to get the newest copies of the main branches,
+staying up to date is easy too:
+
+.Push/pull: Staying up to date
+[caption="Recipe: "]
+=====================================
+Use `git fetch <remote>` or `git remote update` to stay up to date.
+=====================================
+
+Then simply fork your topic branches from the stable remotes as
+explained earlier.
+
+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.
+
+.Push/pull: Merging remote topics
+[caption="Recipe: "]
+=====================================
+`git pull <url> <branch>`
+=====================================
+
+Occasionally, the maintainer may get merge conflicts when he tries to
+pull changes from downstream. In this case, he can ask downstream to
+do the merge and resolve the conflicts themselves (perhaps they will
+know better how to resolve them). It is one of the rare cases where
+downstream 'should' merge from upstream.
+
+
+format-patch/am
+~~~~~~~~~~~~~~~
+
+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.
+
+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 rebase upstream`
+=====================================
+
+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 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 because of renames: `git am -3` will use index
+information contained in patches to reconstruct a 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.
--
1.6.0.2.408.g3709
^ permalink raw reply related
* Interdiff: [3/3] Documentation: add manpage about workflows
From: Thomas Rast @ 2008-09-13 16:11 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano
In-Reply-To: <1221322263-25291-4-git-send-email-trast@student.ethz.ch>
---
Documentation/gitworkflows.txt | 24 ++++++++++++++----------
1 files changed, 14 insertions(+), 10 deletions(-)
diff --git a/Documentation/gitworkflows.txt b/Documentation/gitworkflows.txt
index 3462000..b4b43da 100644
--- a/Documentation/gitworkflows.txt
+++ b/Documentation/gitworkflows.txt
@@ -92,8 +92,8 @@ Topic branches
Any nontrivial feature will require several patches to implement, and
may get extra bugfixes or improvements during its lifetime. If all
-such commits were in one long linear history chain (e.g. if they were
-all committed directly to, 'master'), it becomes very hard to see how
+such commits were in one long linear history chain (e.g., if they were
+all committed directly to 'master'), it becomes very hard to see how
they belong together.
The key concept here is "topic branches". The name is pretty self
@@ -124,8 +124,8 @@ elsewhere should not be rebased. See the section on RECOVERING FROM
UPSTREAM REBASE in linkgit:git-rebase[1].
We should point out that "habitually" (regularly for no real reason)
-merging a main branch into your topics--and by extension, merging
-anything upstream into anything downstream on a regular basis--is
+merging a main branch into your topics -- and by extension, merging
+anything upstream into anything downstream on a regular basis -- is
frowned upon:
.Merge to downstream only at well-defined points
@@ -207,7 +207,7 @@ There are three main tools that can be used for this:
* linkgit:git-fetch[1] that copies remote branches to your repository;
and
-* linkgit:git-pull[1] that is fetch and merge in one go.
+* linkgit:git-pull[1] that does fetch and merge in one go.
Note the last point. Do 'not' use 'git-pull' unless you actually want
to merge the remote branch.
@@ -258,7 +258,7 @@ follows.
Occasionally, the maintainer may get merge conflicts when he tries to
pull changes from downstream. In this case, he can ask downstream to
do the merge and resolve the conflicts themselves (perhaps they will
-know better how to react). It is one of the rare cases where
+know better how to resolve them). It is one of the rare cases where
downstream 'should' merge from upstream.
@@ -274,12 +274,15 @@ maintainer's life easier).
.format-patch/am: Publishing branches/topics
[caption="Recipe: "]
=====================================
-`git format-patch -M upstream..topic` and send out the resulting files.
+* `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] manpage for further usage notes.
-Also you should be aware that the maintainer may impose further
-restrictions, such as "Signed-off-by" requirements.
+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.
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
@@ -319,6 +322,7 @@ 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
--
1.6.0.2.408.g3709
^ permalink raw reply related
* [PATCH] Start conforming code to "git subcmd" style part 3
From: Heikki Orsila @ 2008-09-13 16:30 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Jakub Narebski, Christian Couder,
Andreas Ericsson
User notifications are presented as 'git cmd', and code comments
are presented as '"cmd"' or 'git's cmd', rather than 'git-cmd'.
Signed-off-by: Heikki Orsila <heikki.orsila@iki.fi>
---
builtin-init-db.c | 2 +-
builtin-pack-objects.c | 4 ++--
builtin-read-tree.c | 2 +-
builtin-rev-list.c | 2 +-
builtin-rm.c | 2 +-
builtin-send-pack.c | 2 +-
builtin-tar-tree.c | 14 +++++++-------
builtin-unpack-objects.c | 2 +-
builtin-update-index.c | 8 ++++----
9 files changed, 19 insertions(+), 19 deletions(-)
diff --git a/builtin-init-db.c b/builtin-init-db.c
index baf0d09..8140c12 100644
--- a/builtin-init-db.c
+++ b/builtin-init-db.c
@@ -37,7 +37,7 @@ static void copy_templates_1(char *path, int baselen,
/* Note: if ".git/hooks" file exists in the repository being
* re-initialized, /etc/core-git/templates/hooks/update would
- * cause git-init to fail here. I think this is sane but
+ * cause "git init" to fail here. I think this is sane but
* it means that the set of templates we ship by default, along
* with the way the namespace under .git/ is organized, should
* be really carefully chosen.
diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c
index ba2cf00..217fd49 100644
--- a/builtin-pack-objects.c
+++ b/builtin-pack-objects.c
@@ -23,7 +23,7 @@
#endif
static const char pack_usage[] = "\
-git-pack-objects [{ -q | --progress | --all-progress }] \n\
+git pack-objects [{ -q | --progress | --all-progress }] \n\
[--max-pack-size=N] [--local] [--incremental] \n\
[--window=N] [--window-memory=N] [--depth=N] \n\
[--no-reuse-delta] [--no-reuse-object] [--delta-base-offset] \n\
@@ -1872,7 +1872,7 @@ static void mark_in_pack_object(struct object *object, struct packed_git *p, str
/*
* Compare the objects in the offset order, in order to emulate the
- * "git-rev-list --objects" output that produced the pack originally.
+ * "git rev-list --objects" output that produced the pack originally.
*/
static int ofscmp(const void *a_, const void *b_)
{
diff --git a/builtin-read-tree.c b/builtin-read-tree.c
index dddc304..ac219ac 100644
--- a/builtin-read-tree.c
+++ b/builtin-read-tree.c
@@ -64,7 +64,7 @@ static void prime_cache_tree(void)
}
-static const char read_tree_usage[] = "git-read-tree (<sha> | [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] [--exclude-per-directory=<gitignore>] [--index-output=<file>] <sha1> [<sha2> [<sha3>]])";
+static const char read_tree_usage[] = "git read-tree (<sha> | [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] [--exclude-per-directory=<gitignore>] [--index-output=<file>] <sha1> [<sha2> [<sha3>]])";
static struct lock_file lock_file;
diff --git a/builtin-rev-list.c b/builtin-rev-list.c
index c023003..facaff2 100644
--- a/builtin-rev-list.c
+++ b/builtin-rev-list.c
@@ -178,7 +178,7 @@ static void finish_object(struct object_array_entry *p)
static void show_object(struct object_array_entry *p)
{
/* An object with name "foo\n0000000..." can be used to
- * confuse downstream git-pack-objects very badly.
+ * confuse downstream "git pack-objects" very badly.
*/
const char *ep = strchr(p->name, '\n');
diff --git a/builtin-rm.c b/builtin-rm.c
index 6bd8211..fdac34f 100644
--- a/builtin-rm.c
+++ b/builtin-rm.c
@@ -104,7 +104,7 @@ static int check_local_mod(unsigned char *head, int index_only)
"from both the file and the HEAD\n"
"(use -f to force removal)", name);
else if (!index_only) {
- /* It's not dangerous to git-rm --cached a
+ /* It's not dangerous to "git rm --cached" a
* file if the index matches the file or the
* HEAD, since it means the deleted content is
* still available somewhere.
diff --git a/builtin-send-pack.c b/builtin-send-pack.c
index 7588d22..2af9f29 100644
--- a/builtin-send-pack.c
+++ b/builtin-send-pack.c
@@ -43,7 +43,7 @@ static int pack_objects(int fd, struct ref *refs)
po.out = fd;
po.git_cmd = 1;
if (start_command(&po))
- die("git-pack-objects failed (%s)", strerror(errno));
+ die("git pack-objects failed (%s)", strerror(errno));
/*
* We feed the pack-objects we just spawned with revision
diff --git a/builtin-tar-tree.c b/builtin-tar-tree.c
index cb7007e..edcf72a 100644
--- a/builtin-tar-tree.c
+++ b/builtin-tar-tree.c
@@ -9,19 +9,19 @@
static const char tar_tree_usage[] =
"git tar-tree [--remote=<repo>] <tree-ish> [basedir]\n"
-"*** Note that this command is now deprecated; use git-archive instead.";
+"*** Note that this command is now deprecated; use \"git archive\" instead.";
int cmd_tar_tree(int argc, const char **argv, const char *prefix)
{
/*
- * git-tar-tree is now a wrapper around git-archive --format=tar
+ * "git tar-tree" is now a wrapper around "git archive" --format=tar
*
* $0 --remote=<repo> arg... ==>
- * git-archive --format=tar --remote=<repo> arg...
+ * git archive --format=tar --remote=<repo> arg...
* $0 tree-ish ==>
- * git-archive --format=tar tree-ish
+ * git archive --format=tar tree-ish
* $0 tree-ish basedir ==>
- * git-archive --format-tar --prefix=basedir tree-ish
+ * git archive --format-tar --prefix=basedir tree-ish
*/
int i;
const char **nargv = xcalloc(sizeof(*nargv), argc + 2);
@@ -53,8 +53,8 @@ int cmd_tar_tree(int argc, const char **argv, const char *prefix)
nargv[nargc] = NULL;
fprintf(stderr,
- "*** git-tar-tree is now deprecated.\n"
- "*** Running git-archive instead.\n***");
+ "*** \"git tar-tree\" is now deprecated.\n"
+ "*** Running \"git archive\" instead.\n***");
for (i = 0; i < nargc; i++) {
fputc(' ', stderr);
sq_quote_print(stderr, nargv[i]);
diff --git a/builtin-unpack-objects.c b/builtin-unpack-objects.c
index a891866..40b20f2 100644
--- a/builtin-unpack-objects.c
+++ b/builtin-unpack-objects.c
@@ -13,7 +13,7 @@
#include "fsck.h"
static int dry_run, quiet, recover, has_errors, strict;
-static const char unpack_usage[] = "git-unpack-objects [-n] [-q] [-r] [--strict] < pack-file";
+static const char unpack_usage[] = "git unpack-objects [-n] [-q] [-r] [--strict] < pack-file";
/* We always read in 4kB chunks. */
static unsigned char buffer[4096];
diff --git a/builtin-update-index.c b/builtin-update-index.c
index ce83224..417f972 100644
--- a/builtin-update-index.c
+++ b/builtin-update-index.c
@@ -14,7 +14,7 @@
* Default to not allowing changes to the list of files. The
* tool doesn't actually care, but this makes it harder to add
* files to the revision control by mistake by doing something
- * like "git-update-index *" and suddenly having all the object
+ * like "git update-index *" and suddenly having all the object
* files be revision controlled.
*/
static int allow_add;
@@ -313,18 +313,18 @@ static void read_index_info(int line_termination)
/* This reads lines formatted in one of three formats:
*
* (1) mode SP sha1 TAB path
- * The first format is what "git-apply --index-info"
+ * The first format is what "git apply --index-info"
* reports, and used to reconstruct a partial tree
* that is used for phony merge base tree when falling
* back on 3-way merge.
*
* (2) mode SP type SP sha1 TAB path
- * The second format is to stuff git-ls-tree output
+ * The second format is to stuff "git ls-tree" output
* into the index file.
*
* (3) mode SP sha1 SP stage TAB path
* This format is to put higher order stages into the
- * index file and matches git-ls-files --stage output.
+ * index file and matches "git ls-files --stage" output.
*/
errno = 0;
ul = strtoul(buf.buf, &ptr, 8);
--
1.6.0.1
^ permalink raw reply related
* [PATCH] Cosmetical command name fix
From: Heikki Orsila @ 2008-09-13 16:31 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano
If we came from git.c the first arg would be "archive".
"git-archive" isn't a bug because cmd_archive() doesn't check
the first arg.
Signed-off-by: Heikki Orsila <heikki.orsila@iki.fi>
---
builtin-tar-tree.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/builtin-tar-tree.c b/builtin-tar-tree.c
index edcf72a..dd7326a 100644
--- a/builtin-tar-tree.c
+++ b/builtin-tar-tree.c
@@ -28,7 +28,7 @@ int cmd_tar_tree(int argc, const char **argv, const char *prefix)
char *basedir_arg;
int nargc = 0;
- nargv[nargc++] = "git-archive";
+ nargv[nargc++] = "archive";
nargv[nargc++] = "--format=tar";
if (2 <= argc && !prefixcmp(argv[1], "--remote=")) {
--
1.6.0.1
^ permalink raw reply related
* Git at Better SCM Initiative comparison of VCS (long)
From: Jakub Narebski @ 2008-09-13 17:06 UTC (permalink / raw)
To: git
I have tried a few times to add information about Git to comparison
table of SCMs at 'Better SCM Initiative' (http://better-scm.berlios.de)
http://thread.gmane.org/gmane.comp.version-control.git/66445
http://thread.gmane.org/gmane.comp.version-control.git/67708
but somehow I didn't lead it to conclusion, namely adding Git to
the comparison table. (Sidenote: Data from 'Better SCM : Comparison'
is used also for versioncontrolblog "Version control systems comparison"
at http://versioncontrolblog.com/comparison).
I have thought about trying yet another time... but Git was already
added; see http://better-scm.berlios.de/news/changes-2008-08-07/
Now I have checked information about Git and think that this table
needs a few corrections and, in some places, extra explanation.
Let us here come together with a version we can be happy with, which
I would be then able to send as correction for Better SCM Initiative
comparison (http://better-scm.berlios.de/contribute/).
Below there are excerpts from source of comparison table (from SVN)
http://opensvn.csie.org/betterscm/better-scm-site/trunk/src/comparison/scm-comparison.xml
marked as quoted text (with 'scm>'), optionally un-indented and
re-wrapped for better readibility. My comments follow as if they
were replies to an email.
---
scm> <?xml version='1.0' encoding='utf-8'?>
scm> <?xml-stylesheet type="text/xml" href="compare-ml.xsl"?>
scm> <!DOCTYPE comparison SYSTEM "comparison.dtd">
scm> <!--
scm> TODO:
scm>
scm> * Add intelligent merging of renamed paths.
The comparison has a new criterion: "Intelligent Merging after Moves
or Renames" since 2008-08-07, so the first item in this TODO list
should have been removed, I think.
scm> * Add IDE integration.
scm> * Integration with build/testing management.
scm> * Check-In policies.
scm> * Add Speed (?)
scm> -->
The problem of course with adding new criterion is that it should be
added for _all_ (currently 27) version control systems (SCMs) covered.
scm> <comparison>
scm> <meta>
scm> <implementations>
scm> <impl id="git">
scm> <name>Git</name>
scm> <url>http://git.or.cz/</url>
scm> </impl>
Hmmm... what to do about the fact that currently Git has _two_ forks of
a homepage: http://git.or.cz (aka http://git-scm.org) by Petr 'Pasky'
Baudis and new http://git-scm.com by Scott Chacon, I do wonder...
But those are just aimless musings... the above is O.K.
scm> </implementations>
scm> <timestamp>
scm> $Id: scm-comparison.xml 322 2008-08-09 05:47:26Z shlomif $
scm> </timestamp>
scm> </meta>
scm> <contents>
scm> <section id="main">
scm> <title>Version Control System Comparison</title>
scm> <expl>
scm> This is a comparison of version-control systems. It is split
scm> into several categories and sub-categories under which the
scm> systems are checked.
scm> </expl>
scm> <section id="repos_operations">
scm> <title>Repository Operations</title>
scm> <section id="atomic_commits">
scm> <title>Atomic Commits</title>
scm> <expl>
scm> Support for atomic commits means that if an
scm> operation on the repository is interrupted
scm> in the middle, the repository will not be
scm> left in an inconsistent state. Are the
scm> check-in operations atomic, or can
scm> interrupting an operation leave the
scm> repository in an intermediate state?
scm> </expl>
Here I think the explanation of a criterion (feature) is clear enough.
I might have added that "interruption" include killing of a process
during for example commit, lack of disk space for a full commit, or
a network fail during network operation (fetch or push, or equivalent).
scm> <compare>
scm> <s id="git">Yes. Commits are atomic.</s>
scm> </compare>
O.K.
scm> </section>
scm> <section id="move">
scm> <title>Files and Directories Moves or Renames</title>
scm> <expl>
scm> Does the system support moving a file or directory to
scm> a different location while still retaining the history
scm> of the file? <b>Note:</b> also see the next section
scm> about intelligent merging of renamed paths.
scm> </expl>
In my opinion this criterion is next to worthess without more in depth
clarification of what does it mean to "support" moves or renames; as
entries for different systems are written by different people, if it
is not clear how to check if some feature is supported, some might
write 'no' for some system A, and some other person can write 'yes'
for other system B, even if the support is better in system A than in
system B (and would be considered enough, i.e. 'yes' answer, by the
creator of this criterion).
For me the support for renames/moves and copying (see next section)
means that:
0.) When examining or going to some point in the history (some old
revision/version of a project) the state you get is _exactly_
the same as it was at that time, exactly the same as it was
recorded (comitted) then.
For example tricks with moving *,v files in the CVS repository
break this assertion.
1.) When examining history of a project as a whole version control
system tells you that file was renamed (moved). I would consider
having there renaming represented as copy + delete to be only
a partial support of this feature.
Note that while tool might correctly notify about file renames
(I would consider heuristics which give correct answer in 99%
or so "true life" example to 'correctly notify'), it might notice
full directory renames only as renames of individual files.
I guess that at least for some systems this issue was not taken
into account...
2.) When examining history of an individual file (or perhaps even of
an individual directory), either in the form of list of revisions
which touch given file in the form of "$scm log <file>" output or
some graphical history viewer output, or in the form of annotations
of file contents (so called here 'per-line history') in the form
of "$scm blame <file>" / "$scm annotate <file>", we would want for
SCM to follow history of contents across file renames (and other
code movements if possible; but that is outside of scope of this
criterion).
Side note: history of two files can be more than sum (union) of
histories of individual files.
From the comments I have heard it looks like at least for some version
control systems contributors used the meaning '0', while most users
(readers) would think of '1+2', good if not forgetting about '0'.
Here (and in other places) it would be nice to have actual *TEST*, which
can be used to determine if given version control system "supports"
'Files and Directories Moves or Renames' criterion/feature. Attention!
because Git does similarity based rename detection (contents + pathname
based similarity score), one should use better some larger test vector,
otherwise Git and other systems using rename detection would be at
disadvantage. An example of such test would be t/t*rename* tests from
git; we could also use 'Lorem ipsum' or 'Dominus regit me' test vectors.
So for example 1.) could be tested as:
$ scm add A
$ ...
$ scm mv A B
$ ...
$ scm log [options] # <- has info about A => B rename
while 2.) could be tested as:
$ scm add A
$ ...
$ scm mv A B
$ ...
$ scm log [options] B # <- goes to initial revision of A
By the way, there is even simpler operation than support for renames
that SCM can screw up (file-history based SCM are specially
susceptible). Try to delete a file, and then later create _different_
file (separate history) with the same filename.
scm> <compare>
scm> <s id="git">
scm> Renames are supported for most practical
scm> purposes. Git even detects renames when a file has been
scm> changed afterward the rename. However, due to a peculiar
scm> repository structure, renames are not recorded
scm> explicitly, and Git has to deduce them (which works well
scm> in practice).
scm> </s>
First, a correction to above statement. It is not due to "a peculiar
repository structure", but due to "a design decision" (perhaps with
link to some explanation why it was implemented this way; I planned
to make a wiki page about 'rename tracking' vs. 'rename detection'
with references to various mailing list messages etc., but to this
day it was not created).
Second, we can think about how the above statement could be improved.
For example Git fullfils '0' even without rename detection, due to
the fact that it is whole-tree snapshot-based VCS. From descriptions
for other version control systems (see "Version Control System
Comparison" subpage of "Better SCM Initiative : Comparison" at
http://better-scm.berlios.de/comparison/comparison.html) it looks like
at least some contributors thought that having '0' supported is enough
to say 'Yes' to this question.
Git uses rename detection, not rename tracking (usually file-id/inode
based) to be able to notify about renames in the diff / whatchanged /
diffstat or summary output. So I would say that in practice (with
some unfortunate exceptions) Git fills '1', which means showing renames
in whole project log well.
When talking about rename detection for a single file history, here
the situation gets difficult. On the one hand "git log --follow <file>"
is a bit of hack and works only for simple histories, failing for
example on subtree merge; other example would be 'gitweb/gitweb.perl'
file in git repository, which '--follow' doesn't follow to initial
'gitweb.cgi' file from what once been gitweb repository. One has
to use then "git log -- <old name> <new name>"; this is caused by the
fact that git always concentrated more on full repository history, and
by how path limiting works. On the other hand Git has as far as I know
_unique_ blame tool which is able to follow code movement; this covers
more than only following contents across wholesame file rename. This
feature IMHO is best examined using "git gui blame <file>" or other
graphical blame/annotate viewers (QGit has one, for example).
To be honest git currently does not have _directory_ rename detection
(which for example leads to some quirks in dealing with renames during
merge, to be more exact dealing with new files in a directory which
got renamed by other side); it currently supports directory renames
by detecting renames of files it contains (path similarity is part of
rename-detection similarity score). But this is not insurmountable
obstacle, and does not require changing design and tracking renames.
...Now only put the above in a few short sentences to be used in
"Better SCM Initiative" comparison table...
scm> </compare>
scm> </section>
scm> <section id="intelligent_renames">
scm> <title>Intelligent Merging after Moves or Renames</title>
scm> <expl>
scm> If the system keeps tracks of renames, does it support
scm> intelligent merging of the files in the history after
scm> the rename? (For example, changing a file in a renamed
scm> directory, and trying to merge it).
scm> </expl>
Here also the criterion is not completly clear. The example helps
a little, but it should perhaps be expanded a little. I don't know
also why the example is unnecessary complicated, with renaming
directory; perhaps this version is shorter to describe.
For me "Intelligent Merging after Moves or Renames" consist of the
following items: merging renames, applying change to correct file,
dealing with renamed directories, and new merge conflict types related
to renames and similar things.
Let me explain each concept with a little test case checking if given
SCM support respective feature:
* merging renames: if one side renamed file you should get rename on
merge; renaming a file and then merging that rename.
[on branch b]$ scm mv foo bar
[on branch a]$ scm commit ... # to not have fast-forward case
[on branch a]$ scm merge b
expected result> you have file 'bar', and do not have file 'foo'
* applying change to correct file: if our side renamed a file (or, as
in above example rename directory it is in, which does rename full
pathname of a file indirectly), and possibly change it, and the other
side changed file, we would want merge to bring changes to file after
rename.
[on branch a]$ scm mv foo bar
[on branch a]$ edit bar && scm commit # optionally
[on branch b]$ edit foo
[on branch b]$ scm commit -m 'FOO'
[on branch a]$ scm merge b
expected result> you have changes made on branch 'b' to file 'foo'
(commit 'FOO') in file 'bar'
Note that like in example in previous item all operations take place
_after_ branching point (after creation of branch b off branch a).
This is I guess what most people think when talking about
rename-aware (intelligent) merging.
* renamed directories bring another complication (described for example
on Mark Shuttleworth blog in articles about DVCS, promoting Bazaar-NG),
namely how to deal with merging changes where other side creates
_new files_ in renamed directory.
[on branch a]$ scm mv subdir-foo/ subdir-bar/
[on branch b]$ scm add subdir-foo/baz
[on branch a]$ scm merge b
expected result> New file subdir-bar/baz
There is a bit of controversy about this feature, as for example in
some programming languages (e.g. Java) or in some project build tool
info it is not posible to simply move a file (or create new file in
different directory) without changing file contents. Some say that
is better to fail than to do wrongly clean merge.
scm> <compare>
scm> <s id="accurev">
scm> Unknown. FILL IN.
scm> </s>
As you can see it is new criterion :-)
scm> <s id="git">
scm> No. As detailed in the <a
scm> href="http://git.or.cz/gitwiki/GitFaq#rename-tracking">Git
scm> FAQ</a>:
scm> "Git has a rename command git mv, but that is just a
scm> convenience. The effect is indistinguishable from removing
scm> the file and adding another with different name and the
scm> same content."
scm> </s>
This is of course NOT TRUE. If the author bother checking (which
would be helped if there was available simple shell script, or simple
Perl script, testing 'intelligent_renames' criterion) he/she would
notice that git does apply change to renamed file, both if file
itself is renamed, and if directory it is in gets renamed.
If I understand correctly dealing with file renames and moving files
around (one could say: refactoring directory hierarchy/structure) was
main reason (or one of main reasons) for adding rename detection to
Git. In practice it works quite well (which for the test mean testing
with large enough contents to be able to use similarity based rename
detection).
What Git _currently_ doesn't support (at least for now, with lack of
detection of directories as a whole) is with adding new files to the
renamed directory, as described a bit above.
scm> <section id="copy">
scm> <title>File and Directories Copies</title>
scm> <expl>
scm> Does the version control system support copying
scm> files or directories to a different location at the
scm> repository level, while retaining the history?
scm> </expl>
The same complaint as with the "File and Directory Moves or Renames".
What does "support copying" mean for SCM in question, in this context?
scm> <compare>
scm> <s id="git">No. Copies are not supported.</s>
scm> </compare>
To a large extent NOT TRUE. Copies _ARE_ supported in Git using the
same mechanism of similarity based detection as for renames.
There are however some caveats and limitations compared to rename
detection.
First, you have to enable copies detection. While it is not uncommon
to have rename detection turned on (I'm not sure if it is not on by
default, for example for git-show; nevertheless you can turn it on for
diffs using diff.renames configuration variable, and for example gitweb
web interface by default detects renames), it is much less common to
have copies detection turned on by default, as it is more expensive
operation.
Second, for performance reasons Git finds copies only if the original
file of the copy was modified in the same changeset. You can search
for copies in all files, but it is much more expensive operation.
On the other hand git-blame can be asked to deal with code copying,
even across files; as far as I know Git is the _only_ SCM which has
file line provenance annotation tool which supports this.
scm> <section id="repos_clone">
scm> <title>Remote Repository Replication</title>
scm> <expl>
scm> Does the system support cloning a remote repository to get
scm> a functionally equivalent copy in the local system? That
scm> should be done without any special access to the remote
scm> server except for normal repository access.
scm> </expl>
This means either that SCM in question is distributed, or that there
exists some replication / morroring tool (for centralized SCMs).
scm> <compare>
scm> <s id="bazaar">Yes.</s>
scm> <s id="darcs">Yes.</s>
scm> <s id="mercurial">Yes.</s>
scm> <s id="monotone">Yes.</s>
scm> <s id="git">Yes. This is very intrinsic feature of Git.</s>
In fact this is 'very intrinsic feature' of each distributed SCM...
well, unless one takes into account difference between single-branch
or workdir-per-branch distributed SCM and multiple-branch-per-repository
distributed SCM. Then this is a bit more complicated.
In short: I think that simple 'Yes.' answer for Git would be better.
scm> <section id="push">
scm> <title>Propagating Changes to Parent Repositories</title>
scm> <expl>
scm> Can the system propagate changes from one repository to
scm> another?
scm> </expl>
O.K.
scm> <compare>
scm> <s id="mercurial">Yes.</s>
scm> <s id="monotone">Yes.</s>
scm> <s id="git">Yes. (The Linux kernel development process uses this extremely often).</s>
scm> </compare>
scm> </section>
I'm not sure if this comment is there really necessary. I would avoid
it, especially that as far as I understand Linux kernel development
uses patch+email based system as extensively or even more extensively,
at least onlietenants level.
scm> <section id="permissions">
scm> <title>Repository Permissions</title>
scm> <expl>
scm> Is it possible to define permissions on access to different
scm> parts of a remote repository? Or is access open for all?
scm> </expl>
Side note: Karl Fogel in his book "Producing Open Source Software.
How to Run a Successful Free Software Project" (http://producingoss.com)
wrote basing on his work on _Subversion_ (which is centralized SCM),
that there are usually many advantages to use 'honor system' instead
of repository permission, i.e. use social solution than technological
solution, see "Chapter 3. Technical Infrastructure", section "Version
Control", subsection "Authorization"
http://producingoss.com/en/vc.html#vc-authz
Distributed version control systems like Git, Mercurial or Bazaar-NG
offers even wider selection of ways to implement 'honor system', and
solve "Repository Permissions" problem using social solution.
[Here would be nice to have link to discussion of "Prodicting OSS" book
on git mailing list, and to article discussion it]
scm> <compare>
scm> <s id="bazaar">
scm> Basic access control can be implemented through a
scm> contributed hook script. ACL support for the
scm> Bazaar server is planned.
scm> </s>
scm> <s id="mercurial">
scm> Yes. It is possible to lock down repositories,
scm> subdirectories, or files using hooks.
scm> </s>
scm> <s id="monotone">
scm> Yes. It is possible to restrict incoming changes
scm> from certain sources to be performed only in certain
scm> parts of the repository.
scm> </s>
[...]
scm> <s id="git">
scm> No, but a single server can serve many repositories.
scm> Also, UNIX permissions can be used to some extent.</s>
scm> </compare>
scm> </section>
Side note: why Git entry was not word-wrapped like the entries for most
other SCM, but used single long line? I have rewrapped it for better
readibility.
First, there is possible to lock down repositories, using permissions
of underlying protocols (SSH, WebDAV), or using additional tools like
Gitosis, ssh_acl or example hook contrib/hooks/update-paranoid. It
is possible to lock down (limit access to) branches and tags, which is
not mentioned as scope of this criterion, and I think is more important
feature.
Second, I think it is possible to restrict incoming changes from certain
sources to subdirectories or files using hooks; but as far as I know
there doesn't exist any such example hook.
And third, it is not as important for distributed SCM to have
fine-grained technical solution when there are many social solutions
to this problem; for example in Git when you do a pull from other
repository it would (usually) show you diffstat of changes, so you
can easily see if there were changes made outside some directory limits.
scm> <section id="changesets">
scm> <title>Changesets' Support</title>
scm> <expl>
scm> Does the repository support changesets? Changesets are a way
scm> to group a number of modifications that are relevant to each
scm> other in one atomic package, that can be cancelled or
scm> propagated as needed.
scm> </expl>
Here it is not entirely clean what creator of "Better SCM Initiative"
comparison table had on mind, what he meant by this. Not all version
control systems are changeset based; some are snapshot based. I guess
that for snapshot based SCM the above requirement is equivalent to
"Whole tree commits".
scm> <compare>
scm> <s id="cvs">No. Changes are file-specific.</s>
scm> <s id="subversion">Partial support. There are implicit
scm> changeset that are generated on each commit.
scm> </s>
scm> <s id="bazaar">
scm> Yes. Changesets are supported.
scm> </s>
scm> <s id="darcs">
scm> Yes. Changesets are supported.
scm> </s>
scm> <s id="mercurial">
scm> Yes. Changesets are supported.
scm> </s>
scm> <s id="monotone">
scm> Yes. Changesets are supported.
scm> </s>
scm> <s id="git">
scm> Yes, Changesets are supported,
scm> and there's some flexibility in creating them.
scm> </s>
scm> </compare>
scm> </section>
[Again, Git part was re-wrapped for better readibility]
In my opition, such an _empty_ addition ("there's some flexibility in
creating them") is totally unnecessary; it adds no solid information
(what does it mean "some flexibility") and should be removed.
If it was about Git being at the heart snapshot based rather than delta
(changeset) based, then it should be reworded to make it clear
(if deemed to be necessary).
scm> <section id="annotate">
scm> <title>Tracking Line-wise File History</title>
scm> <expl>
scm> Does the version control system have an option to track the
scm> history of the file line-by-line? I.e., can it show for each line
scm> at which revision it was most recently changed, and by whom?
scm> </expl>
Here it would be nice to have example of such output, but I think
everyone knows what this criterion means in the term of SCM features.
scm> <compare>
scm> <s id="git">Yes. (git blame).</s>
scm> </compare>
Perhaps we could also add that git-blame supports (if requested)
tracking changes across code movement and code copying (crossing
file boundaries if necessary, and can ignore changes in whitespace.
And there is also "pickaxe" search, which can find deleted contents,
which is one of major limitations of usability of line-wise file
history (line provenance) annotations.
On the other hand because Git is based towards whole project history,
and not per file history, git-blame is slow. To migitate that there
is incremental blame mode used to reduce latency in graphical blame
viewers like "git gui blame", contrib/blameview, or the one in QGit.
scm> <section id="features">
scm> <title>Features</title>
scm> <section id="work_on_dir">
scm> <title>Ability to Work only on One Directory of the Repository</title>
scm> <expl>
scm> Can the version control system checkout only one directory of
scm> the repository? Or restrict the check-ins to only one
scm> directory?
scm> </expl>
This is combination of "restricted check-ins" and so called "partial
checkout", or "sparse checkout", or "narrow checkout".
scm> <compare>
scm> <s id="bazaar">For checkouts: No. For checkins: Yes.</s>
scm> <s id="darcs">
scm> It is possible to commit only a certain directory.
scm> However, one must check out the entire repository as a
scm> whole.
scm> </s>
scm> <s id="mercurial">
scm> It is possible to commit changes only in a subset of the
scm> tree. There are plans for partial checkouts.
scm> </s>
scm> <s id="monotone">
scm> It is possible to commit changes only in a subset of the
scm> tree. However, one must extract the entire tree to work
scm> on it.
scm> </s>
scm> <s id="git">
scm> No. However, commits could be restricted somewhat,
scm> see the "Repository Permissions".
scm> </s>
I think (depending of course on "Repository Permissions" part) that the
part about 'work_on_dir' for checkins should be made more clear. Note
also that for this criterion, for distributed version control systems,
one should consider difference between comitting changes (pre-commit
hook), and publishing changes (update and post-receive hook).
I would also add that "There are plans for partial checkout" (or rather
"sparse" checkouts), where "plans" for this mean "preliminary work".
Although implementing this idea seems stalled a bit. I guess that when
Git acquires ability to do sparse checkout, it would have it done
correctly (c.f. git submodules and svn:externals).
scm> <section id="tracking_uncommited_changes">
scm> <title>Tracking Uncommited Changes</title>
scm> <expl>
scm> Does the software have an ability to track the changes in the
scm> working copy that were not yet committed to the repository?
scm> </expl>
This also should be made more clean. Does it mean for example ability
to tell which files have changed, or ability to diff working copy to
either last comitted changes, or to any revision available in repository?
scm> <compare>
scm> <s id="cvs">Yes. Using cvs diff</s>
scm> <s id="git">
scm> Yes.
"Using git diff"? The problem is with [possible] difference between
"git diff", "git diff HEAD", "git diff --cached".
scm>
scm> Also, branches are very lightweight in Git, and
scm> could be considered a kind of storage for "uncommitted"
scm> code in some workflows.
scm> </s>
I'm not sure if it is worth mentioning here _explicit_ staging area
(index) available in Git.
BTW. it would be nice if "git gui", the Git GUI distributed with Git,
had some graphical diff (and diff3) view tool.
scm> <section id="per_file_commit_messages">
scm> <title>Per-File Commit Messages</title>
scm> <expl>
scm> Does the system have a way to assign a per-file commit message
scm> to the changeset, as well as a per-changeset message?
scm> </expl>
scm> <compare>
scm> <s id="git">No. Commit messages are per changeset.</s>
scm> </compare>
scm> </section>
scm> </section>
O.K.
By the way, does anybody know what happened to the 'commit annotations',
aka 'notes' idea?
scm> <section id="technical_status">
scm> <title>Technical Status</title>
scm> <section id="documentation">
scm> <title>Documentation</title>
scm> <expl>
scm> How well is the system documented? How easy is it to
scm> get started using it?
scm> </expl>
scm> <compare>
scm> <s id="git">
scm> Medium. The short help is too terse and obscure.
scm> The man pages are extensive, but tend to be confusing.
scm> The are many tutorials.
scm> </s>
scm> </compare>
scm> </section>
That of course depends on your opinion. I would say "Good", now that
there is "Git User's Manual" distributed with Git, and now that there
started semi-official "Git Community Book" (http://book.git-scm.com).
[Perhaps we could use some survey results do defend that fact.]
scm> <section id="ease_of_deployment">
scm> <title>Ease of Deployment</title>
scm> <expl>
scm> How easy is it to deploy the software? What are
scm> the dependencies and how can they be satisfied?
scm> </expl>
scm> <compare>
scm> <s id="git">
scm> Good. Binary packages are available
scm> for modern platforms. C compiler and Perl are
scm> required. Requires Cygwin on Windows, and has some
scm> UNIXisms.
scm> </s>
scm> </compare>
On one hand there are are still a few important Git commands like
git-am (for patch+email based workflows), git-bisect, git-pull,
git-rebase[1], git-stash and internal parts of git-merge[2] which do
require POSIX shell, and what is inherent in shell scripting some core
utilities like grep, sed, cat; also for some workflows ssh is needed.
This is gets reduced bit by bit due to builtinification efforts.
On the other hand thanks to msysGit project Git does not require Cygwin
to be installed on MS Windows.
I would also remove "has some UNIXisms" which doesn't bring IMVHO
any information.
[1] This I hope would change thanks to builtin git-sequencer from GSoC
(or rather post-GSoC work).
[2] This I hope would change thanks to post-GSoC expansion on
builtin git-merge
scm> <section id="command_set">
scm> <title>Command Set</title>
scm> <expl>
scm> What is the command set? How compatible is it with
scm> the commands of CVS (the current open-source defacto
scm> standard)?
scm> </expl>
Sidenote: I'm not sure if CVS is still "defacto standard"; additionally
distributed SCM have enable vastly different workflows, so it is hard
to compare their command set to that of CVS, and such comparison covers
only subset of DSCM commands.
scm> <compare>
scm> <s id="subversion">
scm> A CVS-like command set which is easy to get used to
scm> for CVS-users.
scm> </s>
scm> <s id="bitkeeper">
scm> A CVS-like command set with some easy-to-get-used-to
scm> complications due to its different way of work and
scm> philosophy.
scm> </s>
scm> <s id="bazaar">
scm> <s id="mercurial">
scm> <s id="monotone">
scm> Tries to follow CVS conventions, but deviates
scm> where there is a different design.
scm> </s>
scm> <s id="perforce">
scm> Very extensive but not compatible with CVS.
scm> </s>
scm> <s id="git">
scm> Command set is very feature-rich,
scm> and not compatible with CVS.
scm> </s>
I wouldn't say that situation with Git is different from situation with
Mercurial, Bazaar-NG and Monotone, especially with respect to subset of
commands which have equivalents in CVS. Although Git doesn't "try to
follow CVS conventions", it does follow BitKeeper convention, then by
transitive also CVS conventions. I would agree with "feature-rich"
comment, though ;-)
scm> <section id="networking">
scm> <title>Networking Support</title>
scm> <expl>
scm> How good is the networking integration of the system?
scm> How compliant is it with existing protocols and infra-structure?
scm> </expl>
scm> <compare>
scm> <s id="bazaar">
scm> Excellent. Works natively over HTTP (read-only),
scm> FTP and SFTP without having Bazaar installed at
scm> the remote end. Works over HTTP, SSH and a custom
scm> protocol when talking to a remote Bazaar
scm> server. Supports RSYNC and WebDAV (experimental)
scm> through plugins.
scm> </s>
scm> <s id="mercurial">
scm> Excellent. Uses HTTP or ssh. Remote access also
scm> works safely without locks over read-only network
scm> filesystems.
scm> </s>
scm> <s id="git">
scm> Excellent. Can use native Git protocol,
scm> but works over rsync, ssh, HTTP and HTTPS also.
scm> </s>
It could be written differently, but O.K.
scm> <section id="portability">
scm> <title>Portability</title>
scm> <expl>
scm> How portable is the version-control system to various
scm> operating systems, computer architectures, and other
scm> types of systems?
scm> </expl>
scm> <compare>
scm> <s id="git">
scm> The client works on most UNIXes, but not on native
scm> MS-Windows. The Cygwin build seems to be workable, though.
scm> </s>
scm> </compare>
scm> </section>
scm> </section>
"Most UNIXes" (or is it Unices)? On what modern UNIX Git doesn't work?
Again, the author of of entries for Git doesn't seem to know about
msysGit project, which is native MS Windows implementation (utilizing
MSYS / MinGW). And what does "Cygwin build _seems_ to be workable"
mean?
The entry for Git lacks also single word descriptions, like "Excellent",
"Very good", "Good", "Medium", that most other SCM have in this part
(and "Windows only" for some).
scm> <section id="user_interaces">
scm> <title>User Interfaces</title>
scm> <section id="web_interface">
scm> <title>Web Interface</title>
scm> <expl>
scm> Does the system have a WWW-based interface that can be
scm> used to browse the tree and the various revisions of the
scm> files, perform arbitrary diffs, etc?
scm> </expl>
scm> <compare>
scm> <s id="git">
scm> Yes. Gitweb is included in distribution.
scm> </s>
scm> </compare>
scm> </section>
For other SCMs there are listed many different web interfaces.
So I would perhaps put here a list, like in
http://git.or.cz/gitwiki/InterfacesFrontendsAndTools#head-e5a6762d6aed31c5a2034d52c1733ead46402c31
(There is slight problem with Gitweb, which has neither homepage nor
separate repository; we can use Gitweb page on Git Wiki, or README
from git.git repository via gitweb ;-).
scm> <section id="availability_of_guis">
scm> <title>Availability of Graphical User-Interfaces.</title>
scm> <expl>
scm> What is the availability of graphical user-interfaces for
scm> the system? How many GUI clients are present for it?
scm> </expl>
scm> <compare>
scm> <s id="git">
scm> Gitk is included in distribution.
scm> QGit and Git-gui tools are also available.
scm> </s>
scm> </compare>
scm> </section>
scm> </section>
git-gui is _also_ included in distribution. So I would say:
<s id="git">
Gitk and git-gui are included in distribution.
<a href="[1]">Other tools</a> are also available.
</s>
[1] http://git.or.cz/gitwiki/InterfacesFrontendsAndTools#head-cee25e252efc24b245482fe9fa8d24ff5d5af1d6
scm> <section id="license">
scm> <title>License</title>
scm> <expl>
scm> What are the licensing terms for the software?
scm> </expl>
scm> <compare>
scm> <s id="git">GNU GPL v2 (open source).</s>
scm> </compare>
O.K.
--
Jakub Narebski
Poland
^ permalink raw reply
* Re: [PATCH] Start conforming code to "git subcmd" style part 3
From: Thomas Rast @ 2008-09-13 17:08 UTC (permalink / raw)
To: Heikki Orsila
Cc: git, Junio C Hamano, Jakub Narebski, Christian Couder,
Andreas Ericsson
In-Reply-To: <20080913163058.GA5108@zakalwe.fi>
[-- Attachment #1: Type: text/plain, Size: 901 bytes --]
Heikki Orsila wrote:
> diff --git a/builtin-tar-tree.c b/builtin-tar-tree.c
> index cb7007e..edcf72a 100644
> --- a/builtin-tar-tree.c
> +++ b/builtin-tar-tree.c
> @@ -9,19 +9,19 @@
>
> static const char tar_tree_usage[] =
> "git tar-tree [--remote=<repo>] <tree-ish> [basedir]\n"
> -"*** Note that this command is now deprecated; use git-archive instead.";
> +"*** Note that this command is now deprecated; use \"git archive\" instead.";
>
> int cmd_tar_tree(int argc, const char **argv, const char *prefix)
> {
> /*
> - * git-tar-tree is now a wrapper around git-archive --format=tar
> + * "git tar-tree" is now a wrapper around "git archive" --format=tar
> *
> * $0 --remote=<repo> arg... ==>
I think the quotes should go one further to the right:
+ * "git tar-tree" is now a wrapper around "git archive --format=tar"
The rest looks fine.
- Thomas
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 197 bytes --]
^ permalink raw reply
* Re: [PATCH] Start conforming code to "git subcmd" style part 3
From: Heikki Orsila @ 2008-09-13 17:13 UTC (permalink / raw)
To: Thomas Rast
Cc: git, Junio C Hamano, Jakub Narebski, Christian Couder,
Andreas Ericsson
In-Reply-To: <200809131908.34145.trast@student.ethz.ch>
On Sat, Sep 13, 2008 at 07:08:31PM +0200, Thomas Rast wrote:
> I think the quotes should go one further to the right:
> + * "git tar-tree" is now a wrapper around "git archive --format=tar"
Ah yes, thanks. Will resubmit.
--
Heikki Orsila
heikki.orsila@iki.fi
http://www.iki.fi/shd
^ permalink raw reply
* [PATCH] Start conforming code to "git subcmd" style part 3
From: Heikki Orsila @ 2008-09-13 17:18 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Jakub Narebski, Christian Couder,
Andreas Ericsson, Thomas Rast
User notifications are presented as 'git cmd', and code comments
are presented as '"cmd"' or 'git's cmd', rather than 'git-cmd'.
Signed-off-by: Heikki Orsila <heikki.orsila@iki.fi>
---
Part 3 resent. A small fix from Thomas Rast for builtin-tar-tree.c.
builtin-init-db.c | 2 +-
builtin-pack-objects.c | 4 ++--
builtin-read-tree.c | 2 +-
builtin-rev-list.c | 2 +-
builtin-rm.c | 2 +-
builtin-send-pack.c | 2 +-
builtin-tar-tree.c | 14 +++++++-------
builtin-unpack-objects.c | 2 +-
builtin-update-index.c | 8 ++++----
9 files changed, 19 insertions(+), 19 deletions(-)
diff --git a/builtin-init-db.c b/builtin-init-db.c
index baf0d09..8140c12 100644
--- a/builtin-init-db.c
+++ b/builtin-init-db.c
@@ -37,7 +37,7 @@ static void copy_templates_1(char *path, int baselen,
/* Note: if ".git/hooks" file exists in the repository being
* re-initialized, /etc/core-git/templates/hooks/update would
- * cause git-init to fail here. I think this is sane but
+ * cause "git init" to fail here. I think this is sane but
* it means that the set of templates we ship by default, along
* with the way the namespace under .git/ is organized, should
* be really carefully chosen.
diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c
index ba2cf00..217fd49 100644
--- a/builtin-pack-objects.c
+++ b/builtin-pack-objects.c
@@ -23,7 +23,7 @@
#endif
static const char pack_usage[] = "\
-git-pack-objects [{ -q | --progress | --all-progress }] \n\
+git pack-objects [{ -q | --progress | --all-progress }] \n\
[--max-pack-size=N] [--local] [--incremental] \n\
[--window=N] [--window-memory=N] [--depth=N] \n\
[--no-reuse-delta] [--no-reuse-object] [--delta-base-offset] \n\
@@ -1872,7 +1872,7 @@ static void mark_in_pack_object(struct object *object, struct packed_git *p, str
/*
* Compare the objects in the offset order, in order to emulate the
- * "git-rev-list --objects" output that produced the pack originally.
+ * "git rev-list --objects" output that produced the pack originally.
*/
static int ofscmp(const void *a_, const void *b_)
{
diff --git a/builtin-read-tree.c b/builtin-read-tree.c
index dddc304..ac219ac 100644
--- a/builtin-read-tree.c
+++ b/builtin-read-tree.c
@@ -64,7 +64,7 @@ static void prime_cache_tree(void)
}
-static const char read_tree_usage[] = "git-read-tree (<sha> | [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] [--exclude-per-directory=<gitignore>] [--index-output=<file>] <sha1> [<sha2> [<sha3>]])";
+static const char read_tree_usage[] = "git read-tree (<sha> | [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] [--exclude-per-directory=<gitignore>] [--index-output=<file>] <sha1> [<sha2> [<sha3>]])";
static struct lock_file lock_file;
diff --git a/builtin-rev-list.c b/builtin-rev-list.c
index c023003..facaff2 100644
--- a/builtin-rev-list.c
+++ b/builtin-rev-list.c
@@ -178,7 +178,7 @@ static void finish_object(struct object_array_entry *p)
static void show_object(struct object_array_entry *p)
{
/* An object with name "foo\n0000000..." can be used to
- * confuse downstream git-pack-objects very badly.
+ * confuse downstream "git pack-objects" very badly.
*/
const char *ep = strchr(p->name, '\n');
diff --git a/builtin-rm.c b/builtin-rm.c
index 6bd8211..fdac34f 100644
--- a/builtin-rm.c
+++ b/builtin-rm.c
@@ -104,7 +104,7 @@ static int check_local_mod(unsigned char *head, int index_only)
"from both the file and the HEAD\n"
"(use -f to force removal)", name);
else if (!index_only) {
- /* It's not dangerous to git-rm --cached a
+ /* It's not dangerous to "git rm --cached" a
* file if the index matches the file or the
* HEAD, since it means the deleted content is
* still available somewhere.
diff --git a/builtin-send-pack.c b/builtin-send-pack.c
index 7588d22..2af9f29 100644
--- a/builtin-send-pack.c
+++ b/builtin-send-pack.c
@@ -43,7 +43,7 @@ static int pack_objects(int fd, struct ref *refs)
po.out = fd;
po.git_cmd = 1;
if (start_command(&po))
- die("git-pack-objects failed (%s)", strerror(errno));
+ die("git pack-objects failed (%s)", strerror(errno));
/*
* We feed the pack-objects we just spawned with revision
diff --git a/builtin-tar-tree.c b/builtin-tar-tree.c
index cb7007e..419a69b 100644
--- a/builtin-tar-tree.c
+++ b/builtin-tar-tree.c
@@ -9,19 +9,19 @@
static const char tar_tree_usage[] =
"git tar-tree [--remote=<repo>] <tree-ish> [basedir]\n"
-"*** Note that this command is now deprecated; use git-archive instead.";
+"*** Note that this command is now deprecated; use \"git archive\" instead.";
int cmd_tar_tree(int argc, const char **argv, const char *prefix)
{
/*
- * git-tar-tree is now a wrapper around git-archive --format=tar
+ * "git tar-tree" is now a wrapper around "git archive --format=tar"
*
* $0 --remote=<repo> arg... ==>
- * git-archive --format=tar --remote=<repo> arg...
+ * git archive --format=tar --remote=<repo> arg...
* $0 tree-ish ==>
- * git-archive --format=tar tree-ish
+ * git archive --format=tar tree-ish
* $0 tree-ish basedir ==>
- * git-archive --format-tar --prefix=basedir tree-ish
+ * git archive --format-tar --prefix=basedir tree-ish
*/
int i;
const char **nargv = xcalloc(sizeof(*nargv), argc + 2);
@@ -53,8 +53,8 @@ int cmd_tar_tree(int argc, const char **argv, const char *prefix)
nargv[nargc] = NULL;
fprintf(stderr,
- "*** git-tar-tree is now deprecated.\n"
- "*** Running git-archive instead.\n***");
+ "*** \"git tar-tree\" is now deprecated.\n"
+ "*** Running \"git archive\" instead.\n***");
for (i = 0; i < nargc; i++) {
fputc(' ', stderr);
sq_quote_print(stderr, nargv[i]);
diff --git a/builtin-unpack-objects.c b/builtin-unpack-objects.c
index a891866..40b20f2 100644
--- a/builtin-unpack-objects.c
+++ b/builtin-unpack-objects.c
@@ -13,7 +13,7 @@
#include "fsck.h"
static int dry_run, quiet, recover, has_errors, strict;
-static const char unpack_usage[] = "git-unpack-objects [-n] [-q] [-r] [--strict] < pack-file";
+static const char unpack_usage[] = "git unpack-objects [-n] [-q] [-r] [--strict] < pack-file";
/* We always read in 4kB chunks. */
static unsigned char buffer[4096];
diff --git a/builtin-update-index.c b/builtin-update-index.c
index ce83224..417f972 100644
--- a/builtin-update-index.c
+++ b/builtin-update-index.c
@@ -14,7 +14,7 @@
* Default to not allowing changes to the list of files. The
* tool doesn't actually care, but this makes it harder to add
* files to the revision control by mistake by doing something
- * like "git-update-index *" and suddenly having all the object
+ * like "git update-index *" and suddenly having all the object
* files be revision controlled.
*/
static int allow_add;
@@ -313,18 +313,18 @@ static void read_index_info(int line_termination)
/* This reads lines formatted in one of three formats:
*
* (1) mode SP sha1 TAB path
- * The first format is what "git-apply --index-info"
+ * The first format is what "git apply --index-info"
* reports, and used to reconstruct a partial tree
* that is used for phony merge base tree when falling
* back on 3-way merge.
*
* (2) mode SP type SP sha1 TAB path
- * The second format is to stuff git-ls-tree output
+ * The second format is to stuff "git ls-tree" output
* into the index file.
*
* (3) mode SP sha1 SP stage TAB path
* This format is to put higher order stages into the
- * index file and matches git-ls-files --stage output.
+ * index file and matches "git ls-files --stage" output.
*/
errno = 0;
ul = strtoul(buf.buf, &ptr, 8);
--
1.6.0.1
^ permalink raw reply related
* Re: CGit and repository list
From: Petr Baudis @ 2008-09-13 19:49 UTC (permalink / raw)
To: Lars Hjemli; +Cc: Johan Herland, git, Jakub Narebski, Kristian H??gsberg
In-Reply-To: <8c5c35580809121620x2de1828cq498b3709f7b0bd1b@mail.gmail.com>
On Sat, Sep 13, 2008 at 01:20:50AM +0200, Lars Hjemli wrote:
> I guess I could add support for something like
>
> scan-paths=/pub/git
>
> in cgitrc (and optionally store the result of the scan as another
> cgitrc-file in the cache directory). Would that improve things for
> you?
Yes, certainly.
> > Unfortunately, the recommended RewriteRule is not working - it does not
> > play well together with query parameters cgit is using, so e.g. browsing
> > past commits does not work. What RewriteRule should I use instead?
>
> On hjemli.net I used to specify "virtual-root=/git" in cgitrc combined
> with this rule in /etc/apache/httpd.conf
>
> RewriteRule ^/git/(.*)$ /cgit/cgit.cgi?url=$1 [L,QSA]
Ah, I see - sorry. I forgot the [L,QSA] part.
I wonder why
http://repo.or.cz/c/libc.git/
has such a funny-looking summary page.
Let me know if you want me to update cgit there sometime. In the next
days I will add some means for switching between cgit and gitweb views.
P.S.: Johan - I discovered the cause of my problems - .strip() is
totally inappropriate string method to call here, it takes a _set_ of
characters.
--
Petr "Pasky" Baudis
The next generation of interesting software will be done
on the Macintosh, not the IBM PC. -- Bill Gates
^ permalink raw reply
* Re: CGit and repository list
From: Lars Hjemli @ 2008-09-13 20:02 UTC (permalink / raw)
To: Petr Baudis; +Cc: Johan Herland, git, Jakub Narebski, Kristian H??gsberg
In-Reply-To: <20080913194938.GI10360@machine.or.cz>
On Sat, Sep 13, 2008 at 9:49 PM, Petr Baudis <pasky@suse.cz> wrote:
> On Sat, Sep 13, 2008 at 01:20:50AM +0200, Lars Hjemli wrote:
>> I guess I could add support for something like
>>
>> scan-paths=/pub/git
>>
>> in cgitrc (and optionally store the result of the scan as another
>> cgitrc-file in the cache directory). Would that improve things for
>> you?
>
> Yes, certainly.
Ok, I'll try to come up with something.
> I wonder why
>
> http://repo.or.cz/c/libc.git/
>
> has such a funny-looking summary page.
I suppose you mean http://repo.or.cz/c/glibc.git/? It looks like cgit
dies when trying to process the tags in this repo. I'll clone it and
see if I can reproduce/fix the problem.
> Let me know if you want me to update cgit there sometime. In the next
> days I will add some means for switching between cgit and gitweb views.
Cool, I'll keep you posted ;-)
--
larsh
^ permalink raw reply
* Re: Git User's Survey 2008 partial summary, part 5 - other SCM
From: david @ 2008-09-13 21:11 UTC (permalink / raw)
To: Jakub Narebski; +Cc: git
In-Reply-To: <200809121244.59067.jnareb@gmail.com>
On Fri, 12 Sep 2008, Jakub Narebski wrote:
> On Fri, 12 Sep 2008 00:51, david@lang.hm wrote:
>> On Thu, 11 Sep 2008, Jakub Narebski wrote:
>>
> True, I have forgot that "I use this SCM" (or "I used this SCM") doesn't
> necessarily mean that one _choose_ this SCM. One can use some SCM
> because it is SCM project uses, or because their company requires it;
> but not necessary, as git-svn and git-p4 show one can use Git, and
> make it interact with respectively Subversion and Perforce, and trying
> to make it look like one uses this other SCM.
I would expect people to still count those as using the other SCM. git-svn
and git-p4 can do a lot, but they don't do everything, once in a while I
would expect to need to use the native commands for the upstream SCM
>> I find it interesting that the number of people who use git and the other
>> DVCS systems in so small. Is this becouse the 'market share' of those
>> other systems is small? Or becouse people who learn git aren't willing to
>> put up with other systems (or vice-versa)? Or is there some other trend
>> or tendancy that makes people who select one DVCS more likely to work on
>> similar projects, so people interested in those types of projects will
>> generally just see a single DVCS system
>
> I don't think 59% (in the example case of using currently Subversion)
> is small. Take into account for example that there are people who (as
> seen from responses to other questions in this survey) use SCM (Git)
> only to track their private work, never publishing. Then there are
> people who do not track (perhaps with exception of web interfaces)
> other projects development using version control systems, even if they
> do follow their development.
Subversion is not a Distributed SCM. I am pointing out the much smaller
overlap between distributed SCM systems.
David Lang
^ permalink raw reply
* externals program, way to do svn:externals-like subproject management without git-submodule
From: Miles Georgi @ 2008-09-13 21:17 UTC (permalink / raw)
To: git
I recently wrote a program called externals to make it more simple for
me to manage/deploy subprojects in my ruby on rails apps. The problem
was that my projects had a bunch of subprojects, some of which were in
svn some in git, and when it came to deploying/managing these
subprojects it was kind of a pain in the neck. Also, I wasn't fully
satisfied with git-submodule. I'm assuming that several people on
this list prefer the git-submodule workflow over svn:externals, but
for me, I find myself performing a lot of extra steps that were
unnecessary when working with svn:externals. I've found the code I
wrote to be really useful so I cleaned it up a bit and released it to
the public as the externals project. It provides an SCM agnostic way
of managing subprojects with an svn:externals-like workflow.
I posted this on the rails list a week ago (though it can certainly be
used in non-rails applications (it does require ruby to be installed,
and is best installed via rubygems)) I didn't get any feedback at
all which was kind of dissapointing. I decided to mention it here to
see if I can get any feedback.
I have a tutorial demonstrating how to use ext here:
http://nopugs.com/ext-tutorial
Any feedback is greatly appreciated
Miles
^ permalink raw reply
* Re: Git User's Survey 2008 partial summary, part 5 - other SCM
From: Jakub Narebski @ 2008-09-13 22:03 UTC (permalink / raw)
To: David Lang; +Cc: git
In-Reply-To: <alpine.DEB.1.10.0809131408010.17867@asgard.lang.hm>
On Sat, 13 Sep 2008, David Lang wrote:
> On Fri, 12 Sep 2008, Jakub Narebski wrote:
>> On Fri, 12 Sep 2008 00:51, david@lang.hm wrote:
>>> On Thu, 11 Sep 2008, Jakub Narebski wrote:
>>>
>> True, I have forgot that "I use this SCM" (or "I used this SCM") doesn't
>> necessarily mean that one _choose_ this SCM. One can use some SCM
>> because it is SCM project uses, or because their company requires it;
>> but not necessary, as git-svn and git-p4 show one can use Git, and
>> make it interact with respectively Subversion and Perforce, and trying
>> to make it look like one uses this other SCM.
>
> I would expect people to still count those as using the other SCM. git-svn
> and git-p4 can do a lot, but they don't do everything, once in a while I
> would expect to need to use the native commands for the upstream SCM
Well, you can check it by analysing correlations between answers.
Unfortunately there is no way to share raw data beside me generating it
and sending, or you registering at Survs.com and me adding you as admin,
but you can emulate it using existing (just created) filters on
"Analyze" page for Git User's Survey 2008:
http://www.survs.com/shareResults?survey=M3PIVU72&rndm=OKJQ45LAG8
http://tinyurl.com/GitSurvey2008Analyze
For example if you chose filter 'publish to git-svn', which select all
replies that have answered question 25.: how do you publish and checked
git-svn option, you can see that among those responders 6 of 555 (1%)
selected that they _never_ used Subversion.
>>> I find it interesting that the number of people who use git and the other
>>> DVCS systems in so small. Is this becouse the 'market share' of those
>>> other systems is small? Or becouse people who learn git aren't willing to
>>> put up with other systems (or vice-versa)? Or is there some other trend
>>> or tendancy that makes people who select one DVCS more likely to work on
>>> similar projects, so people interested in those types of projects will
>>> generally just see a single DVCS system
>>
>> I don't think 59% (in the example case of using currently Subversion)
>> is small. Take into account for example that there are people who (as
>> seen from responses to other questions in this survey) use SCM (Git)
>> only to track their private work, never publishing. Then there are
>> people who do not track (perhaps with exception of web interfaces)
>> other projects development using version control systems, even if they
>> do follow their development.
>
> Subversion is not a Distributed SCM. I am pointing out the much smaller
> overlap between distributed SCM systems.
Oh, now I understand and agree with what you noticed: in "I use" most
you get for distributed SCM is 9%, most in "used it" is 19% (hmmm...
is it really small?).
First, from various nonscientific researches (Ohloh stack count, Debian
popcon, counting well-known projects using given SCM; Google search
trends do not count) it looks like Git has biggest market share from
distributed version control systems (Subversion has larger share, but
it is centralized). So one would expect at most
<share of SCM>/<share of Git>*100%
as a percentage for sum of "I used it" and "I use it" columns, or at
least for "I use it" answer.
Second, one usually choose single SCM for his/her projects. And one
usually interacts (for example tracks) projects which use the same SCM;
kernel folks use Git (and kernel-related projects migrate to Git too,
take for example ALSA project), people who work more on Windows (Mozilla)
and have product competing with Linux (OpenSolaris) ;-) use Mercurial,
Ruby and RoR people moved to Git, Ubuntu / Canonical use Bazaar-NG.
Third different SCM have slightly different UI, and different underlying
models. If you use one, usually you find other SCM concept and commands
unintuitive (and of course vice versa).
But that is just speculation...
--
Jakub Narebski
Poland
^ permalink raw reply
* Re: externals program, way to do svn:externals-like subproject management without git-submodule
From: Avery Pennarun @ 2008-09-13 22:17 UTC (permalink / raw)
To: Miles Georgi; +Cc: git
In-Reply-To: <853238710809131417v3818955sed4c0d3dd411a540@mail.gmail.com>
On Sat, Sep 13, 2008 at 5:17 PM, Miles Georgi <azimux@gmail.com> wrote:
> I posted this on the rails list a week ago (though it can certainly be
> used in non-rails applications (it does require ruby to be installed,
> and is best installed via rubygems)) I didn't get any feedback at
> all which was kind of dissapointing. I decided to mention it here to
> see if I can get any feedback.
>
> I have a tutorial demonstrating how to use ext here:
> http://nopugs.com/ext-tutorial
Hi Miles,
Well, you asked for feedback :)
I myself have found that git-submodule doesn't really do it for me
either. Someday, like you, I was planning to break down and write a
replacement that works more like how I want. I haven't done that, and
now here you are, with a replacement that's *more* like what I want,
but not quite. With that in mind, here is an assortment of
suggestions that I myself have been too lazy to implement.
(The suggestions are based on the tutorial you posted. I haven't
tried ext itself yet.)
1. 'ext export' is not a good name for what it does. It doesn't
actually export anything. It's putting files *into* your working set!
Worse, 'cvs export' for example does something totally different.
'ext qcheckout' (for "quick") or 'ext shallow' (because it makes
shallow clones) might be better names.
2. Your ini file is not quite in ini format. To feel "normal", all
lines should be either [section] lines or key=value lines. It's worth
having your ini-looking files really be ini-like partly because there
are existing tools for parsing/creating those files in any language,
and partly because humans get confused if they don't see what they
expect. Section lines should also have a preceding blank line rather
than one following, though maybe that's just a side effect of your
blog software.
3. The ini file breaks things into sections based on scm, rather than
based on folder. This is restrictive in multiple ways: you can't
define *options* per-scm because the per-scm section is already used
for lists of folders. And you can't define options per-folder because
there is no section to put them into. I'd recommend an ini structure
more like this:
$ cat .externals
[main]
scm = git
layout = rails
[vendor/rails]
url = git://github.com/rails/rails.git
scm = git
[vendor/plugins/acts_as_list]
url = git://github.com/rails/acts_as_list.git
scm = git
[vendor/plugins/foreign_key_migrations]
url = svn://rubyforge.org/var/svn/redhillonrails/trunk/vendor/plugins/foreign_key_migrations
scm = svn
[vendor/plugins/redhillonrails_core]
url = svn://rubyforge.org/var/svn/redhillonrails/trunk/vendor/plugins/redhillonrails_core
scm = svn
Note that it's longer this way, but much more extensible and it's
pretty obvious what it means just by looking at it. Also, most of the
"scm=" lines are actually redundant: externals should be able to
auto-detect them anyhow. In the [main] section, the scm in question
is obvious, because if you can read the .externals file, you know
which scm it is. In the other sections, the URL method: string will
(most of the time) reveal the scm type. For ones where it doesn't,
like http:, then you could supply scm= or default to the same scm as
[main].
4. The built-in rails directory layout support makes me nervous and is
decidedly non-obvious. As a Rails developer, presumably I know that
when I check out (magic url string) that it should to into (magic path
string), and I can supply both. I'd rather not supply just one and
*hope* that the ext program knows wtf I want. In my own case, I'm not
even a Rails developer, so I'm even more nervous.
5. There is no reason to use the ext command to create new subtrees
anyway. Why not let me check out the subtrees for the first time
however I might normally do it (git clone, svn co, etc) and *then*
tell ext to "take a look and write down what I just did"? It saves you
teaching people new command line syntax. Plus I can do a trial run
without touching the ext command, and if it works, I can just say
"great, save these settings" by typing something like "ext save".
6. What about .externals files inside nested projects? I (really do)
have a project that uses a git-submodule called myproj, and *that*
project contains a directory called mylib (ie. myproj/mylib). I would
expect to have a main .externals file and a myproj/.externals file.
If I call ext from the toplevel, I'd expect it to be smart enough to
see both files and do something sane.
7. I really appreciate git-submodule's ability to lock to a specific
commit, although apparently you don't like this. The reason it's
valuable is for consistency: whenever I check out my project, the unit
tests should *always* pass. But if I automatically get the very
latest version of some subproject, they might break my tests, which is
highly annoying. Sometimes we want to get the latest version of
everything (which svn:externals and current ext makes easy and
git-submodule makes hard). But other times, we just want to get a
precisely accurate historical version, which git-submodule makes easy
but ext makes hard. This would actually be pretty easy for you to
implement if we use the new ini file layout above: just add an
*optional* entry in each section called "revision =". In svn, it's a
revision number; in git, it's a commit id. Also, as you correctly
observed, git-submodule's tendency to check things out on a
disconnected HEAD is horrible and error prone. A "branch =" ini
variable would solve that right away (defaulting to 'master' if not
provided), and also let you tell 'git clone' which branch to checkout
in the first place, which is not actually obvious. You could
auto-record these variables as part of "ext save", and auto-grab the
latest in a new "ext latest" command. ("ext update" is not a good
name, as updating does different things on different scms, while
"latest" is unambiguous).
8. Branch switching. If I switch my main project from one branch to
another using git (and yes, I do this very frequently!) I need my
submodules to keep working properly. git-submodule fails
spectacularly at this: 'git submodule init' writes stuff into my
.git/config file, which isn't per-branch, even though .gitmodules is,
but .gitmodules is ignored (except for *new* submodules) after the
first init. It also never auto-unregisters submodules when they
disappear from .gitmodules, and totally can't handle a submodule that
moves from one place to another in the local repo. svn:externals is
differently, but about equally, awful; it goes on wild deletion sprees
when it's in a bad mood. Pretty much anything remotely sane you do
here will beat any existing implementation I know of. Key feature:
don't *delete* submodule dirs when I switch to a branch that doesn't
need them, but stash them away somewhere and bring them back when I
switch back - remembering that when you go to bring them back, we may
want a different revision, branch, and directory name, but it still
makes sense to start with the version we had before.
9. Ordering of 'git push' operations. Currently with git-submodule
it's easy to check something into a subproject, commit the new gitlink
into the parent project, and then push the parent project, while
forgetting to push the subproject back where it came from. If ext
could enforce this somehow (eg. have a 'recursive push' sort of
operation that does innermost first) it would be awesome.
10. Self hosting. Because ext isn't included with any scm, if I use
it in my project I have an extra dependency that people need in order
to build it, and not everybody has 'gem'. It would be great if ext
could drop itself into a subdir of my project and manage updating
itself to the latest version automatically when I ask. Sadly, I guess
it can't itself be a submodule because of the chicken-and-egg problem
:)
I look forward to hearing from you tomorrow when all my suggestions
are implemented :)
But seriously, I don't mind helping out with a few of these if you
like the sound of these ideas. I don't have a tonne of time, but the
correct working of submodules is very important to me, and I'm
suffering a lot at work from the lack of it, so alleviating suffering
== worth my time.
Have fun,
Avery
^ permalink raw reply
* Re: externals program, way to do svn:externals-like subproject management without git-submodule
From: Miles Georgi @ 2008-09-14 3:57 UTC (permalink / raw)
To: git
In-Reply-To: <32541b130809131517k6d1e5e4dsc5f72d54c7e71e55@mail.gmail.com>
Wow! Thanks for the extremely thorough reply.
I'll just answer by numbers, I hope it's not too inconvenient to have
to scroll between emails to see which point I'm talking about :/
1. Oh, I'm not really aware of what "cvs export" does. I assumed it
meant something very similar to "svn export" Running "ext export URL"
on a project manage by subversion with all the subprojects managed by
subversion simply runs "svn export URL" followed by an "svn export"
for each subproject, hence the name. Calling it "shallow" makes sense
for git since I'm using --depth 1, but since "svn export" doesn't
create the .svn directories necessary to make it a working directory,
I don't really know if I would call that shallow. For git's
implementation of export, I was thinking of just doing a clone and
then deleting .git/ which also wouldn't be shallow.
2. Agreed. I wasn't really sure what proper ini format is. I mostly
just superficially mimicked the .git/config format. I had considered
XML but thought it was way too verbose, and considered YAML but it
seemed awkward. I would definitely be happy to change the format to
comply with whatever defines a valid ini file.
3. I am also bothered by the inconsistency of the meaning of [main]
and [git/svn] along with everything you pointed out.
Question? Is it okay to have "/" characters in the ini section name?
I'm assuming it is otherwise you wouldn't have recommended the format
that you did. I wonder if it would be okay to just put the repository
as the section name. That way scm and path could be excluded for
situations where the defaults are sufficient. Although I guess this
would have the implication of changing a projects repository
(something that happens way more frequently than changing the path
it's installed to) some what messy since it's being identified by its
repository.
That's an interesting idea having the subprojects default to the same
SCM as the main project.
4. Using the default paths is optional. In rails applications, 99%
of the time if a subproject is called rails, it is intended by the
developer to belong in vendor/rails, otherwise, 99% of the time it's a
plugin. Rails developers actually got kind of used to using
svn:externals to install plugins because the plugin install script has
a -x option that uses svn:externals. But let's say you have something
you want in the lib directory, you could do:
ext install some://repository/urlsomelib lib/somelib
and it will not put it in vendor/plugins. Rails developers tend to
automatically re-factor code that they intend to use in another
project into a plugin. This is always what I do since plugins are as
easy to make as putting a subproject in lib/ (or elsewhere.)
But yeah, if this feature makes somebody nervous, they can just always
explicitly give the path (which they'll have to do if it's not a rails
app.) It also detects that it's a rails app so it will complain if
you leave the path off in a non-rails app. It won't try to put
something in vendor/plugins of a non-rails app just because a path is
missing.
5. Yeah that's a good idea. I could create a command that adds an
existing subproject to the .externals and updates the ignore properly.
To get this effect at the moment, one would manually add the
subproject to .externals and run "ext update_ignore" I personally
don't usually find myself doing this though. I almost always want the
subproject to be added to the project. I need to make an "ext
uninstall" for backing out if you don't like it. I personally would
rather manually remove the item from .externals than have to issue two
commands to install it. But your idea of a save command is very
powerful, especially with the branch switching ideas you have in #8
below.
6. Hey that's a pretty interesting idea! I hadn't even thought about
that as I have not yet personally encountered that use case. I've
been hoping that rails plugins could have their own vendor/plugins
directory because if they did I would also use something like that all
the time. This is definitely something that should be implemented at
some point.
7. Agreed (for the most part.) I almost never want to do this for my
own projects as I almost always want the branch tip no matter what.
I'd rather run tests and discover that something has broke before
deploying than have to go to all my projects and advance the commit
manually.
However, for large projects that are not written by me, this would be
useful. For example, rails and engines are 2 projects that frequently
break my code. If I blindly deploy an application with the rails
master branch as a subproject after about a month, there's probably a
15% chance it won't function properly (or at all.) the way I
currently have been handling this is by having my own rails repository
at git://github.com/azimux/rails.git that I occaisionally will merge
rails/rails.git with and run tests for my larger applications. If I
like how it behaves I push the merged tip back out to azimux/rails.git
which is what all my projects reference in their .externals file.
I like your idea of a revision= and branch= syntax for the externals
file instead of the syntax I've been using. I also like your idea of
using unambiguous comands like "latest" And I would definitely not
have it disconnected from a branch if it can be avoided. I guess it
would checkout a specific commit but be on a branch, and then if the
developer needed to edit the subproject, they would realize it was
non-fastforward when they pushed and then do a rebase against the
current tip? I'm not 100% sure how this workflow would normally occur
as I've not yet had to rebase anything, and when I was using
git-submodule, I would always checkout a branch tip if I had to edit
the subproject and then would do a git add submodule/path to point at
the new commit when I was done.
8. Oh yes, I feel your pain on this one. I guess there would need to
be a combination of something like "ext switch" if you really want it
switched at the main project level for everybody, or maybe have "ext
save" be smart enough to detect a branch has been switched for
situations where the developer is trying to switch it for good from
the main project level. The implementation of this probably requires
some more thinking but it's definitely very useful if implemented.
9. I wasn't planning on having any sort of commit/push-type features
since the workflows of the SCMs are different when it comes to
commiting/pushing. For example, if it's a subversion project it needs
to do an "svn commit" requiring a log message. And sometimes I really
only want to push a subset of the subprojects that I've modified.
Maybe what I could do is have "ext status" also see if a subproject
could be pushed and issue a warning like "<subproject> has commits
that are missing from <remote name>. Did you forget to push?" This
would be unnecessary for subversion managed subprojects as if it's up
to date, then it's pushed and vice versa, but for git it would be very
helpful for when the status is empty due to commits being performed,
but is not yet pushed out to it's origin. I don't know if I would
like it automatically doing the pushing though, but it could be
doable, maybe with a command with the name "git" in it to specify it's
scm specific, like "ext gitpush" or I could just have an "ext push"
that does nothing for svn/cvs projects.
10. That's an interesting idea but I'm not sure it would be worth the
effort to implement. I would still need to require ruby to be
installed (unless I rewrote it), and then the user would need to
manage the local ext for each project. The chicken/egg thing actually
kinda works out though. You could do "git clone blah/blah.git"
followed by "cd blah; ./ext co" When I deploy I do something similar
with an after_update hook since the deployment software I'm using
doesn't know anything about ext... yet :)
I truely appreciate all the ideas and criticisms. I definitely intend
to implement some your ideas, probably starting with restructuring the
ini file. I should probably start by using a 3rd party ini file
parser instead of the parser I wrote. That would get me on track to
changing the format and changing the format is something that should
probably be done first before people start using it and expecting
backwards compatibility.
Thanks again Avery
Miles
On Sat, Sep 13, 2008 at 3:17 PM, Avery Pennarun <apenwarr@gmail.com> wrote:
> On Sat, Sep 13, 2008 at 5:17 PM, Miles Georgi <azimux@gmail.com> wrote:
>> I posted this on the rails list a week ago (though it can certainly be
>> used in non-rails applications (it does require ruby to be installed,
>> and is best installed via rubygems)) I didn't get any feedback at
>> all which was kind of dissapointing. I decided to mention it here to
>> see if I can get any feedback.
>>
>> I have a tutorial demonstrating how to use ext here:
>> http://nopugs.com/ext-tutorial
>
> Hi Miles,
>
> Well, you asked for feedback :)
>
> I myself have found that git-submodule doesn't really do it for me
> either. Someday, like you, I was planning to break down and write a
> replacement that works more like how I want. I haven't done that, and
> now here you are, with a replacement that's *more* like what I want,
> but not quite. With that in mind, here is an assortment of
> suggestions that I myself have been too lazy to implement.
>
> (The suggestions are based on the tutorial you posted. I haven't
> tried ext itself yet.)
>
> 1. 'ext export' is not a good name for what it does. It doesn't
> actually export anything. It's putting files *into* your working set!
> Worse, 'cvs export' for example does something totally different.
> 'ext qcheckout' (for "quick") or 'ext shallow' (because it makes
> shallow clones) might be better names.
>
> 2. Your ini file is not quite in ini format. To feel "normal", all
> lines should be either [section] lines or key=value lines. It's worth
> having your ini-looking files really be ini-like partly because there
> are existing tools for parsing/creating those files in any language,
> and partly because humans get confused if they don't see what they
> expect. Section lines should also have a preceding blank line rather
> than one following, though maybe that's just a side effect of your
> blog software.
>
> 3. The ini file breaks things into sections based on scm, rather than
> based on folder. This is restrictive in multiple ways: you can't
> define *options* per-scm because the per-scm section is already used
> for lists of folders. And you can't define options per-folder because
> there is no section to put them into. I'd recommend an ini structure
> more like this:
>
> $ cat .externals
>
> [main]
> scm = git
> layout = rails
>
> [vendor/rails]
> url = git://github.com/rails/rails.git
> scm = git
>
> [vendor/plugins/acts_as_list]
> url = git://github.com/rails/acts_as_list.git
> scm = git
>
> [vendor/plugins/foreign_key_migrations]
> url = svn://rubyforge.org/var/svn/redhillonrails/trunk/vendor/plugins/foreign_key_migrations
> scm = svn
>
> [vendor/plugins/redhillonrails_core]
> url = svn://rubyforge.org/var/svn/redhillonrails/trunk/vendor/plugins/redhillonrails_core
> scm = svn
>
> Note that it's longer this way, but much more extensible and it's
> pretty obvious what it means just by looking at it. Also, most of the
> "scm=" lines are actually redundant: externals should be able to
> auto-detect them anyhow. In the [main] section, the scm in question
> is obvious, because if you can read the .externals file, you know
> which scm it is. In the other sections, the URL method: string will
> (most of the time) reveal the scm type. For ones where it doesn't,
> like http:, then you could supply scm= or default to the same scm as
> [main].
>
> 4. The built-in rails directory layout support makes me nervous and is
> decidedly non-obvious. As a Rails developer, presumably I know that
> when I check out (magic url string) that it should to into (magic path
> string), and I can supply both. I'd rather not supply just one and
> *hope* that the ext program knows wtf I want. In my own case, I'm not
> even a Rails developer, so I'm even more nervous.
>
> 5. There is no reason to use the ext command to create new subtrees
> anyway. Why not let me check out the subtrees for the first time
> however I might normally do it (git clone, svn co, etc) and *then*
> tell ext to "take a look and write down what I just did"? It saves you
> teaching people new command line syntax. Plus I can do a trial run
> without touching the ext command, and if it works, I can just say
> "great, save these settings" by typing something like "ext save".
>
> 6. What about .externals files inside nested projects? I (really do)
> have a project that uses a git-submodule called myproj, and *that*
> project contains a directory called mylib (ie. myproj/mylib). I would
> expect to have a main .externals file and a myproj/.externals file.
> If I call ext from the toplevel, I'd expect it to be smart enough to
> see both files and do something sane.
>
> 7. I really appreciate git-submodule's ability to lock to a specific
> commit, although apparently you don't like this. The reason it's
> valuable is for consistency: whenever I check out my project, the unit
> tests should *always* pass. But if I automatically get the very
> latest version of some subproject, they might break my tests, which is
> highly annoying. Sometimes we want to get the latest version of
> everything (which svn:externals and current ext makes easy and
> git-submodule makes hard). But other times, we just want to get a
> precisely accurate historical version, which git-submodule makes easy
> but ext makes hard. This would actually be pretty easy for you to
> implement if we use the new ini file layout above: just add an
> *optional* entry in each section called "revision =". In svn, it's a
> revision number; in git, it's a commit id. Also, as you correctly
> observed, git-submodule's tendency to check things out on a
> disconnected HEAD is horrible and error prone. A "branch =" ini
> variable would solve that right away (defaulting to 'master' if not
> provided), and also let you tell 'git clone' which branch to checkout
> in the first place, which is not actually obvious. You could
> auto-record these variables as part of "ext save", and auto-grab the
> latest in a new "ext latest" command. ("ext update" is not a good
> name, as updating does different things on different scms, while
> "latest" is unambiguous).
>
> 8. Branch switching. If I switch my main project from one branch to
> another using git (and yes, I do this very frequently!) I need my
> submodules to keep working properly. git-submodule fails
> spectacularly at this: 'git submodule init' writes stuff into my
> .git/config file, which isn't per-branch, even though .gitmodules is,
> but .gitmodules is ignored (except for *new* submodules) after the
> first init. It also never auto-unregisters submodules when they
> disappear from .gitmodules, and totally can't handle a submodule that
> moves from one place to another in the local repo. svn:externals is
> differently, but about equally, awful; it goes on wild deletion sprees
> when it's in a bad mood. Pretty much anything remotely sane you do
> here will beat any existing implementation I know of. Key feature:
> don't *delete* submodule dirs when I switch to a branch that doesn't
> need them, but stash them away somewhere and bring them back when I
> switch back - remembering that when you go to bring them back, we may
> want a different revision, branch, and directory name, but it still
> makes sense to start with the version we had before.
>
> 9. Ordering of 'git push' operations. Currently with git-submodule
> it's easy to check something into a subproject, commit the new gitlink
> into the parent project, and then push the parent project, while
> forgetting to push the subproject back where it came from. If ext
> could enforce this somehow (eg. have a 'recursive push' sort of
> operation that does innermost first) it would be awesome.
>
> 10. Self hosting. Because ext isn't included with any scm, if I use
> it in my project I have an extra dependency that people need in order
> to build it, and not everybody has 'gem'. It would be great if ext
> could drop itself into a subdir of my project and manage updating
> itself to the latest version automatically when I ask. Sadly, I guess
> it can't itself be a submodule because of the chicken-and-egg problem
> :)
>
> I look forward to hearing from you tomorrow when all my suggestions
> are implemented :)
>
> But seriously, I don't mind helping out with a few of these if you
> like the sound of these ideas. I don't have a tonne of time, but the
> correct working of submodules is very important to me, and I'm
> suffering a lot at work from the lack of it, so alleviating suffering
> == worth my time.
>
> Have fun,
>
> Avery
>
^ permalink raw reply
* Re: externals program, way to do svn:externals-like subproject management without git-submodule
From: Avery Pennarun @ 2008-09-14 4:21 UTC (permalink / raw)
To: Miles Georgi, Git List
In-Reply-To: <32541b130809132001s5eb79752y9d3a716490ae6c91@mail.gmail.com>
On Sat, Sep 13, 2008 at 9:06 PM, Miles Georgi <azimux@gmail.com> wrote:
> I'll just answer by numbers, I hope it's not too inconvenient to have
> to scroll between emails to see which point I'm talking about :/
In general, it's better to use inline quoting. It's okay if the
quotes get long, because long messages are manageable, but messages
that require you to look at *other* messages at the same time are just
a PITA. Luckily, however, I at least remember what we're talking
about :)
> 1. Oh, I'm not really aware of what "cvs export" does. I assumed it
> meant something very similar to "svn export" Running "ext export URL"
> on a project manage by subversion with all the subprojects managed by
> subversion simply runs "svn export URL" followed by an "svn export"
> for each subproject, hence the name. Calling it "shallow" makes sense
> for git since I'm using --depth 1, but since "svn export" doesn't
> create the .svn directories necessary to make it a working directory,
> I don't really know if I would call that shallow. For git's
> implementation of export, I was thinking of just doing a clone and
> then deleting .git/ which also wouldn't be shallow.
Aha, sorry. In that case, it does do exactly what cvs export and svn
export do, so I take it back. I would never use it (because I always
deploy my .git directories along with the app itself... free
backups!). But the name is correct.
> 3. I am also bothered by the inconsistency of the meaning of [main]
> and [git/svn] along with everything you pointed out.
>
> Question? Is it okay to have "/" characters in the ini section name?
Yes. In general, a section name can have anything except a ] in it,
and a key can have anything but an = in it. (Well, obviously we
should expect that there are no CR, LF, or NUL characters either.)
If you want to do it exactly like git, you would name your sections like
[ext "libs/my/plugin"]
instead of my earlier suggestion of
[libs/my/plugin]
This would be compatible with git-config. Also, this method means
that the [main] section could never be confused with a particular ext
section.
> I wonder if it would be okay to just put the repository
> as the section name. That way scm and path could be excluded for
> situations where the defaults are sufficient. Although I guess this
> would have the implication of changing a projects repository
> (something that happens way more frequently than changing the path
> it's installed to) some what messy since it's being identified by its
> repository.
I think you answered your own question there :) Personally, it feels
natural to me to index a submodule by its local path, and have the URL
be an attribute of that submodule, rather than the other way around.
This makes sense since every local path can only have one submodule on
it, while in insane situations, you can imagine having exactly the
same repo (perhaps different revisions or branches?) cloned into two
different locations.
> But yeah, if this feature makes somebody nervous, they can just always
> explicitly give the path (which they'll have to do if it's not a rails
> app.) It also detects that it's a rails app so it will complain if
> you leave the path off in a non-rails app. It won't try to put
> something in vendor/plugins of a non-rails app just because a path is
> missing.
Okay, if it's not in rails mode, I guess it won't cause problems... as
long as the rails auto-detection is extremely reliable and can be
turned off somehow.
> 5. Yeah that's a good idea. I could create a command that adds an
> existing subproject to the .externals and updates the ignore properly.
> To get this effect at the moment, one would manually add the
> subproject to .externals and run "ext update_ignore" I personally
> don't usually find myself doing this though. I almost always want the
> subproject to be added to the project. I need to make an "ext
> uninstall" for backing out if you don't like it. I personally would
> rather manually remove the item from .externals than have to issue two
> commands to install it. But your idea of a save command is very
> powerful, especially with the branch switching ideas you have in #8
> below.
Right, it wouldn't matter which way you did it, but the other options
below fit really nicely into a 'git save' operation.
Also, I personally think it's more elegant to not have to do "undo"
operations as a normal part of your workflow. Checkout work work work
save seems nicer to me than Checkout uninstall work work work.
[nested submodules]
> 6. Hey that's a pretty interesting idea! I hadn't even thought about
> that as I have not yet personally encountered that use case. I've
> been hoping that rails plugins could have their own vendor/plugins
> directory because if they did I would also use something like that all
> the time. This is definitely something that should be implemented at
> some point.
Well, like I said, I'm doing it right now in one of my projects :)
But it doesn't have to be a high priority.
> 7. Agreed (for the most part.) I almost never want to do this for my
> own projects as I almost always want the branch tip no matter what.
> I'd rather run tests and discover that something has broke before
> deploying than have to go to all my projects and advance the commit
> manually.
Ouch, I would never want to do it that way! If my app has been
deployed for three months and someone reports a minor bug, I just want
to fix that one bug and redeploy safely and immediately. I certainly
don't want to risk breaking everything by upgrading a bunch of
unrelated modules.
> the way I
> currently have been handling this is by having my own rails repository
> at git://github.com/azimux/rails.git that I occaisionally will merge
> rails/rails.git with and run tests for my larger applications. If I
> like how it behaves I push the merged tip back out to azimux/rails.git
> which is what all my projects reference in their .externals file.
This sounds like a convoluted way of just doing what I suggested. :)
Oh, that reminds me of another feature that would be awesome:
*alternate* repository URLs. In your example above, let's say you've
made some rails customizations, anyone cloning your project will have
to get your version. But one day, the rails developers merge in your
changes, so now their primary repo (probably with more bandwidth,
uptime, etc) will work again. If the ext lists *all* the repositories
you might need, ext can just git fetch from all of them, then checkout
the commit in question, and it will always work.
> And I would definitely not
> have it disconnected from a branch if it can be avoided. I guess it
> would checkout a specific commit but be on a branch, and then if the
> developer needed to edit the subproject, they would realize it was
> non-fastforward when they pushed and then do a rebase against the
> current tip? I'm not 100% sure how this workflow would normally occur
> as I've not yet had to rebase anything, and when I was using
> git-submodule, I would always checkout a branch tip if I had to edit
> the subproject and then would do a git add submodule/path to point at
> the new commit when I was done.
It can be simpler than that. Essentially, what you do is:
git fetch origin
git checkout COMMITID
git branch -D BRANCHNAME
git checkout -b BRANCHNAME
The first checkout puts you on a disconnected HEAD temporarily, just
in case you were previously on a branch called BRANCHNAME, which would
have prevented the "delete branch" operation from working. Then we
delete the branch, and recreate it at the new location (COMMITID).
With that in place, git will know how to do everything else
automatically, but it's up to the user. You can pull/merge the latest
changes from another branch, or rebase, etc.
Note that as a safety measure, you probably want to refuse to actually
do the above if either of:
a) The git filesystem or index shows uncommitted files
b) The current git commit != the commit ext thinks is checked out right now.
> 9. I wasn't planning on having any sort of commit/push-type features
> since the workflows of the SCMs are different when it comes to
> commiting/pushing. For example, if it's a subversion project it needs
> to do an "svn commit" requiring a log message. And sometimes I really
> only want to push a subset of the subprojects that I've modified.
I think it would be really cool if ext could just figure this out.
For example, it's easy to tell that in svn, your changes have to be
committed (ie. no dirty tree) and in git, the upstream repo needs to
contain your commitid (it's been pushed).
If you only want to push a subset of projects, that's fine, but you
can do it in the individual subdirs by hand anyhow. On the other
hand, I'd say you *don't* want to ever push the parent repo without
first pushing all your changes, particularly if you have the commitid
encoded in the .externals file, or you'll produce an un-checkout-able
repository.
> Maybe what I could do is have "ext status" also see if a subproject
> could be pushed and issue a warning like "<subproject> has commits
> that are missing from <remote name>. Did you forget to push?" This
> would be unnecessary for subversion managed subprojects as if it's up
> to date, then it's pushed and vice versa, but for git it would be very
> helpful for when the status is empty due to commits being performed,
> but is not yet pushed out to it's origin.
Yes, that would be almost as good.
> I don't know if I would
> like it automatically doing the pushing though, but it could be
> doable, maybe with a command with the name "git" in it to specify it's
> scm specific, like "ext gitpush" or I could just have an "ext push"
> that does nothing for svn/cvs projects.
I don't think it should do nothing for svn/cvs projects: it should
either help you commit, or abort with a helpful message if your repo
is dirty, or something like that.
Hope this helps.
Have fun,
Avery
^ permalink raw reply
* Re: [StGit PATCH] Do not crash if a patch log ref is missing
From: Karl Hasselström @ 2008-09-14 8:08 UTC (permalink / raw)
To: Catalin Marinas; +Cc: git
In-Reply-To: <20080912215449.10270.38860.stgit@localhost.localdomain>
On 2008-09-12 22:54:58 +0100, Catalin Marinas wrote:
> Since we'll get rid of the individual patch logs, StGit should
> ignore if such a ref is missing when deleting the compatibility
> patch files.
I agree this is a good idea from a robustness perspective. Did you
encounter a case where the deletion actually failed?
--
Karl Hasselström, kha@treskal.com
www.treskal.com/kalle
^ permalink raw reply
* [CGIT PATCH] parsing.c: handle unexpected commit/tag content
From: Lars Hjemli @ 2008-09-14 7:53 UTC (permalink / raw)
To: pasky; +Cc: git, Lars Hjemli
In-Reply-To: <8c5c35580809131302w1f51f4ebsede59eb2ae36a99c@mail.gmail.com>
Signed-off-by: Lars Hjemli <hjemli@gmail.com>
---
Can you test this on top of the current master? It seems to fix the problems
with glibc.git.
cgit.h | 2 +-
parsing.c | 108 +++++++++++++++++++++++++++++++++++++++---------------------
2 files changed, 71 insertions(+), 39 deletions(-)
diff --git a/cgit.h b/cgit.h
index 1615616..08fd95a 100644
--- a/cgit.h
+++ b/cgit.h
@@ -85,7 +85,7 @@ struct commitinfo {
struct taginfo {
char *tagger;
char *tagger_email;
- int tagger_date;
+ unsigned long tagger_date;
char *msg;
};
diff --git a/parsing.c b/parsing.c
index 66e8b3d..0396133 100644
--- a/parsing.c
+++ b/parsing.c
@@ -62,6 +62,40 @@ char *substr(const char *head, const char *tail)
return buf;
}
+char *parse_user(char *t, char **name, char **email, unsigned long *date)
+{
+ char *p = t;
+ int mode = 1;
+
+ while (p && *p) {
+ if (mode == 1 && *p == '<') {
+ *name = substr(t, p - 1);
+ t = p;
+ mode++;
+ } else if (mode == 1 && *p == '\n') {
+ *name = substr(t, p);
+ p++;
+ break;
+ } else if (mode == 2 && *p == '>') {
+ *email = substr(t, p + 1);
+ t = p;
+ mode++;
+ } else if (mode == 2 && *p == '\n') {
+ *email = substr(t, p);
+ p++;
+ break;
+ } else if (mode == 3 && isdigit(*p)) {
+ *date = atol(p);
+ mode++;
+ } else if (*p == '\n') {
+ p++;
+ break;
+ }
+ p++;
+ }
+ return p;
+}
+
struct commitinfo *cgit_parse_commit(struct commit *commit)
{
struct commitinfo *ret;
@@ -88,29 +122,17 @@ struct commitinfo *cgit_parse_commit(struct commit *commit)
while (!strncmp(p, "parent ", 7))
p += 48; // "parent " + hex[40] + "\n"
- if (!strncmp(p, "author ", 7)) {
- p += 7;
- t = strchr(p, '<') - 1;
- ret->author = substr(p, t);
- p = t;
- t = strchr(t, '>') + 1;
- ret->author_email = substr(p, t);
- ret->author_date = atol(t+1);
- p = strchr(t, '\n') + 1;
+ if (p && !strncmp(p, "author ", 7)) {
+ p = parse_user(p + 7, &ret->author, &ret->author_email,
+ &ret->author_date);
}
- if (!strncmp(p, "committer ", 9)) {
- p += 9;
- t = strchr(p, '<') - 1;
- ret->committer = substr(p, t);
- p = t;
- t = strchr(t, '>') + 1;
- ret->committer_email = substr(p, t);
- ret->committer_date = atol(t+1);
- p = strchr(t, '\n') + 1;
+ if (p && !strncmp(p, "committer ", 9)) {
+ p = parse_user(p + 9, &ret->committer, &ret->committer_email,
+ &ret->committer_date);
}
- if (!strncmp(p, "encoding ", 9)) {
+ if (p && !strncmp(p, "encoding ", 9)) {
p += 9;
t = strchr(p, '\n') + 1;
ret->msg_encoding = substr(p, t);
@@ -118,25 +140,38 @@ struct commitinfo *cgit_parse_commit(struct commit *commit)
} else
ret->msg_encoding = xstrdup(PAGE_ENCODING);
- while (*p && (*p != '\n'))
- p = strchr(p, '\n') + 1; // skip unknown header fields
+ // skip unknown header fields
+ while (p && *p && (*p != '\n')) {
+ p = strchr(p, '\n');
+ if (p)
+ p++;
+ }
- while (*p == '\n')
- p = strchr(p, '\n') + 1;
+ // skip extra blank lines between headers and message body
+ while (p && *p == '\n') {
+ p = strchr(p, '\n');
+ if (p)
+ p++;
+ }
t = strchr(p, '\n');
if (t) {
- if (*t == '\0')
+ if (*t == '\0') {
ret->subject = "** empty **";
- else
+ return ret;
+ } else {
ret->subject = substr(p, t);
- p = t + 1;
+ p = t + 1;
+ }
- while (*p == '\n')
- p = strchr(p, '\n') + 1;
+ while (p && *p == '\n') {
+ p = strchr(p, '\n');
+ if (p)
+ p++;
+ }
ret->msg = xstrdup(p);
} else
- ret->subject = substr(p, p+strlen(p));
+ ret->subject = xstrdup(p);
if(strcmp(ret->msg_encoding, PAGE_ENCODING)) {
t = reencode_string(ret->subject, PAGE_ENCODING,
@@ -163,7 +198,7 @@ struct taginfo *cgit_parse_tag(struct tag *tag)
void *data;
enum object_type type;
unsigned long size;
- char *p, *t;
+ char *p;
struct taginfo *ret;
data = read_sha1_file(tag->object.sha1, &type, &size);
@@ -185,15 +220,12 @@ struct taginfo *cgit_parse_tag(struct tag *tag)
break;
if (!strncmp(p, "tagger ", 7)) {
- p += 7;
- t = strchr(p, '<') - 1;
- ret->tagger = substr(p, t);
- p = t;
- t = strchr(t, '>') + 1;
- ret->tagger_email = substr(p, t);
- ret->tagger_date = atol(t+1);
+ p = parse_user(p + 7, &ret->tagger, &ret->tagger_email,
+ &ret->tagger_date);
}
- p = strchr(p, '\n') + 1;
+ p = strchr(p, '\n');
+ if (p)
+ p++;
}
while (p && *p && (*p != '\n'))
--
1.6.0.rc1
^ permalink raw reply related
* Re: [StGit PATCH] Autosign newly created patches
From: Karl Hasselström @ 2008-09-14 8:37 UTC (permalink / raw)
To: Catalin Marinas; +Cc: git
In-Reply-To: <20080912215515.10270.32667.stgit@localhost.localdomain>
On 2008-09-12 22:55:56 +0100, Catalin Marinas wrote:
> This patch adds the autosign configuration variable which is checked
> by the "new" command to automatically sign the patch message.
Sounds useful. I have a sign-off command in my .emacs, but I expect
this would be useful for those who don't.
> BTW, what happened to the patchdescr.tmpl file? It doesn't seem to
> be used anymore, however one can save a template file
I don't know. I don't use it myself, so it's perfectly possible that
I've broken it without noticing, seeing as there is no test suite
coverage ...
--
Karl Hasselström, kha@treskal.com
www.treskal.com/kalle
^ permalink raw reply
* Re: [StGit PATCH] Convert "sink" to the new infrastructure
From: Karl Hasselström @ 2008-09-14 8:51 UTC (permalink / raw)
To: Catalin Marinas; +Cc: git
In-Reply-To: <20080912215613.10270.20599.stgit@localhost.localdomain>
On 2008-09-12 23:01:27 +0100, Catalin Marinas wrote:
> This patch converts the sink command to use stgit.lib. The behaviour
> is also changed slightly so that it only allows to sink a set of
> patches if there are applied once,
"if they are applied"?
> I'm not sure about the conflict resolution. In this implementation,
> if a conflict happens, the transaction is aborted. In case we allow
> conflicts, I have to dig further on how to implement it with the new
> transaction mechanism (I think "delete" does this).
goto does it too. The docstring of the StackTransaction class explains
how it works (if it doesn't, we need to improve it):
"""A stack transaction, used for making complex updates to an
StGit stack in one single operation that will either succeed or
fail cleanly.
The basic theory of operation is the following:
1. Create a transaction object.
2. Inside a::
try
...
except TransactionHalted:
pass
block, update the transaction with e.g. methods like
L{pop_patches} and L{push_patch}. This may create new git
objects such as commits, but will not write any refs; this means
that in case of a fatal error we can just walk away, no clean-up
required.
(Some operations may need to touch your index and working tree,
though. But they are cleaned up when needed.)
3. After the C{try} block -- wheher or not the setup ran to
completion or halted part-way through by raising a
L{TransactionHalted} exception -- call the transaction's L{run}
method. This will either succeed in writing the updated state to
your refs and index+worktree, or fail without having done
anything."""
Not all transaction modifications need to be protected by the try
block, only those that may actually raise TransactionHalted (i.e.
those that may conflict). Specifically, in the code below, you need to
put push_patch() in a try block. Otherwise that exception will
propagate all the way up to the top level, and you will never reach
the transaction's run() call which is where refs are updated and the
new tree checked out.
> An additional point - the transaction object supports functions like
> pop_patches and push_patch. Should we change them for consistency
> and simplicity? I.e., apart from current pop_patches with predicate
> add functions that support popping a list or a single patch. The
> same goes for push_patch.
The current set of functions made sense from an implementation
perspective. But you are right that other variants would be helpful
for some callers.
--
Karl Hasselström, kha@treskal.com
www.treskal.com/kalle
^ permalink raw reply
* Re: [CGIT PATCH] parsing.c: handle unexpected commit/tag content
From: Lars Hjemli @ 2008-09-14 8:52 UTC (permalink / raw)
To: pasky; +Cc: git, Lars Hjemli
In-Reply-To: <1221378782-26036-1-git-send-email-hjemli@gmail.com>
On Sun, Sep 14, 2008 at 9:53 AM, Lars Hjemli <hjemli@gmail.com> wrote:
> + // skip extra blank lines between headers and message body
> + while (p && *p == '\n') {
> + p = strchr(p, '\n');
> + if (p)
> + p++;
> + }
Btw, this is just silly so I've changed it:
while (p && *p == '\n')
p++;
The wip-branch at http://hjemli.net/git/cgit has a fixed-up patch.
--
larsh
^ permalink raw reply
* Re: Git User's Survey 2008 partial summary, part 5 - other SCM
From: Nguyen Thai Ngoc Duy @ 2008-09-14 10:45 UTC (permalink / raw)
To: Jakub Narebski; +Cc: git
In-Reply-To: <200809112214.18366.jnareb@gmail.com>
On 9/12/08, Jakub Narebski <jnareb@gmail.com> wrote:
> 15) Do you miss features in git that you know from other SCMs?
> If yes, what features are these (and from which SCM)?
> (Open ended text - Essay)
>
> Total respondents 1046 (some/many of them wrote 'no')
> skipped this question 1249
>
> This is just a very quick summary, based on a first few pages of
> responses, Full analysis is I think best left for after closing the
> survey, because I think this would be a lot of work...
>
> So here is preliminary list, or rather beginning of one:
> * sparse/partial checkout and clone (e.g. Perforce)
Have not read the survey result, but do you recall what is the most
used term for sparse/partial checkout? What SCMs do sparse/partial
checkout? I think it could be usable as it is now in my
will-be-sent-again series, but I don't really know how people want it
to from that.
--
Duy
^ permalink raw reply
* [PATCH 00/16] Narrow/Partial/Sparse checkout
From: Nguyễn Thái Ngọc Duy @ 2008-09-14 13:07 UTC (permalink / raw)
To: git; +Cc: Nguyễn Thái Ngọc Duy
I hope this series is now ready to be reviewed. Documentation is in
place so no more explanation here (main document is in git-checkout.txt).
The series could be splitted into:
Nguyá»
n Thái Ngá»c Duy (6):
Extend index to save more flags
Introduce CE_NO_CHECKOUT bit
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 --narrow-checkout option to "will checkout" entries
Add tests for updating no-checkout entries in index
.gitignore | 1 +
Documentation/git-ls-files.txt | 6 +++
Documentation/git-update-index.txt | 12 ++++++
Makefile | 2 +-
builtin-ls-files.c | 11 ++++++
builtin-update-index.c | 40 +++++++++++++--------
cache.h | 66 +++++++++++++++++++++++++++++++++--
read-cache.c | 57 ++++++++++++++++++++++++-------
t/t2104-update-index-narrow.sh | 36 +++++++++++++++++++
test-index-version.c | 14 ++++++++
10 files changed, 212 insertions(+), 33 deletions(-)
This adds CE_NO_CHECKOUT bit and plumbing support to manipulate it.
This bit is to mark what entry will be checked out.
Nguyá»
n Thái Ngá»c Duy (4):
Prevent diff machinery from examining worktree outside narrow checkout
checkout_entry(): CE_NO_CHECKOUT on checked out entries.
ls-files: apply --deleted on narrow area only
grep: skip files that have not been checked out
builtin-grep.c | 7 ++++++-
builtin-ls-files.c | 2 +-
diff-lib.c | 5 +++--
diff.c | 4 +++-
entry.c | 1 +
t/t2104-update-index-narrow.sh | 6 ++++++
6 files changed, 20 insertions(+), 5 deletions(-)
Various fixes to make sure it works once in this mode.
Nguyá»
n Thái Ngá»c Duy (5):
unpack_trees(): add support for narrow checkout
narrow spec: put '+' before a spec will change semantic of '*'
ls-files: add --narrow-match=spec option for testing narrow matching
clone: support narrow checkout with --path option
checkout: add new options to support narrow checkout
Documentation/git-checkout.txt | 68 ++++++++++++++++++++++++-
Documentation/git-clone.txt | 8 +++-
Documentation/git-ls-files.txt | 7 ++-
builtin-checkout.c | 44 ++++++++++++++++
builtin-clone.c | 13 +++++
builtin-ls-files.c | 14 +++++-
cache.h | 3 +
t/t2011-checkout-narrow.sh | 80 +++++++++++++++++++++++++++++
t/t3003-ls-files-narrow-match.sh | 45 ++++++++++++++++
t/t5703-clone-narrow.sh | 39 ++++++++++++++
unpack-trees.c | 105 ++++++++++++++++++++++++++++++++++++++
unpack-trees.h | 6 ++
12 files changed, 427 insertions(+), 5 deletions(-)
Support for "git checkout" and "git clone" to enter/update/leave
narrow/sparse/partial checkout.
Nguyá»
n Thái Ngá»c Duy (1):
ls-files: add --overlay option
Documentation/git-ls-files.txt | 4 ++++
builtin-ls-files.c | 16 +++++++++++++---
t/t2104-update-index-narrow.sh | 4 ++++
3 files changed, 21 insertions(+), 3 deletions(-)
Bonus stuff, not strictly needed.
^ permalink raw reply
* [PATCH 01/16] Extend index to save more flags
From: Nguyễn Thái Ngọc Duy @ 2008-09-14 13:07 UTC (permalink / raw)
To: git; +Cc: Nguyễn Thái Ngọc Duy
In-Reply-To: <1221397685-27715-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 f725783..1e572e4 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 & 0x80CFFFFF
+#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.96.g2fad1.dirty
^ permalink raw reply related
* [PATCH 02/16] Introduce CE_NO_CHECKOUT bit
From: Nguyễn Thái Ngọc Duy @ 2008-09-14 13:07 UTC (permalink / raw)
To: git; +Cc: Nguyễn Thái Ngọc Duy
In-Reply-To: <1221397685-27715-2-git-send-email-pclouds@gmail.com>
This bit is the basis of narrow checkout. If this bit is on, the entry
is outside narrow checkout and therefore should be ignored (similar
to CE_VALID)
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
cache.h | 10 +++++++++-
read-cache.c | 6 +++---
2 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/cache.h b/cache.h
index 1e572e4..2b2c90f 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.96.g2fad1.dirty
^ permalink raw reply related
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