* What's cooking in git.git (Aug 2008, #05; Tue, 19) @ 2008-08-19 9:05 Junio C Hamano 2008-08-19 11:02 ` Johannes Sixt 2008-08-19 12:54 ` Miklos Vajna 0 siblings, 2 replies; 35+ messages in thread From: Junio C Hamano @ 2008-08-19 9:05 UTC (permalink / raw) To: git Here are the topics that have been cooking. Commits prefixed with '-' are only in 'pu' while commits prefixed with '+' are in 'next'. The topics list the commits in reverse chronological order. The topics meant to be merged to the maintenance series have "maint-" in their names. Tonight's 'pu' does not pass tests because test vectors have not been adjusted for the changes brought in by the jc/diff-prefix topic. ---------------------------------------------------------------- [New Topics] * js/mingw-stat (Mon Aug 18 22:01:06 2008 +0200) 2 commits - Revert "Windows: Use a customized struct stat that also has the st_blocks member." - compat: introduce on_disk_bytes() This gets rid of use of st_blocks member (which is XSI but not POSIX proper), which was originally prompted by recent Haiku port but it turns out MinGW has the same issue as well. Queued on 'pu' just to have a chance to make sure I munged the version j6t sent me correctly before merging it upwards. * ml/submodule-foreach (Sun Aug 10 19:10:04 2008 -0400) 1 commit + git-submodule - Add 'foreach' subcommand * jc/stripspace (Sun Mar 9 00:30:35 2008 -0800) 6 commits - git-am --forge: add Signed-off-by: line for the author - git-am: clean-up Signed-off-by: lines - stripspace: add --log-clean option to clean up signed-off-by: lines - stripspace: use parse_options() - Add "git am -s" test - git-am: refactor code to add signed-off-by line for the committer * pm/log-exit-code (Mon Aug 11 08:46:25 2008 +0200) 2 commits + Teach git log --exit-code to return an appropriate exit code + Teach git log --check to return an appropriate exit code * sb/commit-tree-minileak (Tue Aug 12 00:35:11 2008 +0200) 1 commit + Fix commit_tree() buffer leak * pb/reflog-dwim (Sun Aug 10 22:22:21 2008 +0200) 1 commit + builtin-reflog: Allow reflog expire to name partial ref * jc/send-pack-tell-me-more (Thu Mar 20 00:44:11 2008 -0700) 1 commit - "git push": tellme-more protocol extension * jc/merge-whitespace (Sun Feb 24 23:29:36 2008 -0800) 1 commit - WIP: start teaching the --whitespace=fix to merge machinery * lw/gitweb (Mon Aug 18 21:39:49 2008 +0200) 3 commits - gitweb: use new Git::Repo API, and add optional caching - add new Perl API: Git::Repo, Git::Commit, Git::Tag, and Git::RepoRoot - gitweb: add test suite with Test::WWW::Mechanize::CGI * jc/diff-prefix (Mon Aug 18 20:08:09 2008 -0700) 1 commit - diff: vary default prefix depending on what are compared * jc/blame (Wed Jun 4 22:58:40 2008 -0700) 2 commits - blame: show "previous" information in --porcelain/--incremental format - git-blame: refactor code to emit "porcelain format" output ---------------------------------------------------------------- [Graduated to "master"] * ak/p4 (Thu Aug 14 23:40:39 2008 +0100) 14 commits + Utilise our new p4_read_pipe and p4_write_pipe wrappers + Add p4 read_pipe and write_pipe wrappers + Put in the two other configuration elements found in the source + Put some documentation in about the parameters that have been added + Move git-p4.syncFromOrigin into a configuration parameters section + Consistently use 'git-p4' for the configuration entries + If the user has configured various parameters, use them. + Switch to using 'p4_build_cmd' + If we are in verbose mode, output what we are about to run (or return) + Add a single command that will be used to construct the 'p4' command + Utilise the new 'p4_system' function. + Have a command that specifically invokes 'p4' (via system) + Utilise the new 'p4_read_pipe_lines' command + Create a specific version of the read_pipe_lines command for p4 invocations Warmly received by the primary contributors of git-p4; this was merged as part of 1.6.0. ---------------------------------------------------------------- [Will merge to master soon] * js/checkout-dwim-local (Sat Aug 9 16:00:12 2008 +0200) 1 commit + checkout --track: make up a sensible branch name if '-b' was omitted * bd/diff-strbuf (Wed Aug 13 23:18:22 2008 -0700) 3 commits + xdiff-interface: hide the whole "xdiff_emit_state" business from the caller + Use strbuf for struct xdiff_emit_state's remainder + Make xdi_diff_outf interface for running xdiff_outf diffs Gives measurable performance improvement to textual diff generation. For improving "blame" performance, it might be more effective to hook directly to lower level of xdiff machinery so that we do not even have to generate patch only to discard after reading "@@ -l,k +m,n @@" lines, but that would be a separate topic. * jc/add-stop-at-symlink (Mon Aug 4 00:52:37 2008 -0700) 2 commits + add: refuse to add working tree items beyond symlinks + update-index: refuse to add working tree items beyond symlinks Fix for a longstanding bug that allows "git add" and "git update-index" to add a path "a/b" to the index when "a" is a symbolic link. We would need a similar fix for the case where "a" is a submodule. * dp/hash-literally (Sun Aug 3 18:36:22 2008 +0400) 6 commits + add --no-filters option to git hash-object + add --path option to git hash-object + use parse_options() in git hash-object + correct usage help string for git-hash-object + correct argument checking test for git hash-object + teach index_fd to work with pipes Gives a bit more flexibility to hash-objects by allowing us to lie about the path the contents comes from. * mv/merge-custom (Wed Aug 13 23:32:43 2008 +0200) 7 commits + Update .gitignore to ignore git-help + Builtin git-help. + builtin-help: always load_command_list() in cmd_help() + Add a second testcase for handling invalid strategies in git-merge + Add a new test for using a custom merge strategy + builtin-merge: allow using a custom strategy + builtin-help: make some internal functions available to other builtins * kh/diff-tree (Sun Aug 10 18:13:04 2008 +0200) 4 commits + Add test for diff-tree --stdin with two trees + Teach git diff-tree --stdin to diff trees + diff-tree: Note that the commit ID is printed with --stdin + Refactoring: Split up diff_tree_stdin * mg/count-objects (Fri Aug 15 00:20:20 2008 -0400) 1 commit + count-objects: Add total pack size to verbose output This one is without the human readable bits. * mz/push-verbose (Sat Aug 16 19:58:32 2008 +0200) 1 commit + Make push more verbose about illegal combination of options * jc/index-extended-flags (Sat Aug 16 23:02:08 2008 -0700) 1 commit + index: future proof for "extended" index entries * cc/merge-base-many (Sun Jul 27 13:47:22 2008 -0700) 4 commits + git-merge-octopus: use (merge-base A (merge B C D E...)) for stepwise merge + merge-base-many: add trivial tests based on the documentation + documentation: merge-base: explain "git merge-base" with more than 2 args + merge-base: teach "git merge-base" to drive underlying merge_bases_many() * rs/imap (Wed Jul 9 22:29:02 2008 +0100) 5 commits + Documentation: Improve documentation for git-imap-send(1) + imap-send.c: more style fixes + imap-send.c: style fixes + git-imap-send: Support SSL + git-imap-send: Allow the program to be run from subdirectories of a git tree Some people seem to prefer having this feature available also with gnutls. Such an enhancement can be done in-tree on top of this series if they are so inclined. * jc/add-addremove (Tue Jul 22 22:30:40 2008 -0700) 2 commits + builtin-add.c: optimize -A option and "git add ." + builtin-add.c: restructure the code for maintainability * jk/pager-swap (Tue Jul 22 03:14:12 2008 -0400) 2 commits + spawn pager via run_command interface + run-command: add pre-exec callback This changes the parent-child relationship between the pager and the git process. We used to make pager the parent which meant that the exit status from git is lost from the caller. * ph/enable-threaded (Mon Jul 21 11:23:43 2008 +0200) 1 commit + Enable threaded delta search on *BSD and Linux. * am/cherry-pick-rerere (Sun Aug 10 17:18:55 2008 +0530) 1 commit + Make cherry-pick use rerere for conflict resolution. * js/parallel-test (Mon Aug 18 12:25:40 2008 -0400) 4 commits + Update t/.gitignore to ignore all trash directories + Enable parallel tests + tests: Clarify dependencies between tests, 'aggregate-results' and 'clean' + t9700: remove useless check * jc/test-deeper (Fri Aug 8 02:26:28 2008 -0700) 1 commit + tests: use $TEST_DIRECTORY to refer to the t/ directory This does not actually move "t/test directory" any deeper, but fixes test scripts that assume they run immediately below "t/" to use TEST_DIRECTORY variable. ---------------------------------------------------------------- [Actively Cooking] * sp/missing-thin-base (Tue Aug 12 11:31:06 2008 -0700) 1 commit + pack-objects: Allow missing base objects when creating thin packs * tr/filter-branch (Tue Aug 12 10:45:59 2008 +0200) 3 commits + filter-branch: use --simplify-merges + filter-branch: fix ref rewriting with --subdirectory-filter + filter-branch: Extend test to show rewriting bug Fixes a longstanding filter branch bug. * jc/post-simplify (Fri Aug 15 01:34:51 2008 -0700) 8 commits - revision --simplify-merges: incremental simplification - revision --simplify-merges: prepare for incremental simplification - revision --simplify-merges: make it a no-op without pathspec + revision --simplify-merges: do not leave commits unprocessed + revision --simplify-merges: use decoration instead of commit->util field + Topo-sort before --simplify-merges + revision traversal: show full history with merge simplification + revision.c: whitespace fix "log --full-history" is with too much clutter, "log" itself is too cleverer than some people, and here is the middle level of merge simplification. I started making this incremental but the progress is not so great. * tr/rev-list-docs (Tue Aug 12 01:55:37 2008 +0200) 1 commit + Documentation: rev-list-options: move --simplify-merges documentation ---------------------------------------------------------------- [On Hold] * lt/time-reject-fractional-seconds (Sat Aug 16 21:25:40 2008 -0700) 1 commit - date/time: do not get confused by fractional seconds Linus hints further enhancements as "the right way", so let's see if somebody else steps up and tries it before merging this to 'next'. * jc/cc-ld-dynpath (Sat Aug 16 15:01:23 2008 +0200) 2 commits - configure: auto detect dynamic library path switches - Makefile: Allow CC_LD_DYNPATH to be overriden Needs success reports from people who do use user-defined dynamic library path when they build their "git" before this series can go anywhere. * sb/daemon (Thu Aug 14 20:02:20 2008 +0200) 4 commits - git-daemon: rewrite kindergarden, new option --max-connections - git-daemon: Simplify dead-children reaping logic - git-daemon: use LOG_PID, simplify logging code - git-daemon: call logerror() instead of error() Can somebody who actually runs the daemon standalone comment on this one? * mv/merge-recursive (Tue Aug 12 22:14:00 2008 +0200) 3 commits - Make builtin-revert.c use merge_recursive_generic() - merge-recursive.c: Add more generic merge_recursive_generic() - Split out merge_recursive() to merge-recursive.c I do not think builtlin-revert should use "recursive", but these patches give a good starting point to separate the bulk of the "rename-aware three-way merge" into library form. * sp/smart-http (Sun Aug 3 00:25:17 2008 -0700) 2 commits - [do not merge -- original version] Add Git-aware CGI for Git-aware smart HTTP transport - Add backdoor options to receive-pack for use in Git-aware CGI The "magic" detection protocol was revised to use POST to info/refs; the top one queued is from before that discussion. * cc/bisect (Fri Jul 25 05:36:37 2008 +0200) 2 commits - bisect: only check merge bases when needed - bisect: test merge base if good rev is not an ancestor of bad rev The first one alone does not pass its self-test but combined together they seem to. It does not build confidence as the latter one is supposed to be an optimization only. Resend of fixed-up series is needed. * sg/merge-options (Sun Apr 6 03:23:47 2008 +0200) 1 commit + merge: remove deprecated summary and diffstat options and config variables This was previously in "will be in master soon" category, but it turns out that the synonyms to the ones this one deletes are fairly new invention that happend in 1.5.6 timeframe, and we cannot do this just yet. Perhaps in 1.7.0. * jc/dashless (Wed Jun 25 15:55:11 2008 -0700) 1 commit - Make clients ask for "git program" over ssh and local transport This is the "botched" one. Will be resurrected during 1.7.0 or 1.8.0 timeframe. * jk/renamelimit (Sat May 3 13:58:42 2008 -0700) 1 commit - diff: enable "too large a rename" warning when -M/-C is explicitly asked for This would be the right thing to do for command line use, but gitk will be hit due to tcl/tk's limitation, so I am holding this back for now. ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: What's cooking in git.git (Aug 2008, #05; Tue, 19) 2008-08-19 9:05 What's cooking in git.git (Aug 2008, #05; Tue, 19) Junio C Hamano @ 2008-08-19 11:02 ` Johannes Sixt 2008-08-19 12:35 ` Andreas Färber 2008-08-19 12:54 ` Miklos Vajna 1 sibling, 1 reply; 35+ messages in thread From: Johannes Sixt @ 2008-08-19 11:02 UTC (permalink / raw) To: Junio C Hamano; +Cc: git Junio C Hamano schrieb: > * js/mingw-stat (Mon Aug 18 22:01:06 2008 +0200) 2 commits > - Revert "Windows: Use a customized struct stat that also has the > st_blocks member." > - compat: introduce on_disk_bytes() > > This gets rid of use of st_blocks member (which is XSI but not POSIX > proper), which was originally prompted by recent Haiku port but it turns > out MinGW has the same issue as well. Queued on 'pu' just to have a > chance to make sure I munged the version j6t sent me correctly before > merging it upwards. I tested this again, and it works as expected. -- Hannes ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: What's cooking in git.git (Aug 2008, #05; Tue, 19) 2008-08-19 11:02 ` Johannes Sixt @ 2008-08-19 12:35 ` Andreas Färber 0 siblings, 0 replies; 35+ messages in thread From: Andreas Färber @ 2008-08-19 12:35 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Johannes Sixt Am 19.08.2008 um 13:02 schrieb Johannes Sixt: > Junio C Hamano schrieb: >> * js/mingw-stat (Mon Aug 18 22:01:06 2008 +0200) 2 commits >> - Revert "Windows: Use a customized struct stat that also has the >> st_blocks member." >> - compat: introduce on_disk_bytes() >> >> This gets rid of use of st_blocks member (which is XSI but not POSIX >> proper), which was originally prompted by recent Haiku port but it >> turns >> out MinGW has the same issue as well. Queued on 'pu' just to have a >> chance to make sure I munged the version j6t sent me correctly before >> merging it upwards. > > I tested this again, and it works as expected. So did I for the latter, on Haiku. Together with the hardlink patch not yet queued, this allows to build and install (*) via `make` with suitable arguments. Andreas (*) Haiku's `read` (bash) seems to be broken - using `ls -1` in templates/Makefile works around that, but it should be fixed at the source. http://dev.haiku-os.org/ticket/2646 ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: What's cooking in git.git (Aug 2008, #05; Tue, 19) 2008-08-19 9:05 What's cooking in git.git (Aug 2008, #05; Tue, 19) Junio C Hamano 2008-08-19 11:02 ` Johannes Sixt @ 2008-08-19 12:54 ` Miklos Vajna 2008-08-19 19:19 ` Junio C Hamano 1 sibling, 1 reply; 35+ messages in thread From: Miklos Vajna @ 2008-08-19 12:54 UTC (permalink / raw) To: Junio C Hamano; +Cc: git [-- Attachment #1: Type: text/plain, Size: 895 bytes --] On Tue, Aug 19, 2008 at 02:05:42AM -0700, Junio C Hamano <gitster@pobox.com> wrote: > [On Hold] > (...) > * mv/merge-recursive (Tue Aug 12 22:14:00 2008 +0200) 3 commits > - Make builtin-revert.c use merge_recursive_generic() > - merge-recursive.c: Add more generic merge_recursive_generic() > - Split out merge_recursive() to merge-recursive.c > > I do not think builtlin-revert should use "recursive", but these patches > give a good starting point to separate the bulk of the "rename-aware > three-way merge" into library form. I wanted to send a patch that makes builtin-merge use the new merge_recursive_setup(), but then I was not able to decide to use merge_recursive_generic() or not. What is your preference here? I just want to avoid a "this could be merged, but it uses merge_recursive(), not merge_recursive_generic()" or the opposite of this. :) Thanks. [-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --] ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: What's cooking in git.git (Aug 2008, #05; Tue, 19) 2008-08-19 12:54 ` Miklos Vajna @ 2008-08-19 19:19 ` Junio C Hamano 2008-08-19 20:59 ` Miklos Vajna 0 siblings, 1 reply; 35+ messages in thread From: Junio C Hamano @ 2008-08-19 19:19 UTC (permalink / raw) To: Miklos Vajna; +Cc: git, Stephan Beyer Miklos Vajna <vmiklos@frugalware.org> writes: > On Tue, Aug 19, 2008 at 02:05:42AM -0700, Junio C Hamano <gitster@pobox.com> wrote: >> [On Hold] >> (...) >> * mv/merge-recursive (Tue Aug 12 22:14:00 2008 +0200) 3 commits >> - Make builtin-revert.c use merge_recursive_generic() >> - merge-recursive.c: Add more generic merge_recursive_generic() >> - Split out merge_recursive() to merge-recursive.c >> >> I do not think builtlin-revert should use "recursive", but these patches >> give a good starting point to separate the bulk of the "rename-aware >> three-way merge" into library form. > > I wanted to send a patch that makes builtin-merge use the new > merge_recursive_setup(), but then I was not able to decide to use > merge_recursive_generic() or not. I think git-merge and git-merge-recursive should be the only two that actually trigger the "recursive" behaviour. Everybody else should be using non-recursive one, and that non-recursive one can be shared by the one that is recursive. Here is how the callchain looks like with your variant. cmd_merge_recursive() -> merge_recursive_setup() -> merge_recursive_generic() -> merge_recursive() -> merge_recursive() -> merge_trees() The merge_recursive() is the "recursive" one. The workhorse that is not recursive is merge_trees(). Since the latter is what everybody else ("checkout -m", "revert", "cherry-pick", "am -3", "stash apply") should be using, I think it is pretty much up to "git-merge" and "git-merge-recursive" implementations how the caller of merge_recursive() function is structured. I suspect that you would not need two separate functions, _setup() and _generic(), for these two codepaths, but I didn't look closely. And make_virtual_commit() should become static inside merge_recursive.c; use of these fake commits is strictly an internal implementation issue of how merge_recursive() function works and does not concern the caller, does it? By the way, the calling convention of merge_recursive_generic() looks confusing (even though by the above reasoning it does not matter very much outside "git-merge" and "git-merge-recursive"). Why does it take textual object names for bases but binary object names for head and next? ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: What's cooking in git.git (Aug 2008, #05; Tue, 19) 2008-08-19 19:19 ` Junio C Hamano @ 2008-08-19 20:59 ` Miklos Vajna 2008-08-19 22:00 ` Junio C Hamano 0 siblings, 1 reply; 35+ messages in thread From: Miklos Vajna @ 2008-08-19 20:59 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Stephan Beyer [-- Attachment #1: Type: text/plain, Size: 1148 bytes --] On Tue, Aug 19, 2008 at 12:19:09PM -0700, Junio C Hamano <gitster@pobox.com> wrote: > Since the latter is what everybody else ("checkout -m", "revert", > "cherry-pick", "am -3", "stash apply") should be using, I think it is > pretty much up to "git-merge" and "git-merge-recursive" implementations > how the caller of merge_recursive() function is structured. I suspect > that you would not need two separate functions, _setup() and _generic(), > for these two codepaths, but I didn't look closely. Sure, I can avoid _generic() and use merge_recursive() directly, that's why I asked. > And make_virtual_commit() should become static inside merge_recursive.c; > use of these fake commits is strictly an internal implementation issue of > how merge_recursive() function works and does not concern the caller, does > it? Not exactly. builtin-merge-recursive uses get_ref() - which should not be in merge-recursive.c IMHO - and get_ref() uses make_virtual_commit(). merge_recursive() itself takes commits, so it can be only static if we copy it builtin-merge-recursive as well, causing a code duplication. Or have I missed something here? Thanks. [-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --] ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: What's cooking in git.git (Aug 2008, #05; Tue, 19) 2008-08-19 20:59 ` Miklos Vajna @ 2008-08-19 22:00 ` Junio C Hamano 2008-08-20 22:42 ` Miklos Vajna ` (2 more replies) 0 siblings, 3 replies; 35+ messages in thread From: Junio C Hamano @ 2008-08-19 22:00 UTC (permalink / raw) To: Miklos Vajna; +Cc: git, Stephan Beyer Miklos Vajna <vmiklos@frugalware.org> writes: > On Tue, Aug 19, 2008 at 12:19:09PM -0700, Junio C Hamano <gitster@pobox.com> wrote: >> Since the latter is what everybody else ("checkout -m", "revert", >> "cherry-pick", "am -3", "stash apply") should be using, I think it is >> pretty much up to "git-merge" and "git-merge-recursive" implementations >> how the caller of merge_recursive() function is structured. I suspect >> that you would not need two separate functions, _setup() and _generic(), >> for these two codepaths, but I didn't look closely. > > Sure, I can avoid _generic() and use merge_recursive() directly, that's > why I asked. > >> And make_virtual_commit() should become static inside merge_recursive.c; >> use of these fake commits is strictly an internal implementation issue of >> how merge_recursive() function works and does not concern the caller, does >> it? > > Not exactly. builtin-merge-recursive uses get_ref() - which should not > be in merge-recursive.c IMHO - and get_ref() uses make_virtual_commit(). > merge_recursive() itself takes commits, so it can be only static if we > copy it builtin-merge-recursive as well, causing a code duplication. Or > have I missed something here? I think you have. Let's look at the call chain from cmd_merge_recursive() and think again. cmd_merge_recursive() -> merge_recursive_setup() -> merge_recursive_generic() -> merge_recursive() -> merge_recursive() -> merge_trees() cmd_merge_recursive() takes subtree option and set of object names (two commits and zero or more base commits), massages them and calls merge_recursive(). merge_recursive_setup() and merge_recursive_generic() are involved in this massaging process. merge_recursive() computes the bases itself when given no base, and in a multi-base situation, does its thing recursively to come up with a consolidated base, using virtual commits. After coming up with the three (virtual or real) commits to use, it gives them to merge_trees(), which operate solely on tree objects. In addition, merge_recursive() currently *requires* the caller to wrap bare tree objects in virtual commits, if the caller wants to do a simple three-way merge of trees (in which case because there is no ancestry information available you would naturally not do any recursive behaviour). This "input must be commit" requirement is why you think you need to have get_ref() that uses make_virtual_commit() in the caller. But it does not have to be that way. It is merely an artifact of the current refactoring that kept the interface into merge_recursive() based on commit objects. You could further refine the refactoring so that: - merge_trees(), in addition to the three tree objects, takes options such as use of the subtree behaviour, descriptive names for heads to be used for conflict markers, verbosity level, and other future options (such as "use this lower rename detaction threshold"). Introduce "struct merge_options" for that and pass it around. These show() and output() calls could even become callbacks, but I didn't look very carefully. - merge_recursive(), in addition to that "merge_options" structure, will take heads, and list of common ancestors. - merge_recursive_generic() can be a layer on top of merge_recursive() to allow the caller to feed tree objects. Use of "const unsigned char *" to give raw object names (or even "const char *" to feed texual object names) would be easier for the callers. Wrapping a tree into virtual commit can and should be done at this layer, hidden away inside merge-recursive.c from the callers. Alternatively, you can do away without such preparation step, and move the "wrap a tree into a virtual commit" inside merge_recursive() itself. If you take that route, merge_recursive() will take heads and list of common ancestors all in "const unsigned char *" object names, in addition to the "merge_options" structure. When you rewrite cmd_merge() to make direct call to bypass a subprocess, your callchain would look like: cmd_merge() -> merge_recursive() -> merge_recursive() -> merge_trees() cmd_merge() needs to do the same arrangement for "subtree" and any possible future options, and feed the same set of object names to merge_recursive(). You cannot give a bare tree to "git merge", so you do not have to worry about having to wrap it in a virtual commit. So my gut feeling is that the interface may look something like: struct merge_options { const char *branch1_label; const char *branch2_label; unsigned subtree_merge : 1; int verbosity; /* other options here ... */ }; /* rename-detecting three-way merge, no recursion */ int merge_trees(struct merge_options *, struct tree *head, struct tree *merge, struct tree *common, struct tree **result); /* merge_trees() but with recursive ancestor consolidation */ int merge_recursive(struct merge_options *, struct commit *h1, struct commit *h2, struct commit_list *ca, struct commit **result); /* * "git-merge-recursive" can be fed trees; wrap them into * virtual commits and call merge_recursive() proper. */ int merge_recursive_generic(struct merge_options *, const unsigned char *head, const unsigned char *merge, int num_ca, const unsigned char **ca, struct commit **result); and the call chain would become: cmd_merge_recursive() -> merge_recursive_generic() -> merge_recursive() -> merge_recursive() -> merge_trees() cmd_merge() -> merge_recursive() -> merge_recursive() -> merge_trees() cmd_revert(), cmd_am(), cmd_checkout(), cmd_stash(), ... -> merge_trees() ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: What's cooking in git.git (Aug 2008, #05; Tue, 19) 2008-08-19 22:00 ` Junio C Hamano @ 2008-08-20 22:42 ` Miklos Vajna 2008-08-25 1:44 ` [PATCH] merge-recursive: introduce merge_options Miklos Vajna 2008-09-01 1:06 ` What's cooking in git.git (Aug 2008, #05; Tue, 19) Miklos Vajna 2 siblings, 0 replies; 35+ messages in thread From: Miklos Vajna @ 2008-08-20 22:42 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Stephan Beyer [-- Attachment #1: Type: text/plain, Size: 686 bytes --] On Tue, Aug 19, 2008 at 03:00:27PM -0700, Junio C Hamano <gitster@pobox.com> wrote: > > Not exactly. builtin-merge-recursive uses get_ref() - which should not > > be in merge-recursive.c IMHO - and get_ref() uses make_virtual_commit(). > > merge_recursive() itself takes commits, so it can be only static if we > > copy it builtin-merge-recursive as well, causing a code duplication. Or > > have I missed something here? > > I think you have. > > Let's look at the call chain from cmd_merge_recursive() and think again. Thanks for the detailed answer. I just wanted to say that probably I won't have time to implement this before the weekend; but I plan to do so then. [-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --] ^ permalink raw reply [flat|nested] 35+ messages in thread
* [PATCH] merge-recursive: introduce merge_options 2008-08-19 22:00 ` Junio C Hamano 2008-08-20 22:42 ` Miklos Vajna @ 2008-08-25 1:44 ` Miklos Vajna 2008-08-25 6:06 ` Junio C Hamano 2008-09-01 1:06 ` What's cooking in git.git (Aug 2008, #05; Tue, 19) Miklos Vajna 2 siblings, 1 reply; 35+ messages in thread From: Miklos Vajna @ 2008-08-25 1:44 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Stephan Beyer This makes it possible to avoid passing the labels of branches as arguments to merge_recursive(), merge_trees() and merge_recursive_generic(). It also takes care of subtree merge, output buffering, verbosity, and rename limits - these were global variables till now in merge-recursive.c. A new function, named init_merge_options(), is introduced as well, it clears the struct merge_info, then initializes with default values, finally updates the default values based on the config and environment variables. Signed-off-by: Miklos Vajna <vmiklos@frugalware.org> --- On Tue, Aug 19, 2008 at 03:00:27PM -0700, Junio C Hamano <gitster@pobox.com> wrote: > and the call chain would become: > > cmd_merge_recursive() > -> merge_recursive_generic() > -> merge_recursive() > -> merge_recursive() > -> merge_trees() Actually I still left some extra function, as the merge_options structure should be initialized, and that was done by just initializing global variables before, but now we have to have a new function for it. Other than that, I hope the patch looks like the way you imagined. ;-) Notes: 1) This applies on top of 1c868d4 (merge-recursive.c: Add more generic merge_recursive_generic()). I can rebase this (along with 1c868d4 and 1c868d4^) on top of current master, if this is a problem. 2) I know that this patch is huge, but we want to have the verbosity flag in merge_options, so it has to be passed as an argument in many places. > cmd_merge() > -> merge_recursive() > -> merge_recursive() > -> merge_trees() > > cmd_revert(), cmd_am(), cmd_checkout(), cmd_stash(), ... > -> merge_trees() builtin-checkout already used merge_trees(), so I modified it to use merge_options, otherwise the patch would break the build. 'am' and 'stash' is not (yet) a builtin, so that is not interesting here. If this patch looks OK, then I want to do the builtin-merge and builtin-revert parts as well. builtin-checkout.c | 11 ++- builtin-merge-recursive.c | 43 ++++---- merge-recursive.c | 242 ++++++++++++++++++++++---------------------- merge-recursive.h | 42 ++++++--- 4 files changed, 180 insertions(+), 158 deletions(-) diff --git a/builtin-checkout.c b/builtin-checkout.c index 411cc51..3627996 100644 --- a/builtin-checkout.c +++ b/builtin-checkout.c @@ -264,6 +264,7 @@ static int merge_working_tree(struct checkout_opts *opts, */ struct tree *result; struct tree *work; + struct merge_options o; if (!opts->merge) return 1; parse_commit(old->commit); @@ -282,13 +283,17 @@ static int merge_working_tree(struct checkout_opts *opts, */ add_files_to_cache(NULL, NULL, 0); - work = write_tree_from_memory(); + init_merge_options(&o); + o.verbosity = 0; + work = write_tree_from_memory(&o); ret = reset_tree(new->commit->tree, opts, 1); if (ret) return ret; - merge_trees(new->commit->tree, work, old->commit->tree, - new->name, "local", &result); + o.branch1 = new->name; + o.branch2 = "local"; + merge_trees(&o, new->commit->tree, work, + old->commit->tree, &result); ret = reset_tree(new->commit->tree, opts, 0); if (ret) return ret; diff --git a/builtin-merge-recursive.c b/builtin-merge-recursive.c index 25f540b..6b534c1 100644 --- a/builtin-merge-recursive.c +++ b/builtin-merge-recursive.c @@ -17,32 +17,33 @@ static const char *better_branch_name(const char *branch) int cmd_merge_recursive(int argc, const char **argv, const char *prefix) { - const char *bases[21]; + const unsigned char *bases[21]; unsigned bases_count = 0; int i, failed; - const char *branch1, *branch2; unsigned char h1[20], h2[20]; - int subtree_merge = 0; + struct merge_options o; + struct commit *result; + init_merge_options(&o); if (argv[0]) { int namelen = strlen(argv[0]); if (8 < namelen && !strcmp(argv[0] + namelen - 8, "-subtree")) - subtree_merge = 1; + o.subtree_merge = 1; } - git_config(merge_recursive_config, NULL); - merge_recursive_setup(subtree_merge); if (argc < 4) die("Usage: %s <base>... -- <head> <remote> ...\n", argv[0]); for (i = 1; i < argc; ++i) { - if (!strcmp(argv[i], "--")) { - bases[bases_count] = NULL; + if (!strcmp(argv[i], "--")) break; + if (bases_count < ARRAY_SIZE(bases)-1) { + unsigned char *sha = xmalloc(20); + if (get_sha1(argv[i], sha)) + die("Could not parse object '%s'", argv[i]); + bases[bases_count++] = sha; } - if (bases_count < ARRAY_SIZE(bases)-1) - bases[bases_count++] = argv[i]; else warning("Cannot handle more than %zu bases. " "Ignoring %s.", ARRAY_SIZE(bases)-1, argv[i]); @@ -50,21 +51,21 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix) if (argc - i != 3) /* "--" "<head>" "<remote>" */ die("Not handling anything other than two heads merge."); - branch1 = argv[++i]; - branch2 = argv[++i]; + o.branch1 = argv[++i]; + o.branch2 = argv[++i]; - if (get_sha1(branch1, h1)) - die("Could not resolve ref '%s'", branch1); - if (get_sha1(branch2, h2)) - die("Could not resolve ref '%s'", branch2); + if (get_sha1(o.branch1, h1)) + die("Could not resolve ref '%s'", o.branch1); + if (get_sha1(o.branch2, h2)) + die("Could not resolve ref '%s'", o.branch2); - branch1 = better_branch_name(branch1); - branch2 = better_branch_name(branch2); + o.branch1 = better_branch_name(o.branch1); + o.branch2 = better_branch_name(o.branch2); - if (merge_recursive_verbosity >= 3) - printf("Merging %s with %s\n", branch1, branch2); + if (o.verbosity >= 3) + printf("Merging %s with %s\n", o.branch1, o.branch2); - failed = merge_recursive_generic(bases, h1, branch1, h2, branch2); + failed = merge_recursive_generic(&o, h1, h2, bases_count, bases, &result); if (failed < 0) return 128; /* die() error code */ return failed; diff --git a/merge-recursive.c b/merge-recursive.c index 74a9fdc..ee23396 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -83,16 +83,11 @@ static struct string_list current_file_set = {NULL, 0, 0, 1}; static struct string_list current_directory_set = {NULL, 0, 0, 1}; static int call_depth = 0; -int merge_recursive_verbosity = 2; -static int diff_rename_limit = -1; -static int merge_rename_limit = -1; -static int buffer_output = 1; static struct strbuf obuf = STRBUF_INIT; -static int show(int v) +static int show(int v, struct merge_options *o) { - return (!call_depth && merge_recursive_verbosity >= v) || - merge_recursive_verbosity >= 5; + return (!call_depth && o->verbosity >= v) || o->verbosity >= 5; } static void flush_output(void) @@ -103,12 +98,12 @@ static void flush_output(void) } } -static void output(int v, const char *fmt, ...) +static void output(int v, struct merge_options *o, const char *fmt, ...) { int len; va_list ap; - if (!show(v)) + if (!show(v, o)) return; strbuf_grow(&obuf, call_depth * 2 + 2); @@ -132,7 +127,7 @@ static void output(int v, const char *fmt, ...) } strbuf_setlen(&obuf, obuf.len + len); strbuf_add(&obuf, "\n", 1); - if (!buffer_output) + if (!o->buffer_output) flush_output(); } @@ -219,17 +214,17 @@ static int git_merge_trees(int index_only, return rc; } -struct tree *write_tree_from_memory(void) +struct tree *write_tree_from_memory(struct merge_options *o) { struct tree *result = NULL; if (unmerged_cache()) { int i; - output(0, "There are unmerged index entries:"); + output(0, o, "There are unmerged index entries:"); for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; if (ce_stage(ce)) - output(0, "%d %.*s", ce_stage(ce), ce_namelen(ce), ce->name); + output(0, o, "%d %.*s", ce_stage(ce), ce_namelen(ce), ce->name); } return NULL; } @@ -345,7 +340,8 @@ static struct string_list *get_renames(struct tree *tree, struct tree *o_tree, struct tree *a_tree, struct tree *b_tree, - struct string_list *entries) + struct string_list *entries, + struct merge_options *o) { int i; struct string_list *renames; @@ -355,8 +351,8 @@ static struct string_list *get_renames(struct tree *tree, diff_setup(&opts); DIFF_OPT_SET(&opts, RECURSIVE); opts.detect_rename = DIFF_DETECT_RENAME; - opts.rename_limit = merge_rename_limit >= 0 ? merge_rename_limit : - diff_rename_limit >= 0 ? diff_rename_limit : + opts.rename_limit = o->merge_rename_limit >= 0 ? o->merge_rename_limit : + o->diff_rename_limit >= 0 ? o->diff_rename_limit : 500; opts.warn_on_too_large_rename = 1; opts.output_format = DIFF_FORMAT_NO_OUTPUT; @@ -720,7 +716,8 @@ static struct merge_file_info merge_file(struct diff_filespec *o, static void conflict_rename_rename(struct rename *ren1, const char *branch1, struct rename *ren2, - const char *branch2) + const char *branch2, + struct merge_options *o) { char *del[2]; int delp = 0; @@ -730,13 +727,13 @@ static void conflict_rename_rename(struct rename *ren1, const char *dst_name2 = ren2_dst; if (string_list_has_string(¤t_directory_set, ren1_dst)) { dst_name1 = del[delp++] = unique_path(ren1_dst, branch1); - output(1, "%s is a directory in %s added as %s instead", + output(1, o, "%s is a directory in %s added as %s instead", ren1_dst, branch2, dst_name1); remove_file(0, ren1_dst, 0); } if (string_list_has_string(¤t_directory_set, ren2_dst)) { dst_name2 = del[delp++] = unique_path(ren2_dst, branch2); - output(1, "%s is a directory in %s added as %s instead", + output(1, o, "%s is a directory in %s added as %s instead", ren2_dst, branch1, dst_name2); remove_file(0, ren2_dst, 0); } @@ -758,10 +755,11 @@ static void conflict_rename_rename(struct rename *ren1, } static void conflict_rename_dir(struct rename *ren1, - const char *branch1) + const char *branch1, + struct merge_options *o) { char *new_path = unique_path(ren1->pair->two->path, branch1); - output(1, "Renamed %s to %s instead", ren1->pair->one->path, new_path); + output(1, o, "Renamed %s to %s instead", ren1->pair->one->path, new_path); remove_file(0, ren1->pair->two->path, 0); update_file(0, ren1->pair->two->sha1, ren1->pair->two->mode, new_path); free(new_path); @@ -770,11 +768,12 @@ static void conflict_rename_dir(struct rename *ren1, static void conflict_rename_rename_2(struct rename *ren1, const char *branch1, struct rename *ren2, - const char *branch2) + const char *branch2, + struct merge_options *o) { char *new_path1 = unique_path(ren1->pair->two->path, branch1); char *new_path2 = unique_path(ren2->pair->two->path, branch2); - output(1, "Renamed %s to %s and %s to %s instead", + output(1, o, "Renamed %s to %s and %s to %s instead", ren1->pair->one->path, new_path1, ren2->pair->one->path, new_path2); remove_file(0, ren1->pair->two->path, 0); @@ -786,8 +785,7 @@ static void conflict_rename_rename_2(struct rename *ren1, static int process_renames(struct string_list *a_renames, struct string_list *b_renames, - const char *a_branch, - const char *b_branch) + struct merge_options *o) { int clean_merge = 1, i, j; struct string_list a_by_dst = {NULL, 0, 0, 0}, b_by_dst = {NULL, 0, 0, 0}; @@ -832,15 +830,15 @@ static int process_renames(struct string_list *a_renames, renames1 = a_renames; renames2 = b_renames; renames2Dst = &b_by_dst; - branch1 = a_branch; - branch2 = b_branch; + branch1 = o->branch1; + branch2 = o->branch2; } else { struct rename *tmp; renames1 = b_renames; renames2 = a_renames; renames2Dst = &a_by_dst; - branch1 = b_branch; - branch2 = a_branch; + branch1 = o->branch2; + branch2 = o->branch1; tmp = ren2; ren2 = ren1; ren1 = tmp; @@ -867,7 +865,7 @@ static int process_renames(struct string_list *a_renames, ren2->processed = 1; if (strcmp(ren1_dst, ren2_dst) != 0) { clean_merge = 0; - output(1, "CONFLICT (rename/rename): " + output(1, o, "CONFLICT (rename/rename): " "Rename \"%s\"->\"%s\" in branch \"%s\" " "rename \"%s\"->\"%s\" in \"%s\"%s", src, ren1_dst, branch1, @@ -878,7 +876,7 @@ static int process_renames(struct string_list *a_renames, update_file(0, ren1->pair->one->sha1, ren1->pair->one->mode, src); } - conflict_rename_rename(ren1, branch1, ren2, branch2); + conflict_rename_rename(ren1, branch1, ren2, branch2, o); } else { struct merge_file_info mfi; remove_file(1, ren1_src, 1); @@ -888,13 +886,13 @@ static int process_renames(struct string_list *a_renames, branch1, branch2); if (mfi.merge || !mfi.clean) - output(1, "Renamed %s->%s", src, ren1_dst); + output(1, o, "Renamed %s->%s", src, ren1_dst); if (mfi.merge) - output(2, "Auto-merged %s", ren1_dst); + output(2, o, "Auto-merged %s", ren1_dst); if (!mfi.clean) { - output(1, "CONFLICT (content): merge conflict in %s", + output(1, o, "CONFLICT (content): merge conflict in %s", ren1_dst); clean_merge = 0; @@ -925,14 +923,14 @@ static int process_renames(struct string_list *a_renames, if (string_list_has_string(¤t_directory_set, ren1_dst)) { clean_merge = 0; - output(1, "CONFLICT (rename/directory): Renamed %s->%s in %s " + output(1, o, "CONFLICT (rename/directory): Renamed %s->%s in %s " " directory %s added in %s", ren1_src, ren1_dst, branch1, ren1_dst, branch2); - conflict_rename_dir(ren1, branch1); + conflict_rename_dir(ren1, branch1, o); } else if (sha_eq(src_other.sha1, null_sha1)) { clean_merge = 0; - output(1, "CONFLICT (rename/delete): Renamed %s->%s in %s " + output(1, o, "CONFLICT (rename/delete): Renamed %s->%s in %s " "and deleted in %s", ren1_src, ren1_dst, branch1, branch2); @@ -941,31 +939,31 @@ static int process_renames(struct string_list *a_renames, const char *new_path; clean_merge = 0; try_merge = 1; - output(1, "CONFLICT (rename/add): Renamed %s->%s in %s. " + output(1, o, "CONFLICT (rename/add): Renamed %s->%s in %s. " "%s added in %s", ren1_src, ren1_dst, branch1, ren1_dst, branch2); new_path = unique_path(ren1_dst, branch2); - output(1, "Added as %s instead", new_path); + output(1, o, "Added as %s instead", new_path); update_file(0, dst_other.sha1, dst_other.mode, new_path); } else if ((item = string_list_lookup(ren1_dst, renames2Dst))) { ren2 = item->util; clean_merge = 0; ren2->processed = 1; - output(1, "CONFLICT (rename/rename): Renamed %s->%s in %s. " + output(1, o, "CONFLICT (rename/rename): Renamed %s->%s in %s. " "Renamed %s->%s in %s", ren1_src, ren1_dst, branch1, ren2->pair->one->path, ren2->pair->two->path, branch2); - conflict_rename_rename_2(ren1, branch1, ren2, branch2); + conflict_rename_rename_2(ren1, branch1, ren2, branch2, o); } else try_merge = 1; if (try_merge) { - struct diff_filespec *o, *a, *b; + struct diff_filespec *one, *a, *b; struct merge_file_info mfi; src_other.path = (char *)ren1_src; - o = ren1->pair->one; + one = ren1->pair->one; if (a_renames == renames1) { a = ren1->pair->two; b = &src_other; @@ -973,8 +971,8 @@ static int process_renames(struct string_list *a_renames, b = ren1->pair->two; a = &src_other; } - mfi = merge_file(o, a, b, - a_branch, b_branch); + mfi = merge_file(one, a, b, + o->branch1, o->branch2); if (mfi.clean && sha_eq(mfi.sha, ren1->pair->two->sha1) && @@ -984,20 +982,20 @@ static int process_renames(struct string_list *a_renames, * t6022 test. If you change * it update the test too. */ - output(3, "Skipped %s (merged same as existing)", ren1_dst); + output(3, o, "Skipped %s (merged same as existing)", ren1_dst); else { if (mfi.merge || !mfi.clean) - output(1, "Renamed %s => %s", ren1_src, ren1_dst); + output(1, o, "Renamed %s => %s", ren1_src, ren1_dst); if (mfi.merge) - output(2, "Auto-merged %s", ren1_dst); + output(2, o, "Auto-merged %s", ren1_dst); if (!mfi.clean) { - output(1, "CONFLICT (rename/modify): Merge conflict in %s", + output(1, o, "CONFLICT (rename/modify): Merge conflict in %s", ren1_dst); clean_merge = 0; if (!index_only) update_stages(ren1_dst, - o, a, b, 1); + one, a, b, 1); } update_file(mfi.clean, mfi.sha, mfi.mode, ren1_dst); } @@ -1017,8 +1015,7 @@ static unsigned char *stage_sha(const unsigned char *sha, unsigned mode) /* Per entry merge function */ static int process_entry(const char *path, struct stage_data *entry, - const char *branch1, - const char *branch2) + struct merge_options *o) { /* printf("processing entry, clean cache: %s\n", index_only ? "yes": "no"); @@ -1040,23 +1037,23 @@ static int process_entry(const char *path, struct stage_data *entry, /* Deleted in both or deleted in one and * unchanged in the other */ if (a_sha) - output(2, "Removed %s", path); + output(2, o, "Removed %s", path); /* do not touch working file if it did not exist */ remove_file(1, path, !a_sha); } else { /* Deleted in one and changed in the other */ clean_merge = 0; if (!a_sha) { - output(1, "CONFLICT (delete/modify): %s deleted in %s " + output(1, o, "CONFLICT (delete/modify): %s deleted in %s " "and modified in %s. Version %s of %s left in tree.", - path, branch1, - branch2, branch2, path); + path, o->branch1, + o->branch2, o->branch2, path); update_file(0, b_sha, b_mode, path); } else { - output(1, "CONFLICT (delete/modify): %s deleted in %s " + output(1, o, "CONFLICT (delete/modify): %s deleted in %s " "and modified in %s. Version %s of %s left in tree.", - path, branch2, - branch1, branch1, path); + path, o->branch2, + o->branch1, o->branch1, path); update_file(0, a_sha, a_mode, path); } } @@ -1071,14 +1068,14 @@ static int process_entry(const char *path, struct stage_data *entry, const char *conf; if (a_sha) { - add_branch = branch1; - other_branch = branch2; + add_branch = o->branch1; + other_branch = o->branch2; mode = a_mode; sha = a_sha; conf = "file/directory"; } else { - add_branch = branch2; - other_branch = branch1; + add_branch = o->branch2; + other_branch = o->branch1; mode = b_mode; sha = b_sha; conf = "directory/file"; @@ -1086,13 +1083,13 @@ static int process_entry(const char *path, struct stage_data *entry, if (string_list_has_string(¤t_directory_set, path)) { const char *new_path = unique_path(path, add_branch); clean_merge = 0; - output(1, "CONFLICT (%s): There is a directory with name %s in %s. " + output(1, o, "CONFLICT (%s): There is a directory with name %s in %s. " "Added %s as %s", conf, path, other_branch, path, new_path); remove_file(0, path, 0); update_file(0, sha, mode, new_path); } else { - output(2, "Added %s", path); + output(2, o, "Added %s", path); update_file(1, sha, mode, path); } } else if (a_sha && b_sha) { @@ -1100,32 +1097,32 @@ static int process_entry(const char *path, struct stage_data *entry, /* case D: Modified in both, but differently. */ const char *reason = "content"; struct merge_file_info mfi; - struct diff_filespec o, a, b; + struct diff_filespec one, a, b; if (!o_sha) { reason = "add/add"; o_sha = (unsigned char *)null_sha1; } - output(2, "Auto-merged %s", path); - o.path = a.path = b.path = (char *)path; - hashcpy(o.sha1, o_sha); - o.mode = o_mode; + output(2, o, "Auto-merged %s", path); + one.path = a.path = b.path = (char *)path; + hashcpy(one.sha1, o_sha); + one.mode = o_mode; hashcpy(a.sha1, a_sha); a.mode = a_mode; hashcpy(b.sha1, b_sha); b.mode = b_mode; - mfi = merge_file(&o, &a, &b, - branch1, branch2); + mfi = merge_file(&one, &a, &b, + o->branch1, o->branch2); clean_merge = mfi.clean; if (mfi.clean) update_file(1, mfi.sha, mfi.mode, path); else if (S_ISGITLINK(mfi.mode)) - output(1, "CONFLICT (submodule): Merge conflict in %s " + output(1, o, "CONFLICT (submodule): Merge conflict in %s " "- needs %s", path, sha1_to_hex(b.sha1)); else { - output(1, "CONFLICT (%s): Merge conflict in %s", + output(1, o, "CONFLICT (%s): Merge conflict in %s", reason, path); if (index_only) @@ -1146,11 +1143,10 @@ static int process_entry(const char *path, struct stage_data *entry, return clean_merge; } -int merge_trees(struct tree *head, +int merge_trees(struct merge_options *o, + struct tree *head, struct tree *merge, struct tree *common, - const char *branch1, - const char *branch2, struct tree **result) { int code, clean; @@ -1161,7 +1157,7 @@ int merge_trees(struct tree *head, } if (sha_eq(common->object.sha1, merge->object.sha1)) { - output(0, "Already uptodate!"); + output(0, o, "Already uptodate!"); *result = head; return 1; } @@ -1182,15 +1178,14 @@ int merge_trees(struct tree *head, get_files_dirs(merge); entries = get_unmerged(); - re_head = get_renames(head, common, head, merge, entries); - re_merge = get_renames(merge, common, head, merge, entries); - clean = process_renames(re_head, re_merge, - branch1, branch2); + re_head = get_renames(head, common, head, merge, entries, o); + re_merge = get_renames(merge, common, head, merge, entries, o); + clean = process_renames(re_head, re_merge, o); for (i = 0; i < entries->nr; i++) { const char *path = entries->items[i].string; struct stage_data *e = entries->items[i].util; if (!e->processed - && !process_entry(path, e, branch1, branch2)) + && !process_entry(path, e, o)) clean = 0; } @@ -1203,7 +1198,7 @@ int merge_trees(struct tree *head, clean = 1; if (index_only) - *result = write_tree_from_memory(); + *result = write_tree_from_memory(o); return clean; } @@ -1223,10 +1218,9 @@ static struct commit_list *reverse_commit_list(struct commit_list *list) * Merge the commits h1 and h2, return the resulting virtual * commit object and a flag indicating the cleanness of the merge. */ -int merge_recursive(struct commit *h1, +int merge_recursive(struct merge_options *o, + struct commit *h1, struct commit *h2, - const char *branch1, - const char *branch2, struct commit_list *ca, struct commit **result) { @@ -1235,8 +1229,8 @@ int merge_recursive(struct commit *h1, struct tree *mrtree = mrtree; int clean; - if (show(4)) { - output(4, "Merging:"); + if (show(4, o)) { + output(4, o, "Merging:"); output_commit_title(h1); output_commit_title(h2); } @@ -1246,8 +1240,8 @@ int merge_recursive(struct commit *h1, ca = reverse_commit_list(ca); } - if (show(5)) { - output(5, "found %u common ancestor(s):", commit_list_count(ca)); + if (show(5, o)) { + output(5, o, "found %u common ancestor(s):", commit_list_count(ca)); for (iter = ca; iter; iter = iter->next) output_commit_title(iter->item); } @@ -1264,6 +1258,7 @@ int merge_recursive(struct commit *h1, } for (iter = ca; iter; iter = iter->next) { + struct merge_options opts; call_depth++; /* * When the merge fails, the result contains files @@ -1273,10 +1268,11 @@ int merge_recursive(struct commit *h1, * "conflicts" were already resolved. */ discard_cache(); - merge_recursive(merged_common_ancestors, iter->item, - "Temporary merge branch 1", - "Temporary merge branch 2", - NULL, + memcpy(&opts, o, sizeof(struct merge_options)); + opts.branch1 = "Temporary merge branch 1"; + opts.branch2 = "Temporary merge branch 2"; + merge_recursive(&opts, merged_common_ancestors, + iter->item, NULL, &merged_common_ancestors); call_depth--; @@ -1291,8 +1287,8 @@ int merge_recursive(struct commit *h1, } else index_only = 1; - clean = merge_trees(h1->tree, h2->tree, merged_common_ancestors->tree, - branch1, branch2, &mrtree); + clean = merge_trees(o, h1->tree, h2->tree, merged_common_ancestors->tree, + &mrtree); if (index_only) { *result = make_virtual_commit(mrtree, "merged tree"); @@ -1319,35 +1315,33 @@ static struct commit *get_ref(const unsigned char *sha1, const char *name) return (struct commit *)object; } -int merge_recursive_generic(const char **base_list, - const unsigned char *head_sha1, const char *head_name, - const unsigned char *next_sha1, const char *next_name) +int merge_recursive_generic(struct merge_options *o, + const unsigned char *head, + const unsigned char *merge, + int num_base_list, + const unsigned char **base_list, + struct commit **result) { int clean, index_fd; struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); - struct commit *result; - struct commit *head_commit = get_ref(head_sha1, head_name); - struct commit *next_commit = get_ref(next_sha1, next_name); + struct commit *head_commit = get_ref(head, o->branch1); + struct commit *next_commit = get_ref(merge, o->branch2); struct commit_list *ca = NULL; if (base_list) { int i; - for (i = 0; base_list[i]; ++i) { - unsigned char sha[20]; + for (i = 0; i < num_base_list; ++i) { struct commit *base; - if (get_sha1(base_list[i], sha)) - return error("Could not resolve ref '%s'", - base_list[i]); - if (!(base = get_ref(sha, base_list[i]))) + if (!(base = get_ref(base_list[i], sha1_to_hex(base_list[i])))) return error("Could not parse object '%s'", - base_list[i]); + sha1_to_hex(base_list[i])); commit_list_insert(base, &ca); } } index_fd = hold_locked_index(lock, 1); - clean = merge_recursive(head_commit, next_commit, - head_name, next_name, ca, &result); + clean = merge_recursive(o, head_commit, next_commit, ca, + result); if (active_cache_changed && (write_cache(index_fd, active_cache, active_nr) || commit_locked_index(lock))) @@ -1356,29 +1350,35 @@ int merge_recursive_generic(const char **base_list, return clean ? 0 : 1; } -int merge_recursive_config(const char *var, const char *value, void *cb) +static int merge_recursive_config(const char *var, const char *value, void *cb) { + struct merge_options *o = cb; if (!strcasecmp(var, "merge.verbosity")) { - merge_recursive_verbosity = git_config_int(var, value); + o->verbosity = git_config_int(var, value); return 0; } if (!strcasecmp(var, "diff.renamelimit")) { - diff_rename_limit = git_config_int(var, value); + o->diff_rename_limit = git_config_int(var, value); return 0; } if (!strcasecmp(var, "merge.renamelimit")) { - merge_rename_limit = git_config_int(var, value); + o->merge_rename_limit = git_config_int(var, value); return 0; } return git_default_config(var, value, cb); } -void merge_recursive_setup(int is_subtree_merge) +void init_merge_options(struct merge_options *o) { + memset(o, 0, sizeof(struct merge_options)); + o->verbosity = 2; + o->buffer_output = 1; + o->diff_rename_limit = -1; + o->merge_rename_limit = -1; + git_config(merge_recursive_config, o); if (getenv("GIT_MERGE_VERBOSITY")) - merge_recursive_verbosity = + o->verbosity = strtol(getenv("GIT_MERGE_VERBOSITY"), NULL, 10); - if (merge_recursive_verbosity >= 5) - buffer_output = 0; - subtree_merge = is_subtree_merge; + if (o->verbosity >= 5) + o->buffer_output = 0; } diff --git a/merge-recursive.h b/merge-recursive.h index 4dd6476..72f0a28 100644 --- a/merge-recursive.h +++ b/merge-recursive.h @@ -1,26 +1,42 @@ #ifndef MERGE_RECURSIVE_H #define MERGE_RECURSIVE_H -int merge_recursive(struct commit *h1, +struct merge_options { + const char *branch1; + const char *branch2; + unsigned subtree_merge : 1; + unsigned buffer_output : 1; + int verbosity; + int diff_rename_limit; + int merge_rename_limit; +}; + +/* merge_trees() but with recursive ancestor consolidation */ +int merge_recursive(struct merge_options *o, + struct commit *h1, struct commit *h2, - const char *branch1, - const char *branch2, struct commit_list *ancestors, struct commit **result); -int merge_trees(struct tree *head, +/* rename-detecting three-way merge, no recursion */ +int merge_trees(struct merge_options *o, + struct tree *head, struct tree *merge, struct tree *common, - const char *branch1, - const char *branch2, struct tree **result); -extern int merge_recursive_generic(const char **base_list, - const unsigned char *head_sha1, const char *head_name, - const unsigned char *next_sha1, const char *next_name); -int merge_recursive_config(const char *var, const char *value, void *cb); -void merge_recursive_setup(int is_subtree_merge); -struct tree *write_tree_from_memory(void); -extern int merge_recursive_verbosity; +/* + * "git-merge-recursive" can be fed trees; wrap them into + * virtual commits and call merge_recursive() proper. + */ +int merge_recursive_generic(struct merge_options *o, + const unsigned char *head, + const unsigned char *merge, + int num_ca, + const unsigned char **ca, + struct commit **result); + +void init_merge_options(struct merge_options *o); +struct tree *write_tree_from_memory(struct merge_options *o); #endif -- 1.6.0.rc3.17.gc14c8.dirty ^ permalink raw reply related [flat|nested] 35+ messages in thread
* Re: [PATCH] merge-recursive: introduce merge_options 2008-08-25 1:44 ` [PATCH] merge-recursive: introduce merge_options Miklos Vajna @ 2008-08-25 6:06 ` Junio C Hamano 2008-08-25 14:25 ` Miklos Vajna 0 siblings, 1 reply; 35+ messages in thread From: Junio C Hamano @ 2008-08-25 6:06 UTC (permalink / raw) To: Miklos Vajna; +Cc: git, Stephan Beyer Miklos Vajna <vmiklos@frugalware.org> writes: > 1) This applies on top of 1c868d4 (merge-recursive.c: Add more generic > merge_recursive_generic()). I can rebase this (along with 1c868d4 and > 1c868d4^) on top of current master, if this is a problem. It probably is cleaner to treat this as a fresh topic from scratch on top of 'master', as we do not have anything outstanding in 'next' around this area. > 2) I know that this patch is huge, but we want to have the verbosity > flag in merge_options, so it has to be passed as an argument in many > places. Size of the patch that results purely from addition of the merge_options parameter from top to bottom does not bother me too much. The look quite straightforward conversions, and getting rid of these many global variables is a major step in the right direction. It might however be a good idea to consistently have this at the same place (either the beginning or at the end) of the parameter list of functions that take one. > @@ -1273,10 +1268,11 @@ int merge_recursive(struct commit *h1, > * "conflicts" were already resolved. > */ > discard_cache(); > - merge_recursive(merged_common_ancestors, iter->item, > - "Temporary merge branch 1", > - "Temporary merge branch 2", > - NULL, > + memcpy(&opts, o, sizeof(struct merge_options)); > + opts.branch1 = "Temporary merge branch 1"; > + opts.branch2 = "Temporary merge branch 2"; > + merge_recursive(&opts, merged_common_ancestors, > + iter->item, NULL, > &merged_common_ancestors); > call_depth--; After suggesting to keep label in merge_options, I was wondering how this part should be handled the best. An alternative would be not to do copy the structure but stash away only branch1 and branch2 members before making the recursive call and restore them after it returns, like this: const char *saved_b1, *saved_b2; ... saved_b1 = o->branch1; saved_b2 = o->branch2; o->branch1 = "Temporary merge branch 1"; o->branch2 = "Temporary merge branch 2"; merge_recursive(o, ...); o->branch1 = saved_b1; o->branch2 = saved_b2; call_depth--; ... This might be better in the longer run, as we may want to pass *back* status from merge_recursive() to the caller in fields of merge_options in the future. ^ permalink raw reply [flat|nested] 35+ messages in thread
* [PATCH] merge-recursive: introduce merge_options 2008-08-25 6:06 ` Junio C Hamano @ 2008-08-25 14:25 ` Miklos Vajna 2008-08-28 4:50 ` Junio C Hamano 2008-08-30 15:42 ` [PATCH] merge-recursive: fix subtree merge Miklos Vajna 0 siblings, 2 replies; 35+ messages in thread From: Miklos Vajna @ 2008-08-25 14:25 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Stephan Beyer This makes it possible to avoid passing the labels of branches as arguments to merge_recursive(), merge_trees() and merge_recursive_generic(). It also takes care of subtree merge, output buffering, verbosity, and rename limits - these were global variables till now in merge-recursive.c. A new function, named init_merge_options(), is introduced as well, it clears the struct merge_info, then initializes with default values, finally updates the default values based on the config and environment variables. Signed-off-by: Miklos Vajna <vmiklos@frugalware.org> --- On Sun, Aug 24, 2008 at 11:06:06PM -0700, Junio C Hamano <gitster@pobox.com> wrote: > Miklos Vajna <vmiklos@frugalware.org> writes: > > > 1) This applies on top of 1c868d4 (merge-recursive.c: Add more > > generic > > merge_recursive_generic()). I can rebase this (along with 1c868d4 > > and > > 1c868d4^) on top of current master, if this is a problem. > > It probably is cleaner to treat this as a fresh topic from scratch on > top > of 'master', as we do not have anything outstanding in 'next' around > this > area. I'm now confused about what should I do: 1) Nothing. (That's what I did for now.) 2) Rebase against master and resend. 3) Rebase, squash and resend. > > 2) I know that this patch is huge, but we want to have the verbosity > > flag in merge_options, so it has to be passed as an argument in many > > places. > > Size of the patch that results purely from addition of the > merge_options > parameter from top to bottom does not bother me too much. The look > quite > straightforward conversions, and getting rid of these many global > variables is a major step in the right direction. > > It might however be a good idea to consistently have this at the same > place (either the beginning or at the end) of the parameter list of > functions that take one. OK, I'll move them to the beginning, since that's what we have for the public functions already. > > @@ -1273,10 +1268,11 @@ int merge_recursive(struct commit *h1, > > * "conflicts" were already resolved. > > */ > > discard_cache(); > > - merge_recursive(merged_common_ancestors, iter->item, > > - "Temporary merge branch 1", > > - "Temporary merge branch 2", > > - NULL, > > + memcpy(&opts, o, sizeof(struct merge_options)); > > + opts.branch1 = "Temporary merge branch 1"; > > + opts.branch2 = "Temporary merge branch 2"; > > + merge_recursive(&opts, merged_common_ancestors, > > + iter->item, NULL, > > &merged_common_ancestors); > > call_depth--; > > After suggesting to keep label in merge_options, I was wondering how > this > part should be handled the best. An alternative would be not to do > copy > the structure but stash away only branch1 and branch2 members before > making the recursive call and restore them after it returns, like > this: > > const char *saved_b1, *saved_b2; > ... > saved_b1 = o->branch1; > saved_b2 = o->branch2; > o->branch1 = "Temporary merge branch 1"; > o->branch2 = "Temporary merge branch 2"; > merge_recursive(o, ...); > o->branch1 = saved_b1; > o->branch2 = saved_b2; > call_depth--; > ... > > This might be better in the longer run, as we may want to pass *back* > status from merge_recursive() to the caller in fields of merge_options > in > the future. True, changed. Interdiff: git fetch git://repo.or.cz/git/vmiklos.git git diff 2ff6553..8faf3ac builtin-checkout.c | 11 ++- builtin-merge-recursive.c | 43 ++++---- merge-recursive.c | 260 +++++++++++++++++++++++---------------------- merge-recursive.h | 42 +++++--- 4 files changed, 190 insertions(+), 166 deletions(-) diff --git a/builtin-checkout.c b/builtin-checkout.c index 411cc51..3627996 100644 --- a/builtin-checkout.c +++ b/builtin-checkout.c @@ -264,6 +264,7 @@ static int merge_working_tree(struct checkout_opts *opts, */ struct tree *result; struct tree *work; + struct merge_options o; if (!opts->merge) return 1; parse_commit(old->commit); @@ -282,13 +283,17 @@ static int merge_working_tree(struct checkout_opts *opts, */ add_files_to_cache(NULL, NULL, 0); - work = write_tree_from_memory(); + init_merge_options(&o); + o.verbosity = 0; + work = write_tree_from_memory(&o); ret = reset_tree(new->commit->tree, opts, 1); if (ret) return ret; - merge_trees(new->commit->tree, work, old->commit->tree, - new->name, "local", &result); + o.branch1 = new->name; + o.branch2 = "local"; + merge_trees(&o, new->commit->tree, work, + old->commit->tree, &result); ret = reset_tree(new->commit->tree, opts, 0); if (ret) return ret; diff --git a/builtin-merge-recursive.c b/builtin-merge-recursive.c index 25f540b..6b534c1 100644 --- a/builtin-merge-recursive.c +++ b/builtin-merge-recursive.c @@ -17,32 +17,33 @@ static const char *better_branch_name(const char *branch) int cmd_merge_recursive(int argc, const char **argv, const char *prefix) { - const char *bases[21]; + const unsigned char *bases[21]; unsigned bases_count = 0; int i, failed; - const char *branch1, *branch2; unsigned char h1[20], h2[20]; - int subtree_merge = 0; + struct merge_options o; + struct commit *result; + init_merge_options(&o); if (argv[0]) { int namelen = strlen(argv[0]); if (8 < namelen && !strcmp(argv[0] + namelen - 8, "-subtree")) - subtree_merge = 1; + o.subtree_merge = 1; } - git_config(merge_recursive_config, NULL); - merge_recursive_setup(subtree_merge); if (argc < 4) die("Usage: %s <base>... -- <head> <remote> ...\n", argv[0]); for (i = 1; i < argc; ++i) { - if (!strcmp(argv[i], "--")) { - bases[bases_count] = NULL; + if (!strcmp(argv[i], "--")) break; + if (bases_count < ARRAY_SIZE(bases)-1) { + unsigned char *sha = xmalloc(20); + if (get_sha1(argv[i], sha)) + die("Could not parse object '%s'", argv[i]); + bases[bases_count++] = sha; } - if (bases_count < ARRAY_SIZE(bases)-1) - bases[bases_count++] = argv[i]; else warning("Cannot handle more than %zu bases. " "Ignoring %s.", ARRAY_SIZE(bases)-1, argv[i]); @@ -50,21 +51,21 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix) if (argc - i != 3) /* "--" "<head>" "<remote>" */ die("Not handling anything other than two heads merge."); - branch1 = argv[++i]; - branch2 = argv[++i]; + o.branch1 = argv[++i]; + o.branch2 = argv[++i]; - if (get_sha1(branch1, h1)) - die("Could not resolve ref '%s'", branch1); - if (get_sha1(branch2, h2)) - die("Could not resolve ref '%s'", branch2); + if (get_sha1(o.branch1, h1)) + die("Could not resolve ref '%s'", o.branch1); + if (get_sha1(o.branch2, h2)) + die("Could not resolve ref '%s'", o.branch2); - branch1 = better_branch_name(branch1); - branch2 = better_branch_name(branch2); + o.branch1 = better_branch_name(o.branch1); + o.branch2 = better_branch_name(o.branch2); - if (merge_recursive_verbosity >= 3) - printf("Merging %s with %s\n", branch1, branch2); + if (o.verbosity >= 3) + printf("Merging %s with %s\n", o.branch1, o.branch2); - failed = merge_recursive_generic(bases, h1, branch1, h2, branch2); + failed = merge_recursive_generic(&o, h1, h2, bases_count, bases, &result); if (failed < 0) return 128; /* die() error code */ return failed; diff --git a/merge-recursive.c b/merge-recursive.c index 74a9fdc..5fab301 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -83,16 +83,11 @@ static struct string_list current_file_set = {NULL, 0, 0, 1}; static struct string_list current_directory_set = {NULL, 0, 0, 1}; static int call_depth = 0; -int merge_recursive_verbosity = 2; -static int diff_rename_limit = -1; -static int merge_rename_limit = -1; -static int buffer_output = 1; static struct strbuf obuf = STRBUF_INIT; -static int show(int v) +static int show(struct merge_options *o, int v) { - return (!call_depth && merge_recursive_verbosity >= v) || - merge_recursive_verbosity >= 5; + return (!call_depth && o->verbosity >= v) || o->verbosity >= 5; } static void flush_output(void) @@ -103,12 +98,12 @@ static void flush_output(void) } } -static void output(int v, const char *fmt, ...) +static void output(struct merge_options *o, int v, const char *fmt, ...) { int len; va_list ap; - if (!show(v)) + if (!show(o, v)) return; strbuf_grow(&obuf, call_depth * 2 + 2); @@ -132,7 +127,7 @@ static void output(int v, const char *fmt, ...) } strbuf_setlen(&obuf, obuf.len + len); strbuf_add(&obuf, "\n", 1); - if (!buffer_output) + if (!o->buffer_output) flush_output(); } @@ -219,17 +214,17 @@ static int git_merge_trees(int index_only, return rc; } -struct tree *write_tree_from_memory(void) +struct tree *write_tree_from_memory(struct merge_options *o) { struct tree *result = NULL; if (unmerged_cache()) { int i; - output(0, "There are unmerged index entries:"); + output(o, 0, "There are unmerged index entries:"); for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; if (ce_stage(ce)) - output(0, "%d %.*s", ce_stage(ce), ce_namelen(ce), ce->name); + output(o, 0, "%d %.*s", ce_stage(ce), ce_namelen(ce), ce->name); } return NULL; } @@ -341,11 +336,12 @@ struct rename * 'b_tree') to be able to associate the correct cache entries with * the rename information. 'tree' is always equal to either a_tree or b_tree. */ -static struct string_list *get_renames(struct tree *tree, - struct tree *o_tree, - struct tree *a_tree, - struct tree *b_tree, - struct string_list *entries) +static struct string_list *get_renames(struct merge_options *o, + struct tree *tree, + struct tree *o_tree, + struct tree *a_tree, + struct tree *b_tree, + struct string_list *entries) { int i; struct string_list *renames; @@ -355,8 +351,8 @@ static struct string_list *get_renames(struct tree *tree, diff_setup(&opts); DIFF_OPT_SET(&opts, RECURSIVE); opts.detect_rename = DIFF_DETECT_RENAME; - opts.rename_limit = merge_rename_limit >= 0 ? merge_rename_limit : - diff_rename_limit >= 0 ? diff_rename_limit : + opts.rename_limit = o->merge_rename_limit >= 0 ? o->merge_rename_limit : + o->diff_rename_limit >= 0 ? o->diff_rename_limit : 500; opts.warn_on_too_large_rename = 1; opts.output_format = DIFF_FORMAT_NO_OUTPUT; @@ -717,7 +713,8 @@ static struct merge_file_info merge_file(struct diff_filespec *o, return result; } -static void conflict_rename_rename(struct rename *ren1, +static void conflict_rename_rename(struct merge_options *o, + struct rename *ren1, const char *branch1, struct rename *ren2, const char *branch2) @@ -730,13 +727,13 @@ static void conflict_rename_rename(struct rename *ren1, const char *dst_name2 = ren2_dst; if (string_list_has_string(¤t_directory_set, ren1_dst)) { dst_name1 = del[delp++] = unique_path(ren1_dst, branch1); - output(1, "%s is a directory in %s added as %s instead", + output(o, 1, "%s is a directory in %s added as %s instead", ren1_dst, branch2, dst_name1); remove_file(0, ren1_dst, 0); } if (string_list_has_string(¤t_directory_set, ren2_dst)) { dst_name2 = del[delp++] = unique_path(ren2_dst, branch2); - output(1, "%s is a directory in %s added as %s instead", + output(o, 1, "%s is a directory in %s added as %s instead", ren2_dst, branch1, dst_name2); remove_file(0, ren2_dst, 0); } @@ -757,24 +754,26 @@ static void conflict_rename_rename(struct rename *ren1, free(del[delp]); } -static void conflict_rename_dir(struct rename *ren1, +static void conflict_rename_dir(struct merge_options *o, + struct rename *ren1, const char *branch1) { char *new_path = unique_path(ren1->pair->two->path, branch1); - output(1, "Renamed %s to %s instead", ren1->pair->one->path, new_path); + output(o, 1, "Renamed %s to %s instead", ren1->pair->one->path, new_path); remove_file(0, ren1->pair->two->path, 0); update_file(0, ren1->pair->two->sha1, ren1->pair->two->mode, new_path); free(new_path); } -static void conflict_rename_rename_2(struct rename *ren1, +static void conflict_rename_rename_2(struct merge_options *o, + struct rename *ren1, const char *branch1, struct rename *ren2, const char *branch2) { char *new_path1 = unique_path(ren1->pair->two->path, branch1); char *new_path2 = unique_path(ren2->pair->two->path, branch2); - output(1, "Renamed %s to %s and %s to %s instead", + output(o, 1, "Renamed %s to %s and %s to %s instead", ren1->pair->one->path, new_path1, ren2->pair->one->path, new_path2); remove_file(0, ren1->pair->two->path, 0); @@ -784,10 +783,9 @@ static void conflict_rename_rename_2(struct rename *ren1, free(new_path1); } -static int process_renames(struct string_list *a_renames, - struct string_list *b_renames, - const char *a_branch, - const char *b_branch) +static int process_renames(struct merge_options *o, + struct string_list *a_renames, + struct string_list *b_renames) { int clean_merge = 1, i, j; struct string_list a_by_dst = {NULL, 0, 0, 0}, b_by_dst = {NULL, 0, 0, 0}; @@ -832,15 +830,15 @@ static int process_renames(struct string_list *a_renames, renames1 = a_renames; renames2 = b_renames; renames2Dst = &b_by_dst; - branch1 = a_branch; - branch2 = b_branch; + branch1 = o->branch1; + branch2 = o->branch2; } else { struct rename *tmp; renames1 = b_renames; renames2 = a_renames; renames2Dst = &a_by_dst; - branch1 = b_branch; - branch2 = a_branch; + branch1 = o->branch2; + branch2 = o->branch1; tmp = ren2; ren2 = ren1; ren1 = tmp; @@ -867,7 +865,7 @@ static int process_renames(struct string_list *a_renames, ren2->processed = 1; if (strcmp(ren1_dst, ren2_dst) != 0) { clean_merge = 0; - output(1, "CONFLICT (rename/rename): " + output(o, 1, "CONFLICT (rename/rename): " "Rename \"%s\"->\"%s\" in branch \"%s\" " "rename \"%s\"->\"%s\" in \"%s\"%s", src, ren1_dst, branch1, @@ -878,7 +876,7 @@ static int process_renames(struct string_list *a_renames, update_file(0, ren1->pair->one->sha1, ren1->pair->one->mode, src); } - conflict_rename_rename(ren1, branch1, ren2, branch2); + conflict_rename_rename(o, ren1, branch1, ren2, branch2); } else { struct merge_file_info mfi; remove_file(1, ren1_src, 1); @@ -888,13 +886,13 @@ static int process_renames(struct string_list *a_renames, branch1, branch2); if (mfi.merge || !mfi.clean) - output(1, "Renamed %s->%s", src, ren1_dst); + output(o, 1, "Renamed %s->%s", src, ren1_dst); if (mfi.merge) - output(2, "Auto-merged %s", ren1_dst); + output(o, 2, "Auto-merged %s", ren1_dst); if (!mfi.clean) { - output(1, "CONFLICT (content): merge conflict in %s", + output(o, 1, "CONFLICT (content): merge conflict in %s", ren1_dst); clean_merge = 0; @@ -925,14 +923,14 @@ static int process_renames(struct string_list *a_renames, if (string_list_has_string(¤t_directory_set, ren1_dst)) { clean_merge = 0; - output(1, "CONFLICT (rename/directory): Renamed %s->%s in %s " + output(o, 1, "CONFLICT (rename/directory): Renamed %s->%s in %s " " directory %s added in %s", ren1_src, ren1_dst, branch1, ren1_dst, branch2); - conflict_rename_dir(ren1, branch1); + conflict_rename_dir(o, ren1, branch1); } else if (sha_eq(src_other.sha1, null_sha1)) { clean_merge = 0; - output(1, "CONFLICT (rename/delete): Renamed %s->%s in %s " + output(o, 1, "CONFLICT (rename/delete): Renamed %s->%s in %s " "and deleted in %s", ren1_src, ren1_dst, branch1, branch2); @@ -941,31 +939,31 @@ static int process_renames(struct string_list *a_renames, const char *new_path; clean_merge = 0; try_merge = 1; - output(1, "CONFLICT (rename/add): Renamed %s->%s in %s. " + output(o, 1, "CONFLICT (rename/add): Renamed %s->%s in %s. " "%s added in %s", ren1_src, ren1_dst, branch1, ren1_dst, branch2); new_path = unique_path(ren1_dst, branch2); - output(1, "Added as %s instead", new_path); + output(o, 1, "Added as %s instead", new_path); update_file(0, dst_other.sha1, dst_other.mode, new_path); } else if ((item = string_list_lookup(ren1_dst, renames2Dst))) { ren2 = item->util; clean_merge = 0; ren2->processed = 1; - output(1, "CONFLICT (rename/rename): Renamed %s->%s in %s. " + output(o, 1, "CONFLICT (rename/rename): Renamed %s->%s in %s. " "Renamed %s->%s in %s", ren1_src, ren1_dst, branch1, ren2->pair->one->path, ren2->pair->two->path, branch2); - conflict_rename_rename_2(ren1, branch1, ren2, branch2); + conflict_rename_rename_2(o, ren1, branch1, ren2, branch2); } else try_merge = 1; if (try_merge) { - struct diff_filespec *o, *a, *b; + struct diff_filespec *one, *a, *b; struct merge_file_info mfi; src_other.path = (char *)ren1_src; - o = ren1->pair->one; + one = ren1->pair->one; if (a_renames == renames1) { a = ren1->pair->two; b = &src_other; @@ -973,8 +971,8 @@ static int process_renames(struct string_list *a_renames, b = ren1->pair->two; a = &src_other; } - mfi = merge_file(o, a, b, - a_branch, b_branch); + mfi = merge_file(one, a, b, + o->branch1, o->branch2); if (mfi.clean && sha_eq(mfi.sha, ren1->pair->two->sha1) && @@ -984,20 +982,20 @@ static int process_renames(struct string_list *a_renames, * t6022 test. If you change * it update the test too. */ - output(3, "Skipped %s (merged same as existing)", ren1_dst); + output(o, 3, "Skipped %s (merged same as existing)", ren1_dst); else { if (mfi.merge || !mfi.clean) - output(1, "Renamed %s => %s", ren1_src, ren1_dst); + output(o, 1, "Renamed %s => %s", ren1_src, ren1_dst); if (mfi.merge) - output(2, "Auto-merged %s", ren1_dst); + output(o, 2, "Auto-merged %s", ren1_dst); if (!mfi.clean) { - output(1, "CONFLICT (rename/modify): Merge conflict in %s", + output(o, 1, "CONFLICT (rename/modify): Merge conflict in %s", ren1_dst); clean_merge = 0; if (!index_only) update_stages(ren1_dst, - o, a, b, 1); + one, a, b, 1); } update_file(mfi.clean, mfi.sha, mfi.mode, ren1_dst); } @@ -1016,9 +1014,8 @@ static unsigned char *stage_sha(const unsigned char *sha, unsigned mode) } /* Per entry merge function */ -static int process_entry(const char *path, struct stage_data *entry, - const char *branch1, - const char *branch2) +static int process_entry(struct merge_options *o, + const char *path, struct stage_data *entry) { /* printf("processing entry, clean cache: %s\n", index_only ? "yes": "no"); @@ -1040,23 +1037,23 @@ static int process_entry(const char *path, struct stage_data *entry, /* Deleted in both or deleted in one and * unchanged in the other */ if (a_sha) - output(2, "Removed %s", path); + output(o, 2, "Removed %s", path); /* do not touch working file if it did not exist */ remove_file(1, path, !a_sha); } else { /* Deleted in one and changed in the other */ clean_merge = 0; if (!a_sha) { - output(1, "CONFLICT (delete/modify): %s deleted in %s " + output(o, 1, "CONFLICT (delete/modify): %s deleted in %s " "and modified in %s. Version %s of %s left in tree.", - path, branch1, - branch2, branch2, path); + path, o->branch1, + o->branch2, o->branch2, path); update_file(0, b_sha, b_mode, path); } else { - output(1, "CONFLICT (delete/modify): %s deleted in %s " + output(o, 1, "CONFLICT (delete/modify): %s deleted in %s " "and modified in %s. Version %s of %s left in tree.", - path, branch2, - branch1, branch1, path); + path, o->branch2, + o->branch1, o->branch1, path); update_file(0, a_sha, a_mode, path); } } @@ -1071,14 +1068,14 @@ static int process_entry(const char *path, struct stage_data *entry, const char *conf; if (a_sha) { - add_branch = branch1; - other_branch = branch2; + add_branch = o->branch1; + other_branch = o->branch2; mode = a_mode; sha = a_sha; conf = "file/directory"; } else { - add_branch = branch2; - other_branch = branch1; + add_branch = o->branch2; + other_branch = o->branch1; mode = b_mode; sha = b_sha; conf = "directory/file"; @@ -1086,13 +1083,13 @@ static int process_entry(const char *path, struct stage_data *entry, if (string_list_has_string(¤t_directory_set, path)) { const char *new_path = unique_path(path, add_branch); clean_merge = 0; - output(1, "CONFLICT (%s): There is a directory with name %s in %s. " + output(o, 1, "CONFLICT (%s): There is a directory with name %s in %s. " "Added %s as %s", conf, path, other_branch, path, new_path); remove_file(0, path, 0); update_file(0, sha, mode, new_path); } else { - output(2, "Added %s", path); + output(o, 2, "Added %s", path); update_file(1, sha, mode, path); } } else if (a_sha && b_sha) { @@ -1100,32 +1097,32 @@ static int process_entry(const char *path, struct stage_data *entry, /* case D: Modified in both, but differently. */ const char *reason = "content"; struct merge_file_info mfi; - struct diff_filespec o, a, b; + struct diff_filespec one, a, b; if (!o_sha) { reason = "add/add"; o_sha = (unsigned char *)null_sha1; } - output(2, "Auto-merged %s", path); - o.path = a.path = b.path = (char *)path; - hashcpy(o.sha1, o_sha); - o.mode = o_mode; + output(o, 2, "Auto-merged %s", path); + one.path = a.path = b.path = (char *)path; + hashcpy(one.sha1, o_sha); + one.mode = o_mode; hashcpy(a.sha1, a_sha); a.mode = a_mode; hashcpy(b.sha1, b_sha); b.mode = b_mode; - mfi = merge_file(&o, &a, &b, - branch1, branch2); + mfi = merge_file(&one, &a, &b, + o->branch1, o->branch2); clean_merge = mfi.clean; if (mfi.clean) update_file(1, mfi.sha, mfi.mode, path); else if (S_ISGITLINK(mfi.mode)) - output(1, "CONFLICT (submodule): Merge conflict in %s " + output(o, 1, "CONFLICT (submodule): Merge conflict in %s " "- needs %s", path, sha1_to_hex(b.sha1)); else { - output(1, "CONFLICT (%s): Merge conflict in %s", + output(o, 1, "CONFLICT (%s): Merge conflict in %s", reason, path); if (index_only) @@ -1146,11 +1143,10 @@ static int process_entry(const char *path, struct stage_data *entry, return clean_merge; } -int merge_trees(struct tree *head, +int merge_trees(struct merge_options *o, + struct tree *head, struct tree *merge, struct tree *common, - const char *branch1, - const char *branch2, struct tree **result) { int code, clean; @@ -1161,7 +1157,7 @@ int merge_trees(struct tree *head, } if (sha_eq(common->object.sha1, merge->object.sha1)) { - output(0, "Already uptodate!"); + output(o, 0, "Already uptodate!"); *result = head; return 1; } @@ -1182,15 +1178,14 @@ int merge_trees(struct tree *head, get_files_dirs(merge); entries = get_unmerged(); - re_head = get_renames(head, common, head, merge, entries); - re_merge = get_renames(merge, common, head, merge, entries); - clean = process_renames(re_head, re_merge, - branch1, branch2); + re_head = get_renames(o, head, common, head, merge, entries); + re_merge = get_renames(o, merge, common, head, merge, entries); + clean = process_renames(o, re_head, re_merge); for (i = 0; i < entries->nr; i++) { const char *path = entries->items[i].string; struct stage_data *e = entries->items[i].util; if (!e->processed - && !process_entry(path, e, branch1, branch2)) + && !process_entry(o, path, e)) clean = 0; } @@ -1203,7 +1198,7 @@ int merge_trees(struct tree *head, clean = 1; if (index_only) - *result = write_tree_from_memory(); + *result = write_tree_from_memory(o); return clean; } @@ -1223,10 +1218,9 @@ static struct commit_list *reverse_commit_list(struct commit_list *list) * Merge the commits h1 and h2, return the resulting virtual * commit object and a flag indicating the cleanness of the merge. */ -int merge_recursive(struct commit *h1, +int merge_recursive(struct merge_options *o, + struct commit *h1, struct commit *h2, - const char *branch1, - const char *branch2, struct commit_list *ca, struct commit **result) { @@ -1235,8 +1229,8 @@ int merge_recursive(struct commit *h1, struct tree *mrtree = mrtree; int clean; - if (show(4)) { - output(4, "Merging:"); + if (show(o, 4)) { + output(o, 4, "Merging:"); output_commit_title(h1); output_commit_title(h2); } @@ -1246,8 +1240,8 @@ int merge_recursive(struct commit *h1, ca = reverse_commit_list(ca); } - if (show(5)) { - output(5, "found %u common ancestor(s):", commit_list_count(ca)); + if (show(o, 5)) { + output(o, 5, "found %u common ancestor(s):", commit_list_count(ca)); for (iter = ca; iter; iter = iter->next) output_commit_title(iter->item); } @@ -1264,6 +1258,7 @@ int merge_recursive(struct commit *h1, } for (iter = ca; iter; iter = iter->next) { + const char *saved_b1, *saved_b2; call_depth++; /* * When the merge fails, the result contains files @@ -1273,11 +1268,14 @@ int merge_recursive(struct commit *h1, * "conflicts" were already resolved. */ discard_cache(); - merge_recursive(merged_common_ancestors, iter->item, - "Temporary merge branch 1", - "Temporary merge branch 2", - NULL, - &merged_common_ancestors); + saved_b1 = o->branch1; + saved_b2 = o->branch2; + o->branch1 = "Temporary merge branch 1"; + o->branch2 = "Temporary merge branch 2"; + merge_recursive(o, merged_common_ancestors, iter->item, + NULL, &merged_common_ancestors); + o->branch1 = saved_b1; + o->branch2 = saved_b2; call_depth--; if (!merged_common_ancestors) @@ -1291,8 +1289,8 @@ int merge_recursive(struct commit *h1, } else index_only = 1; - clean = merge_trees(h1->tree, h2->tree, merged_common_ancestors->tree, - branch1, branch2, &mrtree); + clean = merge_trees(o, h1->tree, h2->tree, merged_common_ancestors->tree, + &mrtree); if (index_only) { *result = make_virtual_commit(mrtree, "merged tree"); @@ -1319,35 +1317,33 @@ static struct commit *get_ref(const unsigned char *sha1, const char *name) return (struct commit *)object; } -int merge_recursive_generic(const char **base_list, - const unsigned char *head_sha1, const char *head_name, - const unsigned char *next_sha1, const char *next_name) +int merge_recursive_generic(struct merge_options *o, + const unsigned char *head, + const unsigned char *merge, + int num_base_list, + const unsigned char **base_list, + struct commit **result) { int clean, index_fd; struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); - struct commit *result; - struct commit *head_commit = get_ref(head_sha1, head_name); - struct commit *next_commit = get_ref(next_sha1, next_name); + struct commit *head_commit = get_ref(head, o->branch1); + struct commit *next_commit = get_ref(merge, o->branch2); struct commit_list *ca = NULL; if (base_list) { int i; - for (i = 0; base_list[i]; ++i) { - unsigned char sha[20]; + for (i = 0; i < num_base_list; ++i) { struct commit *base; - if (get_sha1(base_list[i], sha)) - return error("Could not resolve ref '%s'", - base_list[i]); - if (!(base = get_ref(sha, base_list[i]))) + if (!(base = get_ref(base_list[i], sha1_to_hex(base_list[i])))) return error("Could not parse object '%s'", - base_list[i]); + sha1_to_hex(base_list[i])); commit_list_insert(base, &ca); } } index_fd = hold_locked_index(lock, 1); - clean = merge_recursive(head_commit, next_commit, - head_name, next_name, ca, &result); + clean = merge_recursive(o, head_commit, next_commit, ca, + result); if (active_cache_changed && (write_cache(index_fd, active_cache, active_nr) || commit_locked_index(lock))) @@ -1356,29 +1352,35 @@ int merge_recursive_generic(const char **base_list, return clean ? 0 : 1; } -int merge_recursive_config(const char *var, const char *value, void *cb) +static int merge_recursive_config(const char *var, const char *value, void *cb) { + struct merge_options *o = cb; if (!strcasecmp(var, "merge.verbosity")) { - merge_recursive_verbosity = git_config_int(var, value); + o->verbosity = git_config_int(var, value); return 0; } if (!strcasecmp(var, "diff.renamelimit")) { - diff_rename_limit = git_config_int(var, value); + o->diff_rename_limit = git_config_int(var, value); return 0; } if (!strcasecmp(var, "merge.renamelimit")) { - merge_rename_limit = git_config_int(var, value); + o->merge_rename_limit = git_config_int(var, value); return 0; } return git_default_config(var, value, cb); } -void merge_recursive_setup(int is_subtree_merge) +void init_merge_options(struct merge_options *o) { + memset(o, 0, sizeof(struct merge_options)); + o->verbosity = 2; + o->buffer_output = 1; + o->diff_rename_limit = -1; + o->merge_rename_limit = -1; + git_config(merge_recursive_config, o); if (getenv("GIT_MERGE_VERBOSITY")) - merge_recursive_verbosity = + o->verbosity = strtol(getenv("GIT_MERGE_VERBOSITY"), NULL, 10); - if (merge_recursive_verbosity >= 5) - buffer_output = 0; - subtree_merge = is_subtree_merge; + if (o->verbosity >= 5) + o->buffer_output = 0; } diff --git a/merge-recursive.h b/merge-recursive.h index 4dd6476..72f0a28 100644 --- a/merge-recursive.h +++ b/merge-recursive.h @@ -1,26 +1,42 @@ #ifndef MERGE_RECURSIVE_H #define MERGE_RECURSIVE_H -int merge_recursive(struct commit *h1, +struct merge_options { + const char *branch1; + const char *branch2; + unsigned subtree_merge : 1; + unsigned buffer_output : 1; + int verbosity; + int diff_rename_limit; + int merge_rename_limit; +}; + +/* merge_trees() but with recursive ancestor consolidation */ +int merge_recursive(struct merge_options *o, + struct commit *h1, struct commit *h2, - const char *branch1, - const char *branch2, struct commit_list *ancestors, struct commit **result); -int merge_trees(struct tree *head, +/* rename-detecting three-way merge, no recursion */ +int merge_trees(struct merge_options *o, + struct tree *head, struct tree *merge, struct tree *common, - const char *branch1, - const char *branch2, struct tree **result); -extern int merge_recursive_generic(const char **base_list, - const unsigned char *head_sha1, const char *head_name, - const unsigned char *next_sha1, const char *next_name); -int merge_recursive_config(const char *var, const char *value, void *cb); -void merge_recursive_setup(int is_subtree_merge); -struct tree *write_tree_from_memory(void); -extern int merge_recursive_verbosity; +/* + * "git-merge-recursive" can be fed trees; wrap them into + * virtual commits and call merge_recursive() proper. + */ +int merge_recursive_generic(struct merge_options *o, + const unsigned char *head, + const unsigned char *merge, + int num_ca, + const unsigned char **ca, + struct commit **result); + +void init_merge_options(struct merge_options *o); +struct tree *write_tree_from_memory(struct merge_options *o); #endif -- 1.6.0.rc3.17.gc14c8.dirty ^ permalink raw reply related [flat|nested] 35+ messages in thread
* Re: [PATCH] merge-recursive: introduce merge_options 2008-08-25 14:25 ` Miklos Vajna @ 2008-08-28 4:50 ` Junio C Hamano 2008-08-30 15:42 ` [PATCH] merge-recursive: fix subtree merge Miklos Vajna 1 sibling, 0 replies; 35+ messages in thread From: Junio C Hamano @ 2008-08-28 4:50 UTC (permalink / raw) To: Miklos Vajna; +Cc: git, Stephan Beyer Miklos Vajna <vmiklos@frugalware.org> writes: > On Sun, Aug 24, 2008 at 11:06:06PM -0700, Junio C Hamano <gitster@pobox.com> wrote: >> Miklos Vajna <vmiklos@frugalware.org> writes: >> >> > 1) This applies on top of 1c868d4 (merge-recursive.c: Add more >> > generic merge_recursive_generic()). I can rebase this (along with >> > 1c868d4 and 1c868d4^) on top of current master, if this is a problem. >> >> It probably is cleaner to treat this as a fresh topic from scratch on >> top of 'master', as we do not have anything outstanding in 'next' >> around this area. > > I'm now confused about what should I do: > > 1) Nothing. (That's what I did for now.) > > 2) Rebase against master and resend. > > 3) Rebase, squash and resend. What I meant was that the final state after applying this patch may make what "git log master..1c868d4" currently shows (there are two patches if I recall correctly) an incomplete failed experiment, in which case squashing and possibly refactoring (if the result of squashing is too messy) would make the history easier to review. But I looked at the series again after rebasing them myself. If you want to clean-it-up, you could replace them by sending in updates to refactor them. I think they are still ugly, even though the end result is tolerable ;-) ^ permalink raw reply [flat|nested] 35+ messages in thread
* [PATCH] merge-recursive: fix subtree merge 2008-08-25 14:25 ` Miklos Vajna 2008-08-28 4:50 ` Junio C Hamano @ 2008-08-30 15:42 ` Miklos Vajna 2008-08-30 16:39 ` Junio C Hamano 2008-08-30 17:55 ` Junio C Hamano 1 sibling, 2 replies; 35+ messages in thread From: Miklos Vajna @ 2008-08-30 15:42 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Stephan Beyer We should decide if we do a subtree merge based on the merge_options struct, not based on the global variable, which should not even exist at all. Signed-off-by: Miklos Vajna <vmiklos@frugalware.org> --- On Mon, Aug 25, 2008 at 04:25:57PM +0200, Miklos Vajna <vmiklos@frugalware.org> wrote: > It also takes care of subtree merge, output buffering, verbosity, and > rename limits - these were global variables till now in > merge-recursive.c. Actually subtree_merge was not used from the struct merge_options, here is the fix. merge-recursive.c | 4 +--- 1 files changed, 1 insertions(+), 3 deletions(-) diff --git a/merge-recursive.c b/merge-recursive.c index 3a38cc6..457ad84 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -20,8 +20,6 @@ #include "attr.h" #include "merge-recursive.h" -static int subtree_merge; - static struct tree *shift_tree_object(struct tree *one, struct tree *two) { unsigned char shifted[20]; @@ -1152,7 +1150,7 @@ int merge_trees(struct merge_options *o, { int code, clean; - if (subtree_merge) { + if (o->subtree_merge) { merge = shift_tree_object(head, merge); common = shift_tree_object(head, common); } -- 1.6.0 ^ permalink raw reply related [flat|nested] 35+ messages in thread
* Re: [PATCH] merge-recursive: fix subtree merge 2008-08-30 15:42 ` [PATCH] merge-recursive: fix subtree merge Miklos Vajna @ 2008-08-30 16:39 ` Junio C Hamano 2008-08-30 17:55 ` Junio C Hamano 1 sibling, 0 replies; 35+ messages in thread From: Junio C Hamano @ 2008-08-30 16:39 UTC (permalink / raw) To: Miklos Vajna; +Cc: git, Stephan Beyer Miklos Vajna <vmiklos@frugalware.org> writes: > On Mon, Aug 25, 2008 at 04:25:57PM +0200, Miklos Vajna <vmiklos@frugalware.org> wrote: >> It also takes care of subtree merge, output buffering, verbosity, and >> rename limits - these were global variables till now in >> merge-recursive.c. > > Actually subtree_merge was not used from the struct merge_options, here > is the fix. As bd1e8fe (merge-recursive: introduce merge_options, 2008-08-25) is not part of any solid integration branch yet, I'll squash this into it. In the longer term, I suspect that other file scope static variables in merge-recursive.c, such as call_depth, may want to move to merge_options, not as "option" but as "current state". But that is quite minor, as it only affects reentrancy, and I do not see a reason for merge_recursive() to be reentrant (yet). ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] merge-recursive: fix subtree merge 2008-08-30 15:42 ` [PATCH] merge-recursive: fix subtree merge Miklos Vajna 2008-08-30 16:39 ` Junio C Hamano @ 2008-08-30 17:55 ` Junio C Hamano 2008-08-31 23:49 ` Miklos Vajna 1 sibling, 1 reply; 35+ messages in thread From: Junio C Hamano @ 2008-08-30 17:55 UTC (permalink / raw) To: Miklos Vajna; +Cc: git, Stephan Beyer Miklos Vajna <vmiklos@frugalware.org> writes: > On Mon, Aug 25, 2008 at 04:25:57PM +0200, Miklos Vajna <vmiklos@frugalware.org> wrote: >> It also takes care of subtree merge, output buffering, verbosity, and >> rename limits - these were global variables till now in >> merge-recursive.c. > > Actually subtree_merge was not used from the struct merge_options, here > is the fix. This makes me wonder why we didn't see any breakages in the existing tests. ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] merge-recursive: fix subtree merge 2008-08-30 17:55 ` Junio C Hamano @ 2008-08-31 23:49 ` Miklos Vajna 0 siblings, 0 replies; 35+ messages in thread From: Miklos Vajna @ 2008-08-31 23:49 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Stephan Beyer [-- Attachment #1: Type: text/plain, Size: 360 bytes --] On Sat, Aug 30, 2008 at 10:55:24AM -0700, Junio C Hamano <gitster@pobox.com> wrote: > This makes me wonder why we didn't see any breakages in the existing > tests. That is a really interesting question. I have no idea how t6029 can pass without this fix, but actually it does. (Yes, I read that part of the code and the testsuite as well, but still no clue.) [-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --] ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: What's cooking in git.git (Aug 2008, #05; Tue, 19) 2008-08-19 22:00 ` Junio C Hamano 2008-08-20 22:42 ` Miklos Vajna 2008-08-25 1:44 ` [PATCH] merge-recursive: introduce merge_options Miklos Vajna @ 2008-09-01 1:06 ` Miklos Vajna 2008-09-01 1:09 ` [PATCH] builtin-revert: use merge_recursive_generic() Miklos Vajna 2008-09-02 20:02 ` What's cooking in git.git (Aug 2008, #05; Tue, 19) Junio C Hamano 2 siblings, 2 replies; 35+ messages in thread From: Miklos Vajna @ 2008-09-01 1:06 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Stephan Beyer [-- Attachment #1: Type: text/plain, Size: 3467 bytes --] On Tue, Aug 19, 2008 at 03:00:27PM -0700, Junio C Hamano <gitster@pobox.com> wrote: > and the call chain would become: > (...) > cmd_revert(), cmd_am(), cmd_checkout(), cmd_stash(), ... > -> merge_trees() I tried to let cmd_revert() use merge_trees() only and not merge_recursive_generic(), but something is fishy with it. t3501-revert-cherry-pick passes fine, but t3404-rebase-interactive fail, becase once we have a conflict, git diff --name-status says 'M' for the given file and not 'U', which is obviously wrong. I'm sending both patches: the one that works properly using merge_recursive_generic() - and which one passes the testsuite here, and the one that is elegant as it uses merge_trees(), but actually not complete, at least regarding not adding the unmerged entries to the index. So, first here is my failed attempt to use merge_trees() inside builtin-revert: diff --git a/builtin-revert.c b/builtin-revert.c index 3667705..3071518 100644 --- a/builtin-revert.c +++ b/builtin-revert.c @@ -12,6 +12,7 @@ #include "diff.h" #include "revision.h" #include "rerere.h" +#include "merge-recursive.h" /* * This implements the builtins revert and cherry-pick. @@ -201,36 +202,6 @@ static void set_author_ident_env(const char *message) sha1_to_hex(commit->object.sha1)); } -static int merge_recursive(const char *base_sha1, - const char *head_sha1, const char *head_name, - const char *next_sha1, const char *next_name) -{ - char buffer[256]; - const char *argv[6]; - int i = 0; - - sprintf(buffer, "GITHEAD_%s", head_sha1); - setenv(buffer, head_name, 1); - sprintf(buffer, "GITHEAD_%s", next_sha1); - setenv(buffer, next_name, 1); - - /* - * This three way merge is an interesting one. We are at - * $head, and would want to apply the change between $commit - * and $prev on top of us (when reverting), or the change between - * $prev and $commit on top of us (when cherry-picking or replaying). - */ - argv[i++] = "merge-recursive"; - if (base_sha1) - argv[i++] = base_sha1; - argv[i++] = "--"; - argv[i++] = head_sha1; - argv[i++] = next_sha1; - argv[i++] = NULL; - - return run_command_v_opt(argv, RUN_COMMAND_NO_STDIN | RUN_GIT_CMD); -} - static char *help_msg(const unsigned char *sha1) { static char helpbuf[1024]; @@ -271,6 +242,8 @@ static int revert_or_cherry_pick(int argc, const char **argv) char *oneline, *reencoded_message = NULL; const char *message, *encoding; const char *defmsg = xstrdup(git_path("MERGE_MSG")); + struct merge_options o; + struct tree *result; git_config(git_default_config, NULL); me = action == REVERT ? "revert" : "cherry-pick"; @@ -374,13 +347,16 @@ static int revert_or_cherry_pick(int argc, const char **argv) } } - if (merge_recursive(base == NULL ? - NULL : sha1_to_hex(base->object.sha1), - sha1_to_hex(head), "HEAD", - sha1_to_hex(next->object.sha1), oneline) || - write_cache_as_tree(head, 0, NULL)) { + read_cache(); + init_merge_options(&o); + o.branch1 = "HEAD"; + o.branch2 = oneline; + parse_commit(next); + parse_commit(base); + if (!merge_trees(&o, lookup_commit_reference_gently(head, 0)->tree, + next->tree, base->tree, &result) || + write_cache_as_tree(head, 0, NULL)) { add_to_msg("\nConflicts:\n\n"); - read_cache(); for (i = 0; i < active_nr;) { struct cache_entry *ce = active_cache[i++]; if (ce_stage(ce)) { [-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --] ^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH] builtin-revert: use merge_recursive_generic() 2008-09-01 1:06 ` What's cooking in git.git (Aug 2008, #05; Tue, 19) Miklos Vajna @ 2008-09-01 1:09 ` Miklos Vajna 2008-09-02 20:02 ` What's cooking in git.git (Aug 2008, #05; Tue, 19) Junio C Hamano 1 sibling, 0 replies; 35+ messages in thread From: Miklos Vajna @ 2008-09-01 1:09 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Stephan Beyer We had a separate function to run merge-recursive in a separate process, but this is not really necessary, since we have merge_recursive_generic() to do the same, without wasting resources. Signed-off-by: Miklos Vajna <vmiklos@frugalware.org> --- On Mon, Sep 01, 2008 at 03:06:12AM +0200, Miklos Vajna <vmiklos@frugalware.org> wrote: > I'm sending both patches: the one that works properly using > merge_recursive_generic() - and which one passes the testsuite here Here it is. builtin-revert.c | 55 ++++++++++++++++++----------------------------------- 1 files changed, 19 insertions(+), 36 deletions(-) diff --git a/builtin-revert.c b/builtin-revert.c index 3667705..8d4ebcf 100644 --- a/builtin-revert.c +++ b/builtin-revert.c @@ -12,6 +12,7 @@ #include "diff.h" #include "revision.h" #include "rerere.h" +#include "merge-recursive.h" /* * This implements the builtins revert and cherry-pick. @@ -201,36 +202,6 @@ static void set_author_ident_env(const char *message) sha1_to_hex(commit->object.sha1)); } -static int merge_recursive(const char *base_sha1, - const char *head_sha1, const char *head_name, - const char *next_sha1, const char *next_name) -{ - char buffer[256]; - const char *argv[6]; - int i = 0; - - sprintf(buffer, "GITHEAD_%s", head_sha1); - setenv(buffer, head_name, 1); - sprintf(buffer, "GITHEAD_%s", next_sha1); - setenv(buffer, next_name, 1); - - /* - * This three way merge is an interesting one. We are at - * $head, and would want to apply the change between $commit - * and $prev on top of us (when reverting), or the change between - * $prev and $commit on top of us (when cherry-picking or replaying). - */ - argv[i++] = "merge-recursive"; - if (base_sha1) - argv[i++] = base_sha1; - argv[i++] = "--"; - argv[i++] = head_sha1; - argv[i++] = next_sha1; - argv[i++] = NULL; - - return run_command_v_opt(argv, RUN_COMMAND_NO_STDIN | RUN_GIT_CMD); -} - static char *help_msg(const unsigned char *sha1) { static char helpbuf[1024]; @@ -266,12 +237,16 @@ static int index_is_dirty(void) static int revert_or_cherry_pick(int argc, const char **argv) { unsigned char head[20]; + unsigned const char *ca = NULL; struct commit *base, *next, *parent; - int i; + int i, fail; char *oneline, *reencoded_message = NULL; const char *message, *encoding; const char *defmsg = xstrdup(git_path("MERGE_MSG")); + struct merge_options o; + struct commit *result; + init_merge_options(&o); git_config(git_default_config, NULL); me = action == REVERT ? "revert" : "cherry-pick"; setenv(GIT_REFLOG_ACTION, me, 0); @@ -374,11 +349,19 @@ static int revert_or_cherry_pick(int argc, const char **argv) } } - if (merge_recursive(base == NULL ? - NULL : sha1_to_hex(base->object.sha1), - sha1_to_hex(head), "HEAD", - sha1_to_hex(next->object.sha1), oneline) || - write_cache_as_tree(head, 0, NULL)) { + if (base) + ca = base->object.sha1; + o.branch1 = "HEAD"; + o.branch2 = oneline; + fail = merge_recursive_generic(&o, + head, + next->object.sha1, + ca ? 1 : 0, + &ca, + &result); + if (fail < 0) + exit(1); + if (fail || write_cache_as_tree(head, 0, NULL)) { add_to_msg("\nConflicts:\n\n"); read_cache(); for (i = 0; i < active_nr;) { -- 1.6.0 ^ permalink raw reply related [flat|nested] 35+ messages in thread
* Re: What's cooking in git.git (Aug 2008, #05; Tue, 19) 2008-09-01 1:06 ` What's cooking in git.git (Aug 2008, #05; Tue, 19) Miklos Vajna 2008-09-01 1:09 ` [PATCH] builtin-revert: use merge_recursive_generic() Miklos Vajna @ 2008-09-02 20:02 ` Junio C Hamano 2008-09-02 20:43 ` Junio C Hamano 2008-09-02 22:05 ` [PATCH 0/2] Move call_depth and index_only to struct merge_options Miklos Vajna 1 sibling, 2 replies; 35+ messages in thread From: Junio C Hamano @ 2008-09-02 20:02 UTC (permalink / raw) To: Miklos Vajna; +Cc: git, Stephan Beyer Miklos Vajna <vmiklos@frugalware.org> writes: > I tried to let cmd_revert() use merge_trees() only and not > merge_recursive_generic(), but something is fishy with it. > t3501-revert-cherry-pick passes fine, but t3404-rebase-interactive fail, > becase once we have a conflict, git diff --name-status says 'M' for the > given file and not 'U', which is obviously wrong. I think this is because you are forgotting to write the index file out. You are calling "git commit -n" at the end if a cherry-pick/revert is clean, or giving the user back an unmerged state in the index otherwise. In either case, after merge_trees() gives you a potentially unmerged index back in-core, you need to write it to the $GIT_INDEX_FILE for later users. Also notice that your output is awfully silent. You are forgetting to flush the buffered output that is kept in "obuf". Please check what other extra things merge_recursive() function does that merge_trees() doesn't; the above two are what I've spotted by code inspection, but there may be others. It could be an indication of incorrect interface layering when the builtin was refactored. I found it a bit disturbing that "index_only" and "call_depth" were not part of merge_options structure. The machinery is not yet meant to be reentrant, so we may rely the previous call to the function (either merge_recursive() or merge_trees() revert them to a sane initial value, but it is a bit unnerving, having to depend on that assumption. I think your code happily dereferences NULL when picking the root commit is involved, although I do not think the failure in the test suite you saw is related to this omission. Here is a partial fix to address the above issues I noticed on top of your version; untested. builtin-revert.c | 46 ++++++++++++++++++++++++++++++++++++---------- 1 files changed, 36 insertions(+), 10 deletions(-) diff --git i/builtin-revert.c w/builtin-revert.c index 3071518..41f3ca2 100644 --- i/builtin-revert.c +++ w/builtin-revert.c @@ -234,16 +234,27 @@ static int index_is_dirty(void) return !!DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES); } +static struct tree *empty_tree(void) +{ + struct tree *tree = xcalloc(1, sizeof(struct tree)); + + tree->object.parsed = 1; + tree->object.type = OBJ_TREE; + pretend_sha1_file(NULL, 0, OBJ_TREE, tree->object.sha1); + return tree; +} + static int revert_or_cherry_pick(int argc, const char **argv) { unsigned char head[20]; struct commit *base, *next, *parent; - int i; + int i, index_fd, clean; char *oneline, *reencoded_message = NULL; const char *message, *encoding; const char *defmsg = xstrdup(git_path("MERGE_MSG")); struct merge_options o; - struct tree *result; + struct tree *result, *next_tree, *base_tree, *head_tree; + static struct lock_file index_lock; git_config(git_default_config, NULL); me = action == REVERT ? "revert" : "cherry-pick"; @@ -254,6 +265,10 @@ static int revert_or_cherry_pick(int argc, const char **argv) if (action == REVERT && !no_replay) die("revert is incompatible with replay"); + index_fd = hold_locked_index(&index_lock, 1); + + if (read_cache() < 0) + die("git %s: failed to read the index", me); if (no_commit) { /* * We do not intend to commit immediately. We just want to @@ -266,12 +281,10 @@ static int revert_or_cherry_pick(int argc, const char **argv) } else { if (get_sha1("HEAD", head)) die ("You do not have a valid HEAD"); - if (read_cache() < 0) - die("could not read the index"); if (index_is_dirty()) die ("Dirty index: cannot %s", me); - discard_cache(); } + discard_cache(); if (!commit->parents) { if (action == REVERT) @@ -305,6 +318,10 @@ static int revert_or_cherry_pick(int argc, const char **argv) die ("Cannot get commit message for %s", sha1_to_hex(commit->object.sha1)); + if (parent && parse_commit(parent) < 0) + die("%s: cannot parse parent commit %s", + me, sha1_to_hex(parent->object.sha1)); + /* * "commit" is an existing commit. We would want to apply * the difference it introduces since its first parent "prev" @@ -351,11 +368,20 @@ static int revert_or_cherry_pick(int argc, const char **argv) init_merge_options(&o); o.branch1 = "HEAD"; o.branch2 = oneline; - parse_commit(next); - parse_commit(base); - if (!merge_trees(&o, lookup_commit_reference_gently(head, 0)->tree, - next->tree, base->tree, &result) || - write_cache_as_tree(head, 0, NULL)) { + + head_tree = parse_tree_indirect(head); + next_tree = next ? next->tree : empty_tree(); + base_tree = base ? base->tree : empty_tree(); + + clean = merge_trees(&o, + head_tree, + next_tree, base_tree, &result); + + if (write_cache(index_fd, active_cache, active_nr) || + commit_locked_index(&index_lock)) + die("%s: Unable to write new index file", me); + + if (!clean) { add_to_msg("\nConflicts:\n\n"); for (i = 0; i < active_nr;) { struct cache_entry *ce = active_cache[i++]; ^ permalink raw reply related [flat|nested] 35+ messages in thread
* Re: What's cooking in git.git (Aug 2008, #05; Tue, 19) 2008-09-02 20:02 ` What's cooking in git.git (Aug 2008, #05; Tue, 19) Junio C Hamano @ 2008-09-02 20:43 ` Junio C Hamano 2008-09-02 22:05 ` [PATCH 0/2] Move call_depth and index_only to struct merge_options Miklos Vajna 1 sibling, 0 replies; 35+ messages in thread From: Junio C Hamano @ 2008-09-02 20:43 UTC (permalink / raw) To: Miklos Vajna; +Cc: git, Stephan Beyer Junio C Hamano <gitster@pobox.com> writes: > Miklos Vajna <vmiklos@frugalware.org> writes: > >> I tried to let cmd_revert() use merge_trees() only and not >> merge_recursive_generic(), but something is fishy with it. > Here is a partial fix to address the above issues I noticed on > top of your version; untested. This has a few fix-ups in addition to the one I sent earlier (not incremental, this applies directly on top of yours, bypassing the earlier one), and has passed the self tests. builtin-revert.c | 47 +++++++++++++++++++++++++++++++++++++---------- 1 files changed, 37 insertions(+), 10 deletions(-) diff --git i/builtin-revert.c w/builtin-revert.c index 3071518..8486539 100644 --- i/builtin-revert.c +++ w/builtin-revert.c @@ -234,16 +234,27 @@ static int index_is_dirty(void) return !!DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES); } +static struct tree *empty_tree(void) +{ + struct tree *tree = xcalloc(1, sizeof(struct tree)); + + tree->object.parsed = 1; + tree->object.type = OBJ_TREE; + pretend_sha1_file(NULL, 0, OBJ_TREE, tree->object.sha1); + return tree; +} + static int revert_or_cherry_pick(int argc, const char **argv) { unsigned char head[20]; struct commit *base, *next, *parent; - int i; + int i, index_fd, clean; char *oneline, *reencoded_message = NULL; const char *message, *encoding; const char *defmsg = xstrdup(git_path("MERGE_MSG")); struct merge_options o; - struct tree *result; + struct tree *result, *next_tree, *base_tree, *head_tree; + static struct lock_file index_lock; git_config(git_default_config, NULL); me = action == REVERT ? "revert" : "cherry-pick"; @@ -254,6 +265,8 @@ static int revert_or_cherry_pick(int argc, const char **argv) if (action == REVERT && !no_replay) die("revert is incompatible with replay"); + if (read_cache() < 0) + die("git %s: failed to read the index", me); if (no_commit) { /* * We do not intend to commit immediately. We just want to @@ -266,12 +279,12 @@ static int revert_or_cherry_pick(int argc, const char **argv) } else { if (get_sha1("HEAD", head)) die ("You do not have a valid HEAD"); - if (read_cache() < 0) - die("could not read the index"); if (index_is_dirty()) die ("Dirty index: cannot %s", me); - discard_cache(); } + discard_cache(); + + index_fd = hold_locked_index(&index_lock, 1); if (!commit->parents) { if (action == REVERT) @@ -305,6 +318,10 @@ static int revert_or_cherry_pick(int argc, const char **argv) die ("Cannot get commit message for %s", sha1_to_hex(commit->object.sha1)); + if (parent && parse_commit(parent) < 0) + die("%s: cannot parse parent commit %s", + me, sha1_to_hex(parent->object.sha1)); + /* * "commit" is an existing commit. We would want to apply * the difference it introduces since its first parent "prev" @@ -351,11 +368,21 @@ static int revert_or_cherry_pick(int argc, const char **argv) init_merge_options(&o); o.branch1 = "HEAD"; o.branch2 = oneline; - parse_commit(next); - parse_commit(base); - if (!merge_trees(&o, lookup_commit_reference_gently(head, 0)->tree, - next->tree, base->tree, &result) || - write_cache_as_tree(head, 0, NULL)) { + + head_tree = parse_tree_indirect(head); + next_tree = next ? next->tree : empty_tree(); + base_tree = base ? base->tree : empty_tree(); + + clean = merge_trees(&o, + head_tree, + next_tree, base_tree, &result); + + if (active_cache_changed && + (write_cache(index_fd, active_cache, active_nr) || + commit_locked_index(&index_lock))) + die("%s: Unable to write new index file", me); + + if (!clean) { add_to_msg("\nConflicts:\n\n"); for (i = 0; i < active_nr;) { struct cache_entry *ce = active_cache[i++]; ^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 0/2] Move call_depth and index_only to struct merge_options 2008-09-02 20:02 ` What's cooking in git.git (Aug 2008, #05; Tue, 19) Junio C Hamano 2008-09-02 20:43 ` Junio C Hamano @ 2008-09-02 22:05 ` Miklos Vajna 2008-09-02 22:05 ` [PATCH 1/2] merge-recursive: move call_depth " Miklos Vajna 2008-09-02 22:39 ` [PATCH 0/2] Move call_depth and index_only to struct merge_options Junio C Hamano 1 sibling, 2 replies; 35+ messages in thread From: Miklos Vajna @ 2008-09-02 22:05 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Stephan Beyer On Tue, Sep 02, 2008 at 01:02:31PM -0700, Junio C Hamano <gitster@pobox.com> wrote: > I found it a bit disturbing that "index_only" and "call_depth" were > not > part of merge_options structure. Here are two patches to do it, on top of current mv/merge-recursive. Both patches are pretty trivial, I think, but I split them as the second one is larger. Now in some cases we have function calls like merge_file(o, one, a, b, o->branch1, o->branch2); but I don't think we can avoid it, as the last two parameters are not always like this (two times are like this, and once conditionally swapped). I'm not sure if it worth to introduce a new "int swap" parameter, just to avoid the last two one. Miklos Vajna (2): merge-recursive: move call_depth to struct merge_options merge-recursive: move index_only to struct merge_options merge-recursive.c | 164 ++++++++++++++++++++++++++--------------------------- merge-recursive.h | 13 ++++ 2 files changed, 93 insertions(+), 84 deletions(-) ^ permalink raw reply [flat|nested] 35+ messages in thread
* [PATCH 1/2] merge-recursive: move call_depth to struct merge_options 2008-09-02 22:05 ` [PATCH 0/2] Move call_depth and index_only to struct merge_options Miklos Vajna @ 2008-09-02 22:05 ` Miklos Vajna 2008-09-02 22:05 ` [PATCH 2/2] merge-recursive: move index_only " Miklos Vajna 2008-09-02 22:13 ` [PATCH] Makefile: add merge_recursive.h to LIB_H Miklos Vajna 2008-09-02 22:39 ` [PATCH 0/2] Move call_depth and index_only to struct merge_options Junio C Hamano 1 sibling, 2 replies; 35+ messages in thread From: Miklos Vajna @ 2008-09-02 22:05 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Stephan Beyer Signed-off-by: Miklos Vajna <vmiklos@frugalware.org> --- merge-recursive.c | 25 ++++++++++++------------- merge-recursive.h | 1 + 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/merge-recursive.c b/merge-recursive.c index 457ad84..5bb20aa 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -80,12 +80,11 @@ struct stage_data static struct string_list current_file_set = {NULL, 0, 0, 1}; static struct string_list current_directory_set = {NULL, 0, 0, 1}; -static int call_depth = 0; static struct strbuf obuf = STRBUF_INIT; static int show(struct merge_options *o, int v) { - return (!call_depth && o->verbosity >= v) || o->verbosity >= 5; + return (!o->call_depth && o->verbosity >= v) || o->verbosity >= 5; } static void flush_output(void) @@ -104,9 +103,9 @@ static void output(struct merge_options *o, int v, const char *fmt, ...) if (!show(o, v)) return; - strbuf_grow(&obuf, call_depth * 2 + 2); - memset(obuf.buf + obuf.len, ' ', call_depth * 2); - strbuf_setlen(&obuf, obuf.len + call_depth * 2); + strbuf_grow(&obuf, o->call_depth * 2 + 2); + memset(obuf.buf + obuf.len, ' ', o->call_depth * 2); + strbuf_setlen(&obuf, obuf.len + o->call_depth * 2); va_start(ap, fmt); len = vsnprintf(obuf.buf + obuf.len, strbuf_avail(&obuf), fmt, ap); @@ -129,11 +128,11 @@ static void output(struct merge_options *o, int v, const char *fmt, ...) flush_output(); } -static void output_commit_title(struct commit *commit) +static void output_commit_title(struct merge_options *o, struct commit *commit) { int i; flush_output(); - for (i = call_depth; i--;) + for (i = o->call_depth; i--;) fputs(" ", stdout); if (commit->util) printf("virtual %s\n", (char *)commit->util); @@ -1230,8 +1229,8 @@ int merge_recursive(struct merge_options *o, if (show(o, 4)) { output(o, 4, "Merging:"); - output_commit_title(h1); - output_commit_title(h2); + output_commit_title(o, h1); + output_commit_title(o, h2); } if (!ca) { @@ -1242,7 +1241,7 @@ int merge_recursive(struct merge_options *o, if (show(o, 5)) { output(o, 5, "found %u common ancestor(s):", commit_list_count(ca)); for (iter = ca; iter; iter = iter->next) - output_commit_title(iter->item); + output_commit_title(o, iter->item); } merged_common_ancestors = pop_commit(&ca); @@ -1258,7 +1257,7 @@ int merge_recursive(struct merge_options *o, for (iter = ca; iter; iter = iter->next) { const char *saved_b1, *saved_b2; - call_depth++; + o->call_depth++; /* * When the merge fails, the result contains files * with conflict markers. The cleanness flag is @@ -1275,14 +1274,14 @@ int merge_recursive(struct merge_options *o, NULL, &merged_common_ancestors); o->branch1 = saved_b1; o->branch2 = saved_b2; - call_depth--; + o->call_depth--; if (!merged_common_ancestors) die("merge returned no commit"); } discard_cache(); - if (!call_depth) { + if (!o->call_depth) { read_cache(); index_only = 0; } else diff --git a/merge-recursive.h b/merge-recursive.h index 72f0a28..4f55374 100644 --- a/merge-recursive.h +++ b/merge-recursive.h @@ -9,6 +9,7 @@ struct merge_options { int verbosity; int diff_rename_limit; int merge_rename_limit; + int call_depth; }; /* merge_trees() but with recursive ancestor consolidation */ -- 1.6.0.1 ^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 2/2] merge-recursive: move index_only to struct merge_options 2008-09-02 22:05 ` [PATCH 1/2] merge-recursive: move call_depth " Miklos Vajna @ 2008-09-02 22:05 ` Miklos Vajna 2008-09-02 22:13 ` [PATCH] Makefile: add merge_recursive.h to LIB_H Miklos Vajna 1 sibling, 0 replies; 35+ messages in thread From: Miklos Vajna @ 2008-09-02 22:05 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Stephan Beyer Signed-off-by: Miklos Vajna <vmiklos@frugalware.org> --- merge-recursive.c | 139 ++++++++++++++++++++++++++--------------------------- merge-recursive.h | 12 +++++ 2 files changed, 80 insertions(+), 71 deletions(-) diff --git a/merge-recursive.c b/merge-recursive.c index 5bb20aa..4af657c 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -165,17 +165,6 @@ static int add_cacheinfo(unsigned int mode, const unsigned char *sha1, return add_cache_entry(ce, options); } -/* - * This is a global variable which is used in a number of places but - * only written to in the 'merge' function. - * - * index_only == 1 => Don't leave any non-stage 0 entries in the cache and - * don't update the working directory. - * 0 => Leave unmerged entries in the cache and update - * the working directory. - */ -static int index_only = 0; - static void init_tree_desc_from_tree(struct tree_desc *desc, struct tree *tree) { parse_tree(tree); @@ -428,10 +417,11 @@ static int remove_path(const char *name) return ret; } -static int remove_file(int clean, const char *path, int no_wd) +static int remove_file(struct merge_options *o, int clean, + const char *path, int no_wd) { - int update_cache = index_only || clean; - int update_working_directory = !index_only && !no_wd; + int update_cache = o->index_only || clean; + int update_working_directory = !o->index_only && !no_wd; if (update_cache) { if (remove_file_from_cache(path)) @@ -509,13 +499,14 @@ static int make_room_for_path(const char *path) return error(msg, path, ": perhaps a D/F conflict?"); } -static void update_file_flags(const unsigned char *sha, +static void update_file_flags(struct merge_options *o, + const unsigned char *sha, unsigned mode, const char *path, int update_cache, int update_wd) { - if (index_only) + if (o->index_only) update_wd = 0; if (update_wd) { @@ -574,12 +565,13 @@ static void update_file_flags(const unsigned char *sha, add_cacheinfo(mode, sha, path, 0, update_wd, ADD_CACHE_OK_TO_ADD); } -static void update_file(int clean, +static void update_file(struct merge_options *o, + int clean, const unsigned char *sha, unsigned mode, const char *path) { - update_file_flags(sha, mode, path, index_only || clean, !index_only); + update_file_flags(o, sha, mode, path, o->index_only || clean, !o->index_only); } /* Low level file merging, update and removal */ @@ -609,8 +601,9 @@ static void fill_mm(const unsigned char *sha1, mmfile_t *mm) mm->size = size; } -static int merge_3way(mmbuffer_t *result_buf, - struct diff_filespec *o, +static int merge_3way(struct merge_options *o, + mmbuffer_t *result_buf, + struct diff_filespec *one, struct diff_filespec *a, struct diff_filespec *b, const char *branch1, @@ -623,13 +616,13 @@ static int merge_3way(mmbuffer_t *result_buf, name1 = xstrdup(mkpath("%s:%s", branch1, a->path)); name2 = xstrdup(mkpath("%s:%s", branch2, b->path)); - fill_mm(o->sha1, &orig); + fill_mm(one->sha1, &orig); fill_mm(a->sha1, &src1); fill_mm(b->sha1, &src2); merge_status = ll_merge(result_buf, a->path, &orig, &src1, name1, &src2, name2, - index_only); + o->index_only); free(name1); free(name2); @@ -639,9 +632,12 @@ static int merge_3way(mmbuffer_t *result_buf, return merge_status; } -static struct merge_file_info merge_file(struct diff_filespec *o, - struct diff_filespec *a, struct diff_filespec *b, - const char *branch1, const char *branch2) +static struct merge_file_info merge_file(struct merge_options *o, + struct diff_filespec *one, + struct diff_filespec *a, + struct diff_filespec *b, + const char *branch1, + const char *branch2) { struct merge_file_info result; result.merge = 0; @@ -657,31 +653,31 @@ static struct merge_file_info merge_file(struct diff_filespec *o, hashcpy(result.sha, b->sha1); } } else { - if (!sha_eq(a->sha1, o->sha1) && !sha_eq(b->sha1, o->sha1)) + if (!sha_eq(a->sha1, one->sha1) && !sha_eq(b->sha1, one->sha1)) result.merge = 1; /* * Merge modes */ - if (a->mode == b->mode || a->mode == o->mode) + if (a->mode == b->mode || a->mode == one->mode) result.mode = b->mode; else { result.mode = a->mode; - if (b->mode != o->mode) { + if (b->mode != one->mode) { result.clean = 0; result.merge = 1; } } - if (sha_eq(a->sha1, b->sha1) || sha_eq(a->sha1, o->sha1)) + if (sha_eq(a->sha1, b->sha1) || sha_eq(a->sha1, one->sha1)) hashcpy(result.sha, b->sha1); - else if (sha_eq(b->sha1, o->sha1)) + else if (sha_eq(b->sha1, one->sha1)) hashcpy(result.sha, a->sha1); else if (S_ISREG(a->mode)) { mmbuffer_t result_buf; int merge_status; - merge_status = merge_3way(&result_buf, o, a, b, + merge_status = merge_3way(o, &result_buf, one, a, b, branch1, branch2); if ((merge_status < 0) || !result_buf.ptr) @@ -726,22 +722,22 @@ static void conflict_rename_rename(struct merge_options *o, dst_name1 = del[delp++] = unique_path(ren1_dst, branch1); output(o, 1, "%s is a directory in %s adding as %s instead", ren1_dst, branch2, dst_name1); - remove_file(0, ren1_dst, 0); + remove_file(o, 0, ren1_dst, 0); } if (string_list_has_string(¤t_directory_set, ren2_dst)) { dst_name2 = del[delp++] = unique_path(ren2_dst, branch2); output(o, 1, "%s is a directory in %s adding as %s instead", ren2_dst, branch1, dst_name2); - remove_file(0, ren2_dst, 0); + remove_file(o, 0, ren2_dst, 0); } - if (index_only) { + if (o->index_only) { remove_file_from_cache(dst_name1); remove_file_from_cache(dst_name2); /* * Uncomment to leave the conflicting names in the resulting tree * - * update_file(0, ren1->pair->two->sha1, ren1->pair->two->mode, dst_name1); - * update_file(0, ren2->pair->two->sha1, ren2->pair->two->mode, dst_name2); + * update_file(o, 0, ren1->pair->two->sha1, ren1->pair->two->mode, dst_name1); + * update_file(o, 0, ren2->pair->two->sha1, ren2->pair->two->mode, dst_name2); */ } else { update_stages(dst_name1, NULL, ren1->pair->two, NULL, 1); @@ -757,8 +753,8 @@ static void conflict_rename_dir(struct merge_options *o, { char *new_path = unique_path(ren1->pair->two->path, branch1); output(o, 1, "Renaming %s to %s instead", ren1->pair->one->path, new_path); - remove_file(0, ren1->pair->two->path, 0); - update_file(0, ren1->pair->two->sha1, ren1->pair->two->mode, new_path); + remove_file(o, 0, ren1->pair->two->path, 0); + update_file(o, 0, ren1->pair->two->sha1, ren1->pair->two->mode, new_path); free(new_path); } @@ -773,9 +769,9 @@ static void conflict_rename_rename_2(struct merge_options *o, output(o, 1, "Renaming %s to %s and %s to %s instead", ren1->pair->one->path, new_path1, ren2->pair->one->path, new_path2); - remove_file(0, ren1->pair->two->path, 0); - update_file(0, ren1->pair->two->sha1, ren1->pair->two->mode, new_path1); - update_file(0, ren2->pair->two->sha1, ren2->pair->two->mode, new_path2); + remove_file(o, 0, ren1->pair->two->path, 0); + update_file(o, 0, ren1->pair->two->sha1, ren1->pair->two->mode, new_path1); + update_file(o, 0, ren2->pair->two->sha1, ren2->pair->two->mode, new_path2); free(new_path2); free(new_path1); } @@ -867,17 +863,18 @@ static int process_renames(struct merge_options *o, "rename \"%s\"->\"%s\" in \"%s\"%s", src, ren1_dst, branch1, src, ren2_dst, branch2, - index_only ? " (left unresolved)": ""); - if (index_only) { + o->index_only ? " (left unresolved)": ""); + if (o->index_only) { remove_file_from_cache(src); - update_file(0, ren1->pair->one->sha1, + update_file(o, 0, ren1->pair->one->sha1, ren1->pair->one->mode, src); } conflict_rename_rename(o, ren1, branch1, ren2, branch2); } else { struct merge_file_info mfi; - remove_file(1, ren1_src, 1); - mfi = merge_file(ren1->pair->one, + remove_file(o, 1, ren1_src, 1); + mfi = merge_file(o, + ren1->pair->one, ren1->pair->two, ren2->pair->two, branch1, @@ -893,14 +890,14 @@ static int process_renames(struct merge_options *o, ren1_dst); clean_merge = 0; - if (!index_only) + if (!o->index_only) update_stages(ren1_dst, ren1->pair->one, ren1->pair->two, ren2->pair->two, 1 /* clear */); } - update_file(mfi.clean, mfi.sha, mfi.mode, ren1_dst); + update_file(o, mfi.clean, mfi.sha, mfi.mode, ren1_dst); } } else { /* Renamed in 1, maybe changed in 2 */ @@ -909,7 +906,7 @@ static int process_renames(struct merge_options *o, struct diff_filespec src_other, dst_other; int try_merge, stage = a_renames == renames1 ? 3: 2; - remove_file(1, ren1_src, index_only || stage == 3); + remove_file(o, 1, ren1_src, o->index_only || stage == 3); hashcpy(src_other.sha1, ren1->src_entry->stages[stage].sha); src_other.mode = ren1->src_entry->stages[stage].mode; @@ -931,7 +928,7 @@ static int process_renames(struct merge_options *o, "and deleted in %s", ren1_src, ren1_dst, branch1, branch2); - update_file(0, ren1->pair->two->sha1, ren1->pair->two->mode, ren1_dst); + update_file(o, 0, ren1->pair->two->sha1, ren1->pair->two->mode, ren1_dst); } else if (!sha_eq(dst_other.sha1, null_sha1)) { const char *new_path; clean_merge = 0; @@ -942,7 +939,7 @@ static int process_renames(struct merge_options *o, ren1_dst, branch2); new_path = unique_path(ren1_dst, branch2); output(o, 1, "Adding as %s instead", new_path); - update_file(0, dst_other.sha1, dst_other.mode, new_path); + update_file(o, 0, dst_other.sha1, dst_other.mode, new_path); } else if ((item = string_list_lookup(ren1_dst, renames2Dst))) { ren2 = item->util; clean_merge = 0; @@ -969,7 +966,7 @@ static int process_renames(struct merge_options *o, b = ren1->pair->two; a = &src_other; } - mfi = merge_file(one, a, b, + mfi = merge_file(o, one, a, b, o->branch1, o->branch2); if (mfi.clean && @@ -991,11 +988,11 @@ static int process_renames(struct merge_options *o, ren1_dst); clean_merge = 0; - if (!index_only) + if (!o->index_only) update_stages(ren1_dst, one, a, b, 1); } - update_file(mfi.clean, mfi.sha, mfi.mode, ren1_dst); + update_file(o, mfi.clean, mfi.sha, mfi.mode, ren1_dst); } } } @@ -1037,7 +1034,7 @@ static int process_entry(struct merge_options *o, if (a_sha) output(o, 2, "Removing %s", path); /* do not touch working file if it did not exist */ - remove_file(1, path, !a_sha); + remove_file(o, 1, path, !a_sha); } else { /* Deleted in one and changed in the other */ clean_merge = 0; @@ -1046,13 +1043,13 @@ static int process_entry(struct merge_options *o, "and modified in %s. Version %s of %s left in tree.", path, o->branch1, o->branch2, o->branch2, path); - update_file(0, b_sha, b_mode, path); + update_file(o, 0, b_sha, b_mode, path); } else { output(o, 1, "CONFLICT (delete/modify): %s deleted in %s " "and modified in %s. Version %s of %s left in tree.", path, o->branch2, o->branch1, o->branch1, path); - update_file(0, a_sha, a_mode, path); + update_file(o, 0, a_sha, a_mode, path); } } @@ -1084,11 +1081,11 @@ static int process_entry(struct merge_options *o, output(o, 1, "CONFLICT (%s): There is a directory with name %s in %s. " "Adding %s as %s", conf, path, other_branch, path, new_path); - remove_file(0, path, 0); - update_file(0, sha, mode, new_path); + remove_file(o, 0, path, 0); + update_file(o, 0, sha, mode, new_path); } else { output(o, 2, "Adding %s", path); - update_file(1, sha, mode, path); + update_file(o, 1, sha, mode, path); } } else if (a_sha && b_sha) { /* Case C: Added in both (check for same permissions) and */ @@ -1110,12 +1107,12 @@ static int process_entry(struct merge_options *o, hashcpy(b.sha1, b_sha); b.mode = b_mode; - mfi = merge_file(&one, &a, &b, + mfi = merge_file(o, &one, &a, &b, o->branch1, o->branch2); clean_merge = mfi.clean; if (mfi.clean) - update_file(1, mfi.sha, mfi.mode, path); + update_file(o, 1, mfi.sha, mfi.mode, path); else if (S_ISGITLINK(mfi.mode)) output(o, 1, "CONFLICT (submodule): Merge conflict in %s " "- needs %s", path, sha1_to_hex(b.sha1)); @@ -1123,10 +1120,10 @@ static int process_entry(struct merge_options *o, output(o, 1, "CONFLICT (%s): Merge conflict in %s", reason, path); - if (index_only) - update_file(0, mfi.sha, mfi.mode, path); + if (o->index_only) + update_file(o, 0, mfi.sha, mfi.mode, path); else - update_file_flags(mfi.sha, mfi.mode, path, + update_file_flags(o, mfi.sha, mfi.mode, path, 0 /* update_cache */, 1 /* update_working_directory */); } } else if (!o_sha && !a_sha && !b_sha) { @@ -1134,7 +1131,7 @@ static int process_entry(struct merge_options *o, * this entry was deleted altogether. a_mode == 0 means * we had that path and want to actively remove it. */ - remove_file(1, path, !a_mode); + remove_file(o, 1, path, !a_mode); } else die("Fatal merge failure, shouldn't happen."); @@ -1160,7 +1157,7 @@ int merge_trees(struct merge_options *o, return 1; } - code = git_merge_trees(index_only, common, head, merge); + code = git_merge_trees(o->index_only, common, head, merge); if (code != 0) die("merging of trees %s and %s failed", @@ -1195,7 +1192,7 @@ int merge_trees(struct merge_options *o, else clean = 1; - if (index_only) + if (o->index_only) *result = write_tree_from_memory(o); return clean; @@ -1283,14 +1280,14 @@ int merge_recursive(struct merge_options *o, discard_cache(); if (!o->call_depth) { read_cache(); - index_only = 0; + o->index_only = 0; } else - index_only = 1; + o->index_only = 1; clean = merge_trees(o, h1->tree, h2->tree, merged_common_ancestors->tree, &mrtree); - if (index_only) { + if (o->index_only) { *result = make_virtual_commit(mrtree, "merged tree"); commit_list_insert(h1, &(*result)->parents); commit_list_insert(h2, &(*result)->parents->next); diff --git a/merge-recursive.h b/merge-recursive.h index 4f55374..6622c3e 100644 --- a/merge-recursive.h +++ b/merge-recursive.h @@ -10,6 +10,18 @@ struct merge_options { int diff_rename_limit; int merge_rename_limit; int call_depth; + /* + * This variable is used in a number of places but only written + * to in the 'merge_recursive' function. + * + * index_only == 1 => Don't leave any non-stage 0 entries in + * the cache and don't update the working + * directory. + * 0 => Leave unmerged entries in the cache and + * update the working directory. + */ + int index_only; + }; /* merge_trees() but with recursive ancestor consolidation */ -- 1.6.0.1 ^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH] Makefile: add merge_recursive.h to LIB_H 2008-09-02 22:05 ` [PATCH 1/2] merge-recursive: move call_depth " Miklos Vajna 2008-09-02 22:05 ` [PATCH 2/2] merge-recursive: move index_only " Miklos Vajna @ 2008-09-02 22:13 ` Miklos Vajna 2008-09-02 22:39 ` Junio C Hamano 1 sibling, 1 reply; 35+ messages in thread From: Miklos Vajna @ 2008-09-02 22:13 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Stephan Beyer When modifying merge-recursive.h, for example builtin-merge-recursive.c have to be recompiled which was not true till now, causing various runtime errors using an incremental build. Signed-off-by: Miklos Vajna <vmiklos@frugalware.org> --- On Wed, Sep 03, 2008 at 12:05:32AM +0200, Miklos Vajna <vmiklos@frugalware.org> wrote: > Subject: Re: [PATCH 1/2] merge-recursive: move call_depth to struct > merge_options While testing this one, I got some weird errors, finally they gone after a 'touch builtin-merge-recursive.c', I guess this is the right fix. Makefile | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Makefile b/Makefile index f697618..bec6a84 100644 --- a/Makefile +++ b/Makefile @@ -362,6 +362,7 @@ LIB_H += list-objects.h LIB_H += ll-merge.h LIB_H += log-tree.h LIB_H += mailmap.h +LIB_H += merge_recursive.h LIB_H += object.h LIB_H += pack.h LIB_H += pack-refs.h -- 1.6.0.1 ^ permalink raw reply related [flat|nested] 35+ messages in thread
* Re: [PATCH] Makefile: add merge_recursive.h to LIB_H 2008-09-02 22:13 ` [PATCH] Makefile: add merge_recursive.h to LIB_H Miklos Vajna @ 2008-09-02 22:39 ` Junio C Hamano 2008-09-02 23:49 ` Miklos Vajna 0 siblings, 1 reply; 35+ messages in thread From: Junio C Hamano @ 2008-09-02 22:39 UTC (permalink / raw) To: Miklos Vajna; +Cc: git, Stephan Beyer Miklos Vajna <vmiklos@frugalware.org> writes: > When modifying merge-recursive.h, for example builtin-merge-recursive.c > have to be recompiled which was not true till now, causing various > runtime errors using an incremental build. > > Signed-off-by: Miklos Vajna <vmiklos@frugalware.org> > --- > > On Wed, Sep 03, 2008 at 12:05:32AM +0200, Miklos Vajna <vmiklos@frugalware.org> wrote: >> Subject: Re: [PATCH 1/2] merge-recursive: move call_depth to struct >> merge_options > > While testing this one, I got some weird errors, finally they gone after > a 'touch builtin-merge-recursive.c', I guess this is the right fix. Thanks. ^ permalink raw reply [flat|nested] 35+ messages in thread
* [PATCH] Makefile: add merge_recursive.h to LIB_H 2008-09-02 22:39 ` Junio C Hamano @ 2008-09-02 23:49 ` Miklos Vajna 0 siblings, 0 replies; 35+ messages in thread From: Miklos Vajna @ 2008-09-02 23:49 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Stephan Beyer When modifying merge-recursive.h, for example builtin-merge-recursive.c have to be recompiled which was not true till now, causing various runtime errors using an incremental build. Signed-off-by: Miklos Vajna <vmiklos@frugalware.org> --- n Tue, Sep 02, 2008 at 03:39:57PM -0700, Junio C Hamano <gitster@pobox.com> wrote: > > While testing this one, I got some weird errors, finally they gone > > after > > a 'touch builtin-merge-recursive.c', I guess this is the right fix. > > Thanks. Ugh, typo. It is called 'merge-recursive.h'. Sorry. Makefile | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/Makefile b/Makefile index f697618..1647831 100644 --- a/Makefile +++ b/Makefile @@ -362,6 +362,7 @@ LIB_H += list-objects.h LIB_H += ll-merge.h LIB_H += log-tree.h LIB_H += mailmap.h +LIB_H += merge-recursive.h LIB_H += object.h LIB_H += pack.h LIB_H += pack-refs.h -- 1.6.0.1 ^ permalink raw reply related [flat|nested] 35+ messages in thread
* Re: [PATCH 0/2] Move call_depth and index_only to struct merge_options 2008-09-02 22:05 ` [PATCH 0/2] Move call_depth and index_only to struct merge_options Miklos Vajna 2008-09-02 22:05 ` [PATCH 1/2] merge-recursive: move call_depth " Miklos Vajna @ 2008-09-02 22:39 ` Junio C Hamano 2008-09-03 0:16 ` [PATCH] merge-recursive: get rid of the index_only global variable Miklos Vajna 2008-09-03 0:39 ` [PATCH] merge-recursive: move the global obuf to struct merge_options Miklos Vajna 1 sibling, 2 replies; 35+ messages in thread From: Junio C Hamano @ 2008-09-02 22:39 UTC (permalink / raw) To: Miklos Vajna; +Cc: git, Stephan Beyer Miklos Vajna <vmiklos@frugalware.org> writes: > On Tue, Sep 02, 2008 at 01:02:31PM -0700, Junio C Hamano <gitster@pobox.com> wrote: >> I found it a bit disturbing that "index_only" and "call_depth" were >> not >> part of merge_options structure. > > Here are two patches to do it, on top of current mv/merge-recursive. I suspected that it always holds that "index_only === !!call_depth". Shouldn't strbuf obuf be part of the merge_options structure that describes the current call status? ^ permalink raw reply [flat|nested] 35+ messages in thread
* [PATCH] merge-recursive: get rid of the index_only global variable 2008-09-02 22:39 ` [PATCH 0/2] Move call_depth and index_only to struct merge_options Junio C Hamano @ 2008-09-03 0:16 ` Miklos Vajna 2008-09-03 0:39 ` [PATCH] merge-recursive: move the global obuf to struct merge_options Miklos Vajna 1 sibling, 0 replies; 35+ messages in thread From: Miklos Vajna @ 2008-09-03 0:16 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Stephan Beyer struct merge_options as already a call_depth member, where index_only == !!call_depth. We always use index_only as a condition, so we can just use call_depth instead of index_only. Signed-off-by: Miklos Vajna <vmiklos@frugalware.org> --- On Tue, Sep 02, 2008 at 03:39:33PM -0700, Junio C Hamano <gitster@pobox.com> wrote: > I suspected that it always holds that "index_only === !!call_depth". Uhm, yes. Here is an updated version that just removes the global index_only and does not touch the header. The patch is still large, as I still needed to introduce struct merge_options as the first parameter in several functions. merge-recursive.c | 140 +++++++++++++++++++++++++--------------------------- 1 files changed, 67 insertions(+), 73 deletions(-) diff --git a/merge-recursive.c b/merge-recursive.c index 5bb20aa..c426589 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -165,17 +165,6 @@ static int add_cacheinfo(unsigned int mode, const unsigned char *sha1, return add_cache_entry(ce, options); } -/* - * This is a global variable which is used in a number of places but - * only written to in the 'merge' function. - * - * index_only == 1 => Don't leave any non-stage 0 entries in the cache and - * don't update the working directory. - * 0 => Leave unmerged entries in the cache and update - * the working directory. - */ -static int index_only = 0; - static void init_tree_desc_from_tree(struct tree_desc *desc, struct tree *tree) { parse_tree(tree); @@ -428,10 +417,11 @@ static int remove_path(const char *name) return ret; } -static int remove_file(int clean, const char *path, int no_wd) +static int remove_file(struct merge_options *o, int clean, + const char *path, int no_wd) { - int update_cache = index_only || clean; - int update_working_directory = !index_only && !no_wd; + int update_cache = o->call_depth || clean; + int update_working_directory = !o->call_depth && !no_wd; if (update_cache) { if (remove_file_from_cache(path)) @@ -509,13 +499,14 @@ static int make_room_for_path(const char *path) return error(msg, path, ": perhaps a D/F conflict?"); } -static void update_file_flags(const unsigned char *sha, +static void update_file_flags(struct merge_options *o, + const unsigned char *sha, unsigned mode, const char *path, int update_cache, int update_wd) { - if (index_only) + if (o->call_depth) update_wd = 0; if (update_wd) { @@ -574,12 +565,13 @@ static void update_file_flags(const unsigned char *sha, add_cacheinfo(mode, sha, path, 0, update_wd, ADD_CACHE_OK_TO_ADD); } -static void update_file(int clean, +static void update_file(struct merge_options *o, + int clean, const unsigned char *sha, unsigned mode, const char *path) { - update_file_flags(sha, mode, path, index_only || clean, !index_only); + update_file_flags(o, sha, mode, path, o->call_depth || clean, !o->call_depth); } /* Low level file merging, update and removal */ @@ -609,8 +601,9 @@ static void fill_mm(const unsigned char *sha1, mmfile_t *mm) mm->size = size; } -static int merge_3way(mmbuffer_t *result_buf, - struct diff_filespec *o, +static int merge_3way(struct merge_options *o, + mmbuffer_t *result_buf, + struct diff_filespec *one, struct diff_filespec *a, struct diff_filespec *b, const char *branch1, @@ -623,13 +616,13 @@ static int merge_3way(mmbuffer_t *result_buf, name1 = xstrdup(mkpath("%s:%s", branch1, a->path)); name2 = xstrdup(mkpath("%s:%s", branch2, b->path)); - fill_mm(o->sha1, &orig); + fill_mm(one->sha1, &orig); fill_mm(a->sha1, &src1); fill_mm(b->sha1, &src2); merge_status = ll_merge(result_buf, a->path, &orig, &src1, name1, &src2, name2, - index_only); + o->call_depth); free(name1); free(name2); @@ -639,9 +632,12 @@ static int merge_3way(mmbuffer_t *result_buf, return merge_status; } -static struct merge_file_info merge_file(struct diff_filespec *o, - struct diff_filespec *a, struct diff_filespec *b, - const char *branch1, const char *branch2) +static struct merge_file_info merge_file(struct merge_options *o, + struct diff_filespec *one, + struct diff_filespec *a, + struct diff_filespec *b, + const char *branch1, + const char *branch2) { struct merge_file_info result; result.merge = 0; @@ -657,31 +653,31 @@ static struct merge_file_info merge_file(struct diff_filespec *o, hashcpy(result.sha, b->sha1); } } else { - if (!sha_eq(a->sha1, o->sha1) && !sha_eq(b->sha1, o->sha1)) + if (!sha_eq(a->sha1, one->sha1) && !sha_eq(b->sha1, one->sha1)) result.merge = 1; /* * Merge modes */ - if (a->mode == b->mode || a->mode == o->mode) + if (a->mode == b->mode || a->mode == one->mode) result.mode = b->mode; else { result.mode = a->mode; - if (b->mode != o->mode) { + if (b->mode != one->mode) { result.clean = 0; result.merge = 1; } } - if (sha_eq(a->sha1, b->sha1) || sha_eq(a->sha1, o->sha1)) + if (sha_eq(a->sha1, b->sha1) || sha_eq(a->sha1, one->sha1)) hashcpy(result.sha, b->sha1); - else if (sha_eq(b->sha1, o->sha1)) + else if (sha_eq(b->sha1, one->sha1)) hashcpy(result.sha, a->sha1); else if (S_ISREG(a->mode)) { mmbuffer_t result_buf; int merge_status; - merge_status = merge_3way(&result_buf, o, a, b, + merge_status = merge_3way(o, &result_buf, one, a, b, branch1, branch2); if ((merge_status < 0) || !result_buf.ptr) @@ -726,22 +722,22 @@ static void conflict_rename_rename(struct merge_options *o, dst_name1 = del[delp++] = unique_path(ren1_dst, branch1); output(o, 1, "%s is a directory in %s adding as %s instead", ren1_dst, branch2, dst_name1); - remove_file(0, ren1_dst, 0); + remove_file(o, 0, ren1_dst, 0); } if (string_list_has_string(¤t_directory_set, ren2_dst)) { dst_name2 = del[delp++] = unique_path(ren2_dst, branch2); output(o, 1, "%s is a directory in %s adding as %s instead", ren2_dst, branch1, dst_name2); - remove_file(0, ren2_dst, 0); + remove_file(o, 0, ren2_dst, 0); } - if (index_only) { + if (o->call_depth) { remove_file_from_cache(dst_name1); remove_file_from_cache(dst_name2); /* * Uncomment to leave the conflicting names in the resulting tree * - * update_file(0, ren1->pair->two->sha1, ren1->pair->two->mode, dst_name1); - * update_file(0, ren2->pair->two->sha1, ren2->pair->two->mode, dst_name2); + * update_file(o, 0, ren1->pair->two->sha1, ren1->pair->two->mode, dst_name1); + * update_file(o, 0, ren2->pair->two->sha1, ren2->pair->two->mode, dst_name2); */ } else { update_stages(dst_name1, NULL, ren1->pair->two, NULL, 1); @@ -757,8 +753,8 @@ static void conflict_rename_dir(struct merge_options *o, { char *new_path = unique_path(ren1->pair->two->path, branch1); output(o, 1, "Renaming %s to %s instead", ren1->pair->one->path, new_path); - remove_file(0, ren1->pair->two->path, 0); - update_file(0, ren1->pair->two->sha1, ren1->pair->two->mode, new_path); + remove_file(o, 0, ren1->pair->two->path, 0); + update_file(o, 0, ren1->pair->two->sha1, ren1->pair->two->mode, new_path); free(new_path); } @@ -773,9 +769,9 @@ static void conflict_rename_rename_2(struct merge_options *o, output(o, 1, "Renaming %s to %s and %s to %s instead", ren1->pair->one->path, new_path1, ren2->pair->one->path, new_path2); - remove_file(0, ren1->pair->two->path, 0); - update_file(0, ren1->pair->two->sha1, ren1->pair->two->mode, new_path1); - update_file(0, ren2->pair->two->sha1, ren2->pair->two->mode, new_path2); + remove_file(o, 0, ren1->pair->two->path, 0); + update_file(o, 0, ren1->pair->two->sha1, ren1->pair->two->mode, new_path1); + update_file(o, 0, ren2->pair->two->sha1, ren2->pair->two->mode, new_path2); free(new_path2); free(new_path1); } @@ -867,17 +863,18 @@ static int process_renames(struct merge_options *o, "rename \"%s\"->\"%s\" in \"%s\"%s", src, ren1_dst, branch1, src, ren2_dst, branch2, - index_only ? " (left unresolved)": ""); - if (index_only) { + o->call_depth ? " (left unresolved)": ""); + if (o->call_depth) { remove_file_from_cache(src); - update_file(0, ren1->pair->one->sha1, + update_file(o, 0, ren1->pair->one->sha1, ren1->pair->one->mode, src); } conflict_rename_rename(o, ren1, branch1, ren2, branch2); } else { struct merge_file_info mfi; - remove_file(1, ren1_src, 1); - mfi = merge_file(ren1->pair->one, + remove_file(o, 1, ren1_src, 1); + mfi = merge_file(o, + ren1->pair->one, ren1->pair->two, ren2->pair->two, branch1, @@ -893,14 +890,14 @@ static int process_renames(struct merge_options *o, ren1_dst); clean_merge = 0; - if (!index_only) + if (!o->call_depth) update_stages(ren1_dst, ren1->pair->one, ren1->pair->two, ren2->pair->two, 1 /* clear */); } - update_file(mfi.clean, mfi.sha, mfi.mode, ren1_dst); + update_file(o, mfi.clean, mfi.sha, mfi.mode, ren1_dst); } } else { /* Renamed in 1, maybe changed in 2 */ @@ -909,7 +906,7 @@ static int process_renames(struct merge_options *o, struct diff_filespec src_other, dst_other; int try_merge, stage = a_renames == renames1 ? 3: 2; - remove_file(1, ren1_src, index_only || stage == 3); + remove_file(o, 1, ren1_src, o->call_depth || stage == 3); hashcpy(src_other.sha1, ren1->src_entry->stages[stage].sha); src_other.mode = ren1->src_entry->stages[stage].mode; @@ -931,7 +928,7 @@ static int process_renames(struct merge_options *o, "and deleted in %s", ren1_src, ren1_dst, branch1, branch2); - update_file(0, ren1->pair->two->sha1, ren1->pair->two->mode, ren1_dst); + update_file(o, 0, ren1->pair->two->sha1, ren1->pair->two->mode, ren1_dst); } else if (!sha_eq(dst_other.sha1, null_sha1)) { const char *new_path; clean_merge = 0; @@ -942,7 +939,7 @@ static int process_renames(struct merge_options *o, ren1_dst, branch2); new_path = unique_path(ren1_dst, branch2); output(o, 1, "Adding as %s instead", new_path); - update_file(0, dst_other.sha1, dst_other.mode, new_path); + update_file(o, 0, dst_other.sha1, dst_other.mode, new_path); } else if ((item = string_list_lookup(ren1_dst, renames2Dst))) { ren2 = item->util; clean_merge = 0; @@ -969,7 +966,7 @@ static int process_renames(struct merge_options *o, b = ren1->pair->two; a = &src_other; } - mfi = merge_file(one, a, b, + mfi = merge_file(o, one, a, b, o->branch1, o->branch2); if (mfi.clean && @@ -991,11 +988,11 @@ static int process_renames(struct merge_options *o, ren1_dst); clean_merge = 0; - if (!index_only) + if (!o->call_depth) update_stages(ren1_dst, one, a, b, 1); } - update_file(mfi.clean, mfi.sha, mfi.mode, ren1_dst); + update_file(o, mfi.clean, mfi.sha, mfi.mode, ren1_dst); } } } @@ -1037,7 +1034,7 @@ static int process_entry(struct merge_options *o, if (a_sha) output(o, 2, "Removing %s", path); /* do not touch working file if it did not exist */ - remove_file(1, path, !a_sha); + remove_file(o, 1, path, !a_sha); } else { /* Deleted in one and changed in the other */ clean_merge = 0; @@ -1046,13 +1043,13 @@ static int process_entry(struct merge_options *o, "and modified in %s. Version %s of %s left in tree.", path, o->branch1, o->branch2, o->branch2, path); - update_file(0, b_sha, b_mode, path); + update_file(o, 0, b_sha, b_mode, path); } else { output(o, 1, "CONFLICT (delete/modify): %s deleted in %s " "and modified in %s. Version %s of %s left in tree.", path, o->branch2, o->branch1, o->branch1, path); - update_file(0, a_sha, a_mode, path); + update_file(o, 0, a_sha, a_mode, path); } } @@ -1084,11 +1081,11 @@ static int process_entry(struct merge_options *o, output(o, 1, "CONFLICT (%s): There is a directory with name %s in %s. " "Adding %s as %s", conf, path, other_branch, path, new_path); - remove_file(0, path, 0); - update_file(0, sha, mode, new_path); + remove_file(o, 0, path, 0); + update_file(o, 0, sha, mode, new_path); } else { output(o, 2, "Adding %s", path); - update_file(1, sha, mode, path); + update_file(o, 1, sha, mode, path); } } else if (a_sha && b_sha) { /* Case C: Added in both (check for same permissions) and */ @@ -1110,12 +1107,12 @@ static int process_entry(struct merge_options *o, hashcpy(b.sha1, b_sha); b.mode = b_mode; - mfi = merge_file(&one, &a, &b, + mfi = merge_file(o, &one, &a, &b, o->branch1, o->branch2); clean_merge = mfi.clean; if (mfi.clean) - update_file(1, mfi.sha, mfi.mode, path); + update_file(o, 1, mfi.sha, mfi.mode, path); else if (S_ISGITLINK(mfi.mode)) output(o, 1, "CONFLICT (submodule): Merge conflict in %s " "- needs %s", path, sha1_to_hex(b.sha1)); @@ -1123,10 +1120,10 @@ static int process_entry(struct merge_options *o, output(o, 1, "CONFLICT (%s): Merge conflict in %s", reason, path); - if (index_only) - update_file(0, mfi.sha, mfi.mode, path); + if (o->call_depth) + update_file(o, 0, mfi.sha, mfi.mode, path); else - update_file_flags(mfi.sha, mfi.mode, path, + update_file_flags(o, mfi.sha, mfi.mode, path, 0 /* update_cache */, 1 /* update_working_directory */); } } else if (!o_sha && !a_sha && !b_sha) { @@ -1134,7 +1131,7 @@ static int process_entry(struct merge_options *o, * this entry was deleted altogether. a_mode == 0 means * we had that path and want to actively remove it. */ - remove_file(1, path, !a_mode); + remove_file(o, 1, path, !a_mode); } else die("Fatal merge failure, shouldn't happen."); @@ -1160,7 +1157,7 @@ int merge_trees(struct merge_options *o, return 1; } - code = git_merge_trees(index_only, common, head, merge); + code = git_merge_trees(o->call_depth, common, head, merge); if (code != 0) die("merging of trees %s and %s failed", @@ -1195,7 +1192,7 @@ int merge_trees(struct merge_options *o, else clean = 1; - if (index_only) + if (o->call_depth) *result = write_tree_from_memory(o); return clean; @@ -1281,16 +1278,13 @@ int merge_recursive(struct merge_options *o, } discard_cache(); - if (!o->call_depth) { + if (!o->call_depth) read_cache(); - index_only = 0; - } else - index_only = 1; clean = merge_trees(o, h1->tree, h2->tree, merged_common_ancestors->tree, &mrtree); - if (index_only) { + if (o->call_depth) { *result = make_virtual_commit(mrtree, "merged tree"); commit_list_insert(h1, &(*result)->parents); commit_list_insert(h2, &(*result)->parents->next); -- 1.6.0.1 ^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH] merge-recursive: move the global obuf to struct merge_options 2008-09-02 22:39 ` [PATCH 0/2] Move call_depth and index_only to struct merge_options Junio C Hamano 2008-09-03 0:16 ` [PATCH] merge-recursive: get rid of the index_only global variable Miklos Vajna @ 2008-09-03 0:39 ` Miklos Vajna 2008-09-03 17:34 ` Miklos Vajna 1 sibling, 1 reply; 35+ messages in thread From: Miklos Vajna @ 2008-09-03 0:39 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Stephan Beyer Signed-off-by: Miklos Vajna <vmiklos@frugalware.org> --- On Tue, Sep 02, 2008 at 03:39:33PM -0700, Junio C Hamano <gitster@pobox.com> wrote: > Shouldn't strbuf obuf be part of the merge_options structure that > describes the current call status? It can be done, see below. :-) BTW, there are 3 leftovers: make_virtual_commit()'s virtual_id and the global current_file_set/current_directory_set. I guess all of them could be moved to merge_options as well. (I don't have more time today to do so, but I can do it tomorrow, unless you see some fundamental problem with it.) merge-recursive.c | 37 ++++++++++++++++++------------------- merge-recursive.h | 1 + 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/merge-recursive.c b/merge-recursive.c index c426589..d4f12d0 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -80,18 +80,16 @@ struct stage_data static struct string_list current_file_set = {NULL, 0, 0, 1}; static struct string_list current_directory_set = {NULL, 0, 0, 1}; -static struct strbuf obuf = STRBUF_INIT; - static int show(struct merge_options *o, int v) { return (!o->call_depth && o->verbosity >= v) || o->verbosity >= 5; } -static void flush_output(void) +static void flush_output(struct merge_options *o) { - if (obuf.len) { - fputs(obuf.buf, stdout); - strbuf_reset(&obuf); + if (o->obuf.len) { + fputs(o->obuf.buf, stdout); + strbuf_reset(&o->obuf); } } @@ -103,35 +101,35 @@ static void output(struct merge_options *o, int v, const char *fmt, ...) if (!show(o, v)) return; - strbuf_grow(&obuf, o->call_depth * 2 + 2); - memset(obuf.buf + obuf.len, ' ', o->call_depth * 2); - strbuf_setlen(&obuf, obuf.len + o->call_depth * 2); + strbuf_grow(&o->obuf, o->call_depth * 2 + 2); + memset(o->obuf.buf + o->obuf.len, ' ', o->call_depth * 2); + strbuf_setlen(&o->obuf, o->obuf.len + o->call_depth * 2); va_start(ap, fmt); - len = vsnprintf(obuf.buf + obuf.len, strbuf_avail(&obuf), fmt, ap); + len = vsnprintf(o->obuf.buf + o->obuf.len, strbuf_avail(&o->obuf), fmt, ap); va_end(ap); if (len < 0) len = 0; - if (len >= strbuf_avail(&obuf)) { - strbuf_grow(&obuf, len + 2); + if (len >= strbuf_avail(&o->obuf)) { + strbuf_grow(&o->obuf, len + 2); va_start(ap, fmt); - len = vsnprintf(obuf.buf + obuf.len, strbuf_avail(&obuf), fmt, ap); + len = vsnprintf(o->obuf.buf + o->obuf.len, strbuf_avail(&o->obuf), fmt, ap); va_end(ap); - if (len >= strbuf_avail(&obuf)) { + if (len >= strbuf_avail(&o->obuf)) { die("this should not happen, your snprintf is broken"); } } - strbuf_setlen(&obuf, obuf.len + len); - strbuf_add(&obuf, "\n", 1); + strbuf_setlen(&o->obuf, o->obuf.len + len); + strbuf_add(&o->obuf, "\n", 1); if (!o->buffer_output) - flush_output(); + flush_output(o); } static void output_commit_title(struct merge_options *o, struct commit *commit) { int i; - flush_output(); + flush_output(o); for (i = o->call_depth; i--;) fputs(" ", stdout); if (commit->util) @@ -1289,7 +1287,7 @@ int merge_recursive(struct merge_options *o, commit_list_insert(h1, &(*result)->parents); commit_list_insert(h2, &(*result)->parents->next); } - flush_output(); + flush_output(o); return clean; } @@ -1375,4 +1373,5 @@ void init_merge_options(struct merge_options *o) strtol(getenv("GIT_MERGE_VERBOSITY"), NULL, 10); if (o->verbosity >= 5) o->buffer_output = 0; + strbuf_init(&o->obuf, 0); } diff --git a/merge-recursive.h b/merge-recursive.h index 4f55374..be84d9b 100644 --- a/merge-recursive.h +++ b/merge-recursive.h @@ -10,6 +10,7 @@ struct merge_options { int diff_rename_limit; int merge_rename_limit; int call_depth; + struct strbuf obuf; }; /* merge_trees() but with recursive ancestor consolidation */ -- 1.6.0.1 ^ permalink raw reply related [flat|nested] 35+ messages in thread
* Re: [PATCH] merge-recursive: move the global obuf to struct merge_options 2008-09-03 0:39 ` [PATCH] merge-recursive: move the global obuf to struct merge_options Miklos Vajna @ 2008-09-03 17:34 ` Miklos Vajna 2008-09-03 17:34 ` [PATCH 1/2] merge-recursive: move current_{file,directory}_set " Miklos Vajna 2008-09-04 19:05 ` [PATCH] merge-recursive: move the global obuf to struct merge_options Junio C Hamano 0 siblings, 2 replies; 35+ messages in thread From: Miklos Vajna @ 2008-09-03 17:34 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Stephan Beyer On Wed, Sep 03, 2008 at 02:39:09AM +0200, Miklos Vajna <vmiklos@frugalware.org> wrote: > BTW, there are 3 leftovers: make_virtual_commit()'s virtual_id and the > global current_file_set/current_directory_set. I guess all of them > could be moved to merge_options as well. (I don't have more time today > to do so, but I can do it tomorrow, unless you see some fundamental > problem with it.) Here are the two patches, that do this. These, and the 4 other related patches which are not yet in git.git at the moment are also available in the 'merge-recursive' branch of git://repo.or.cz/git/vmiklos.git. Miklos Vajna (2): merge-recursive: move current_{file,directory}_set to struct merge_options merge-recursive: move make_virtual_commit()'s virtual_id to merge_options merge-recursive.c | 80 ++++++++++++++++++++++++++++------------------------ merge-recursive.h | 5 +++ 2 files changed, 48 insertions(+), 37 deletions(-) ^ permalink raw reply [flat|nested] 35+ messages in thread
* [PATCH 1/2] merge-recursive: move current_{file,directory}_set to struct merge_options 2008-09-03 17:34 ` Miklos Vajna @ 2008-09-03 17:34 ` Miklos Vajna 2008-09-03 17:34 ` [PATCH 2/2] merge-recursive: move make_virtual_commit()'s virtual_id to merge_options Miklos Vajna 2008-09-04 19:05 ` [PATCH] merge-recursive: move the global obuf to struct merge_options Junio C Hamano 1 sibling, 1 reply; 35+ messages in thread From: Miklos Vajna @ 2008-09-03 17:34 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Stephan Beyer Signed-off-by: Miklos Vajna <vmiklos@frugalware.org> --- merge-recursive.c | 56 +++++++++++++++++++++++++++------------------------- merge-recursive.h | 4 +++ 2 files changed, 33 insertions(+), 27 deletions(-) diff --git a/merge-recursive.c b/merge-recursive.c index d4f12d0..964b8f3 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -77,9 +77,6 @@ struct stage_data unsigned processed:1; }; -static struct string_list current_file_set = {NULL, 0, 0, 1}; -static struct string_list current_directory_set = {NULL, 0, 0, 1}; - static int show(struct merge_options *o, int v) { return (!o->call_depth && o->verbosity >= v) || o->verbosity >= 5; @@ -235,22 +232,23 @@ static int save_files_dirs(const unsigned char *sha1, memcpy(newpath, base, baselen); memcpy(newpath + baselen, path, len); newpath[baselen + len] = '\0'; + struct merge_options *o = context; if (S_ISDIR(mode)) - string_list_insert(newpath, ¤t_directory_set); + string_list_insert(newpath, &o->current_directory_set); else - string_list_insert(newpath, ¤t_file_set); + string_list_insert(newpath, &o->current_file_set); free(newpath); return READ_TREE_RECURSIVE; } -static int get_files_dirs(struct tree *tree) +static int get_files_dirs(struct merge_options *o, struct tree *tree) { int n; - if (read_tree_recursive(tree, "", 0, 0, NULL, save_files_dirs, NULL)) + if (read_tree_recursive(tree, "", 0, 0, NULL, save_files_dirs, o)) return 0; - n = current_file_set.nr + current_directory_set.nr; + n = o->current_file_set.nr + o->current_directory_set.nr; return n; } @@ -434,7 +432,7 @@ static int remove_file(struct merge_options *o, int clean, return 0; } -static char *unique_path(const char *path, const char *branch) +static char *unique_path(struct merge_options *o, const char *path, const char *branch) { char *newpath = xmalloc(strlen(path) + 1 + strlen(branch) + 8 + 1); int suffix = 0; @@ -446,12 +444,12 @@ static char *unique_path(const char *path, const char *branch) for (; *p; ++p) if ('/' == *p) *p = '_'; - while (string_list_has_string(¤t_file_set, newpath) || - string_list_has_string(¤t_directory_set, newpath) || + while (string_list_has_string(&o->current_file_set, newpath) || + string_list_has_string(&o->current_directory_set, newpath) || lstat(newpath, &st) == 0) sprintf(p, "_%d", suffix++); - string_list_insert(newpath, ¤t_file_set); + string_list_insert(newpath, &o->current_file_set); return newpath; } @@ -716,14 +714,14 @@ static void conflict_rename_rename(struct merge_options *o, const char *ren2_dst = ren2->pair->two->path; const char *dst_name1 = ren1_dst; const char *dst_name2 = ren2_dst; - if (string_list_has_string(¤t_directory_set, ren1_dst)) { - dst_name1 = del[delp++] = unique_path(ren1_dst, branch1); + if (string_list_has_string(&o->current_directory_set, ren1_dst)) { + dst_name1 = del[delp++] = unique_path(o, ren1_dst, branch1); output(o, 1, "%s is a directory in %s adding as %s instead", ren1_dst, branch2, dst_name1); remove_file(o, 0, ren1_dst, 0); } - if (string_list_has_string(¤t_directory_set, ren2_dst)) { - dst_name2 = del[delp++] = unique_path(ren2_dst, branch2); + if (string_list_has_string(&o->current_directory_set, ren2_dst)) { + dst_name2 = del[delp++] = unique_path(o, ren2_dst, branch2); output(o, 1, "%s is a directory in %s adding as %s instead", ren2_dst, branch1, dst_name2); remove_file(o, 0, ren2_dst, 0); @@ -749,7 +747,7 @@ static void conflict_rename_dir(struct merge_options *o, struct rename *ren1, const char *branch1) { - char *new_path = unique_path(ren1->pair->two->path, branch1); + char *new_path = unique_path(o, ren1->pair->two->path, branch1); output(o, 1, "Renaming %s to %s instead", ren1->pair->one->path, new_path); remove_file(o, 0, ren1->pair->two->path, 0); update_file(o, 0, ren1->pair->two->sha1, ren1->pair->two->mode, new_path); @@ -762,8 +760,8 @@ static void conflict_rename_rename_2(struct merge_options *o, struct rename *ren2, const char *branch2) { - char *new_path1 = unique_path(ren1->pair->two->path, branch1); - char *new_path2 = unique_path(ren2->pair->two->path, branch2); + char *new_path1 = unique_path(o, ren1->pair->two->path, branch1); + char *new_path2 = unique_path(o, ren2->pair->two->path, branch2); output(o, 1, "Renaming %s to %s and %s to %s instead", ren1->pair->one->path, new_path1, ren2->pair->one->path, new_path2); @@ -913,7 +911,7 @@ static int process_renames(struct merge_options *o, try_merge = 0; - if (string_list_has_string(¤t_directory_set, ren1_dst)) { + if (string_list_has_string(&o->current_directory_set, ren1_dst)) { clean_merge = 0; output(o, 1, "CONFLICT (rename/directory): Rename %s->%s in %s " " directory %s added in %s", @@ -935,7 +933,7 @@ static int process_renames(struct merge_options *o, "%s added in %s", ren1_src, ren1_dst, branch1, ren1_dst, branch2); - new_path = unique_path(ren1_dst, branch2); + new_path = unique_path(o, ren1_dst, branch2); output(o, 1, "Adding as %s instead", new_path); update_file(o, 0, dst_other.sha1, dst_other.mode, new_path); } else if ((item = string_list_lookup(ren1_dst, renames2Dst))) { @@ -1073,8 +1071,8 @@ static int process_entry(struct merge_options *o, sha = b_sha; conf = "directory/file"; } - if (string_list_has_string(¤t_directory_set, path)) { - const char *new_path = unique_path(path, add_branch); + if (string_list_has_string(&o->current_directory_set, path)) { + const char *new_path = unique_path(o, path, add_branch); clean_merge = 0; output(o, 1, "CONFLICT (%s): There is a directory with name %s in %s. " "Adding %s as %s", @@ -1165,10 +1163,10 @@ int merge_trees(struct merge_options *o, if (unmerged_cache()) { struct string_list *entries, *re_head, *re_merge; int i; - string_list_clear(¤t_file_set, 1); - string_list_clear(¤t_directory_set, 1); - get_files_dirs(head); - get_files_dirs(merge); + string_list_clear(&o->current_file_set, 1); + string_list_clear(&o->current_directory_set, 1); + get_files_dirs(o, head); + get_files_dirs(o, merge); entries = get_unmerged(); re_head = get_renames(o, head, common, head, merge, entries); @@ -1374,4 +1372,8 @@ void init_merge_options(struct merge_options *o) if (o->verbosity >= 5) o->buffer_output = 0; strbuf_init(&o->obuf, 0); + memset(&o->current_file_set, 0, sizeof(struct string_list)); + o->current_file_set.strdup_strings = 1; + memset(&o->current_directory_set, 0, sizeof(struct string_list)); + o->current_directory_set.strdup_strings = 1; } diff --git a/merge-recursive.h b/merge-recursive.h index be84d9b..fd138ca 100644 --- a/merge-recursive.h +++ b/merge-recursive.h @@ -1,6 +1,8 @@ #ifndef MERGE_RECURSIVE_H #define MERGE_RECURSIVE_H +#include "string-list.h" + struct merge_options { const char *branch1; const char *branch2; @@ -11,6 +13,8 @@ struct merge_options { int merge_rename_limit; int call_depth; struct strbuf obuf; + struct string_list current_file_set; + struct string_list current_directory_set; }; /* merge_trees() but with recursive ancestor consolidation */ -- 1.6.0.1 ^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 2/2] merge-recursive: move make_virtual_commit()'s virtual_id to merge_options 2008-09-03 17:34 ` [PATCH 1/2] merge-recursive: move current_{file,directory}_set " Miklos Vajna @ 2008-09-03 17:34 ` Miklos Vajna 2008-09-04 19:03 ` Junio C Hamano 0 siblings, 1 reply; 35+ messages in thread From: Miklos Vajna @ 2008-09-03 17:34 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Stephan Beyer This is the last patch in this series, now all static variables in merge-recursive.c are moved to struct merge_options. Signed-off-by: Miklos Vajna <vmiklos@frugalware.org> --- merge-recursive.c | 24 ++++++++++++++---------- merge-recursive.h | 1 + 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/merge-recursive.c b/merge-recursive.c index 964b8f3..4fa3308 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -40,13 +40,14 @@ static struct tree *shift_tree_object(struct tree *one, struct tree *two) * - *(int *)commit->object.sha1 set to the virtual id. */ -struct commit *make_virtual_commit(struct tree *tree, const char *comment) +struct commit *make_virtual_commit(struct merge_options *o, + struct tree *tree, + const char *comment) { struct commit *commit = xcalloc(1, sizeof(struct commit)); - static unsigned virtual_id = 1; commit->tree = tree; commit->util = (void*)comment; - *(int*)commit->object.sha1 = virtual_id++; + *(int*)commit->object.sha1 = o->virtual_id++; /* avoid warnings */ commit->object.parsed = 1; return commit; @@ -1245,7 +1246,7 @@ int merge_recursive(struct merge_options *o, tree->object.parsed = 1; tree->object.type = OBJ_TREE; pretend_sha1_file(NULL, 0, OBJ_TREE, tree->object.sha1); - merged_common_ancestors = make_virtual_commit(tree, "ancestor"); + merged_common_ancestors = make_virtual_commit(o, tree, "ancestor"); } for (iter = ca; iter; iter = iter->next) { @@ -1281,7 +1282,7 @@ int merge_recursive(struct merge_options *o, &mrtree); if (o->call_depth) { - *result = make_virtual_commit(mrtree, "merged tree"); + *result = make_virtual_commit(o, mrtree, "merged tree"); commit_list_insert(h1, &(*result)->parents); commit_list_insert(h2, &(*result)->parents->next); } @@ -1289,7 +1290,9 @@ int merge_recursive(struct merge_options *o, return clean; } -static struct commit *get_ref(const unsigned char *sha1, const char *name) +static struct commit *get_ref(struct merge_options *o, + const unsigned char *sha1, + const char *name) { struct object *object; @@ -1297,7 +1300,7 @@ static struct commit *get_ref(const unsigned char *sha1, const char *name) if (!object) return NULL; if (object->type == OBJ_TREE) - return make_virtual_commit((struct tree*)object, name); + return make_virtual_commit(o, (struct tree*)object, name); if (object->type != OBJ_COMMIT) return NULL; if (parse_commit((struct commit *)object)) @@ -1314,15 +1317,15 @@ int merge_recursive_generic(struct merge_options *o, { int clean, index_fd; struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); - struct commit *head_commit = get_ref(head, o->branch1); - struct commit *next_commit = get_ref(merge, o->branch2); + struct commit *head_commit = get_ref(o, head, o->branch1); + struct commit *next_commit = get_ref(o, merge, o->branch2); struct commit_list *ca = NULL; if (base_list) { int i; for (i = 0; i < num_base_list; ++i) { struct commit *base; - if (!(base = get_ref(base_list[i], sha1_to_hex(base_list[i])))) + if (!(base = get_ref(o, base_list[i], sha1_to_hex(base_list[i])))) return error("Could not parse object '%s'", sha1_to_hex(base_list[i])); commit_list_insert(base, &ca); @@ -1376,4 +1379,5 @@ void init_merge_options(struct merge_options *o) o->current_file_set.strdup_strings = 1; memset(&o->current_directory_set, 0, sizeof(struct string_list)); o->current_directory_set.strdup_strings = 1; + o->virtual_id = 1; } diff --git a/merge-recursive.h b/merge-recursive.h index fd138ca..bc23fe0 100644 --- a/merge-recursive.h +++ b/merge-recursive.h @@ -15,6 +15,7 @@ struct merge_options { struct strbuf obuf; struct string_list current_file_set; struct string_list current_directory_set; + unsigned virtual_id; }; /* merge_trees() but with recursive ancestor consolidation */ -- 1.6.0.1 ^ permalink raw reply related [flat|nested] 35+ messages in thread
* Re: [PATCH 2/2] merge-recursive: move make_virtual_commit()'s virtual_id to merge_options 2008-09-03 17:34 ` [PATCH 2/2] merge-recursive: move make_virtual_commit()'s virtual_id to merge_options Miklos Vajna @ 2008-09-04 19:03 ` Junio C Hamano 2008-09-05 17:26 ` [PATCH] merge-recursive: get rid of virtual_id Miklos Vajna 0 siblings, 1 reply; 35+ messages in thread From: Junio C Hamano @ 2008-09-04 19:03 UTC (permalink / raw) To: Miklos Vajna; +Cc: git, Stephan Beyer, Alex Riesen, Johannes Schindelin I do not think this one is a good idea. What does it mean for a two "virtual commits" that are returned from separate calls to make_virtual_commit() to have the same virtual_id? I do not know offhand if the existing code does something like: commit = lookup_commit(commit->object.sha1) or if (hashcmp(commit1->object.sha1, commit2->object.sha1)) ... but if there is such a code, I think this change makes the problem "virtual id" has even worse. With the current single function local static "virtual_id", at least during a program's lifetime it is guaranteed that there won't be any two instances of virtual commits created for different purposes that share the same (fake) sha1 value. If you call merge_recursive more than once in your process, using a fresh "struct merge_options" each time, that guarantee is lost with your change. The only purpose of a "virtual commit", as I understand it, is to allow you to pass a tree resulting from an internal merge to a function that expects you to call with three commit objects to come up with a new tree that is the result of the merge. The code stores a "virtual_id" as a phoney sha1 value in the object, but I do not think the actual value is used for anything but debugging purposes (Alex, Dscho, please correct me as necessary). Does it hurt if we get rid of virtual_id and always leave the object->sha1 field of virtual commits 0{40} as it is initialized? I further suspect we _could_ fix the API that requires you to pass three commits to accept three trees instead and get rid of virtual commits altogether, but then we would lose an easy access to the message of commits that are being merged, and we would need to pass these strings as separate parameters (or part of merge_options) --- which might be a good clean-up in a longer run, but I do not think it is absolutely necessary during this round. ^ permalink raw reply [flat|nested] 35+ messages in thread
* [PATCH] merge-recursive: get rid of virtual_id 2008-09-04 19:03 ` Junio C Hamano @ 2008-09-05 17:26 ` Miklos Vajna 0 siblings, 0 replies; 35+ messages in thread From: Miklos Vajna @ 2008-09-05 17:26 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Stephan Beyer, Alex Riesen, Johannes Schindelin We now just leave the object->sha1 field of virtual commits 0{40} as it is initialized, as a unique hash is not necessary in case of virtual commits. Signed-off-by: Miklos Vajna <vmiklos@frugalware.org> --- On Thu, Sep 04, 2008 at 12:03:08PM -0700, Junio C Hamano <gitster@pobox.com> wrote: > Does it hurt if we get rid of virtual_id and always leave the > object->sha1 field of virtual commits 0{40} as it is initialized? I don't think so. Here is a patch that does it. merge-recursive.c | 6 +----- 1 files changed, 1 insertions(+), 5 deletions(-) diff --git a/merge-recursive.c b/merge-recursive.c index 1c24c31..dbdb9ac 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -35,18 +35,14 @@ static struct tree *shift_tree_object(struct tree *one, struct tree *two) } /* - * A virtual commit has - * - (const char *)commit->util set to the name, and - * - *(int *)commit->object.sha1 set to the virtual id. + * A virtual commit has (const char *)commit->util set to the name. */ struct commit *make_virtual_commit(struct tree *tree, const char *comment) { struct commit *commit = xcalloc(1, sizeof(struct commit)); - static unsigned virtual_id = 1; commit->tree = tree; commit->util = (void*)comment; - *(int*)commit->object.sha1 = virtual_id++; /* avoid warnings */ commit->object.parsed = 1; return commit; -- 1.6.0.1 ^ permalink raw reply related [flat|nested] 35+ messages in thread
* Re: [PATCH] merge-recursive: move the global obuf to struct merge_options 2008-09-03 17:34 ` Miklos Vajna 2008-09-03 17:34 ` [PATCH 1/2] merge-recursive: move current_{file,directory}_set " Miklos Vajna @ 2008-09-04 19:05 ` Junio C Hamano 1 sibling, 0 replies; 35+ messages in thread From: Junio C Hamano @ 2008-09-04 19:05 UTC (permalink / raw) To: Miklos Vajna; +Cc: git, Stephan Beyer Miklos Vajna <vmiklos@frugalware.org> writes: > These, and the 4 other related patches which are not yet in git.git at > the moment are also available in the 'merge-recursive' branch of > git://repo.or.cz/git/vmiklos.git. Thanks. I already expressed my doubts about "move make_virtual_commit()". "add merge-recursive to LIB_H" should go to 'maint' as a build-fix, so it does not have to be on this topic. If this is meant to be a pullable topic branch, I'd prefer if you didn't have that commit. I cherry picked call-depth, index-only removal, obuf and current_{f/d} but haven't pushed the results out. ^ permalink raw reply [flat|nested] 35+ messages in thread
end of thread, other threads:[~2008-09-05 17:27 UTC | newest] Thread overview: 35+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2008-08-19 9:05 What's cooking in git.git (Aug 2008, #05; Tue, 19) Junio C Hamano 2008-08-19 11:02 ` Johannes Sixt 2008-08-19 12:35 ` Andreas Färber 2008-08-19 12:54 ` Miklos Vajna 2008-08-19 19:19 ` Junio C Hamano 2008-08-19 20:59 ` Miklos Vajna 2008-08-19 22:00 ` Junio C Hamano 2008-08-20 22:42 ` Miklos Vajna 2008-08-25 1:44 ` [PATCH] merge-recursive: introduce merge_options Miklos Vajna 2008-08-25 6:06 ` Junio C Hamano 2008-08-25 14:25 ` Miklos Vajna 2008-08-28 4:50 ` Junio C Hamano 2008-08-30 15:42 ` [PATCH] merge-recursive: fix subtree merge Miklos Vajna 2008-08-30 16:39 ` Junio C Hamano 2008-08-30 17:55 ` Junio C Hamano 2008-08-31 23:49 ` Miklos Vajna 2008-09-01 1:06 ` What's cooking in git.git (Aug 2008, #05; Tue, 19) Miklos Vajna 2008-09-01 1:09 ` [PATCH] builtin-revert: use merge_recursive_generic() Miklos Vajna 2008-09-02 20:02 ` What's cooking in git.git (Aug 2008, #05; Tue, 19) Junio C Hamano 2008-09-02 20:43 ` Junio C Hamano 2008-09-02 22:05 ` [PATCH 0/2] Move call_depth and index_only to struct merge_options Miklos Vajna 2008-09-02 22:05 ` [PATCH 1/2] merge-recursive: move call_depth " Miklos Vajna 2008-09-02 22:05 ` [PATCH 2/2] merge-recursive: move index_only " Miklos Vajna 2008-09-02 22:13 ` [PATCH] Makefile: add merge_recursive.h to LIB_H Miklos Vajna 2008-09-02 22:39 ` Junio C Hamano 2008-09-02 23:49 ` Miklos Vajna 2008-09-02 22:39 ` [PATCH 0/2] Move call_depth and index_only to struct merge_options Junio C Hamano 2008-09-03 0:16 ` [PATCH] merge-recursive: get rid of the index_only global variable Miklos Vajna 2008-09-03 0:39 ` [PATCH] merge-recursive: move the global obuf to struct merge_options Miklos Vajna 2008-09-03 17:34 ` Miklos Vajna 2008-09-03 17:34 ` [PATCH 1/2] merge-recursive: move current_{file,directory}_set " Miklos Vajna 2008-09-03 17:34 ` [PATCH 2/2] merge-recursive: move make_virtual_commit()'s virtual_id to merge_options Miklos Vajna 2008-09-04 19:03 ` Junio C Hamano 2008-09-05 17:26 ` [PATCH] merge-recursive: get rid of virtual_id Miklos Vajna 2008-09-04 19:05 ` [PATCH] merge-recursive: move the global obuf to struct merge_options Junio C Hamano
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).