* Re: GIT 0.99.7d, and end of week status.
From: Matthias Urlichs @ 2005-09-29 4:40 UTC (permalink / raw)
To: git
In-Reply-To: <20050927101744.GD30889@pasky.or.cz>
Hi, Petr Baudis wrote:
> However, I still think
> that the user should be required to specify the to-be-merged head manually
> if the default choice isn't explicitly written in the remotes file.
I tend to agree -- intentional octopus merges are rare enough.
For most people, anyway. ;-)
--
Matthias Urlichs | {M:U} IT Design @ m-u-it.de | smurf@smurf.noris.de
Disclaimer: The quote was selected randomly. Really. | http://smurf.noris.de
- -
It is not a good omen when goldfish commit suicide.
^ permalink raw reply
* Re: First cut at git port to Cygwin
From: Martin Langhoff @ 2005-09-29 4:46 UTC (permalink / raw)
To: H. Peter Anvin; +Cc: Git Mailing List
In-Reply-To: <433B3B10.5050407@zytor.com>
On 9/29/05, H. Peter Anvin <hpa@zytor.com> wrote:
> Another funny which I haven't been able to figure out yet is that 'gitk'
> scrunches all its output up into a few pixels at the top of the window.
> If I maximize the window, I can manually resize most of the panes and
> the output looks correct
This is visible on OSX too, and someone's mentioned it's a Tk oddity
with rootless X. Does it do the same if you run X with a root window?
> I have set up a git-on-Cygwin temporary tree at:
>
> http://www.kernel.org/pub/scm/git/git-cygwin.git
Getting a 404 on that. Doesn't show up on gitweb either. I guess I
have to wait...
Is there a way to get gitweb to "compare" branches using git-cherry? I
often look at branches via git-web and it's impossible to tell what
makes them unique...
cheers,
martin
^ permalink raw reply
* Re: Multi-head fetch proposal
From: Junio C Hamano @ 2005-09-29 4:45 UTC (permalink / raw)
To: Johannes Schindelin; +Cc: git
In-Reply-To: <Pine.LNX.4.63.0509290149540.19126@wgmdd8.biozentrum.uni-wuerzburg.de>
I was wondering why I always end up fetching 35 or so objects
when I ask master, maint and pu from my public repository, and
wanted to spend today digging on this one. Instead I ended up
wasting the day on something else (I just sent it out), but I am
glad you were looking into it.
Of course, with your patch the problem does not happen anymore.
^ permalink raw reply
* Re: First cut at git port to Cygwin
From: Junio C Hamano @ 2005-09-29 4:30 UTC (permalink / raw)
To: H. Peter Anvin; +Cc: git
In-Reply-To: <433B3B10.5050407@zytor.com>
"H. Peter Anvin" <hpa@zytor.com> writes:
> There are still funnies. In particular, Cygwin and Samba handle
> symlinks differently, so you can't trivially share a repository via
> Samba. Linus' "symbolic refs" changes should eventually take care of that.
I just sent out "The other side of Linus' symbolic refs" patch,
saying that Cygwin capable of doing symlink would probably made
it irrelevant. But it may not be a waste after all, considering
what you said above.
^ permalink raw reply
* [PATCH] Add git-symbolic-ref
From: Junio C Hamano @ 2005-09-29 4:24 UTC (permalink / raw)
To: git
This adds the counterpart of git-update-ref that lets you read
and create "symbolic refs". By default it uses a symbolic link
to represent ".git/HEAD -> refs/heads/master", but it can be
compiled to use the textfile symbolic ref. In that case, the
.git/HEAD file would typically read "ref: refs/heads/master".
The places that did 'readlink .git/HEAD' and 'ln -s
refs/heads/blah .git/HEAD' have been converted to use new
git-symbolic-ref command, so that they can deal with either
implementation.
I suspect that I ended up wasting my git day of this week
working on this, given that Cygwin seems to be capable of
emulating symlinks using .lnk files. On the other hand, even
Linux folks may be on vfat or similar fs that does not have
symlinks so who knows. On yet another hand, a project can have
symlinks stored in the repository, and in order to check things
out the filesystem needs to have symlinks anyway, so maybe this
is a big wasted effort. Mumble mumble mumble...
Signed-off-by: Junio C Hamano <junkio@cox.net>
---
Makefile | 2 +-
cache.h | 1 +
fsck-objects.c | 28 ++++++++++------------------
git-bisect.sh | 7 ++++---
git-branch.sh | 6 ++++--
git-checkout.sh | 3 ++-
git-commit.sh | 17 ++++++++---------
git-sh-setup.sh | 4 ++--
git-status.sh | 4 ++--
init-db.c | 10 +++++-----
refs.c | 46 ++++++++++++++++++++++++++++++++++++++++++++--
setup.c | 16 ++++++++++------
show-branch.c | 13 +++++++++----
symbolic-ref.c | 34 ++++++++++++++++++++++++++++++++++
t/t5400-send-pack.sh | 6 +++---
15 files changed, 139 insertions(+), 58 deletions(-)
create mode 100644 symbolic-ref.c
15de68abcb00ede12ac4b67c3f0ecac7cfffd0b4
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -116,7 +116,7 @@ PROGRAMS = \
git-ssh-upload git-tar-tree git-unpack-file \
git-unpack-objects git-update-index git-update-server-info \
git-upload-pack git-verify-pack git-write-tree \
- git-update-ref \
+ git-update-ref git-symbolic-ref \
$(SIMPLE_PROGRAMS)
# Backward compatibility -- to be removed in 0.99.8
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -231,6 +231,7 @@ extern int get_sha1_hex(const char *hex,
extern char *sha1_to_hex(const unsigned char *sha1); /* static buffer result! */
extern int read_ref(const char *filename, unsigned char *sha1);
extern const char *resolve_ref(const char *path, unsigned char *sha1);
+extern int create_symref(const char *git_HEAD, const char *refs_heads_master);
/* General helper functions */
extern void usage(const char *err) NORETURN;
diff --git a/fsck-objects.c b/fsck-objects.c
--- a/fsck-objects.c
+++ b/fsck-objects.c
@@ -402,25 +402,17 @@ static void fsck_object_dir(const char *
static int fsck_head_link(void)
{
- int fd, count;
- char hex[40];
unsigned char sha1[20];
- static char path[PATH_MAX], link[PATH_MAX];
- const char *git_dir = get_git_dir();
-
- snprintf(path, sizeof(path), "%s/HEAD", git_dir);
- if (readlink(path, link, sizeof(link)) < 0)
- return error("HEAD is not a symlink");
- if (strncmp("refs/heads/", link, 11))
- return error("HEAD points to something strange (%s)", link);
- fd = open(path, O_RDONLY);
- if (fd < 0)
- return error("HEAD: %s", strerror(errno));
- count = read(fd, hex, sizeof(hex));
- close(fd);
- if (count < 0)
- return error("HEAD: %s", strerror(errno));
- if (count < 40 || get_sha1_hex(hex, sha1))
+ const char *git_HEAD = strdup(git_path("HEAD"));
+ const char *git_refs_heads_master = resolve_ref(git_HEAD, sha1);
+ int pfxlen = strlen(git_HEAD) - 4; /* strip .../.git/ part */
+
+ if (!git_refs_heads_master)
+ return error("HEAD is not a symbolic ref");
+ if (strncmp(git_refs_heads_master + pfxlen, "refs/heads/", 11))
+ return error("HEAD points to something strange (%s)",
+ git_refs_heads_master + pfxlen);
+ if (!memcmp(null_sha1, sha1, 20))
return error("HEAD: not a valid git pointer");
return 0;
}
diff --git a/git-bisect.sh b/git-bisect.sh
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -38,7 +38,8 @@ bisect_start() {
# Verify HEAD. If we were bisecting before this, reset to the
# top-of-line master first!
#
- head=$(readlink $GIT_DIR/HEAD) || die "Bad HEAD - I need a symlink"
+ head=$(GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD) ||
+ die "Bad HEAD - I need a symbolic ref"
case "$head" in
refs/heads/bisect*)
git checkout master || exit
@@ -46,7 +47,7 @@ bisect_start() {
refs/heads/*)
;;
*)
- die "Bad HEAD - strange symlink"
+ die "Bad HEAD - strange symbolic ref"
;;
esac
@@ -135,7 +136,7 @@ bisect_next() {
echo "$rev" > "$GIT_DIR/refs/heads/new-bisect"
git checkout new-bisect || exit
mv "$GIT_DIR/refs/heads/new-bisect" "$GIT_DIR/refs/heads/bisect" &&
- ln -sf refs/heads/bisect "$GIT_DIR/HEAD"
+ GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD refs/heads/bisect
git-show-branch "$rev"
}
diff --git a/git-branch.sh b/git-branch.sh
--- a/git-branch.sh
+++ b/git-branch.sh
@@ -14,7 +14,8 @@ If two arguments, create a new branch <b
delete_branch () {
option="$1" branch_name="$2"
- headref=$(readlink "$GIT_DIR/HEAD" | sed -e 's|^refs/heads/||')
+ headref=$(GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD |
+ sed -e 's|^refs/heads/||')
case ",$headref," in
",$branch_name,")
die "Cannot delete the branch you are on." ;;
@@ -67,7 +68,8 @@ done
case "$#" in
0)
- headref=$(readlink "$GIT_DIR/HEAD" | sed -e 's|^refs/heads/||')
+ headref=$(GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD |
+ sed -e 's|^refs/heads/||')
git-rev-parse --symbolic --all |
sed -ne 's|^refs/heads/||p' |
sort |
diff --git a/git-checkout.sh b/git-checkout.sh
--- a/git-checkout.sh
+++ b/git-checkout.sh
@@ -71,7 +71,8 @@ if [ "$?" -eq 0 ]; then
echo $new > "$GIT_DIR/refs/heads/$newbranch"
branch="$newbranch"
fi
- [ "$branch" ] && ln -sf "refs/heads/$branch" "$GIT_DIR/HEAD"
+ [ "$branch" ] &&
+ GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD "refs/heads/$branch"
rm -f "$GIT_DIR/MERGE_HEAD"
else
exit 1
diff --git a/git-commit.sh b/git-commit.sh
--- a/git-commit.sh
+++ b/git-commit.sh
@@ -153,15 +153,8 @@ if [ -f "$GIT_DIR/MERGE_HEAD" ]; then
fi >>.editmsg
PARENTS="-p HEAD"
-if [ ! -r "$GIT_DIR/HEAD" ]; then
- if [ -z "$(git-ls-files)" ]; then
- echo Nothing to commit 1>&2
- exit 1
- fi
- PARENTS=""
- current=
-else
- current=$(git-rev-parse --verify HEAD)
+if GIT_DIR="$GIT_DIR" git-rev-parse --verify HEAD >/dev/null 2>&1
+then
if [ -f "$GIT_DIR/MERGE_HEAD" ]; then
PARENTS="-p HEAD "`sed -e 's/^/-p /' "$GIT_DIR/MERGE_HEAD"`
fi
@@ -194,6 +187,12 @@ else
export GIT_AUTHOR_EMAIL
export GIT_AUTHOR_DATE
fi
+else
+ if [ -z "$(git-ls-files)" ]; then
+ echo Nothing to commit 1>&2
+ exit 1
+ fi
+ PARENTS=""
fi
git-status >>.editmsg
if [ "$?" != "0" -a ! -f $GIT_DIR/MERGE_HEAD ]
diff --git a/git-sh-setup.sh b/git-sh-setup.sh
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -13,10 +13,10 @@
unset CDPATH
die() {
- echo "$@" >&2
+ echo >&2 "$@"
exit 1
}
-[ -h "$GIT_DIR/HEAD" ] &&
+GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD >/dev/null 2>&1 &&
[ -d "$GIT_DIR/refs" ] &&
[ -d "$GIT_OBJECT_DIRECTORY/00" ]
diff --git a/git-status.sh b/git-status.sh
--- a/git-status.sh
+++ b/git-status.sh
@@ -31,7 +31,7 @@ report () {
[ "$header" ]
}
-branch=`readlink "$GIT_DIR/HEAD"`
+branch=$(GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD)
case "$branch" in
refs/heads/master) ;;
*) echo "# On branch $branch" ;;
@@ -39,7 +39,7 @@ esac
git-update-index --refresh >/dev/null 2>&1
-if test -f "$GIT_DIR/HEAD"
+if GIT_DIR="$GIT_DIR" git-rev-parse --verify HEAD >/dev/null 2>&1
then
git-diff-index -M --cached HEAD |
sed 's/^://' |
diff --git a/init-db.c b/init-db.c
--- a/init-db.c
+++ b/init-db.c
@@ -166,6 +166,7 @@ static void create_default_files(const c
{
unsigned len = strlen(git_dir);
static char path[PATH_MAX];
+ unsigned char sha1[20];
if (len > sizeof(path)-50)
die("insane git directory %s", git_dir);
@@ -186,15 +187,14 @@ static void create_default_files(const c
/*
* Create the default symlink from ".git/HEAD" to the "master"
- * branch
+ * branch, if it does not exist yet.
*/
strcpy(path + len, "HEAD");
- if (symlink("refs/heads/master", path) < 0) {
- if (errno != EEXIST) {
- perror(path);
+ if (read_ref(path, sha1) < 0) {
+ if (create_symref(path, "refs/heads/master") < 0)
exit(1);
- }
}
+ path[len] = 0;
copy_templates(path, len, template_path);
}
diff --git a/refs.c b/refs.c
--- a/refs.c
+++ b/refs.c
@@ -9,6 +9,10 @@ const unsigned char null_sha1[20] = { 0,
/* We allow "recursive" symbolic refs. Only within reason, though */
#define MAXDEPTH 5
+#ifndef USE_SYMLINK_HEAD
+#define USE_SYMLINK_HEAD 1
+#endif
+
const char *resolve_ref(const char *path, unsigned char *sha1)
{
int depth = MAXDEPTH, len;
@@ -22,9 +26,14 @@ const char *resolve_ref(const char *path
if (--depth < 0)
return NULL;
- /* Special case: non-existing file */
+ /* Special case: non-existing file.
+ * But if this is the first round, i.e. the user
+ * gave us ".git/NO_SUCH_SYMLINK" which does not even
+ * exist, we should barf. ".git/HEAD" symlink which
+ * points at "refs/heads/master" not yet born is OK.
+ */
if (lstat(path, &st) < 0) {
- if (errno != ENOENT)
+ if (errno != ENOENT || depth == MAXDEPTH - 1)
return NULL;
memset(sha1, 0, 20);
return path;
@@ -67,6 +76,39 @@ const char *resolve_ref(const char *path
return path;
}
+int create_symref(const char *git_HEAD, const char *refs_heads_master)
+{
+#if USE_SYMLINK_HEAD
+ unlink(git_HEAD);
+ return symlink(refs_heads_master, git_HEAD);
+#else
+ const char *lockpath;
+ char ref[1000];
+ int fd, len, written;
+
+ len = snprintf(ref, sizeof(ref), "ref: %s\n", refs_heads_master);
+ if (sizeof(ref) <= len) {
+ error("refname too long: %s", refs_heads_master);
+ return -1;
+ }
+ lockpath = mkpath("%s.lock", git_HEAD);
+ fd = open(lockpath, O_CREAT | O_EXCL | O_WRONLY, 0666);
+ written = write(fd, ref, len);
+ close(fd);
+ if (written != len) {
+ unlink(lockpath);
+ error("Unable to write to %s", lockpath);
+ return -2;
+ }
+ if (rename(lockpath, git_HEAD) < 0) {
+ unlink(lockpath);
+ error("Unable to create %s", git_HEAD);
+ return -3;
+ }
+ return 0;
+#endif
+}
+
int read_ref(const char *filename, unsigned char *sha1)
{
if (resolve_ref(filename, sha1) && memcmp(sha1, null_sha1, 20))
diff --git a/setup.c b/setup.c
--- a/setup.c
+++ b/setup.c
@@ -76,18 +76,22 @@ const char **get_pathspec(const char *pr
* Test it it looks like we're at the top
* level git directory. We want to see a
*
- * - a HEAD symlink and a refs/ directory under ".git"
* - either a .git/objects/ directory _or_ the proper
* GIT_OBJECT_DIRECTORY environment variable
+ * - a refs/ directory under ".git"
+ * - either a HEAD symlink or a HEAD file that is formatted as
+ * a proper "ref:".
*/
static int is_toplevel_directory(void)
{
- struct stat st;
+ unsigned char sha1[20];
- return !lstat(".git/HEAD", &st) &&
- S_ISLNK(st.st_mode) &&
- !access(".git/refs/", X_OK) &&
- (getenv(DB_ENVIRONMENT) || !access(".git/objects/", X_OK));
+ if (access(".git/refs/", X_OK) ||
+ access(getenv(DB_ENVIRONMENT) ?
+ getenv(DB_ENVIRONMENT) : ".git/objects/", X_OK) ||
+ (resolve_ref(".git/HEAD", sha1) == NULL))
+ return 0;
+ return 1;
}
const char *setup_git_directory(void)
diff --git a/show-branch.c b/show-branch.c
--- a/show-branch.c
+++ b/show-branch.c
@@ -349,6 +349,7 @@ int main(int ac, char **av)
int all_heads = 0, all_tags = 0;
int all_mask, all_revs, shown_merge_point;
char head_path[128];
+ const char *head_path_p;
int head_path_len;
unsigned char head_sha1[20];
int merge_base = 0;
@@ -430,11 +431,15 @@ int main(int ac, char **av)
if (0 <= extra)
join_revs(&list, &seen, num_rev, extra);
- head_path_len = readlink(".git/HEAD", head_path, sizeof(head_path)-1);
- if ((head_path_len < 0) || get_sha1("HEAD", head_sha1))
+ head_path_p = resolve_ref(git_path("HEAD"), head_sha1);
+ if (head_path_p) {
+ head_path_len = strlen(head_path_p);
+ memcpy(head_path, head_path_p, head_path_len + 1);
+ }
+ else {
+ head_path_len = 0;
head_path[0] = 0;
- else
- head_path[head_path_len] = 0;
+ }
if (merge_base)
return show_merge_base(seen, num_rev);
diff --git a/symbolic-ref.c b/symbolic-ref.c
new file mode 100644
--- /dev/null
+++ b/symbolic-ref.c
@@ -0,0 +1,34 @@
+#include "cache.h"
+
+static const char git_symbolic_ref_usage[] =
+"git-symbolic-ref name [ref]";
+
+static void check_symref(const char *HEAD)
+{
+ unsigned char sha1[20];
+ const char *git_HEAD = strdup(git_path("%s", HEAD));
+ const char *git_refs_heads_master = resolve_ref(git_HEAD, sha1);
+ if (git_refs_heads_master) {
+ /* we want to strip the .git/ part */
+ int pfxlen = strlen(git_HEAD) - strlen(HEAD);
+ puts(git_refs_heads_master + pfxlen);
+ }
+ else
+ die("No such ref: %s", HEAD);
+}
+
+int main(int argc, const char **argv)
+{
+ setup_git_directory();
+ switch (argc) {
+ case 2:
+ check_symref(argv[1]);
+ break;
+ case 3:
+ create_symref(strdup(git_path("%s", argv[1])), argv[2]);
+ break;
+ default:
+ usage(git_symbolic_ref_usage);
+ }
+ return 0;
+}
diff --git a/t/t5400-send-pack.sh b/t/t5400-send-pack.sh
--- a/t/t5400-send-pack.sh
+++ b/t/t5400-send-pack.sh
@@ -20,12 +20,12 @@ test_expect_success setup '
commit=$(echo "Commit #$i" | git-commit-tree $tree -p $parent) &&
parent=$commit || return 1
done &&
- echo "$commit" >.git/HEAD &&
+ git-update-ref HEAD "$commit" &&
git-clone -l ./. victim &&
cd victim &&
git-log &&
cd .. &&
- echo $zero >.git/HEAD &&
+ git-update-ref HEAD "$zero" &&
parent=$zero &&
for i in $cnt
do
@@ -33,7 +33,7 @@ test_expect_success setup '
commit=$(echo "Rebase #$i" | git-commit-tree $tree -p $parent) &&
parent=$commit || return 1
done &&
- echo "$commit" >.git/HEAD &&
+ git-update-ref HEAD "$commit" &&
echo Rebase &&
git-log'
^ permalink raw reply
* Re: Edit log message after commit
From: Tony Luck @ 2005-09-29 4:17 UTC (permalink / raw)
To: Kevin Leung; +Cc: git
In-Reply-To: <dhfjcu$36f$1@sea.gmane.org>
> Is there any method to edit the log message after committed?
> I couldn't find any information in Documentation and in git mailing list.
No. Once a git object is created it is immutable (since its name is the
hash of its contents). If you realise right after you make a commit that
you want to change the message, you would have to redo it ... use
git diff or git whatchanged to get the details and the diffs, then use
git reset to backup, and re-apply.
If you have made subsequent commits, then you'll have to back those
out and redo them too.
If you have published your tree, then it's better to live with the 'bad'
commit than try to re-write history.
-Tony
^ permalink raw reply
* Re: Edit log message after commit
From: Junio C Hamano @ 2005-09-29 4:15 UTC (permalink / raw)
To: Kevin Leung; +Cc: git
In-Reply-To: <dhfjcu$36f$1@sea.gmane.org>
Kevin Leung <hysoka@gmail.com> writes:
> Is there any method to edit the log message after committed? I
> couldn't find any information in Documentation and in git
> mailing list.
Undoing and re-committing can be done with the following
recipe.
There is a *big* *red* *warning*, though. If you have already
made available the commit you are about to undo to others, and
later other people have made more commits on top of them,
merging their changes back to your repository would make the
commit history look a bit funny. You could still do this
without damaging the repository. This warning only applies to
the shape of the commit graph.
First, the easiest case. Undoing and recommitting the latest
commit in the current branch.
(1) Run "git diff HEAD" and make sure that your working tree
matches the latest commit you are about to undo. Then:
$ git reset --soft HEAD^
This leaves the working tree intact (i.e. it still has what
you to have in the commit you are "fixing").
(2) Optional. If you wanted to make changes other than commit
log, do your edit here in the working tree. When done, run
"git diff HEAD" to make sure the changes are what you want
the "fixed" commit to have.
(3) Run:
$ git commit -c ORIG_HEAD
If you made changes in (2) and have not done
"git-update-index" on them, you may want to add '-a' there.
If you are just redoing the log message you probably would
not.
This gives you the editor with the log message from the
commit you undone in step (1). Do your edit and exit the
editor as usual.
Look at the output in "gitk HEAD ORIG_HEAD" to understand what
happened. You just rewound a commit, and made a different
commit.
Harder, more cumbersome case, is when you realize that you made
a mistake a several commits ago. This is described in detail in
Documentation/howto/revert-branch-rebase. Read it.
^ permalink raw reply
* Edit log message after commit
From: Kevin Leung @ 2005-09-29 2:28 UTC (permalink / raw)
To: git
Hi,
Is there any method to edit the log message after committed? I couldn't find any information in Documentation and in git mailing list.
Regards,
Kevin Leung
^ permalink raw reply
* First cut at git port to Cygwin
From: H. Peter Anvin @ 2005-09-29 0:53 UTC (permalink / raw)
To: Git Mailing List
I have made a first cut at a git port to Cygwin. It looks like the
"git-diff-tree -p" problem has been resolved independently, or at least
I can't reproduce it on a fresh Cygwin install (running on XP Home), but
I have added support for running without the IPv6 and the getaddrinfo() API.
There are still funnies. In particular, Cygwin and Samba handle
symlinks differently, so you can't trivially share a repository via
Samba. Linus' "symbolic refs" changes should eventually take care of that.
Another funny which I haven't been able to figure out yet is that 'gitk'
scrunches all its output up into a few pixels at the top of the window.
If I maximize the window, I can manually resize most of the panes and
the output looks correct, but the highlighted text in the top panes show
up in black on a really really dark blue background and is thus illegible.
I have set up a git-on-Cygwin temporary tree at:
http://www.kernel.org/pub/scm/git/git-cygwin.git
-hpa
^ permalink raw reply
* Multi-head fetch proposal
From: Johannes Schindelin @ 2005-09-29 0:25 UTC (permalink / raw)
To: Git Mailing List
Hi,
I reported a while ago that a fetch downloaded objects which were already
in the repository. While that was true, it was not the whole truth: This
only happened with multi-head fetch.
As far as I can tell, what happened was this:
- fetch-pack connected to the server
- it asked correctly for the remote refs
- it then opened a (local) pipe to git-rev-list
- it sent quite a few refs from that pipe over the wire
- on the other side, upload-pack marked these refs as "fetcher got those"
- since upload-pack has a limit on that list (only 16) it soon said STFU
- it turned out that quite a few common refs were not yet marked
- so upload-pack would upload these
The reason is that git-rev-list would happily output parents of refs
which were already acknowledged by upload-pack to be common refs.
I just sent out a patch which makes this irrelevant for the case that most
or all of these heads are already fetched.
Now, to really solve the multi-head problem, which really is the problem
"how to find the edges of the common commits", I propose the following:
For each remote ref known to be not in the local repository, find the 1st,
2nd, 4th, 8th, ... parents. Send these to upload-pack to be marked. For
each ack'ed ref (i.e. remote side also has it), do a binary search to find
the edge (i.e. the youngest common ref) on that DAG branch.
(To ease the burden on the server side, one coul mark only the edges
as stop gaps for upload-pack. However, it might make things too
complicated.)
Of course, the trick is to do that asynchronously, so that the network
bandwidth is used optimally. This means that not each ack'ed ref
leads to a binary search, but only those refs where no descendant was
ack'ed.
BTW this does not need any change of the protocol. In fact, it only needs
a change to fetch-pack.
I'd also increase MAX_HAS in upload-pack.
Ciao,
Dscho
^ permalink raw reply
* [PATCH] fetch-pack should not ask for a ref which is already there
From: Johannes Schindelin @ 2005-09-28 23:49 UTC (permalink / raw)
To: Git Mailing List
With this patch, instead of blindly asking for every remote ref, fetch-pack
first looks in the local repository if that ref is already there.
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
---
fetch-pack.c | 30 ++++++++++++++++++++----------
1 files changed, 20 insertions(+), 10 deletions(-)
6bf41421bed0d640677c5233d2be6813b2211979
diff --git a/fetch-pack.c b/fetch-pack.c
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -16,20 +16,27 @@ static int find_common(int fd[2], unsign
int count = 0, flushes = 0, retval;
FILE *revs;
- revs = popen("git-rev-list $(git-rev-parse --all)", "r");
- if (!revs)
- die("unable to run 'git-rev-list'");
-
while (refs) {
unsigned char *remote = refs->old_sha1;
- if (verbose)
- fprintf(stderr,
- "want %s (%s)\n", sha1_to_hex(remote),
- refs->name);
- packet_write(fd[1], "want %s\n", sha1_to_hex(remote));
+ if(!has_sha1_file(remote)) {
+ if (verbose)
+ fprintf(stderr,
+ "want %s (%s)\n", sha1_to_hex(remote),
+ refs->name);
+ packet_write(fd[1], "want %s\n", sha1_to_hex(remote));
+ count++;
+ }
refs = refs->next;
}
packet_flush(fd[1]);
+
+ if(count==0)
+ return 1;
+
+ revs = popen("git-rev-list $(git-rev-parse --all)", "r");
+ if (!revs)
+ die("unable to run 'git-rev-list'");
+
flushes = 1;
retval = -1;
while (fgets(line, sizeof(line), revs) != NULL) {
@@ -86,7 +93,10 @@ static int fetch_pack(int fd[2], int nr_
packet_flush(fd[1]);
die("no matching remote head");
}
- if (find_common(fd, sha1, ref) < 0)
+ status = find_common(fd, sha1, ref);
+ if(status > 0)
+ return 0;
+ if(status < 0)
fprintf(stderr, "warning: no common commits\n");
pid = fork();
if (pid < 0)
^ permalink raw reply
* Re: [PATCH] Use git-update-ref in scripts.
From: Fredrik Kuivinen @ 2005-09-28 21:19 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Linus Torvalds, Git Mailing List, Fredrik Kuivinen
In-Reply-To: <7vek79q8jj.fsf@assigned-by-dhcp.cox.net>
On Wed, Sep 28, 2005 at 12:47:12PM -0700, Junio C Hamano wrote:
> Junio C Hamano <junkio@cox.net> writes:
>
> > Linus Torvalds <torvalds@osdl.org> writes:
> >
> >> On Wed, 28 Sep 2005, Junio C Hamano wrote:
> >>>
> >> I don't like doing the diff before-hand, but it looked like the default
> >> was to try just one strategy, and avoid the diff in that case.
> >
> > By 'diff before-hand' I take it to mean the savestate for later
> > rounds to keep the pre-merge state. You are correct that it is
> > not done in a single strategy case, and 'git pull' by default
> > would use only one of Daniel's git-merge-resolve or in the
> > multi-remote case git-merge-octopus, depending on the number of
> > heads being merged. BTW, I decided not to use diff, just in
> > case somebody has binary blob we cannot reproduce with diff and
> > patch.
>
> I see two more diffs that turns out to be problematic in
> git-merge.sh code.
>
> (1) As a safety measure I have a check to make sure the index
> is in sync with $head. This visibly hurts; on my slow disk
> and CPU with a couple of locally modified paths in the
> working tree, this check takes about a second in the kernel
> tree with hot cache.
>
> git-merge-resolve uses "git-read-tree -u -m O A B" form, so
> this is totally unnecessary. I am not so sure about
> Fredrik's git-merge-recursive (I haven't looked at it for a
> while).
>
git-merge-recursive also uses 'git-read-tree -u -m O A B' so it
shouldn't have any problems with this change.
> (2) savestate uses "git diff $head" to find out the list of
> paths that have local modifications, but the current code
> calls it after the check described above, so "git-ls-files
> -m" is enough. On a kernel tree with hot cache and index
> in sync with HEAD, "git-ls-files -m" is about 3-4 times as
> fast with a couple of locally modified files.
>
> Keeping (1) and using 'git-ls-files -m' in (2) is optimizing for
> a wrong path. On the other hand, (1) is a safety measure, and
> if it is kept (2) becomes a quite cheap operation.
>
> I am inclined to just remove the check in (1), and make it the
> responsibility of merge strategies to make sure it does not
> commit unrelated changes.
>
> Comments?
>
Looks good to me.
- Fredrik
^ permalink raw reply
* Re: More Porcelains?
From: Matthias Urlichs @ 2005-09-28 20:22 UTC (permalink / raw)
To: git
In-Reply-To: <7v64sn8hml.fsf_-_@assigned-by-dhcp.cox.net>
Hi, Junio C Hamano wrote:
> Matthias Urlichs said he is doing something with Python
Python integration needs either lots of fork+exec, a git rewrite in
Python, or a libgit reorganization in library-ized C.
I'm doing the latter, but my free time is kindof limited for now.
My library-ize branch is at
git fetch http://netz.smurf.noris.de/git/git.git libize
if anybody wants to have a look. My first goal is to get object access
working sanely (because that's what I need for my Python project).
I haven't merged up for some time, though.
--
Matthias Urlichs | {M:U} IT Design @ m-u-it.de | smurf@smurf.noris.de
Disclaimer: The quote was selected randomly. Really. | http://smurf.noris.de
- -
Paul's Law:
In America, it's not how much an item costs, it's how much you save.
^ permalink raw reply
* Re: [PATCH] Use git-update-ref in scripts.
From: Junio C Hamano @ 2005-09-28 19:47 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Git Mailing List, Fredrik Kuivinen
In-Reply-To: <7vk6h1rr9l.fsf@assigned-by-dhcp.cox.net>
Junio C Hamano <junkio@cox.net> writes:
> Linus Torvalds <torvalds@osdl.org> writes:
>
>> On Wed, 28 Sep 2005, Junio C Hamano wrote:
>>>
>> I don't like doing the diff before-hand, but it looked like the default
>> was to try just one strategy, and avoid the diff in that case.
>
> By 'diff before-hand' I take it to mean the savestate for later
> rounds to keep the pre-merge state. You are correct that it is
> not done in a single strategy case, and 'git pull' by default
> would use only one of Daniel's git-merge-resolve or in the
> multi-remote case git-merge-octopus, depending on the number of
> heads being merged. BTW, I decided not to use diff, just in
> case somebody has binary blob we cannot reproduce with diff and
> patch.
I see two more diffs that turns out to be problematic in
git-merge.sh code.
(1) As a safety measure I have a check to make sure the index
is in sync with $head. This visibly hurts; on my slow disk
and CPU with a couple of locally modified paths in the
working tree, this check takes about a second in the kernel
tree with hot cache.
git-merge-resolve uses "git-read-tree -u -m O A B" form, so
this is totally unnecessary. I am not so sure about
Fredrik's git-merge-recursive (I haven't looked at it for a
while).
(2) savestate uses "git diff $head" to find out the list of
paths that have local modifications, but the current code
calls it after the check described above, so "git-ls-files
-m" is enough. On a kernel tree with hot cache and index
in sync with HEAD, "git-ls-files -m" is about 3-4 times as
fast with a couple of locally modified files.
Keeping (1) and using 'git-ls-files -m' in (2) is optimizing for
a wrong path. On the other hand, (1) is a safety measure, and
if it is kept (2) becomes a quite cheap operation.
I am inclined to just remove the check in (1), and make it the
responsibility of merge strategies to make sure it does not
commit unrelated changes.
Comments?
^ permalink raw reply
* Re: [PATCH] Use git-update-ref in scripts.
From: Junio C Hamano @ 2005-09-28 18:28 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Git Mailing List
In-Reply-To: <Pine.LNX.4.58.0509281106370.3308@g5.osdl.org>
Linus Torvalds <torvalds@osdl.org> writes:
> In many ways, the most irritating part for me about that is that an email
> that wants to give a publically accessible part has to be something like
>
> "Please pull from
>
> rsync://rsync.kernel.org/path
>
> to get the xyz updates"
>
> and then I cut-and-paste it but have to delete the "rsync://", and replace
> the "rsync.kernel.org/" with "master.kernel.org:/".
>
> Sad.
Hopefully that would be rectified when git-daemon goes on-line,
now I've merged updates from HPA ;-).
^ permalink raw reply
* Re: [PATCH] Use git-update-ref in scripts.
From: Junio C Hamano @ 2005-09-28 18:17 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Git Mailing List
In-Reply-To: <Pine.LNX.4.58.0509281007200.3308@g5.osdl.org>
Linus Torvalds <torvalds@osdl.org> writes:
> On Wed, 28 Sep 2005, Junio C Hamano wrote:
>>
> I don't like doing the diff before-hand, but it looked like the default
> was to try just one strategy, and avoid the diff in that case.
By 'diff before-hand' I take it to mean the savestate for later
rounds to keep the pre-merge state. You are correct that it is
not done in a single strategy case, and 'git pull' by default
would use only one of Daniel's git-merge-resolve or in the
multi-remote case git-merge-octopus, depending on the number of
heads being merged. BTW, I decided not to use diff, just in
case somebody has binary blob we cannot reproduce with diff and
patch.
> Actually, my preference would be to have a unconditional simple case
> first. If there's only one possible base, and the trivial merge succeeds
> (ie no three-way merges needed at all, just a single git-read-tree), do
> that part unconditionally.
>
> That actually matches 90% of all merges I do, and I'd be much happier with
> git-merge if it did that first and if it then does something more complex
> (including diffs etc) afterwards, I'm much less likely to worry.
Hmph. That sort of makes sense but to make the unconditional
simple case really fast it should use read-tree -m -u which
_would_ smudge if things do not go well, which implies you need
savestate before that which would make it slower -- wouldn't it?
I think using Daniel's git-merge-resolve and nothing else by
default would be equivalent of having that unconditional simple
case upfront.
^ permalink raw reply
* Re: [PATCH] Use git-update-ref in scripts.
From: Linus Torvalds @ 2005-09-28 18:14 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Git Mailing List
In-Reply-To: <7v3bnpt81e.fsf@assigned-by-dhcp.cox.net>
On Wed, 28 Sep 2005, Junio C Hamano wrote:
>
> I was wondering the URL shorthand you mentioned is being used in
> practice. In theory, you do not "have to write out in full"
> anymore ;-).
Almost always, I end up cut-and-pasting the thing from an email.
In many ways, the most irritating part for me about that is that an email
that wants to give a publically accessible part has to be something like
"Please pull from
rsync://rsync.kernel.org/path
to get the xyz updates"
and then I cut-and-paste it but have to delete the "rsync://", and replace
the "rsync.kernel.org/" with "master.kernel.org:/".
Sad.
So I've actually considered a totally Linus-only hack that does that
automatically, ie something like this untested patch.. (same goes for http
too, for that matter)
Linus
diff --git a/git-parse-remote.sh b/git-parse-remote.sh
--- a/git-parse-remote.sh
+++ b/git-parse-remote.sh
@@ -32,7 +32,7 @@ get_remote_url () {
data_source=$(get_data_source "$1")
case "$data_source" in
'')
- echo "$1" ;;
+ echo "$1" | sed 's/rsync:[^/]*kernel.org/master.kernel.org:/ ;;
remotes)
sed -ne '/^URL: */{
s///p
^ permalink raw reply
* Re: index file screwed up
From: Chuck Lever @ 2005-09-28 17:43 UTC (permalink / raw)
To: Linus Torvalds; +Cc: git
In-Reply-To: <Pine.LNX.4.58.0509280831130.3308@g5.osdl.org>
[-- Attachment #1: Type: text/plain, Size: 2720 bytes --]
Linus Torvalds wrote:
>
> On Wed, 28 Sep 2005, Chuck Lever wrote:
>
>>i was working with a version of git that had a bug in add_cache_entry()
>>that introduced a sorting error in my index.
>>
>>[cel@dexter main]$ stg refresh -f
>>Refreshing patch "git-switch-branch"...AUTHORS: unmerged
>>(098c1d3e9fe5c39b859ccff6c7d36d2c193d1b62)
>>AUTHORS: unmerged (098c1d3e9fe5c39b859ccff6c7d36d2c193d1b62)
>>COPYING: unmerged (d60c31a97a544b53039088d14fe9114583c0efc3)
>>COPYING: unmerged (d60c31a97a544b53039088d14fe9114583c0efc3)
>>INSTALL: unmerged (8d2bebd9d1824f1b7af5cfe6fbd11f9cbfde6d74)
>>INSTALL: unmerged (8d2bebd9d1824f1b7af5cfe6fbd11f9cbfde6d74)
>>MANIFEST.in: unmerged (581d0be2a5fb3569b06681b7d559f1279aa4104b)
>>MANIFEST.in: unmerged (581d0be2a5fb3569b06681b7d559f1279aa4104b)
>>README: unmerged (184ded8e08cb92a14b79c79f9919469ba352ab70)
>>README: unmerged (184ded8e08cb92a14b79c79f9919469ba352ab70)
>>...
>>fatal: git-write-tree: verify_merged: not able to write tree
>>stg refresh: git-write-tree failed
>>
>>[cel@dexter main]$
>>
>>how do i recover?
>
>
> You don't. Your index is toast.
>
> Let's hope you didn't write any unsorted trees with _earlier_ (non-merge)
> commits.
well, i did get this working, but i "cheated."
first i switched back to a known good version of git. then, before i
received your advice, i replaced the damaged index file with a file
system snapshot backup from a couple of hours earlier. after a couple
of "stg refresh" commands, things seem back to normal.
it could be useful to have a few backup versions of the index file (like
index.1, index.2, etc) and have write-tree rotate them before writing
out a new index.
btw, the git version was my own, using a trie/list cache. it mostly
works, except for this little sorting bug.
> Do this:
>
> - build a new and trustworthy git somewhere else (from a tar-file if
> nothing else). Install it.
>
> - get rid of the index and any half-way data in your working tree (you
> might want to save any diffs with "git diff HEAD" first, but I suspect
> you don't really care, since the changes came from some stg stuff, so
> you can always re-create them, no?)
>
> git reset --hard HEAD
>
> - run fsck, to verify that all your trees are sorted (if they aren't, you
> be screwed, but "git-convert-objects" should be able to fix it for
> you - possibly with some additional logic).
>
> git-fsck-objects --full
>
> - restart and try again.
>
> That _should_ get you running again.
>
> Linus
> -
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
[-- Attachment #2: cel.vcf --]
[-- Type: text/x-vcard, Size: 439 bytes --]
begin:vcard
fn:Chuck Lever
n:Lever;Charles
org:Network Appliance, Incorporated;Linux NFS Client Development
adr:535 West William Street, Suite 3100;;Center for Information Technology Integration;Ann Arbor;MI;48103-4943;USA
email;internet:cel@citi.umich.edu
title:Member of Technical Staff
tel;work:+1 734 763 4415
tel;fax:+1 734 763 4434
tel;home:+1 734 668 1089
x-mozilla-html:FALSE
url:http://www.monkey.org/~cel/
version:2.1
end:vcard
^ permalink raw reply
* Re: [PATCH] Use git-update-ref in scripts.
From: Junio C Hamano @ 2005-09-28 17:29 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Git Mailing List
In-Reply-To: <Pine.LNX.4.58.0509281007200.3308@g5.osdl.org>
Linus Torvalds <torvalds@osdl.org> writes:
> Heh. My kernel has none of that. Well, it obviously has refs, but even
> there it literally has just one head: "master". The rest are the standard
> tags you see in public.
I was wondering the URL shorthand you mentioned is being used in
practice. In theory, you do not "have to write out in full"
anymore ;-).
Message-ID: <Pine.LNX.4.58.0507151529590.19183@g5.osdl.org>
From: Linus Torvalds <torvalds@osdl.org>
Date: Fri, 15 Jul 2005 15:42:42 -0700 (PDT)
And it's not necessarily just the branch handling, but more of a generic
shorthand: I'd love to be able to mix something like
git pull jgarzik/misc-2.6 upstream
and "jgarzik" would be expanded (through something like .git/branches) to
"master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/"), resulting in the
_full_ path being expanded to
master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/misc-2.6 upstream
which I have to write out in full (or, more commonly, cut-and-paste) right
now.
^ permalink raw reply
* Re: Cogito: cg-clone doesn't like packed tag objects
From: Junio C Hamano @ 2005-09-28 17:22 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Petr Baudis, Tom Prince, git
In-Reply-To: <Pine.LNX.4.58.0509271414000.3308@g5.osdl.org>
Linus Torvalds <torvalds@osdl.org> writes:
>> we could send phony entries like this:
>>
>> b92c9c07fe2d0d89c4f692573583c4753b5355d2 deref/tags/junio-gpg-pub
>> a3eb250f996bf5e12376ec88622c4ccaabf20ea8 deref/tags/v0.99
>> 78d9d414123ad6f4f522ffecbcd9e4a7562948fd deref/tags/v0.99.1
>
> Yes, it would work,..
> in general, it's just a really ugly special case, I think.
I think we could do this instead, to make it less ugly.
b92c9c07fe2d0d89c4f692573583c4753b5355d2 refs/tags/junio-gpg-pub!*
a3eb250f996bf5e12376ec88622c4ccaabf20ea8 refs/tags/v0.99^0
I am not sure what the syntax should be, but the idea is to
express the "refname" side using "extended SHA1" syntax. In the
above example, I added a postfix '!*' to mean "deref tag
zero-or-more times until you get a non-tag" ('!' to mean deref
tag once and complain if the object is not tag, '!!' is deref
twice, '!!!' is to deref three times and so on). It might be
better to spell "v0.99^0" as "v0.99!*" in this context. [*1*]
Both git-clone-pack and git-fetch-pack need to be told to ignore
funny tagnames with trailing '!*', otherwise they would ask for
the pointed-at object (which is not harmful but redundant) and
the clone would create "refs/tags/v0.99!*", a file with a funny
name. Git-peek-remote should report that, and server-info.c
should be told to prepare these extra entries for ls-remote over
other protocols.
But I tend to agree that this is really a special case needed to
support the "tagged objects are automatically followed by tags
that tag them" model, and not needed if we stay in "tag is just
a ref, and a ref is just an object name, and asking for an
object pulls in other objects that are reachable from them"
model. So it is not a very high priority for me, but I think
this is one way to help Cogito cleanly, and I am willing to see
how much damage this would cause to other parts of the core, *if*
Cogito wants to use this mechanism.
The alternative would be what Pasky outlined in his message --
bypassing git transport layer to fetch single object by hand,
repeatedly dereferencing it until he gets a non-tag. I think
that is unnecessary misery for him.
[Footnote]
*1* The difference from '^0' is that '!' does not complain on
non-commit, and can be used to peel the onion one layer at a
time. I do not know how useful the latter is in practice but
somebody may want to express chains of trust by signing tags.
^ permalink raw reply
* [PATCH] HTTP partial transfer support for object, pack, and index transfers
From: Nick Hengeveld @ 2005-09-28 17:14 UTC (permalink / raw)
To: git
HTTP partial transfer support for object, pack, and index transfers
Signed-off-by: Nick Hengeveld <nickh@reactrix.com>
---
http-fetch.c | 185 ++++++++++++++++++++++++++++++++++++++++++++++++++--------
1 files changed, 161 insertions(+), 24 deletions(-)
492f6dfd5f0e7030fe96b3646a07a9adb1a7a2d0
diff --git a/http-fetch.c b/http-fetch.c
--- a/http-fetch.c
+++ b/http-fetch.c
@@ -13,8 +13,12 @@
#define curl_global_init(a) do { /* nothing */ } while(0)
#endif
+#define PREV_BUF_SIZE 4096
+#define RANGE_HEADER_SIZE 30
+
static CURL *curl;
static struct curl_slist *no_pragma_header;
+static struct curl_slist *no_range_header;
static char *initial_base;
@@ -82,12 +86,37 @@ void prefetch(unsigned char *sha1)
{
}
+int relink_or_rename(char *old, char *new) {
+ int ret;
+
+ ret = link(old, new);
+ if (ret < 0) {
+ /* Same Coda hack as in write_sha1_file(sha1_file.c) */
+ ret = errno;
+ if (ret == EXDEV && !rename(old, new))
+ return 0;
+ }
+ unlink(old);
+ if (ret) {
+ if (ret != EEXIST)
+ return ret;
+ }
+
+ return 0;
+}
+
static int got_alternates = 0;
static int fetch_index(struct alt_base *repo, unsigned char *sha1)
{
char *filename;
char *url;
+ char tmpfile[PATH_MAX];
+ int ret;
+ long prev_posn = 0;
+ char range[RANGE_HEADER_SIZE];
+ struct curl_slist *range_header = NULL;
+ CURLcode curl_result;
FILE *indexfile;
@@ -103,7 +132,8 @@ static int fetch_index(struct alt_base *
repo->base, sha1_to_hex(sha1));
filename = sha1_pack_index_name(sha1);
- indexfile = fopen(filename, "w");
+ snprintf(tmpfile, sizeof(tmpfile), "%s.temp", filename);
+ indexfile = fopen(tmpfile, "a");
if (!indexfile)
return error("Unable to open local file %s for pack index",
filename);
@@ -113,12 +143,35 @@ static int fetch_index(struct alt_base *
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, no_pragma_header);
- if (curl_easy_perform(curl)) {
+ /* If there is data present from a previous transfer attempt,
+ resume where it left off */
+ prev_posn = ftell(indexfile);
+ if (prev_posn>0) {
+ if (get_verbosely)
+ fprintf(stderr,
+ "Resuming fetch of index for pack %s at byte %ld\n",
+ sha1_to_hex(sha1), prev_posn);
+ sprintf(range, "Range: bytes=%ld-", prev_posn);
+ range_header = curl_slist_append(range_header, range);
+ curl_easy_setopt(curl, CURLOPT_HTTPHEADER, range_header);
+ }
+
+ /* Clear out the Range: header after performing the request, so
+ other curl requests don't inherit inappropriate header data */
+ curl_result = curl_easy_perform(curl);
+ curl_easy_setopt(curl, CURLOPT_HTTPHEADER, no_range_header);
+ if (curl_result != 0) {
fclose(indexfile);
return error("Unable to get pack index %s", url);
}
fclose(indexfile);
+
+ ret = relink_or_rename(tmpfile, filename);
+ if (ret)
+ return error("unable to write index filename %s: %s",
+ filename, strerror(ret));
+
return 0;
}
@@ -299,6 +352,12 @@ static int fetch_pack(struct alt_base *r
struct packed_git **lst;
FILE *packfile;
char *filename;
+ char tmpfile[PATH_MAX];
+ int ret;
+ long prev_posn = 0;
+ char range[RANGE_HEADER_SIZE];
+ struct curl_slist *range_header = NULL;
+ CURLcode curl_result;
if (fetch_indices(repo))
return -1;
@@ -318,7 +377,8 @@ static int fetch_pack(struct alt_base *r
repo->base, sha1_to_hex(target->sha1));
filename = sha1_pack_name(target->sha1);
- packfile = fopen(filename, "w");
+ snprintf(tmpfile, sizeof(tmpfile), "%s.temp", filename);
+ packfile = fopen(tmpfile, "a");
if (!packfile)
return error("Unable to open local file %s for pack",
filename);
@@ -327,14 +387,36 @@ static int fetch_pack(struct alt_base *r
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite);
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, no_pragma_header);
-
- if (curl_easy_perform(curl)) {
+
+ /* If there is data present from a previous transfer attempt,
+ resume where it left off */
+ prev_posn = ftell(packfile);
+ if (prev_posn>0) {
+ if (get_verbosely)
+ fprintf(stderr,
+ "Resuming fetch of pack %s at byte %ld\n",
+ sha1_to_hex(target->sha1), prev_posn);
+ sprintf(range, "Range: bytes=%ld-", prev_posn);
+ range_header = curl_slist_append(range_header, range);
+ curl_easy_setopt(curl, CURLOPT_HTTPHEADER, range_header);
+ }
+
+ /* Clear out the Range: header after performing the request, so
+ other curl requests don't inherit inappropriate header data */
+ curl_result = curl_easy_perform(curl);
+ curl_easy_setopt(curl, CURLOPT_HTTPHEADER, no_range_header);
+ if (curl_result != 0) {
fclose(packfile);
return error("Unable to get pack file %s", url);
}
fclose(packfile);
+ ret = relink_or_rename(tmpfile, filename);
+ if (ret)
+ return error("unable to write pack filename %s: %s",
+ filename, strerror(ret));
+
lst = &repo->packs;
while (*lst != target)
lst = &((*lst)->next);
@@ -351,14 +433,29 @@ int fetch_object(struct alt_base *repo,
char *filename = sha1_file_name(sha1);
unsigned char real_sha1[20];
char tmpfile[PATH_MAX];
+ char prevfile[PATH_MAX];
int ret;
char *url;
char *posn;
+ int prevlocal;
+ unsigned char prev_buf[PREV_BUF_SIZE];
+ ssize_t prev_read = 0;
+ long prev_posn = 0;
+ char range[RANGE_HEADER_SIZE];
+ struct curl_slist *range_header = NULL;
+ CURLcode curl_result;
+
+ snprintf(tmpfile, sizeof(tmpfile), "%s.temp", filename);
+ snprintf(prevfile, sizeof(prevfile), "%s.prev", filename);
+ unlink(prevfile);
+ rename(tmpfile, prevfile);
+ unlink(tmpfile);
+
+ local = open(tmpfile, O_WRONLY | O_CREAT | O_EXCL, 0666);
- snprintf(tmpfile, sizeof(tmpfile), "%s/obj_XXXXXX",
- get_object_directory());
+ /* Note: if another instance starts now, it will turn our new
+ tmpfile into its prevfile. */
- local = mkstemp(tmpfile);
if (local < 0)
return error("Couldn't create temporary file %s for %s: %s\n",
tmpfile, filename, strerror(errno));
@@ -386,8 +483,56 @@ int fetch_object(struct alt_base *repo,
curl_easy_setopt(curl, CURLOPT_URL, url);
- if (curl_easy_perform(curl)) {
- unlink(filename);
+ /* If a previous temp file is present, process what was already
+ fetched. */
+ prevlocal = open(prevfile, O_RDONLY);
+ if (prevlocal != -1) {
+ do {
+ prev_read = read(prevlocal, prev_buf, PREV_BUF_SIZE);
+ if (prev_read>0) {
+ if (fwrite_sha1_file(prev_buf,
+ 1,
+ prev_read,
+ NULL) == prev_read) {
+ prev_posn += prev_read;
+ } else {
+ prev_read = -1;
+ }
+ }
+ } while (prev_read > 0);
+ close(prevlocal);
+ }
+ unlink(prevfile);
+
+ /* Reset inflate/SHA1 if there was an error reading the previous temp
+ file; also rewind to the beginning of the local file. */
+ if (prev_read == -1) {
+ memset(&stream, 0, sizeof(stream));
+ inflateInit(&stream);
+ SHA1_Init(&c);
+ if (prev_posn>0) {
+ prev_posn = 0;
+ lseek(local, SEEK_SET, 0);
+ }
+ }
+
+ /* If we have successfully processed data from a previous fetch
+ attempt, only fetch the data we don't already have. */
+ if (prev_posn>0) {
+ if (get_verbosely)
+ fprintf(stderr,
+ "Resuming fetch of object %s at byte %ld\n",
+ hex, prev_posn);
+ sprintf(range, "Range: bytes=%ld-", prev_posn);
+ range_header = curl_slist_append(range_header, range);
+ curl_easy_setopt(curl, CURLOPT_HTTPHEADER, range_header);
+ }
+
+ /* Clear out the Range: header after performing the request, so
+ other curl requests don't inherit inappropriate header data */
+ curl_result = curl_easy_perform(curl);
+ curl_easy_setopt(curl, CURLOPT_HTTPHEADER, no_range_header);
+ if (curl_result != 0) {
return -1;
}
@@ -403,20 +548,11 @@ int fetch_object(struct alt_base *repo,
unlink(tmpfile);
return error("File %s has bad hash\n", hex);
}
- ret = link(tmpfile, filename);
- if (ret < 0) {
- /* Same Coda hack as in write_sha1_file(sha1_file.c) */
- ret = errno;
- if (ret == EXDEV && !rename(tmpfile, filename))
- goto out;
- }
- unlink(tmpfile);
- if (ret) {
- if (ret != EEXIST)
- return error("unable to write sha1 filename %s: %s",
- filename, strerror(ret));
- }
- out:
+ ret = relink_or_rename(tmpfile, filename);
+ if (ret)
+ return error("unable to write sha1 filename %s: %s",
+ filename, strerror(ret));
+
pull_say("got %s\n", hex);
return 0;
}
@@ -505,6 +641,7 @@ int main(int argc, char **argv)
curl = curl_easy_init();
no_pragma_header = curl_slist_append(no_pragma_header, "Pragma:");
+ no_range_header = curl_slist_append(no_range_header, "Range:");
curl_ssl_verify = getenv("GIT_SSL_NO_VERIFY") ? 0 : 1;
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, curl_ssl_verify);
^ permalink raw reply
* Re: [PATCH] Use git-update-ref in scripts.
From: Linus Torvalds @ 2005-09-28 17:13 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Git Mailing List
In-Reply-To: <7vek79w2ps.fsf@assigned-by-dhcp.cox.net>
On Wed, 28 Sep 2005, Junio C Hamano wrote:
>
> Have you had a chance to look at the git-merge change to remove
> the stupid clean-tree requirements? I have been planning to
> inflict the 'use git-merge instead of git-resolve' change on you
> sometime soonish (like today ;-).
I don't like doing the diff before-hand, but it looked like the default
was to try just one strategy, and avoid the diff in that case.
Actually, my preference would be to have a unconditional simple case
first. If there's only one possible base, and the trivial merge succeeds
(ie no three-way merges needed at all, just a single git-read-tree), do
that part unconditionally.
That actually matches 90% of all merges I do, and I'd be much happier with
git-merge if it did that first and if it then does something more complex
(including diffs etc) afterwards, I'm much less likely to worry.
> Could I have a copy of .git/{branches,remotes,refs}/* from the
> primary repository you do your kernel work please?
Heh. My kernel has none of that. Well, it obviously has refs, but even
there it literally has just one head: "master". The rest are the standard
tags you see in public.
So if you clone the public kernel,. you'll actually have a superset of
what I have, since you'll have the "origin" thing ;)
Linus
^ permalink raw reply
* Re: [PATCH] Use git-update-ref in scripts.
From: Junio C Hamano @ 2005-09-28 16:56 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Git Mailing List
In-Reply-To: <Pine.LNX.4.58.0509280819000.3308@g5.osdl.org>
Linus Torvalds <torvalds@osdl.org> writes:
> git-resolve might want to verify the old head. On the other hand, it looks
> like it's being phased out, so maybe nobody cares?
It was my mistake -- git-merge does it, and I should do the
same in git-resolve. Thanks for pointing it out.
Have you had a chance to look at the git-merge change to remove
the stupid clean-tree requirements? I have been planning to
inflict the 'use git-merge instead of git-resolve' change on you
sometime soonish (like today ;-). Having said that, I myself
would vote against phasing out 'git-resolve' -- being able to
say 'git resolve master hold fast' to fast forward the master
head to topic branch head of 'hold' (my topic branches are often
rebased to allow this) is quite useful.
I have one unrelated request.
Could I have a copy of .git/{branches,remotes,refs}/* from the
primary repository you do your kernel work please?
^ permalink raw reply
* Re: git cvsimport?
From: Wolfgang Denk @ 2005-09-28 16:35 UTC (permalink / raw)
To: skimo; +Cc: git
In-Reply-To: <20050928160427.GU15165MdfPADPa@greensroom.kotnet.org>
In message <20050928160427.GU15165MdfPADPa@greensroom.kotnet.org> you wrote:
>
> > -> cvsps -u -A --cvs-direct --root :pserver:denx@cvs.semihalf.com:/cvs duts
> > connect error: Network is unreachable
> > cvs rlog: cannot find module `duts' - ignored
>
> Does leaving out the --cvs-direct have any effect ?
Yes, the "Network is unreachable" disappears:
-> cvsps -u -A --root :pserver:denx@cvs.semihalf.com:/cvs duts
cvs rlog: cannot find module `duts' - ignored
This is cvsps version 2.1.
Best regards,
Wolfgang Denk
--
Software Engineering: Embedded and Realtime Systems, Embedded Linux
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
Your csh still thinks true is false. Write to your vendor today and
tell them that next year Configure ought to "rm /bin/csh" unless they
fix their blasted shell. :-)
- Larry Wall in Configure from the perl distribution
^ permalink raw reply
* Re: git cvsimport?
From: Sven Verdoolaege @ 2005-09-28 16:04 UTC (permalink / raw)
To: Wolfgang Denk; +Cc: git
In-Reply-To: <20050928154955.EB723353BE5@atlas.denx.de>
On Wed, Sep 28, 2005 at 05:49:55PM +0200, Wolfgang Denk wrote:
> In message <20050928151812.GS15165MdfPADPa@greensroom.kotnet.org> you wrote:
> >
> > > I have problems importing a CVS repository:
> ...
> > What does
> > cvsps -u -A --cvs-direct --root :pserver:denx@cvs.semihalf.com:/cvs duts
> > say ?
>
> -> cvsps -u -A --cvs-direct --root :pserver:denx@cvs.semihalf.com:/cvs duts
> connect error: Network is unreachable
> cvs rlog: cannot find module `duts' - ignored
Does leaving out the --cvs-direct have any effect ?
skimo
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox