diff options
author | Junio C Hamano <junkio@cox.net> | 2006-04-19 16:12:57 -0700 |
---|---|---|
committer | Junio C Hamano <junkio@cox.net> | 2006-04-19 16:12:57 -0700 |
commit | 60571f75ab81f9e1d5a5f351ac07f6d86a461230 (patch) | |
tree | eeae35ba6480dcd50b9d02abb70eedd09ba95937 | |
parent | Merge branch 'master' into next (diff) | |
parent | Add git-unresolve <paths>... (diff) | |
download | tgif-60571f75ab81f9e1d5a5f351ac07f6d86a461230.tar.xz |
Merge branch 'jc/unresolve' into next
* jc/unresolve:
Add git-unresolve <paths>...
get_tree_entry(): make it available from tree-walk
sha1_name.c: no need to include diff.h; tree-walk.h will do.
sha1_name.c: prepare to make get_tree_entry() reusable from others.
pre-commit hook: complain about conflict markers.
git-merge: a bit more readable user guidance.
diff: move diff.c to diff-lib.c to make room.
git log: don't do merge diffs by default
Allow "git repack" users to specify repacking window/depth
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Makefile | 5 | ||||
-rw-r--r-- | diff-lib.c (renamed from diff.c) | 0 | ||||
-rwxr-xr-x | git-merge.sh | 2 | ||||
-rwxr-xr-x | git-repack.sh | 8 | ||||
-rw-r--r-- | git.c | 2 | ||||
-rw-r--r-- | sha1_name.c | 59 | ||||
-rw-r--r-- | templates/hooks--pre-commit | 3 | ||||
-rw-r--r-- | tree-walk.c | 50 | ||||
-rw-r--r-- | tree-walk.h | 2 | ||||
-rw-r--r-- | unresolve.c | 146 |
11 files changed, 215 insertions, 63 deletions
diff --git a/.gitignore b/.gitignore index 145f8555ad..a536f32497 100644 --- a/.gitignore +++ b/.gitignore @@ -111,6 +111,7 @@ git-tag git-tar-tree git-unpack-file git-unpack-objects +git-unresolve git-update-index git-update-ref git-update-server-info @@ -165,7 +165,8 @@ PROGRAMS = \ git-upload-pack$X git-verify-pack$X git-write-tree$X \ git-update-ref$X git-symbolic-ref$X git-check-ref-format$X \ git-name-rev$X git-pack-redundant$X git-repo-config$X git-var$X \ - git-describe$X git-merge-tree$X git-blame$X git-imap-send$X + git-describe$X git-merge-tree$X git-blame$X git-imap-send$X \ + git-unresolve$X BUILT_INS = git-log$X @@ -199,7 +200,7 @@ LIB_H = \ tree-walk.h log-tree.h DIFF_OBJS = \ - diff.o diffcore-break.o diffcore-order.o \ + diff-lib.o diffcore-break.o diffcore-order.o \ diffcore-pickaxe.o diffcore-rename.o tree-diff.o combine-diff.o \ diffcore-delta.o log-tree.o diff --git a/git-merge.sh b/git-merge.sh index 78ab422e4e..b834e79c98 100755 --- a/git-merge.sh +++ b/git-merge.sh @@ -335,5 +335,5 @@ Conflicts: then git-rerere fi - die "Automatic merge failed; fix up by hand" + die "Automatic merge failed; fix conflicts and then commit the result." fi diff --git a/git-repack.sh b/git-repack.sh index a5d349fd09..e0c9f323c3 100755 --- a/git-repack.sh +++ b/git-repack.sh @@ -5,9 +5,9 @@ USAGE='[-a] [-d] [-f] [-l] [-n] [-q]' . git-sh-setup - + no_update_info= all_into_one= remove_redundant= -local= quiet= no_reuse_delta= +local= quiet= no_reuse_delta= extra= while case "$#" in 0) break ;; esac do case "$1" in @@ -17,6 +17,8 @@ do -q) quiet=-q ;; -f) no_reuse_delta=--no-reuse-delta ;; -l) local=--local ;; + --window=*) extra="$extra $1" ;; + --depth=*) extra="$extra $1" ;; *) usage ;; esac shift @@ -40,7 +42,7 @@ case ",$all_into_one," in find . -type f \( -name '*.pack' -o -name '*.idx' \) -print` ;; esac -pack_objects="$pack_objects $local $quiet $no_reuse_delta" +pack_objects="$pack_objects $local $quiet $no_reuse_delta$extra" name=$(git-rev-list --objects --all $rev_list 2>&1 | git-pack-objects --non-empty $pack_objects .tmp-pack) || exit 1 @@ -368,8 +368,6 @@ static int cmd_log(int argc, const char **argv, char **envp) init_revisions(&rev); rev.always_show_header = 1; rev.diffopt.recursive = 1; - rev.combine_merges = 1; - rev.ignore_merges = 0; return cmd_log_wc(argc, argv, envp, &rev); } diff --git a/sha1_name.c b/sha1_name.c index 0cd1139e06..345935bb2b 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -3,7 +3,7 @@ #include "commit.h" #include "tree.h" #include "blob.h" -#include "diff.h" +#include "tree-walk.h" static int find_short_object_filename(int len, const char *name, unsigned char *sha1) { @@ -450,59 +450,6 @@ static int get_sha1_1(const char *name, int len, unsigned char *sha1) return get_short_sha1(name, len, sha1, 0); } -static int get_tree_entry(const unsigned char *, const char *, unsigned char *); - -static int find_tree_entry(struct tree_desc *t, const char *name, unsigned char *result) -{ - int namelen = strlen(name); - while (t->size) { - const char *entry; - const unsigned char *sha1; - int entrylen, cmp; - unsigned mode; - - sha1 = tree_entry_extract(t, &entry, &mode); - update_tree_entry(t); - entrylen = strlen(entry); - if (entrylen > namelen) - continue; - cmp = memcmp(name, entry, entrylen); - if (cmp > 0) - continue; - if (cmp < 0) - break; - if (entrylen == namelen) { - memcpy(result, sha1, 20); - return 0; - } - if (name[entrylen] != '/') - continue; - if (!S_ISDIR(mode)) - break; - if (++entrylen == namelen) { - memcpy(result, sha1, 20); - return 0; - } - return get_tree_entry(sha1, name + entrylen, result); - } - return -1; -} - -static int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned char *sha1) -{ - int retval; - void *tree; - struct tree_desc t; - - tree = read_object_with_reference(tree_sha1, tree_type, &t.size, NULL); - if (!tree) - return -1; - t.buf = tree; - retval = find_tree_entry(&t, name, sha1); - free(tree); - return retval; -} - /* * This is like "get_sha1_basic()", except it allows "sha1 expressions", * notably "xyz^" for "parent of xyz" @@ -510,6 +457,7 @@ static int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsi int get_sha1(const char *name, unsigned char *sha1) { int ret; + unsigned unused; prepare_alt_odb(); ret = get_sha1_1(name, strlen(name), sha1); @@ -518,7 +466,8 @@ int get_sha1(const char *name, unsigned char *sha1) if (cp) { unsigned char tree_sha1[20]; if (!get_sha1_1(name, cp-name, tree_sha1)) - return get_tree_entry(tree_sha1, cp+1, sha1); + return get_tree_entry(tree_sha1, cp+1, sha1, + &unused); } } return ret; diff --git a/templates/hooks--pre-commit b/templates/hooks--pre-commit index 43d3b6ef4a..723a9ef210 100644 --- a/templates/hooks--pre-commit +++ b/templates/hooks--pre-commit @@ -61,6 +61,9 @@ perl -e ' if (/^\s* /) { bad_line("indent SP followed by a TAB", $_); } + if (/^(?:[<>=]){7}/) { + bad_line("unresolved merge conflict", $_); + } } } exit($found_bad); diff --git a/tree-walk.c b/tree-walk.c index bf8bfdfdf8..9f7abb7cb3 100644 --- a/tree-walk.c +++ b/tree-walk.c @@ -115,3 +115,53 @@ void traverse_trees(int n, struct tree_desc *t, const char *base, traverse_callb free(entry); } +static int find_tree_entry(struct tree_desc *t, const char *name, unsigned char *result, unsigned *mode) +{ + int namelen = strlen(name); + while (t->size) { + const char *entry; + const unsigned char *sha1; + int entrylen, cmp; + + sha1 = tree_entry_extract(t, &entry, mode); + update_tree_entry(t); + entrylen = strlen(entry); + if (entrylen > namelen) + continue; + cmp = memcmp(name, entry, entrylen); + if (cmp > 0) + continue; + if (cmp < 0) + break; + if (entrylen == namelen) { + memcpy(result, sha1, 20); + return 0; + } + if (name[entrylen] != '/') + continue; + if (!S_ISDIR(*mode)) + break; + if (++entrylen == namelen) { + memcpy(result, sha1, 20); + return 0; + } + return get_tree_entry(sha1, name + entrylen, result, mode); + } + return -1; +} + +int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned char *sha1, unsigned *mode) +{ + int retval; + void *tree; + struct tree_desc t; + + tree = read_object_with_reference(tree_sha1, tree_type, &t.size, NULL); + if (!tree) + return -1; + t.buf = tree; + retval = find_tree_entry(&t, name, sha1, mode); + free(tree); + return retval; +} + diff --git a/tree-walk.h b/tree-walk.h index 76893e36c3..47438fe1c0 100644 --- a/tree-walk.h +++ b/tree-walk.h @@ -22,4 +22,6 @@ typedef void (*traverse_callback_t)(int n, unsigned long mask, struct name_entry void traverse_trees(int n, struct tree_desc *t, const char *base, traverse_callback_t callback); +int get_tree_entry(const unsigned char *, const char *, unsigned char *, unsigned *); + #endif diff --git a/unresolve.c b/unresolve.c new file mode 100644 index 0000000000..0b23b9bc75 --- /dev/null +++ b/unresolve.c @@ -0,0 +1,146 @@ +#include "cache.h" +#include "tree-walk.h" + +static const char unresolve_usage[] = +"git-unresolve <paths>..."; + +static struct cache_file cache_file; +static unsigned char head_sha1[20]; +static unsigned char merge_head_sha1[20]; + +static struct cache_entry *read_one_ent(const char *which, + unsigned char *ent, const char *path, + int namelen, int stage) +{ + unsigned mode; + unsigned char sha1[20]; + int size; + struct cache_entry *ce; + + if (get_tree_entry(ent, path, sha1, &mode)) { + error("%s: not in %s branch.", path, which); + return NULL; + } + if (mode == S_IFDIR) { + error("%s: not a blob in %s branch.", path, which); + return NULL; + } + size = cache_entry_size(namelen); + ce = xcalloc(1, size); + + memcpy(ce->sha1, sha1, 20); + memcpy(ce->name, path, namelen); + ce->ce_flags = create_ce_flags(namelen, stage); + ce->ce_mode = create_ce_mode(mode); + return ce; +} + +static int unresolve_one(const char *path) +{ + int namelen = strlen(path); + int pos; + int ret = 0; + struct cache_entry *ce_2 = NULL, *ce_3 = NULL; + + /* See if there is such entry in the index. */ + pos = cache_name_pos(path, namelen); + if (pos < 0) { + /* If there isn't, either it is unmerged, or + * resolved as "removed" by mistake. We do not + * want to do anything in the former case. + */ + pos = -pos-1; + if (pos < active_nr) { + struct cache_entry *ce = active_cache[pos]; + if (ce_namelen(ce) == namelen && + !memcmp(ce->name, path, namelen)) { + fprintf(stderr, + "%s: skipping still unmerged path.\n", + path); + goto free_return; + } + } + } + + /* Grab blobs from given path from HEAD and MERGE_HEAD, + * stuff HEAD version in stage #2, + * stuff MERGE_HEAD version in stage #3. + */ + ce_2 = read_one_ent("our", head_sha1, path, namelen, 2); + ce_3 = read_one_ent("their", merge_head_sha1, path, namelen, 3); + + if (!ce_2 || !ce_3) { + ret = -1; + goto free_return; + } + if (!memcmp(ce_2->sha1, ce_3->sha1, 20) && + ce_2->ce_mode == ce_3->ce_mode) { + fprintf(stderr, "%s: identical in both, skipping.\n", + path); + goto free_return; + } + + remove_file_from_cache(path); + if (add_cache_entry(ce_2, ADD_CACHE_OK_TO_ADD)) { + error("%s: cannot add our version to the index.", path); + ret = -1; + goto free_return; + } + if (!add_cache_entry(ce_3, ADD_CACHE_OK_TO_ADD)) + return 0; + error("%s: cannot add their version to the index.", path); + ret = -1; + free_return: + free(ce_2); + free(ce_3); + return ret; +} + +static void read_head_pointers(void) +{ + if (read_ref(git_path("HEAD"), head_sha1)) + die("Cannot read HEAD -- no initial commit yet?"); + if (read_ref(git_path("MERGE_HEAD"), merge_head_sha1)) { + fprintf(stderr, "Not in the middle of a merge.\n"); + exit(0); + } +} + +int main(int ac, char **av) +{ + int i; + int err = 0; + int newfd; + + if (ac < 2) + usage(unresolve_usage); + + git_config(git_default_config); + + /* Read HEAD and MERGE_HEAD; if MERGE_HEAD does not exist, we + * are not doing a merge, so exit with success status. + */ + read_head_pointers(); + + /* Otherwise we would need to update the cache. */ + newfd= hold_index_file_for_update(&cache_file, get_index_file()); + if (newfd < 0) + die("unable to create new cachefile"); + + if (read_cache() < 0) + die("cache corrupted"); + + for (i = 1; i < ac; i++) { + char *arg = av[i]; + err |= unresolve_one(arg); + } + if (err) + die("Error encountered; index not updated."); + + if (active_cache_changed) { + if (write_cache(newfd, active_cache, active_nr) || + commit_index_file(&cache_file)) + die("Unable to write new cachefile"); + } + return 0; +} |