* [PATCH] Handle deltified object correctly in git-*-pull family.
From: Junio C Hamano @ 2005-06-02 18:55 UTC (permalink / raw)
To: Linus Torvalds; +Cc: git
In-Reply-To: <Pine.LNX.4.58.0506020959250.1876@ppc970.osdl.org>
When a remote repository is deltified, we need to get the
objects that a deltified object we want to obtain is based upon.
The initial parts of each retrieved SHA1 file is inflated and
inspected to see if it is deltified, and its base object is
asked from the remote side when it is. Since this partial
inflation and inspection has a small performance hit, it can
optionally be skipped by giving -d flag to git-*-pull commands.
This flag should be used only when the remote repository is
known to have no deltified objects.
Rsync transport does not have this problem since it fetches
everything the remote side has.
Signed-off-by: Junio C Hamano <junkio@cox.net>
---
*** Now uses parse_sha1_header() and unpack_sha1_rest(). I
*** decided not to make it the callers responsibility to check
*** what we have already got and fixed unpack_sha1_rest() to
*** avoid copying more than size bytes.
Documentation/git-http-pull.txt | 6 ++++-
Documentation/git-local-pull.txt | 6 ++++-
Documentation/git-rpull.txt | 6 ++++-
cache.h | 1 +
pull.h | 3 +++
http-pull.c | 4 +++-
local-pull.c | 4 +++-
pull.c | 7 ++++++
rpull.c | 4 +++-
sha1_file.c | 43 +++++++++++++++++++++++++++++++++++++-
10 files changed, 77 insertions(+), 7 deletions(-)
diff --git a/Documentation/git-http-pull.txt b/Documentation/git-http-pull.txt
--- a/Documentation/git-http-pull.txt
+++ b/Documentation/git-http-pull.txt
@@ -9,7 +9,7 @@ git-http-pull - Downloads a remote GIT r
SYNOPSIS
--------
-'git-http-pull' [-c] [-t] [-a] [-v] commit-id url
+'git-http-pull' [-c] [-t] [-a] [-v] [-d] commit-id url
DESCRIPTION
-----------
@@ -21,6 +21,10 @@ Downloads a remote GIT repository via HT
Get trees associated with the commit objects.
-a::
Get all the objects.
+-d::
+ Do not check for delta base objects (use this option
+ only when you know the remote repository is not
+ deltified).
-v::
Report what is downloaded.
diff --git a/Documentation/git-local-pull.txt b/Documentation/git-local-pull.txt
--- a/Documentation/git-local-pull.txt
+++ b/Documentation/git-local-pull.txt
@@ -9,7 +9,7 @@ git-local-pull - Duplicates another GIT
SYNOPSIS
--------
-'git-local-pull' [-c] [-t] [-a] [-l] [-s] [-n] [-v] commit-id path
+'git-local-pull' [-c] [-t] [-a] [-l] [-s] [-n] [-v] [-d] commit-id path
DESCRIPTION
-----------
@@ -23,6 +23,10 @@ OPTIONS
Get trees associated with the commit objects.
-a::
Get all the objects.
+-d::
+ Do not check for delta base objects (use this option
+ only when you know the remote repository is not
+ deltified).
-v::
Report what is downloaded.
diff --git a/Documentation/git-rpull.txt b/Documentation/git-rpull.txt
--- a/Documentation/git-rpull.txt
+++ b/Documentation/git-rpull.txt
@@ -10,7 +10,7 @@ git-rpull - Pulls from a remote reposito
SYNOPSIS
--------
-'git-rpull' [-c] [-t] [-a] [-v] commit-id url
+'git-rpull' [-c] [-t] [-a] [-d] [-v] commit-id url
DESCRIPTION
-----------
@@ -25,6 +25,10 @@ OPTIONS
Get trees associated with the commit objects.
-a::
Get all the objects.
+-d::
+ Do not check for delta base objects (use this option
+ only when you know the remote repository is not
+ deltified).
-v::
Report what is downloaded.
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -153,6 +153,7 @@ extern char *sha1_file_name(const unsign
extern void * map_sha1_file(const unsigned char *sha1, unsigned long *size);
extern int unpack_sha1_header(z_stream *stream, void *map, unsigned long mapsize, void *buffer, unsigned long size);
extern int parse_sha1_header(char *hdr, char *type, unsigned long *sizep);
+extern int sha1_delta_base(const unsigned char *, unsigned char *);
extern void * unpack_sha1_file(void *map, unsigned long mapsize, char *type, unsigned long *size);
extern void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size);
extern int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
diff --git a/pull.h b/pull.h
--- a/pull.h
+++ b/pull.h
@@ -13,6 +13,9 @@ extern int get_history;
/** Set to fetch the trees in the commit history. **/
extern int get_all;
+/* Set to zero to skip the check for delta object base. */
+extern int get_delta;
+
/* Set to be verbose */
extern int get_verbosely;
diff --git a/http-pull.c b/http-pull.c
--- a/http-pull.c
+++ b/http-pull.c
@@ -103,6 +103,8 @@ int main(int argc, char **argv)
get_tree = 1;
} else if (argv[arg][1] == 'c') {
get_history = 1;
+ } else if (argv[arg][1] == 'd') {
+ get_delta = 0;
} else if (argv[arg][1] == 'a') {
get_all = 1;
get_tree = 1;
@@ -113,7 +115,7 @@ int main(int argc, char **argv)
arg++;
}
if (argc < arg + 2) {
- usage("git-http-pull [-c] [-t] [-a] [-v] commit-id url");
+ usage("git-http-pull [-c] [-t] [-a] [-d] [-v] commit-id url");
return 1;
}
commit_id = argv[arg];
diff --git a/local-pull.c b/local-pull.c
--- a/local-pull.c
+++ b/local-pull.c
@@ -74,7 +74,7 @@ int fetch(unsigned char *sha1)
}
static const char *local_pull_usage =
-"git-local-pull [-c] [-t] [-a] [-l] [-s] [-n] [-v] commit-id path";
+"git-local-pull [-c] [-t] [-a] [-l] [-s] [-n] [-v] [-d] commit-id path";
/*
* By default we only use file copy.
@@ -92,6 +92,8 @@ int main(int argc, char **argv)
get_tree = 1;
else if (argv[arg][1] == 'c')
get_history = 1;
+ else if (argv[arg][1] == 'd')
+ get_delta = 0;
else if (argv[arg][1] == 'a') {
get_all = 1;
get_tree = 1;
diff --git a/pull.c b/pull.c
--- a/pull.c
+++ b/pull.c
@@ -6,6 +6,7 @@
int get_tree = 0;
int get_history = 0;
+int get_delta = 1;
int get_all = 0;
int get_verbosely = 0;
static unsigned char current_commit_sha1[20];
@@ -37,6 +38,12 @@ static int make_sure_we_have_it(const ch
status = fetch(sha1);
if (status && what)
report_missing(what, sha1);
+ if (get_delta) {
+ char delta_sha1[20];
+ status = sha1_delta_base(sha1, delta_sha1);
+ if (0 < status)
+ status = make_sure_we_have_it(what, delta_sha1);
+ }
return status;
}
diff --git a/rpull.c b/rpull.c
--- a/rpull.c
+++ b/rpull.c
@@ -27,6 +27,8 @@ int main(int argc, char **argv)
get_tree = 1;
} else if (argv[arg][1] == 'c') {
get_history = 1;
+ } else if (argv[arg][1] == 'd') {
+ get_delta = 0;
} else if (argv[arg][1] == 'a') {
get_all = 1;
get_tree = 1;
@@ -37,7 +39,7 @@ int main(int argc, char **argv)
arg++;
}
if (argc < arg + 2) {
- usage("git-rpull [-c] [-t] [-a] [-v] commit-id url");
+ usage("git-rpull [-c] [-t] [-a] [-v] [-d] commit-id url");
return 1;
}
commit_id = argv[arg];
diff --git a/sha1_file.c b/sha1_file.c
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -325,7 +325,13 @@ void *unpack_sha1_rest(z_stream *stream,
int bytes = strlen(buffer) + 1;
char *buf = xmalloc(1+size);
- memcpy(buf, buffer + bytes, stream->total_out - bytes);
+ /* (stream->total_out - bytes) is what we already have. The
+ * caller could be asking for something smaller than that.
+ */
+ if (size < stream->total_out - bytes)
+ memcpy(buf, buffer + bytes, size);
+ else
+ memcpy(buf, buffer + bytes, stream->total_out - bytes);
bytes = stream->total_out - bytes;
if (bytes < size) {
stream->next_out = buf + bytes;
@@ -401,6 +407,41 @@ void * unpack_sha1_file(void *map, unsig
return unpack_sha1_rest(&stream, hdr, *size);
}
+int sha1_delta_base(const unsigned char *sha1, unsigned char *base_sha1)
+{
+ int ret;
+ unsigned long mapsize, size;
+ void *map;
+ z_stream stream;
+ char hdr[1024], type[20];
+ void *delta_data_head;
+
+ map = map_sha1_file(sha1, &mapsize);
+ if (!map)
+ return -1;
+ ret = unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr));
+ if (ret < Z_OK || parse_sha1_header(hdr, type, &size) < 0) {
+ ret = -1;
+ goto out;
+ }
+ if (strcmp(type, "delta")) {
+ ret = 0;
+ goto out;
+ }
+ delta_data_head = unpack_sha1_rest(&stream, hdr, 20);
+ if (!delta_data_head) {
+ ret = -1;
+ goto out;
+ }
+ ret = 1;
+ memcpy(base_sha1, delta_data_head, 20);
+ free(delta_data_head);
+ out:
+ inflateEnd(&stream);
+ munmap(map, mapsize);
+ return ret;
+}
+
void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size)
{
unsigned long mapsize;
------------
^ permalink raw reply
* [PATCH] Find size of SHA1 object without inflating everything.
From: Junio C Hamano @ 2005-06-02 18:57 UTC (permalink / raw)
To: Linus Torvalds; +Cc: git
In-Reply-To: <Pine.LNX.4.58.0506020959250.1876@ppc970.osdl.org>
This adds sha1_file_size() helper function and uses it in the
rename/copy similarity estimator. The helper function handles
deltified object as well.
Signed-off-by: Junio C Hamano <junkio@cox.net>
---
*** The U*MAX fix patch from previous round still applies, so I am
*** resending it to you. This probably would depend on it, so
*** please apply U*MAX fix patch before this one.
cache.h | 1 +
diff.c | 11 ++++++----
sha1_file.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 71 insertions(+), 5 deletions(-)
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -154,6 +154,7 @@ extern void * map_sha1_file(const unsign
extern int unpack_sha1_header(z_stream *stream, void *map, unsigned long mapsize, void *buffer, unsigned long size);
extern int parse_sha1_header(char *hdr, char *type, unsigned long *sizep);
extern int sha1_delta_base(const unsigned char *, unsigned char *);
+extern int sha1_file_size(const unsigned char *, unsigned long *);
extern void * unpack_sha1_file(void *map, unsigned long mapsize, char *type, unsigned long *size);
extern void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size);
extern int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
diff --git a/diff.c b/diff.c
--- a/diff.c
+++ b/diff.c
@@ -333,7 +333,6 @@ int diff_populate_filespec(struct diff_f
close(fd);
}
else {
- /* We cannot do size only for SHA1 blobs */
char type[20];
struct sha1_size_cache *e;
@@ -343,11 +342,13 @@ int diff_populate_filespec(struct diff_f
s->size = e->size;
return 0;
}
+ if (!sha1_file_size(s->sha1, &s->size))
+ locate_size_cache(s->sha1, s->size);
+ }
+ else {
+ s->data = read_sha1_file(s->sha1, type, &s->size);
+ s->should_free = 1;
}
- s->data = read_sha1_file(s->sha1, type, &s->size);
- s->should_free = 1;
- if (s->data && size_only)
- locate_size_cache(s->sha1, s->size);
}
return 0;
}
diff --git a/sha1_file.c b/sha1_file.c
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -442,6 +442,70 @@ int sha1_delta_base(const unsigned char
return ret;
}
+int sha1_file_size(const unsigned char *sha1, unsigned long *sizep)
+{
+ int ret, status;
+ unsigned long mapsize, size;
+ void *map;
+ z_stream stream;
+ char hdr[1024], type[20];
+ void *delta_data_head;
+ const unsigned char *data;
+ unsigned char cmd;
+ int i;
+
+ map = map_sha1_file(sha1, &mapsize);
+ if (!map)
+ return -1;
+ ret = unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr));
+ status = -1;
+ if (ret < Z_OK || parse_sha1_header(hdr, type, &size) < 0)
+ goto out;
+ if (strcmp(type, "delta")) {
+ *sizep = size;
+ status = 0;
+ goto out;
+ }
+
+ /* We are dealing with delta object. Inflated, the first 20
+ * bytes hold the base object SHA1, and delta data follows
+ * immediately after it.
+ */
+ delta_data_head = unpack_sha1_rest(&stream, hdr, 200);
+
+ /* The initial part of the delta starts at delta_data_head +
+ * 20. Borrow code from patch-delta to read the result size.
+ */
+
+ data = delta_data_head + 20;
+
+ /* Skip over the source size; we are not interested in
+ * it and we cannot verify it because we do not want
+ * to read the base object.
+ */
+ cmd = *data++;
+ while (cmd) {
+ if (cmd & 1)
+ data++;
+ cmd >>= 1;
+ }
+ /* Read the result size */
+ size = i = 0;
+ cmd = *data++;
+ while (cmd) {
+ if (cmd & 1)
+ size |= *data++ << i;
+ i += 8;
+ cmd >>= 1;
+ }
+ *sizep = size;
+ status = 0;
+ out:
+ inflateEnd(&stream);
+ munmap(map, mapsize);
+ return status;
+}
+
void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size)
{
unsigned long mapsize;
------------
^ permalink raw reply
* Re: [SCRIPT] cg-rpush & locking
From: Daniel Barkalow @ 2005-06-02 19:12 UTC (permalink / raw)
To: Linus Torvalds
Cc: Tony Lindgren, Matthias Urlichs, Thomas Glanzmann, Nicolas Pitre,
git
In-Reply-To: <Pine.LNX.4.58.0506020741480.1876@ppc970.osdl.org>
On Thu, 2 Jun 2005, Linus Torvalds wrote:
> The real reason I'd prefer to not do locking is that _if_ the remote tree
> is actually more than just a CVS-like "public repository", ie if somebody
> actually does _development_ in the remote tree (hey, it may be crazy, but
> git makes this usage pattern possible), then we should eventually plan on
> having all of the regular "git-commit-script" and "git-pull-script" etc
> _also_ do locking, since they also change HEAD.
It might be okay to have a single tree to which is applied patches from
emails sent by non-maintainers, pulls from non-maintainers with accessible
repositories, and pushes from home repositories of maintainers. It makes
sense to deal well with different ways to get refined commits into the
public repository. Of course, you probably don't want to carry out merges
there, so the cases where pull or commit loses the race are quite
different; you want to throw it back to the author for rebasing.
-Daniel
*This .sig left intentionally blank*
^ permalink raw reply
* Re: qgit-0.3
From: Radoslaw Szkodzinski @ 2005-06-02 19:18 UTC (permalink / raw)
To: Marco Costalba; +Cc: git, berkus
In-Reply-To: <20050601111949.90043.qmail@web26303.mail.ukl.yahoo.com>
Marco Costalba wrote:
>New version of qgit, the QT/C++ git viewer.
>
>Download at:
>
>http://prdownloads.sourceforge.net/qgit/qgit-0.3.tar.gz?download
>
>This time we use scons instead of qmake as build system (many thanks to Stanislav Karchebny), I
>hope people have less problems compiling it.
>
>
>
Actually, your scons build system is botched, it can't find qt module.
Only after I installed a system global scons, that one could build qgit.
>As before just run make and copy the bin in the path.
>
>
>
So why do you put ${SCONS} install as the install target in the Makefile?
However, the tool's great, really.
Theres only one cosmetic problem: The windows do not support UTF-8 somehow.
My GIT_COMMITTER_NAME contains them and they're displayed as single
bytes they consist of. Remember, default and only git encoding is UTF-8.
AstralStorm
^ permalink raw reply
* Re: [SCRIPT] cg-rpush & locking
From: Dan Holmsand @ 2005-06-02 19:15 UTC (permalink / raw)
To: git; +Cc: Matthias Urlichs
In-Reply-To: <20050531190005.GE18723@atomide.com>
[-- Attachment #1: Type: text/plain, Size: 1658 bytes --]
Tony Lindgren wrote:
> Anybody have any better ideas for locking that also works with
> rsync?
Since this seems to be Push Day on the git list, here's my feeble
attempt at the same thing (attached cg-push script).
I do stuff in this order:
1. read remote HEAD
2. check that a merge from local HEAD to remote would be
fast-forward, otherwise tell people to pull and merge.
3. push objects using --ignore-existing (or equivalent)
4. write lock file with --ignore-existing. The lock file
contains, in particular, the HEAD to be written.
5. read remote HEAD (again) and the lock file. Bail if HEAD
changed since the first read, or if the lock file isn't
the one we attempted to write.
6. write remote HEAD and delete lock file in using rsync's
--delete-after
This should always be safe, since rsync (as I understand the man page)
always writes to temp files, and then renames into place. Checking for
fast-forward-mergability assures that other peoples changes don't get lost.
cg-push determines uri and foreign branch name using the same rules as
cg-pull, which is real nice as it allows you to do:
$ cg-clone me@myserver.example.com:git-repos/myrepo.git mystuff
$ cd mystuff
# write some stuff
$ cg-commit
$ cg-push
and later
$ cg-update
# write more stuff
$ cg-commit
$ cg-push
and even later
$ cg-branch-add pub me@myserver.example.com:public-repos/myrepo.git
$ cg-push pub
So, you can work pretty much exactly as you would do in CVS or svn, if
you're so inclined, safely sharing a common repository among many users.
Which is kinda neat, if I may say so myself...
/dan
[-- Attachment #2: cg-push --]
[-- Type: text/plain, Size: 6219 bytes --]
#! /usr/bin/env bash
#
# Push changes to a remote git repository
#
# Copyright (c) Dan Holmsand, 2005.
#
# Based on cg-pull,
# Copyright (c) Petr Baudis, 2005.
#
# Takes the branch name as an argument, defaulting to "origin" (see
# `cg-branch-add` for some description of branch names).
#
# Takes one optional option: --force, that makes cg-push write objects
# regardless of lock-files and remote state. Use with care...
#
# cg-push supports two types of location specifiers:
#
# 1. local paths - simple directory names of git repositories
# 2. rsync - using the "[user@]machine:some/path" syntax
#
# Typical use would look something like this:
#
# # clone a remote branch:
# cg-clone me@myserver.example.com:repo.git myrepo
# cd myrepo
#
# # make some changes, and then do:
# cg-commit
# cg-push
#
# cg-push is safe to use even if multiple users concurrently push
# to the same repository. Here's how this works:
#
# First, cg-push checks that the local repository is fully merged with
# the remote one (this will always be the case if there is only one
# user). Otherwise, you need to cg-update from the remote repository
# before you can cg-push to it.
#
# Then, cg-push writes all the object files that are missing in the
# remote repository.
#
# To finish, cg-push writes a lock file to the remote site (ignoring
# any preexisting lock file), checks that our lock file actually got
# written, checks that the remote head is still the same (i.e. that
# the remote site hasn't been updated while we were copying objects),
# writes the new remote head and removes the lock.
#
# The head of the local repository is also updated in the process (as if
# the remote branch had been cg-pull'ed).
#
# cg-push requires that there already is a repository in place at the
# remote location, but it actually only checks that it has a
# "refs/heads" subdirectory. So, creating a remote repo ready for
# cg-pushing is as easy "mkdir -p repo.git/heads/refs" at the remote
# location.
# TODO: Write tags as well.
. ${COGITO_LIB}cg-Xlib
force=
if [ "$1" = --force ]; then
force=1; shift
fi
name=$1
[ "$name" ] || { [ -s $_git/refs/heads/origin ] && name=origin; }
[ "$name" ] || die "what to push to?"
uri=$(cat "$_git/branches/$name" 2>/dev/null) || die "unknown branch: $name"
rembranch=master
if echo "$uri" | grep -q '#'; then
rembranch=$(echo $uri | cut -d '#' -f 2)
uri=$(echo $uri | cut -d '#' -f 1)
fi
case $uri in
*:*)
readhead=rsync_readhead
writeobjects=rsync_writeobjects
writehead=rsync_writehead
lock=rsync_lock
;;
*)
if [ -d "$uri" ]; then
[ -d "$uri/.git" ] && uri=$uri/.git
readhead=local_readhead
writeobjects=local_writeobjects
writehead=local_writehead
lock=local_lock
else
die "Don't know how to push to $uri"
fi
;;
esac
tmpd=$(mktemp -d -t cgpush.XXXXXX) || exit 1
trap "rm -rf $tmpd" SIGTERM EXIT
cid=$(commit-id) || exit 1
lock_msg="locked by $USER@$HOSTNAME on $(date) for writing $cid"
unset locked remhead
rsync_readhead() {
rm -f "$tmpd/*" || return 1
rsync $RSYNC_FLAGS --include="$rembranch" --include="$rembranch.lock" \
--exclude='*' -r "$uri/refs/heads/" "$tmpd/" >&2 ||
die "Fetching heads from $uri failed. Aborting."
if [ "$locked" ]; then
[ -s "$tmpd/$rembranch.lock" ] ||
die "Couldn't acquire lock. Aborting."
local rem_lock_msg=$(cat "$tmpd/$rembranch.lock")
[ "$lock_msg" = "$rem_lock_msg" ] ||
die "Remote is locked ($rem_lock_msg)."
fi
[ ! -e "$tmpd/$rembranch" ] || cat "$tmpd/$rembranch"
}
rsync_writeobjects() {
[ -d "$_git/objects/" ] || die "no objects to copy"
rsync $RSYNC_FLAGS -vr --ignore-existing --whole-file \
"$_git/objects/" "$uri/objects/"
}
rsync_lock() {
echo "$lock_msg" > $tmpd/new_head_lock_file || return 1
rsync $RSYNC_FLAGS --ignore-existing --whole-file \
$tmpd/new_head_lock_file "$uri/refs/heads/$rembranch.lock"
}
rsync_writehead() {
local heads=$tmpd/newhead
mkdir $heads && echo "$1" > "$heads/$rembranch" || return 1
rsync $RSYNC_FLAGS --include="$rembranch" --include="$rembranch.lock" \
--exclude='*' --delete-after -r $heads/ "$uri/refs/heads/"
}
local_readhead() {
local lheads=$uri/refs/heads
[ -d "$lheads" ] || die "no remote heads found at $uri"
[ ! -e "$lheads/$rembranch" ] || cat "$lheads/$rembranch"
}
local_writeobjects() {
[ -d "$_git/objects/" ] || die "no objects to copy"
[ -d "$uri/objects" ] ||
GIT_DIR=$uri GIT_OBJECT_DIRECTORY=$uri/objects git-init-db ||
die "git-init-db failed"
# Note: We could use git-local-pull here, but this is safer
# (git-*-pull don't react well to failures or kills), and
# has the same semantics as rsync pushing.
local dest=$(cd "$uri/objects" && pwd) || exit 1
( cd "$_git/objects" && find -type f | while read f; do
[ -f "$dest/$f" ] && continue
ln "$f" "$dest/$f" 2>/dev/null ||
cp "$f" "$dest/$f" || exit 1
done )
}
local_lock() {
([ "$force" ] || set -C
echo "$lockmsg" > "$uri/refs/heads/$rembranch.lock") 2>/dev/null
}
local_writehead() {
local head=$uri/refs/heads/$rembranch
echo "$1" > "$head.new" && mv "$head.new" "$head" &&
rm "$head.lock"
}
echo "Checking remote repository"
remhead=$($readhead) || exit 1
[ "$remhead" ] || echo "Creating new branch"
if [ "$remhead" -a -z "$force" ]; then
if [ "$remhead" = "$cid" ]; then
echo "Remote branch \`$name' is already pushed"
exit 0
fi
git-cat-file commit "$remhead" &> /dev/null ||
die "You need to pull from $name first. Aborting."
base=$(git-merge-base "$remhead" "$cid") && [ "$base" ] ||
die "You need to merge $name. Aborting."
if [ "$base" = "$cid" ]; then
echo "No changes to push"; exit 0
fi
[ "$base" = "$remhead" ] ||
die "You need to merge $name first. Aborting."
fi
echo "Writing objects"
$writeobjects || die "Failed to write objects. Aborting."
echo
echo "Writing new head"
$lock || die "Couldn't acquire lock on remote. Aborting."
if [ ! "$force" ]; then
locked=1
remhead2=$($readhead) || die "Aborting."
[ "$remhead" = "$remhead2" ] ||
die "Remote head changed during copy. Aborting."
fi
$writehead "$cid" || die "WARNING: Error writing remote head. Aborting."
echo "Push to $name succeeded"
echo "$cid" > "$_git/refs/heads/$name"
echo "Updated local head for $name to $cid"
^ permalink raw reply
* Problem with cogito and Linux tree tags
From: Radoslaw Szkodzinski @ 2005-06-02 19:36 UTC (permalink / raw)
To: git
My cg-version is:
cogito-0.10 (20e473c9afd8b5d2d549b0e7881473600beb9c37)
cg-tag-ls output is:
v2.6.11 5dc01c595e6c6ec9ccda4f6f69c131c0dd945f8c
v2.6.11-tree 5dc01c595e6c6ec9ccda4f6f69c131c0dd945f8c
v2.6.12-rc2 9e734775f7c22d2f89943ad6c745571f1930105f
v2.6.12-rc3 0397236d43e48e821cce5bbe6a80a1a56bb7cc3a
v2.6.12-rc4 ebb5573ea8beaf000d4833735f3e53acb9af844c
v2.6.12-rc5 06f6d9e2f140466eeb41e494e14167f90210f89d
The ID of the commit that says "Linux 2.6.12-rc5" is:
137318b273db26b889675101fbd02d2e84cae5e3
The v2.6.12-rc5 tag hash isn't a tree or commit hash, it is unusable.
I don't know what causes that...
AstralStorm
^ permalink raw reply
* CVS migration section to the tutorial.
From: Junio C Hamano @ 2005-06-02 19:43 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Git Mailing List
In-Reply-To: <Pine.LNX.4.58.0505301253070.1876@ppc970.osdl.org>
I think a section to discuss "I am used to doing 'cvs xxx' to solve
this problem, how do I do that in GIT" would be a good idea. Here is
an example to talk about "cvs annotate".
------------
CVS annotate.
The core GIT itself does not do "cvs annotate" equivalent, but it has
something much nicer.
Let's step back a bit and think about the reason why you would want to
do "cvs annotate a-file.c" to begin with.
- Are you really interested in _all_ the lines in that file?
- Are you interested in lines _only_ in that file and do not
care if the file was created by renaming from a different
file?
You would use "cvs annotate" on a file when you have trouble with a
function (or even a single "if" statement in that function) that
happens to be defined in the file, which does not do what you want it
to do. And you would want to find out why it was written in that way,
because you are about to modify it to suit your needs, and at the same
time you do not want to break its current callers. For that, you want
to find out why the original author did things that way in the
original context. That's why you want "cvs annotate". So your answer
to the first question _should_ be "no". You do not care about the
whole file, only a segment of it.
Also, in the original context, the same statement might have appeared
at first in a different file and later the file was renamed to
"a-file.c". Or the entire program may have constructs similar to the
"if" statement you are having trouble with in different places, that
you are still not aware of. So your answer to the second question
_should_ be "no" as well.
As an example, assuming that you have this piece code that you are
interested in in the HEAD version:
if (frotz) {
nitfol();
}
you would use git-rev-list and git-diff-tree like this:
$ git-rev-list HEAD |
git-diff-tree --stdin -v -p -S'if (frotz) {
nitfol();
}'
We have already talked about the "--stdin" form of git-diff-tree
command that reads the list of commits and compares each commit with
its parents. What the -S flag and its argument does is called
"pickaxe", a tool for software archaeologists. When "pickaxe" is
used, git-diff-tree command outputs differences between two commits
only if one tree has the specified string in a file and the
corresponding file in the other tree does not. The above example
looks for a commit that has the "if" statement in it in a file, but
its parent commit does not have it in the same shape in the
corresponding file (or the other way around, where the parent has it
and the commit does not), and the differences between them are shown,
along with the commit message (thanks to the -v flag). It does not
show anything for commits that do not touch this "if" statement.
To make things more interesting, you can give the -C flag to
git-diff-tree, like this:
$ git-rev-list HEAD |
git-diff-tree --stdin -v -p -C -S'if (frotz) {
nitfol();
}'
When the -C flag is used, file renames and copies are followed. So if
the "if" statement in question happens to be in "a-file.c" in the
current HEAD commit, even if the file was originally called "o-file.c"
and then renamed in an earlier commit, or if the file was created by
copying an existing "o-file.c" in an earlier commit, you will not lose
track. If the "if" statement did not change across such rename or
copy, then the commit that does rename or copy would not show in the
output, and if the "if" statement was modified while the file was
still called "o-file.c", it would find the commit that changed the
statement when it was in "o-file.c".
[ BTW, the current versions of "git-diff-tree -C" is not eager enough
to find copies, and it will miss the fact that a-file.c was created
by copying o-file.c unless o-file.c was somehow changed in the same
commit.]
To make things even more interesting, you can use the --pickaxe-all
flag in addition to the -S flag. This causes the differences from all
the files contained in those two commits, not just the differences
between the files that contain this changed "if" statement:
$ git-rev-list HEAD |
git-diff-tree --stdin -v -p -C -S'if (frotz) {
nitfol();
}' --pickaxe-all
^ permalink raw reply
* Re: Problem with cogito and Linux tree tags
From: Dan Holmsand @ 2005-06-02 19:48 UTC (permalink / raw)
To: git
In-Reply-To: <429F5FA5.2030306@gorzow.mm.pl>
Radoslaw Szkodzinski wrote:
The v2.6.12-rc5 tag hash isn't a tree or commit hash, it is unusable.
> I don't know what causes that...
It's a tag object. If you cg-pull via http, you won't get any of those,
though.
Try rsync instead:
$ cg-branch-add kernel
rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
$ cg-pull kernel
/dan
^ permalink raw reply
* Re: [PATCH] cg-log: cleanup line wrapping by using bash internals
From: Junio C Hamano @ 2005-06-02 20:01 UTC (permalink / raw)
To: Jonas Fonseca; +Cc: Petr Baudis, git
In-Reply-To: <20050602144621.GB16143@diku.dk>
>>>>> "JF" == Jonas Fonseca <fonseca@diku.dk> writes:
JF> BTW, I noticed the following errors:
JF> fatal: internal error in diffcore: unmodified entry remains
JF> fatal: internal error in diffcore: unmodified entry remains
JF> fatal: internal error in diffcore: unmodified entry remains
JF> with both current cogito and git.
If you have acquired this fix and still see the above please let
me know.
Commit 67574c403f1e27660bbd0348b81b31adc9889b20
Author Junio C Hamano <junkio@cox.net>, Wed Jun 1 11:38:07 2005 -0700
Committer Linus Torvalds <torvalds@ppc970.osdl.org>, Wed Jun 1 13:24:03 2005 -0700
[PATCH] diff: mode bits fixes
The core GIT repository has trees that record regular file mode
in 0664 instead of normalized 0644 pattern. Comparing such a
tree with another tree that records the same file in 0644
pattern without content changes with git-diff-tree causes it to
feed otherwise unmodified pairs to the diff_change() routine,
which triggers a sanity check routine and barfs. This patch
fixes the problem, along with the fix to another caller that
uses unnormalized mode bits to call diff_change() routine in a
similar way.
Without this patch, you will see "fatal error" from diff-tree
when you run git-deltafy-script on the core GIT repository
itself.
Signed-off-by: Junio C Hamano <junkio@cox.net>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
^ permalink raw reply
* Re: Problem with cogito and Linux tree tags
From: Radoslaw Szkodzinski @ 2005-06-02 20:01 UTC (permalink / raw)
To: Dan Holmsand; +Cc: git
In-Reply-To: <429F6270.50009@gmail.com>
Dan Holmsand wrote:
>
> Radoslaw Szkodzinski wrote:
> The v2.6.12-rc5 tag hash isn't a tree or commit hash, it is unusable.
>
>> I don't know what causes that...
>
>
> It's a tag object. If you cg-pull via http, you won't get any of
> those, though.
>
I thought it was one of these. Seems cogito can't handle them yet.
> Try rsync instead:
>
Guess what, I did it by rsync.
AstralStorm
^ permalink raw reply
* Re: [PATCH] git-tar-tree: add a test case (resent)
From: Junio C Hamano @ 2005-06-02 20:05 UTC (permalink / raw)
To: Rene Scharfe; +Cc: Linus Torvalds, git
In-Reply-To: <20050602185046.GA3717@lsrfire.ath.cx>
I like the test but suspect it belongs to t5000 series according
to the numbering scheme Pasky originaly did.
^ permalink raw reply
* Re: Problem with cogito and Linux tree tags
From: Dan Holmsand @ 2005-06-02 20:19 UTC (permalink / raw)
To: git
In-Reply-To: <429F6591.8080005@gorzow.mm.pl>
Radoslaw Szkodzinski wrote:
> Dan Holmsand wrote:
>>It's a tag object. If you cg-pull via http, you won't get any of
>>those, though.
> I thought it was one of these. Seems cogito can't handle them yet.
Ah. I forgot just how old cogito-0.10 has gotten. Current cogito handles
these just fine. You should be able to read the tag object slightly more
manually, though:
$ git-cat-file tag 06f6d9e2f140466eeb41e494e14167f90210f89d
which tells you that v2.6.12-rc5 is commit
2a24ab628aa7b190be32f63dfb6d96f3fb61580a
/dan
^ permalink raw reply
* Re: [PATCH] git-tar-tree: add a test case (resent)
From: Rene Scharfe @ 2005-06-02 20:50 UTC (permalink / raw)
To: Junio C Hamano, Linus Torvalds; +Cc: git
In-Reply-To: <7v64ww34of.fsf@assigned-by-dhcp.cox.net>
On Thu, Jun 02, 2005 at 01:05:36PM -0700, Junio C Hamano wrote:
> I like the test but suspect it belongs to t5000 series according
> to the numbering scheme Pasky originaly did.
The README says:
3 - the other basic commands (e.g. ls-files)
[...]
5 - the pull and exporting commands
So I guess you're right. I shouldn't have stopped reading after point
three..
Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx>
diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh
new file mode 100755
--- /dev/null
+++ b/t/t5000-tar-tree.sh
@@ -0,0 +1,106 @@
+#!/bin/sh
+#
+# Copyright (C) 2005 Rene Scharfe
+#
+
+test_description='git-tar-tree and git-get-tar-commit-id test
+
+This test covers the topics of long paths, file contents, commit date
+handling and commit id embedding:
+
+ Paths longer than 100 characters require the use of a pax extended
+ header to store them. The test creates files with pathes both longer
+ and shorter than 100 chars, and also checks symlinks with long and
+ short pathes both as their own name and as target path.
+
+ The contents of the repository is compared to the extracted tar
+ archive. The repository contains simple text files, symlinks and a
+ binary file (/bin/sh).
+
+ git-tar-tree applies the commit date to every file in the archive it
+ creates. The test sets the commit date to a specific value and checks
+ if the tar archive contains that value.
+
+ When giving git-tar-tree a commit id (in contrast to a tree id) it
+ embeds this commit id into the tar archive as a comment. The test
+ checks the ability of git-get-tar-commit-id to figure it out from the
+ tar file.
+
+'
+
+. ./test-lib.sh
+
+test_expect_success \
+ 'populate workdir' \
+ 'mkdir a b c &&
+ p48=1.......10........20........30........40......48 &&
+ p50=1.......10........20........30........40........50 &&
+ p98=${p48}${p50} &&
+ echo simple textfile >a/a &&
+ echo 100 chars in path >a/${p98} &&
+ echo 101 chars in path >a/${p98}x &&
+ echo 102 chars in path >a/${p98}xx &&
+ echo 103 chars in path >a/${p98}xxx &&
+ mkdir a/bin &&
+ cp /bin/sh a/bin/sh &&
+ ln -s a a/l1 &&
+ ln -s ${p98}xx a/l100 &&
+ ln -s ${p98}xxx a/l101 &&
+ ln -s ${p98}xxx a/l${p98} &&
+ (cd a && find .) | sort >a.lst'
+
+test_expect_success \
+ 'add files to repository' \
+ 'find a -type f | xargs git-update-cache --add &&
+ find a -type l | xargs git-update-cache --add &&
+ treeid=`git-write-tree` &&
+ echo $treeid >treeid &&
+ TZ= GIT_COMMITTER_DATE="2005-05-27 22:00:00" \
+ git-commit-tree $treeid </dev/null >.git/HEAD'
+
+test_expect_success \
+ 'git-tar-tree' \
+ 'git-tar-tree HEAD >b.tar'
+
+test_expect_success \
+ 'validate file modification time' \
+ 'tar tvf b.tar a/a | awk \{print\ \$4,\$5\} >b.mtime &&
+ echo "2005-05-27 22:00:00" >expected.mtime &&
+ diff expected.mtime b.mtime'
+
+test_expect_success \
+ 'git-get-tar-commit-id' \
+ 'git-get-tar-commit-id <b.tar >b.commitid &&
+ diff .git/HEAD b.commitid'
+
+test_expect_success \
+ 'extract tar archive' \
+ '(cd b && tar xf -) <b.tar'
+
+test_expect_success \
+ 'validate filenames' \
+ '(cd b/a && find .) | sort >b.lst &&
+ diff a.lst b.lst'
+
+test_expect_success \
+ 'validate file contents' \
+ 'diff -r a b/a'
+
+test_expect_success \
+ 'git-tar-tree with prefix' \
+ 'git-tar-tree HEAD prefix >c.tar'
+
+test_expect_success \
+ 'extract tar archive with prefix' \
+ '(cd c && tar xf -) <c.tar'
+
+test_expect_success \
+ 'validate filenames with prefix' \
+ '(cd c/prefix/a && find .) | sort >c.lst &&
+ diff a.lst c.lst'
+
+test_expect_success \
+ 'validate file contents with prefix' \
+ 'diff -r a c/prefix/a'
+
+test_done
^ permalink raw reply
* Re: [PATCH] Make rsh protocol extensible
From: Petr Baudis @ 2005-06-02 20:59 UTC (permalink / raw)
To: Daniel Barkalow; +Cc: git
In-Reply-To: <Pine.LNX.4.21.0505190108490.30848-100000@iabervon.org>
Dear diary, on Thu, May 19, 2005 at 07:11:46AM CEST, I got a letter
where Daniel Barkalow <barkalow@iabervon.org> told me that...
> This changes the rsh protocol to allow reporting failure in getting an
> object without breaking the connection, and to allow other types of
> request than for objects to be made. It is a preliminary to any more
> extensive pull operation.
>
> Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>
I wanted to apply it but then I figured out that I will better hold it
and ask you what do you think about it now after few weeks. ;-) Should I
still go on and apply it to Cogito?
--
Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
C++: an octopus made by nailing extra legs onto a dog. -- Steve Taylor
^ permalink raw reply
* Upstream merging and conflicts (was Re: Using cvs2git to track an external CVS project)
From: Martin Langhoff @ 2005-06-02 20:59 UTC (permalink / raw)
To: Git Mailing List
In-Reply-To: <46a038f905060213104d9ad96f@mail.gmail.com>
(reposted with appropriate subject)
On 6/2/05, Anton Altaparmakov <aia21@cam.ac.uk> wrote:
> Disregarding anything about cvs2git there is one point you may not be
> thinking about but you may want to care about: when you send something
> upstream to the cvs repository and then get it back via cvs2git you will
> get a completely different commit to the one your local git repository
> has.
If upstream hasn't touched the files I'm patching, and cvs2gig/cvs2ps
use -kk there is some hope that the objects should be the same...
right?
> So while the file changes inside those two commits are the same
> the actual commits are not and you will end up with all those commits in
> duplicate because of it as well as an automatic merge commit to merge
> the two commits.
So, this is the scenario for a situation where the files I'm patching
have changed upstream, so upstream merges my patch on top of previous
patches, and I get commit objects echoed back that logically contain
my patch but git sees as different.
Is it any better if upstream is using git as well? Is there any chance
for a private branch or tree to survive anything but a "perfect match"
merge where upstream and the branch are in perfect sync before and
after?
I understand this is architected to _not_ support cherry picking in
the darcs/arch sense and I think it's a good idea. But it seems than
any non-trivial merge ends up being a completely manual process.
Anyone having to work on a series of patches for Linux that get
accepted in stages is going to find himself forced to a potentially
time-consuming remerge every time Linus does a partial merge. Argh.
So it seems to me that git is well suited for a set of closely related
HEADs that are very aggressive in synching with each other. Synching
work is pushed out to the peripheral branches -- a design decision I
agree with -- but there's very little support to help me keep a
peripheral branch in sync.
The assumption that those peripheral branches must be short-lived and
discardable is valid for a limited set of cases -- very circumscribed
to short-term dev work. As soon as a dev branch has to run a little
longer, it cannot afford to not sync with the HEAD. Particularly, it
cannot skip a _single_ patch coming from HEAD.
And if I'm doing development from my branch and pushing to HEAD, and
the guy doing the merge in HEAD merges my patches in a different order
I'll have a spurious conflict.
I use peripheral branches to track versions of code in production,
that may have different sets of patches applied. For that purpose,
patch-based SCMs are quite helpful (you can ask what patch is applied
where), but as Linus pointed out, they don't actually help convergence
at all. Git pulls towards convergence like a demon AFAICS -- yet some
primitive patch trading smarts would save a lot of effort at the
borders of the dev network.
cheers,
martin
^ permalink raw reply
* Re: Problem with cogito and Linux tree tags
From: Radoslaw Szkodzinski @ 2005-06-02 21:02 UTC (permalink / raw)
To: Dan Holmsand; +Cc: git
In-Reply-To: <429F69B6.4030806@gmail.com>
Dan Holmsand wrote:
>
> $ git-cat-file tag 06f6d9e2f140466eeb41e494e14167f90210f89d
>
> which tells you that v2.6.12-rc5 is commit
> 2a24ab628aa7b190be32f63dfb6d96f3fb61580a
>
Ok. This doesn't work too. That cogito version really works fine, but I
had that branch cloned from a local repository gotten from rsync and
probably that's the problem.
The tags weren't propagated, but they should be.
AstralStorm
^ permalink raw reply
* (was Re: Using cvs2git to track an external CVS project)
From: Martin Langhoff @ 2005-06-02 20:10 UTC (permalink / raw)
To: Anton Altaparmakov; +Cc: Git Mailing List
In-Reply-To: <1117631266.26067.40.camel@imp.csi.cam.ac.uk>
On 6/2/05, Anton Altaparmakov <aia21@cam.ac.uk> wrote:
> Disregarding anything about cvs2git there is one point you may not be
> thinking about but you may want to care about: when you send something
> upstream to the cvs repository and then get it back via cvs2git you will
> get a completely different commit to the one your local git repository
> has.
If upstream hasn't touched the files I'm patching, and cvs2gig/cvs2ps
use -kk there is some hope that the objects should be the same...
right?
> So while the file changes inside those two commits are the same
> the actual commits are not and you will end up with all those commits in
> duplicate because of it as well as an automatic merge commit to merge
> the two commits.
So, this is the scenario for a situation where the files I'm patching
have changed upstream, so upstream merges my patch on top of previous
patches, and I get commit objects echoed back that logically contain
my patch but git sees as different.
Is it any better if upstream is using git as well? Is there any chance
for a private branch or tree to survive anything but a "perfect match"
merge where upstream and the branch are in perfect sync before and
after?
I understand this is architected to _not_ support cherry picking in
the darcs/arch sense and I think it's a good idea. But it seems than
any non-trivial merge ends up being a completely manual process.
Anyone having to work on a series of patches for Linux that get
accepted in stages is going to find himself forced to a potentially
time-consuming remerge every time Linus does a partial merge. Argh.
So it seems to me that git is well suited for a set of closely related
HEADs that are very aggressive in synching with each other. Synching
work is pushed out to the peripheral branches -- a design decision I
agree with -- but there's very little support to help me keep a
peripheral branch in sync.
The assumption that those peripheral branches must be short-lived and
discardable is valid for a limited set of cases -- very circumscribed
to short-term dev work. As soon as a dev branch has to run a little
longer, it cannot afford to not sync with the HEAD. Particularly, it
cannot skip a _single_ patch coming from HEAD.
And if I'm doing development from my branch and pushing to HEAD, and
the guy doing the merge in HEAD merges my patches in a different order
I'll have a spurious conflict.
I use peripheral branches to track versions of code in production,
that may have different sets of patches applied. For that purpose,
patch-based SCMs are quite helpful (you can ask what patch is applied
where), but as Linus pointed out, they don't actually help convergence
at all. Git pulls towards convergence like a demon AFAICS -- yet some
primitive patch trading smarts would save a lot of effort at the
borders of the dev network.
cheers,
martin
^ permalink raw reply
* Re: cg-update with local uncommitted changes
From: Petr Baudis @ 2005-06-02 21:14 UTC (permalink / raw)
To: Marcel Holtmann; +Cc: GIT Mailing List
In-Reply-To: <1117481244.7072.209.camel@pegasus>
Dear diary, on Mon, May 30, 2005 at 09:27:24PM CEST, I got a letter
where Marcel Holtmann <marcel@holtmann.org> told me that...
> Hi Petr,
Hello,
> let me be more specific. It only works in the fast forward case. If we
> actually must merge the trees, because I have local committed changes
> and not committed changes, I see this:
>
> link 74966c42ddd874192c318acfc5f013e56c50606a
> link b27ddcd47e293557e0605b98b2a1e8429035cdc5
> link 568ad7814e266f84b4ac28c15a0cadfb2fdb6c80
> Tree change: f345b0a066572206aac4a4f9a57d746e213b6bff:74966c42ddd874192c318acfc5f013e56c50606a
> :100644 100644 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 568ad7814e266f84b4ac28c15a0cadfb2fdb6c80 M README
>
> Applying changes...
> usage.c: needs update
> cg-merge: merge blocked: local changes
>
> I changed the README in test1 repository and committed it. Then I
> changed Makefile in test2 repository and committed it. After that I
> modified usage.c and left it uncommitted. Then I pulled in the README
> change from test1 repository.
yes, and that is all right. If you are actually doing the merge with
commit, you need to have the tree clean before, since any changes you
make to the tree are counted as conflict fixes, and you don't want your
older changes to mix into that.
--
Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
C++: an octopus made by nailing extra legs onto a dog. -- Steve Taylor
^ permalink raw reply
* Re: cg-update with local uncommitted changes
From: Marcel Holtmann @ 2005-06-02 21:26 UTC (permalink / raw)
To: Petr Baudis; +Cc: GIT Mailing List
In-Reply-To: <20050602211444.GF32189@pasky.ji.cz>
Hi Petr,
> > let me be more specific. It only works in the fast forward case. If we
> > actually must merge the trees, because I have local committed changes
> > and not committed changes, I see this:
> >
> > link 74966c42ddd874192c318acfc5f013e56c50606a
> > link b27ddcd47e293557e0605b98b2a1e8429035cdc5
> > link 568ad7814e266f84b4ac28c15a0cadfb2fdb6c80
> > Tree change: f345b0a066572206aac4a4f9a57d746e213b6bff:74966c42ddd874192c318acfc5f013e56c50606a
> > :100644 100644 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 568ad7814e266f84b4ac28c15a0cadfb2fdb6c80 M README
> >
> > Applying changes...
> > usage.c: needs update
> > cg-merge: merge blocked: local changes
> >
> > I changed the README in test1 repository and committed it. Then I
> > changed Makefile in test2 repository and committed it. After that I
> > modified usage.c and left it uncommitted. Then I pulled in the README
> > change from test1 repository.
>
> yes, and that is all right. If you are actually doing the merge with
> commit, you need to have the tree clean before, since any changes you
> make to the tree are counted as conflict fixes, and you don't want your
> older changes to mix into that.
but not if the merge does not conflict with the local changes. This is
what Bitkeeper is doing. It lets you pull new stuff as long as it does
not conflict with your local uncommitted changes. Actually I liked that
feature a lot, because I was able the follow the latest Linux mainline
tree and work on my stuff.
Regards
Marcel
^ permalink raw reply
* Re: [COGITO PATCH] mirroring repositories
From: Petr Baudis @ 2005-06-02 21:24 UTC (permalink / raw)
To: Michael Frank; +Cc: git
In-Reply-To: <1117402883.8536.5.camel@localhost.localdomain>
Dear diary, on Sun, May 29, 2005 at 11:41:23PM CEST, I got a letter
where Michael Frank <msfrank@syntaxjockey.com> told me that...
> The attached patch adds the two programs cg-mirror-add and
> cg-mirror-sync. Say you do all of your work on your laptop and you want
> to make a mirror of your repository available to the public. You
> specify the location of the mirror with cg-mirror-add:
>
> $ cg-mirror-add scp://my.server:/var/www/repos/project.git
>
> which locally creates the file .git/mirrors. Whenever you want to
> upload your changes, you run cg-mirror-sync.
FWIW, I think this is the wrong approach - full-blown pushing makes much
more sense since it's a full superset of mirroring and it's more
universal, and not *that* more complicated to do (basically just the
HEAD stuff - and I think the race conditions around that don't matter
that much in the real life if you take some basic crude protections).
--
Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
C++: an octopus made by nailing extra legs onto a dog. -- Steve Taylor
^ permalink raw reply
* Re: [PATCH] Handle deltified object correctly in git-*-pull family.
From: Nicolas Pitre @ 2005-06-02 21:31 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Linus Torvalds, git
In-Reply-To: <7v3bs07fmu.fsf@assigned-by-dhcp.cox.net>
On Thu, 2 Jun 2005, Junio C Hamano wrote:
> The initial parts of each retrieved SHA1 file is inflated and
> inspected to see if it is deltified, and its base object is
> asked from the remote side when it is. Since this partial
> inflation and inspection has a small performance hit, it can
> optionally be skipped by giving -d flag to git-*-pull commands.
It is still way more expensive than it could.
> diff --git a/sha1_file.c b/sha1_file.c
> --- a/sha1_file.c
> +++ b/sha1_file.c
> @@ -325,7 +325,13 @@ void *unpack_sha1_rest(z_stream *stream,
> int bytes = strlen(buffer) + 1;
> char *buf = xmalloc(1+size);
>
> - memcpy(buf, buffer + bytes, stream->total_out - bytes);
> + /* (stream->total_out - bytes) is what we already have. The
> + * caller could be asking for something smaller than that.
> + */
> + if (size < stream->total_out - bytes)
> + memcpy(buf, buffer + bytes, size);
> + else
> + memcpy(buf, buffer + bytes, stream->total_out - bytes);
> bytes = stream->total_out - bytes;
> if (bytes < size) {
> stream->next_out = buf + bytes;
This hunk is completely unneeded.
> @@ -401,6 +407,41 @@ void * unpack_sha1_file(void *map, unsig
> return unpack_sha1_rest(&stream, hdr, *size);
> }
>
> +int sha1_delta_base(const unsigned char *sha1, unsigned char *base_sha1)
> +{
> + int ret;
> + unsigned long mapsize, size;
> + void *map;
> + z_stream stream;
> + char hdr[1024], type[20];
Don't make hdr 1024 bytes long. If you do so unpack_sha1_header() will
uncompress up to 1024 bytes which is way above required. Instead,
consider a value of say 64 which is plenty sufficient (10 for the type
string, another 10 for the size, 20 for the reference sha1 and another
10 for the beginning of the delta data that must include the size, and
the rest for good measure).
> + void *delta_data_head;
> +
> + map = map_sha1_file(sha1, &mapsize);
> + if (!map)
> + return -1;
> + ret = unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr));
> + if (ret < Z_OK || parse_sha1_header(hdr, type, &size) < 0) {
> + ret = -1;
> + goto out;
> + }
> + if (strcmp(type, "delta")) {
> + ret = 0;
> + goto out;
> + }
> + delta_data_head = unpack_sha1_rest(&stream, hdr, 20);
Here you don't need to call unpack_sha1_rest() at all which would call
xmalloc and another memcpy needlessly. Instead, just use:
memcpy(base_sha1, hdr + strlen(hdr) + 1, 20);
and you're done. No need to call an extra free() either.
And maybe this function should live in delta.c instead?
Nicolas
^ permalink raw reply
* Re: [PATCH] Handle deltified object correctly in git-*-pull family.
From: Nicolas Pitre @ 2005-06-02 21:36 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Linus Torvalds, git
In-Reply-To: <Pine.LNX.4.63.0506021713330.17354@localhost.localdomain>
On Thu, 2 Jun 2005, Nicolas Pitre wrote:
> Here you don't need to call unpack_sha1_rest() at all which would call
> xmalloc and another memcpy needlessly. Instead, just use:
>
> memcpy(base_sha1, hdr + strlen(hdr) + 1, 20);
>
> and you're done. No need to call an extra free() either.
>
> And maybe this function should live in delta.c instead?
Forget about my suggestion of moving it to delta.c. Since it assumes
knowledge of the object header format it better stay close to the other
functions in sha1_file.c.
Nicolas
^ permalink raw reply
* Re: [PATCH] Find size of SHA1 object without inflating everything.
From: Linus Torvalds @ 2005-06-02 22:10 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7vwtpc60z3.fsf_-_@assigned-by-dhcp.cox.net>
On Thu, 2 Jun 2005, Junio C Hamano wrote:
>
> +int sha1_file_size(const unsigned char *sha1, unsigned long *sizep)
...
> + ret = unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr));
...
> + delta_data_head = unpack_sha1_rest(&stream, hdr, 200);
Why do you do this? You've already unpacked 1024 bytes (including the
header), now you want to unpack at least 200 bytes past the header (which
is less than what you already did.
So here "unpack_sha1_rest()" just ends up being a "xmalloc + memcpy", but
since you don't actually want the malloc (indeed, you're leaking it, as
far as I can tell), it seems to be all bad..
Linus
^ permalink raw reply
* [PATCH 1/2] Handle deltified object correctly in git-*-pull family.
From: Junio C Hamano @ 2005-06-02 22:19 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Nicolas Pitre, git
In-Reply-To: <Pine.LNX.4.63.0506021733520.17354@localhost.localdomain>
>>>>> "NP" == Nicolas Pitre <nico@cam.org> writes:
>> Here you don't need to call unpack_sha1_rest() at all which would call
>> xmalloc and another memcpy needlessly. Instead,...
Like this...
------------
When a remote repository is deltified, we need to get the
objects that a deltified object we want to obtain is based upon.
The initial parts of each retrieved SHA1 file is inflated and
inspected to see if it is deltified, and its base object is
asked from the remote side when it is. Since this partial
inflation and inspection has a small performance hit, it can
optionally be skipped by giving -d flag to git-*-pull commands.
This flag should be used only when the remote repository is
known to have no deltified objects.
Rsync transport does not have this problem since it fetches
everything the remote side has.
Signed-off-by: Junio C Hamano <junkio@cox.net>
---
*** Thanks and credits goes to Nico for suggesting not to
*** use unpack_sha1_rest().
Documentation/git-http-pull.txt | 6 +++++-
Documentation/git-local-pull.txt | 6 +++++-
Documentation/git-rpull.txt | 6 +++++-
cache.h | 1 +
pull.h | 3 +++
http-pull.c | 4 +++-
local-pull.c | 4 +++-
pull.c | 7 +++++++
rpull.c | 4 +++-
sha1_file.c | 31 +++++++++++++++++++++++++++++++
10 files changed, 66 insertions(+), 6 deletions(-)
diff --git a/Documentation/git-http-pull.txt b/Documentation/git-http-pull.txt
--- a/Documentation/git-http-pull.txt
+++ b/Documentation/git-http-pull.txt
@@ -9,7 +9,7 @@ git-http-pull - Downloads a remote GIT r
SYNOPSIS
--------
-'git-http-pull' [-c] [-t] [-a] [-v] commit-id url
+'git-http-pull' [-c] [-t] [-a] [-v] [-d] commit-id url
DESCRIPTION
-----------
@@ -21,6 +21,10 @@ Downloads a remote GIT repository via HT
Get trees associated with the commit objects.
-a::
Get all the objects.
+-d::
+ Do not check for delta base objects (use this option
+ only when you know the remote repository is not
+ deltified).
-v::
Report what is downloaded.
diff --git a/Documentation/git-local-pull.txt b/Documentation/git-local-pull.txt
--- a/Documentation/git-local-pull.txt
+++ b/Documentation/git-local-pull.txt
@@ -9,7 +9,7 @@ git-local-pull - Duplicates another GIT
SYNOPSIS
--------
-'git-local-pull' [-c] [-t] [-a] [-l] [-s] [-n] [-v] commit-id path
+'git-local-pull' [-c] [-t] [-a] [-l] [-s] [-n] [-v] [-d] commit-id path
DESCRIPTION
-----------
@@ -23,6 +23,10 @@ OPTIONS
Get trees associated with the commit objects.
-a::
Get all the objects.
+-d::
+ Do not check for delta base objects (use this option
+ only when you know the remote repository is not
+ deltified).
-v::
Report what is downloaded.
diff --git a/Documentation/git-rpull.txt b/Documentation/git-rpull.txt
--- a/Documentation/git-rpull.txt
+++ b/Documentation/git-rpull.txt
@@ -10,7 +10,7 @@ git-rpull - Pulls from a remote reposito
SYNOPSIS
--------
-'git-rpull' [-c] [-t] [-a] [-v] commit-id url
+'git-rpull' [-c] [-t] [-a] [-d] [-v] commit-id url
DESCRIPTION
-----------
@@ -25,6 +25,10 @@ OPTIONS
Get trees associated with the commit objects.
-a::
Get all the objects.
+-d::
+ Do not check for delta base objects (use this option
+ only when you know the remote repository is not
+ deltified).
-v::
Report what is downloaded.
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -153,6 +153,7 @@ extern char *sha1_file_name(const unsign
extern void * map_sha1_file(const unsigned char *sha1, unsigned long *size);
extern int unpack_sha1_header(z_stream *stream, void *map, unsigned long mapsize, void *buffer, unsigned long size);
extern int parse_sha1_header(char *hdr, char *type, unsigned long *sizep);
+extern int sha1_delta_base(const unsigned char *, unsigned char *);
extern void * unpack_sha1_file(void *map, unsigned long mapsize, char *type, unsigned long *size);
extern void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size);
extern int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
diff --git a/pull.h b/pull.h
--- a/pull.h
+++ b/pull.h
@@ -13,6 +13,9 @@ extern int get_history;
/** Set to fetch the trees in the commit history. **/
extern int get_all;
+/* Set to zero to skip the check for delta object base. */
+extern int get_delta;
+
/* Set to be verbose */
extern int get_verbosely;
diff --git a/http-pull.c b/http-pull.c
--- a/http-pull.c
+++ b/http-pull.c
@@ -103,6 +103,8 @@ int main(int argc, char **argv)
get_tree = 1;
} else if (argv[arg][1] == 'c') {
get_history = 1;
+ } else if (argv[arg][1] == 'd') {
+ get_delta = 0;
} else if (argv[arg][1] == 'a') {
get_all = 1;
get_tree = 1;
@@ -113,7 +115,7 @@ int main(int argc, char **argv)
arg++;
}
if (argc < arg + 2) {
- usage("git-http-pull [-c] [-t] [-a] [-v] commit-id url");
+ usage("git-http-pull [-c] [-t] [-a] [-d] [-v] commit-id url");
return 1;
}
commit_id = argv[arg];
diff --git a/local-pull.c b/local-pull.c
--- a/local-pull.c
+++ b/local-pull.c
@@ -74,7 +74,7 @@ int fetch(unsigned char *sha1)
}
static const char *local_pull_usage =
-"git-local-pull [-c] [-t] [-a] [-l] [-s] [-n] [-v] commit-id path";
+"git-local-pull [-c] [-t] [-a] [-l] [-s] [-n] [-v] [-d] commit-id path";
/*
* By default we only use file copy.
@@ -92,6 +92,8 @@ int main(int argc, char **argv)
get_tree = 1;
else if (argv[arg][1] == 'c')
get_history = 1;
+ else if (argv[arg][1] == 'd')
+ get_delta = 0;
else if (argv[arg][1] == 'a') {
get_all = 1;
get_tree = 1;
diff --git a/pull.c b/pull.c
--- a/pull.c
+++ b/pull.c
@@ -6,6 +6,7 @@
int get_tree = 0;
int get_history = 0;
+int get_delta = 1;
int get_all = 0;
int get_verbosely = 0;
static unsigned char current_commit_sha1[20];
@@ -37,6 +38,12 @@ static int make_sure_we_have_it(const ch
status = fetch(sha1);
if (status && what)
report_missing(what, sha1);
+ if (get_delta) {
+ char delta_sha1[20];
+ status = sha1_delta_base(sha1, delta_sha1);
+ if (0 < status)
+ status = make_sure_we_have_it(what, delta_sha1);
+ }
return status;
}
diff --git a/rpull.c b/rpull.c
--- a/rpull.c
+++ b/rpull.c
@@ -27,6 +27,8 @@ int main(int argc, char **argv)
get_tree = 1;
} else if (argv[arg][1] == 'c') {
get_history = 1;
+ } else if (argv[arg][1] == 'd') {
+ get_delta = 0;
} else if (argv[arg][1] == 'a') {
get_all = 1;
get_tree = 1;
@@ -37,7 +39,7 @@ int main(int argc, char **argv)
arg++;
}
if (argc < arg + 2) {
- usage("git-rpull [-c] [-t] [-a] [-v] commit-id url");
+ usage("git-rpull [-c] [-t] [-a] [-v] [-d] commit-id url");
return 1;
}
commit_id = argv[arg];
diff --git a/sha1_file.c b/sha1_file.c
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -401,6 +401,37 @@ void * unpack_sha1_file(void *map, unsig
return unpack_sha1_rest(&stream, hdr, *size);
}
+int sha1_delta_base(const unsigned char *sha1, unsigned char *base_sha1)
+{
+ int ret;
+ unsigned long mapsize, size;
+ void *map;
+ z_stream stream;
+ char hdr[64], type[20];
+ void *delta_data_head;
+
+ map = map_sha1_file(sha1, &mapsize);
+ if (!map)
+ return -1;
+ ret = unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr));
+ if (ret < Z_OK || parse_sha1_header(hdr, type, &size) < 0) {
+ ret = -1;
+ goto out;
+ }
+ if (strcmp(type, "delta")) {
+ ret = 0;
+ goto out;
+ }
+
+ delta_data_head = hdr + strlen(hdr) + 1;
+ ret = 1;
+ memcpy(base_sha1, delta_data_head, 20);
+ out:
+ inflateEnd(&stream);
+ munmap(map, mapsize);
+ return ret;
+}
+
void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size)
{
unsigned long mapsize;
------------
^ permalink raw reply
* [PATCH 2/2] Find size of SHA1 object without inflating everything.
From: Junio C Hamano @ 2005-06-02 22:20 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Nicolas Pitre, git
In-Reply-To: <Pine.LNX.4.63.0506021733520.17354@localhost.localdomain>
This adds sha1_file_size() helper function and uses it in the
rename/copy similarity estimator. The helper function handles
deltified object as well.
Signed-off-by: Junio C Hamano <junkio@cox.net>
---
*** Thanks and credits goes to Nico for suggesting not to
*** use unpack_sha1_rest().
cache.h | 1 +
diff.c | 11 ++++++-----
sha1_file.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 67 insertions(+), 5 deletions(-)
diff --git a/cache.h b/cache.h
--- a/cache.h
+++ b/cache.h
@@ -154,6 +154,7 @@ extern void * map_sha1_file(const unsign
extern int unpack_sha1_header(z_stream *stream, void *map, unsigned long mapsize, void *buffer, unsigned long size);
extern int parse_sha1_header(char *hdr, char *type, unsigned long *sizep);
extern int sha1_delta_base(const unsigned char *, unsigned char *);
+extern int sha1_file_size(const unsigned char *, unsigned long *);
extern void * unpack_sha1_file(void *map, unsigned long mapsize, char *type, unsigned long *size);
extern void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size);
extern int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
diff --git a/diff.c b/diff.c
--- a/diff.c
+++ b/diff.c
@@ -333,7 +333,6 @@ int diff_populate_filespec(struct diff_f
close(fd);
}
else {
- /* We cannot do size only for SHA1 blobs */
char type[20];
struct sha1_size_cache *e;
@@ -343,11 +342,13 @@ int diff_populate_filespec(struct diff_f
s->size = e->size;
return 0;
}
+ if (!sha1_file_size(s->sha1, &s->size))
+ locate_size_cache(s->sha1, s->size);
+ }
+ else {
+ s->data = read_sha1_file(s->sha1, type, &s->size);
+ s->should_free = 1;
}
- s->data = read_sha1_file(s->sha1, type, &s->size);
- s->should_free = 1;
- if (s->data && size_only)
- locate_size_cache(s->sha1, s->size);
}
return 0;
}
diff --git a/sha1_file.c b/sha1_file.c
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -432,6 +432,66 @@ int sha1_delta_base(const unsigned char
return ret;
}
+int sha1_file_size(const unsigned char *sha1, unsigned long *sizep)
+{
+ int ret, status;
+ unsigned long mapsize, size;
+ void *map;
+ z_stream stream;
+ char hdr[64], type[20];
+ const unsigned char *data;
+ unsigned char cmd;
+ int i;
+
+ map = map_sha1_file(sha1, &mapsize);
+ if (!map)
+ return -1;
+ ret = unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr));
+ status = -1;
+ if (ret < Z_OK || parse_sha1_header(hdr, type, &size) < 0)
+ goto out;
+ if (strcmp(type, "delta")) {
+ *sizep = size;
+ status = 0;
+ goto out;
+ }
+
+ /* We are dealing with a delta object. Inflated, the first
+ * 20 bytes hold the base object SHA1, and delta data follows
+ * immediately after it.
+ *
+ * The initial part of the delta starts at delta_data_head +
+ * 20. Borrow code from patch-delta to read the result size.
+ */
+ data = hdr + strlen(hdr) + 1 + 20;
+
+ /* Skip over the source size; we are not interested in
+ * it and we cannot verify it because we do not want
+ * to read the base object.
+ */
+ cmd = *data++;
+ while (cmd) {
+ if (cmd & 1)
+ data++;
+ cmd >>= 1;
+ }
+ /* Read the result size */
+ size = i = 0;
+ cmd = *data++;
+ while (cmd) {
+ if (cmd & 1)
+ size |= *data++ << i;
+ i += 8;
+ cmd >>= 1;
+ }
+ *sizep = size;
+ status = 0;
+ out:
+ inflateEnd(&stream);
+ munmap(map, mapsize);
+ return status;
+}
+
void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size)
{
unsigned long mapsize;
------------
^ 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