git-diff-tree
git-fetch
git-fetch-pack
+git-fmt-merge-msg
git-format-patch
git-fsck-objects
git-get-tar-commit-id
git-unpack-file
git-unpack-objects
git-update-index
+git-update-ref
git-update-server-info
git-upload-pack
git-var
fputs("\n", stderr);
}
-int objerror(struct object *obj, const char *err, ...)
+static int objerror(struct object *obj, const char *err, ...)
{
va_list params;
va_start(params, err);
return -1;
}
-int objwarning(struct object *obj, const char *err, ...)
+static int objwarning(struct object *obj, const char *err, ...)
{
va_list params;
va_start(params, err);
tree=$(git-write-tree) || exit 1
echo Wrote tree $tree
-commit=$(git-commit-tree $tree -p $(cat "$GIT_DIR"/HEAD) < "$final") || exit 1
+parent=$(git-rev-parse --verify HEAD) &&
+commit=$(git-commit-tree $tree -p $parent <"$final") || exit 1
echo Committed: $commit
-echo $commit > "$GIT_DIR"/HEAD
+git-update-ref HEAD $commit $parent || exit
if test -x "$GIT_DIR"/hooks/post-applypatch
then
exit 1
fi
PARENTS=""
+ current=
else
+ current=$(git-rev-parse --verify HEAD)
if [ -f "$GIT_DIR/MERGE_HEAD" ]; then
PARENTS="-p HEAD "`sed -e 's/^/-p /' "$GIT_DIR/MERGE_HEAD"`
fi
then
tree=$(git-write-tree) &&
commit=$(cat .cmitmsg | git-commit-tree $tree $PARENTS) &&
- echo $commit > "$GIT_DIR/HEAD" &&
+ git-update-ref HEAD $commit $current &&
rm -f -- "$GIT_DIR/MERGE_HEAD"
else
echo >&2 "* no commit message? aborting commit."
remote_name_="$3"
remote_nick_="$4"
local_name_="$5"
+ case "$6" in
+ t) not_for_merge_='not-for-merge' ;;
+ '') not_for_merge_= ;;
+ esac
# remote-nick is the URL given on the command line (or a shorthand)
# remote-name is the $GIT_DIR relative refs/ path we computed
if git-cat-file commit "$head_" >/dev/null 2>&1
then
headc_=$(git-rev-parse --verify "$head_^0") || exit
- echo "$headc_ $note_" >>$GIT_DIR/FETCH_HEAD
+ echo "$headc_ $not_for_merge_ $note_" >>$GIT_DIR/FETCH_HEAD
echo >&2 "* committish: $head_"
echo >&2 " $note_"
else
+ echo "$head_ not-for-merge $note_" >>$GIT_DIR/FETCH_HEAD
echo >&2 "* non-commit: $head_"
echo >&2 " $note_"
fi
else
echo >&2 "* $1: storing $3"
fi
- echo "$2" >"$GIT_DIR/$1" ;;
+ git-update-ref "$1" "$2"
+ ;;
refs/heads/*)
- # NEEDSWORK: use the same cmpxchg protocol here.
- echo "$2" >"$GIT_DIR/$1.lock"
- if test -f "$GIT_DIR/$1"
+ # $1 is the ref being updated.
+ # $2 is the new value for the ref.
+ local=$(git-rev-parse --verify "$1^0" 2>/dev/null)
+ if test "$local"
then
- local=$(git-rev-parse --verify "$1^0") &&
+ # Require fast-forward.
mb=$(git-merge-base "$local" "$2") &&
case "$2,$mb" in
$local,*)
;;
*,$local)
echo >&2 "* $1: fast forward to $3"
+ git-update-ref "$1" "$2" "$local"
;;
*)
false
;;
esac || {
echo >&2 "* $1: does not fast forward to $3;"
- case "$force,$single_force" in
- t,* | *,t)
+ case ",$force,$single_force," in
+ *,t,*)
echo >&2 " forcing update."
+ git-update-ref "$1" "$2" "$local"
;;
*)
- mv "$GIT_DIR/$1.lock" "$GIT_DIR/$1.remote"
- echo >&2 " leaving it in '$1.remote'"
+ echo >&2 " not updating."
;;
esac
}
else
- echo >&2 "* $1: storing $3"
+ echo >&2 "* $1: storing $3"
+ git-update-ref "$1" "$2"
fi
- test -f "$GIT_DIR/$1.lock" &&
- mv "$GIT_DIR/$1.lock" "$GIT_DIR/$1"
;;
esac
}
case "$update_head_ok" in
'')
- orig_head=$(cat "$GIT_DIR/HEAD" 2>/dev/null)
+ orig_head=$(git-rev-parse --verify HEAD 2>/dev/null)
;;
esac
# These are relative path from $GIT_DIR, typically starting at refs/
# but may be HEAD
+ if expr "$ref" : '\.' >/dev/null
+ then
+ not_for_merge=t
+ ref=$(expr "$ref" : '\.\(.*\)')
+ else
+ not_for_merge=
+ fi
if expr "$ref" : '\+' >/dev/null
then
single_force=t
rsync://*)
TMP_HEAD="$GIT_DIR/TMP_HEAD"
rsync -L -q "$remote/$remote_name" "$TMP_HEAD" || exit 1
- head=$(git-rev-parse TMP_HEAD)
+ head=$(git-rev-parse --verify TMP_HEAD)
rm -f "$TMP_HEAD"
test "$rsync_slurped_objects" || {
rsync -av --ignore-existing --exclude info \
continue ;;
esac
- append_fetch_head "$head" "$remote" "$remote_name" "$remote_nick" "$local_name"
+ append_fetch_head "$head" "$remote" \
+ "$remote_name" "$remote_nick" "$local_name" "$not_for_merge"
done
case "$ref" in
+$remote_name:*)
single_force=t
+ not_for_merge=
+ found="$ref"
+ break ;;
+ .+$remote_name:*)
+ single_force=t
+ not_for_merge=t
+ found="$ref"
+ break ;;
+ .$remote_name:*)
+ not_for_merge=t
found="$ref"
break ;;
$remote_name:*)
+ not_for_merge=
found="$ref"
break ;;
esac
done
-
local_name=$(expr "$found" : '[^:]*:\(.*\)')
- append_fetch_head "$sha1" "$remote" "$remote_name" "$remote_nick" "$local_name"
+ append_fetch_head "$sha1" "$remote" \
+ "$remote_name" "$remote_nick" "$local_name" "$not_for_merge"
done || exit
;;
esac
*,, | t,* )
;;
*)
- curr_head=$(cat "$GIT_DIR/HEAD" 2>/dev/null)
+ curr_head=$(git-rev-parse --verify HEAD 2>/dev/null)
if test "$curr_head" != "$orig_head"
then
- echo "$orig_head" >$GIT_DIR/HEAD
+ git-update-ref HEAD "$orig_head"
die "Cannot fetch into the current branch."
fi
;;
my ($bname, $tname, $gname, $src);
chomp;
s/^[0-9a-f]* //;
+ next if (/^not-for-merge/);
+ s/^ //;
if (s/ of (.*)$//) {
$src = $1;
} else {
$src{$src}{GENERIC});
my $this = join(', ', @this);
if ($src ne '.') {
- $this .= " from $src";
+ $this .= " of $src";
}
push @msg, $this;
}
}
savestate() {
- git diff -r -z --name-only $head | cpio -0 -o >"$GIR_DIR/MERGE_SAVE"
+ # Stash away any local modifications.
+ git-diff-index -r -z --name-only $head |
+ cpio -0 -o >"$GIR_DIR/MERGE_SAVE"
}
restorestate() {
# Again the most common case of merging one remote.
echo "Updating from $head to $1."
git-update-index --refresh 2>/dev/null
- git-read-tree -u -m $head "$1" || exit 1
- git-rev-parse --verify "$1^0" > "$GIT_DIR/HEAD"
+ git-read-tree -u -m $head "$1" &&
+ new_head=$(git-rev-parse --verify "$1^0") &&
+ git-update-ref HEAD "$new_head" "$head" || exit 1
summary "$1"
dropsave
exit 0
# we use, it would operate on the index, possibly affecting the
# working tree, and when resolved cleanly, have the desired tree
# in the index -- this means that the index must be in sync with
-# the $head commit.
-files=$(git-diff-index --cached --name-only $head) || exit
-if [ "$files" ]; then
- echo >&2 "Dirty index: cannot merge (dirty: $files)"
- exit 1
-fi
+# the $head commit. The strategies are responsible to ensure this.
case "$use_strategies" in
?*' '?*)
do
parents="$parents -p $remote"
done
- result_commit=$(echo "$merge_msg" | git-commit-tree $result_tree $parents)
+ result_commit=$(echo "$merge_msg" | git-commit-tree $result_tree $parents) || exit
echo "Committed merge $result_commit, made by $wt_strategy."
- echo $result_commit >"$GIT_DIR/HEAD"
+ git-update-ref HEAD $result_commit $head
summary $result_commit
dropsave
exit 0
result_commit=$(git-fmt-merge-msg <"$GIT_DIR/FETCH_HEAD" |
git-commit-tree $MRT $PARENT)
echo "Committed merge $result_commit"
-echo $result_commit >"$GIT_DIR"/HEAD
+git-update-ref HEAD $result_commit $head
git-diff-tree -p $head $result_commit | git-apply --stat
esac
}
-# Subroutine to canonicalize remote:local notation
+# Subroutine to canonicalize remote:local notation.
canon_refs_list_for_fetch () {
+ # Leave only the first one alone; add prefix . to the rest
+ # to prevent the secondary branches to be merged by default.
+ dot_prefix=
for ref
do
force=
heads/* | tags/* ) local="refs/$local" ;;
*) local="refs/heads/$local" ;;
esac
- echo "${force}${remote}:${local}"
+ echo "${dot_prefix}${force}${remote}:${local}"
+ dot_prefix=.
done
}
echo "refs/heads/${remote_branch}:refs/heads/$1"
;;
remotes)
+ # This prefixes the second and later default refspecs
+ # with a '.', to signal git-fetch to mark them
+ # not-for-merge.
canon_refs_list_for_fetch $(sed -ne '/^Pull: */{
s///p
}' "$GIT_DIR/remotes/$1")
. git-sh-setup || die "Not a git archive"
-orig_head=$(cat "$GIT_DIR/HEAD") || die "Pulling into a black hole?"
+orig_head=$(git-rev-parse --verify HEAD) || die "Pulling into a black hole?"
git-fetch --update-head-ok "$@" || exit 1
-curr_head=$(cat "$GIT_DIR/HEAD")
+curr_head=$(git-rev-parse --verify HEAD)
if test "$curr_head" != "$orig_head"
then
# The fetch involved updating the current branch.
die "You need to first update your working tree."
fi
-merge_head=$(sed -e 's/ .*//' "$GIT_DIR"/FETCH_HEAD | tr '\012' ' ')
+merge_head=$(sed -e '/ not-for-merge /d' \
+ -e 's/ .*//' "$GIT_DIR"/FETCH_HEAD | \
+ tr '\012' ' ')
case "$merge_head" in
'')
esac
merge_name=$(git-fmt-merge-msg <"$GIT_DIR/FETCH_HEAD")
-git-resolve "$(cat "$GIT_DIR"/HEAD)" $merge_head "$merge_name"
+git-resolve "$curr_head" $merge_head "$merge_name"
die "Your working tree does not match $ours_symbolic."
git-read-tree -m -u $ours $upstream &&
-git-rev-parse --verify "$upstream^0" >"$GIT_DIR/HEAD" || exit
+new_head=$(git-rev-parse --verify "$upstream^0") &&
+git-update-ref HEAD "$new_head" || exit
tmp=.rebase-tmp$$
fail=$tmp-fail
continue ;;
esac
echo >&2 "* Applying: $msg"
- S=`cat "$GIT_DIR/HEAD"` &&
+ S=$(git-rev-parse --verify HEAD) &&
git-cherry-pick --replay $commit || {
echo >&2 "* Not applying the patch and continuing."
echo $commit >>$fail
else
rm -f "$GIT_DIR/ORIG_HEAD"
fi
-echo "$rev" >"$GIT_DIR/HEAD"
+git-update-ref HEAD "$rev"
case "$reset_type" in
--hard )
"$head")
echo "Updating from $head to $merge."
git-read-tree -u -m $head $merge || exit 1
- echo $merge > "$GIT_DIR"/HEAD
+ git-update-ref HEAD "$merge" "$head"
git-diff-tree -p $head $merge | git-apply --stat
dropheads
exit 0
fi
result_commit=$(echo "$merge_msg" | git-commit-tree $result_tree -p $head -p $merge)
echo "Committed merge $result_commit"
-echo $result_commit > "$GIT_DIR"/HEAD
+git-update-ref HEAD "$result_commit" "$head"
git-diff-tree -p $head $result_commit | git-apply --stat
dropheads
struct alt_base *next;
};
-struct alt_base *alt = NULL;
+static struct alt_base *alt = NULL;
static SHA_CTX c;
static z_stream stream;
static int zret;
static int curl_ssl_verify;
+static char *ssl_cert;
+static char *ssl_key;
+static char *ssl_capath;
+static char *ssl_cainfo;
struct buffer
{
return 0;
}
-int fetch_object(struct alt_base *repo, unsigned char *sha1)
+static int fetch_object(struct alt_base *repo, unsigned char *sha1)
{
char *hex = sha1_to_hex(sha1);
char *filename = sha1_file_name(sha1);
curl_easy_setopt(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
#endif
+ if ((ssl_cert = getenv("GIT_SSL_CERT")) != NULL) {
+ curl_easy_setopt(curl, CURLOPT_SSLCERT, ssl_cert);
+ }
+ if ((ssl_key = getenv("GIT_SSL_KEY")) != NULL) {
+ curl_easy_setopt(curl, CURLOPT_SSLKEY, ssl_key);
+ }
+#if LIBCURL_VERSION_NUM >= 0x070908
+ if ((ssl_capath = getenv("GIT_SSL_CAPATH")) != NULL) {
+ curl_easy_setopt(curl, CURLOPT_CAPATH, ssl_capath);
+ }
+#endif
+ if ((ssl_cainfo = getenv("GIT_SSL_CAINFO")) != NULL) {
+ curl_easy_setopt(curl, CURLOPT_CAINFO, ssl_cainfo);
+ }
+
alt = xmalloc(sizeof(*alt));
alt->base = url;
alt->got_indices = 0;
We have so far tested only empty index and clean-and-matching-A index
case which are trivial. Make sure index requirements are also
-checked. The table also lists alternative semantics which is not
-currently implemented.
+checked.
-"git-diff-tree -m O A B"
+"git-read-tree -m O A B"
O A B result index requirements
-------------------------------------------------------------------
1 missing missing missing - must not exist.
------------------------------------------------------------------
- 2 missing missing exists no merge must not exist.
- ------------------------------------
- (ALT) take B* must match B, if exists.
+ 2 missing missing exists take B* must match B, if exists.
------------------------------------------------------------------
- 3 missing exists missing no merge must match A and be
- up-to-date, if exists.
- ------------------------------------
- (ALT) take A* must match A, if exists.
+ 3 missing exists missing take A* must match A, if exists.
------------------------------------------------------------------
4 missing exists A!=B no merge must match A and be
up-to-date, if exists.
------------------------------------------------------------------
- 5 missing exists A==B no merge must match A and be
- up-to-date, if exists.
- ------------------------------------
- (ALT) take A must match A, if exists.
+ 5 missing exists A==B take A must match A, if exists.
------------------------------------------------------------------
- 6 exists missing missing no merge must not exist.
- ------------------------------------
- (ALT) remove must not exist.
+ 6 exists missing missing remove must not exist.
------------------------------------------------------------------
7 exists missing O!=B no merge must not exist.
------------------------------------------------------------------
- 8 exists missing O==B no merge must not exist.
- ------------------------------------
- (ALT) remove must not exist.
+ 8 exists missing O==B remove must not exist.
------------------------------------------------------------------
9 exists O!=A missing no merge must match A and be
up-to-date, if exists.
------------------------------------------------------------------
- 10 exists O==A missing no merge must match A and be
- up-to-date, if exists.
- ------------------------------------
- (ALT) remove ditto
+ 10 exists O==A missing remove ditto
------------------------------------------------------------------
11 exists O!=A O!=B no merge must match A and be
A!=B up-to-date, if exists.
------------------------------------------------------------------
13 exists O!=A O==B take A must match A, if exists.
------------------------------------------------------------------
- 14 exists O==A O!=B take B must match A and be
- be up-to-date, if exists.
- ------------------------------------
- (ALT) take B if exists, must either (1)
+ 14 exists O==A O!=B take B if exists, must either (1)
match A and be up-to-date,
or (2) match B.
------------------------------------------------------------------
*multi* in one in another
-------------------------------------------------------------------
-Note: if we want to implement 2ALT and 3ALT we need to be careful.
-The tree A may contain DF (file) when tree B require DF to be a
-directory by having DF/DF (file).
+Note: we need to be careful in case 2 and 3. The tree A may contain
+DF (file) when tree B require DF to be a directory by having DF/DF
+(file).
END_OF_CASE_TABLE
#define MAXDEPTH 5
-const char *resolve_ref(const char *path, unsigned char *sha1)
+static const char *resolve_ref(const char *path, unsigned char *sha1)
{
int depth = MAXDEPTH, len;
char buffer[256];