From 93d69d86912c44206543f6670e93f9fc6f2f859f Mon Sep 17 00:00:00 2001 From: Jon Loeliger Date: Sun, 6 Nov 2005 23:30:56 -0600 Subject: [PATCH 1/2] Refactored merge options into separate merge-options.txt. Refactored fetch options into separate fetch-options.txt. Made git-merge use merge-options. Made git-fetch use fetch-options. Made git-pull use merge-options and fetch-options. Added --help option to git-pull and git-format-patch scripts. Rewrote Documentation/Makefile to dynamically determine include dependencies. Signed-off-by: Jon Loeliger Signed-off-by: Junio C Hamano --- Documentation/Makefile | 23 +++++++++++++---------- Documentation/fetch-options.txt | 14 ++++++++++++++ Documentation/git-fetch.txt | 16 ++++------------ Documentation/git-merge.txt | 2 +- Documentation/git-pull.txt | 17 +++++++---------- Documentation/merge-options.txt | 16 ++++++++++++++++ Documentation/merge-pull-opts.txt | 14 -------------- git-format-patch.sh | 4 ++++ git-pull.sh | 12 +++++++++++- 9 files changed, 70 insertions(+), 48 deletions(-) create mode 100644 Documentation/fetch-options.txt create mode 100644 Documentation/merge-options.txt delete mode 100644 Documentation/merge-pull-opts.txt mode change 100755 => 100644 git-pull.sh diff --git a/Documentation/Makefile b/Documentation/Makefile index 741f14cfad..bb9533ff03 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -49,22 +49,25 @@ install: man $(INSTALL) $(DOC_MAN1) $(DESTDIR)/$(man1) $(INSTALL) $(DOC_MAN7) $(DESTDIR)/$(man7) -# 'include' dependencies -$(patsubst %.txt,%.1,$(wildcard git-diff-*.txt)): \ - diff-format.txt diff-options.txt -$(patsubst %.txt,%.html,$(wildcard git-diff-*.txt)): \ - diff-format.txt diff-options.txt -$(patsubst %,%.1,git-fetch git-pull git-push): pull-fetch-param.txt -$(patsubst %,%.html,git-fetch git-pull git-push): pull-fetch-param.txt +# +# Determine "include::" file references in asciidoc files. +# +TEXTFILES = $(wildcard *.txt) +DEPFILES = $(TEXTFILES:%.txt=%.dep) -$(patsubst %,%.1,git-merge git-pull): merge-pull-opts.txt -$(patsubst %,%.html,git-merge git-pull): merge-pull-opts.txt +%.dep : %.txt + @rm -f $@ + @$(foreach dep, $(shell grep include:: $< | sed -e 's/include::/ /' -e 's/\[\]//'), \ + echo $(<:%.txt=%.html) $(<:%.txt=%.1) : $(dep) >> $@; ) + +-include $(DEPFILES) git.7: ../README + clean: - rm -f *.xml *.html *.1 *.7 howto-index.txt howto/*.html + rm -f *.xml *.html *.1 *.7 howto-index.txt howto/*.html *.dep %.html : %.txt asciidoc -b xhtml11 -d manpage -f asciidoc.conf $< diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt new file mode 100644 index 0000000000..12d12b27e8 --- /dev/null +++ b/Documentation/fetch-options.txt @@ -0,0 +1,14 @@ +-a, \--append:: + Append ref names and object names of fetched refs to the + existing contents of `.git/FETCH_HEAD`. Without this + option old data in `.git/FETCH_HEAD` will be overwritten. + +-f, \--force:: + +-t, \--tags:: + +-u, \--update-head-ok:: + By default `git-fetch` refuses to update the head which + corresponds to the current branch. This flag disables the + check. Note that fetching into the current branch will not + update the index and working directory, so use it with care. diff --git a/Documentation/git-fetch.txt b/Documentation/git-fetch.txt index 73f8a99ffe..438240c0cf 100644 --- a/Documentation/git-fetch.txt +++ b/Documentation/git-fetch.txt @@ -8,7 +8,7 @@ git-fetch - Download objects and a head from another repository. SYNOPSIS -------- -'git-fetch' ... +'git-fetch' ... DESCRIPTION @@ -17,24 +17,16 @@ Fetches named heads or tags from another repository, along with the objects necessary to complete them. The ref names and their object names of fetched refs are stored -in $GIT_DIR/FETCH_HEAD. This information is left for a later merge +in `.git/FETCH_HEAD`. This information is left for a later merge operation done by "git resolve" or "git octopus". OPTIONS ------- -include::pull-fetch-param.txt[] +include::fetch-options.txt[] --a, \--append:: - Append ref names and object names of fetched refs to the - existing contents of $GIT_DIR/FETCH_HEAD. Without this - option old data in $GIT_DIR/FETCH_HEAD will be overwritten. +include::pull-fetch-param.txt[] --u, \--update-head-ok:: - By default 'git-fetch' refuses to update the head which - corresponds to the current branch. This flag disables the - check. Note that fetching into the current branch will not - update the index and working directory, so use it with care. SEE ALSO diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt index b3ef19bae4..904e2fc4c5 100644 --- a/Documentation/git-merge.txt +++ b/Documentation/git-merge.txt @@ -19,7 +19,7 @@ which drives multiple merge strategy scripts. OPTIONS ------- -include::merge-pull-opts.txt[] +include::merge-options.txt[] :: The commit message to be used for the merge commit (in case diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt index 7ebb08da0c..c65ca9a530 100644 --- a/Documentation/git-pull.txt +++ b/Documentation/git-pull.txt @@ -20,21 +20,18 @@ Note that you can use `.` (current directory) as the to pull from the local repository -- this is useful when merging local branches into the current branch. + OPTIONS ------- -include::pull-fetch-param.txt[] +include::merge-options.txt[] --a, \--append:: - Append ref names and object names of fetched refs to the - existing contents of `$GIT_DIR/FETCH_HEAD`. Without this - option old data in `$GIT_DIR/FETCH_HEAD` will be overwritten. +include::fetch-options.txt[] -include::merge-pull-opts.txt[] +include::pull-fetch-param.txt[] include::merge-strategies.txt[] - EXAMPLES -------- @@ -72,7 +69,7 @@ $ git fetch origin master:origin +pu:pu maint:maint $ git pull . origin ------------------------------------------------ + -Here, a typical `$GIT_DIR/remotes/origin` file from a +Here, a typical `.git/remotes/origin` file from a `git-clone` operation is used in combination with command line options to `git-fetch` to first update multiple branches of the local repository and then @@ -85,7 +82,7 @@ known to have already obtained and made available all the necessary objects. -Pull of multiple branches from one repository using `$GIT_DIR/remotes` file:: +Pull of multiple branches from one repository using `.git/remotes` file:: + ------------------------------------------------ $ cat .git/remotes/origin @@ -98,7 +95,7 @@ $ git checkout master $ git pull origin ------------------------------------------------ + -Here, a typical `$GIT_DIR/remotes/origin` file from a +Here, a typical `.git/remotes/origin` file from a `git-clone` operation has been hand-modified to include the branch-mapping of additional remote and local heads directly. A single `git-pull` operation while diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt new file mode 100644 index 0000000000..eebaf3aaff --- /dev/null +++ b/Documentation/merge-options.txt @@ -0,0 +1,16 @@ +-n, \--no-summary:: + Do not show diffstat at the end of the merge. + +--no-commit:: + Perform the merge but pretend the merge failed and do + not autocommit, to give the user a chance to inspect and + further tweak the merge result before committing. + + +-s , \--strategy=:: + Use the given merge strategy; can be supplied more than + once to specify them in the order they should be tried. + If there is no `-s` option, a built-in list of strategies + is used instead (`git-merge-resolve` when merging a single + head, `git-merge-octopus` otherwise). + diff --git a/Documentation/merge-pull-opts.txt b/Documentation/merge-pull-opts.txt deleted file mode 100644 index d9164a04a6..0000000000 --- a/Documentation/merge-pull-opts.txt +++ /dev/null @@ -1,14 +0,0 @@ --n, --no-summary:: - Do not show diffstat at the end of the merge. - ---no-commit:: - Perform the merge but pretend the merge failed and do - not autocommit, to give the user a chance to inspect and - further tweak the merge result before committing. - --s :: - use that merge strategy; can be given more than once to - specify them in the order they should be tried. If - there is no `-s` option, built-in list of strategies is - used instead (`git-merge-resolve` when merging a single - head, `git-merge-octopus` otherwise). diff --git a/git-format-patch.sh b/git-format-patch.sh index b43ba3909c..548d2d5847 100755 --- a/git-format-patch.sh +++ b/git-format-patch.sh @@ -8,6 +8,7 @@ usage () { echo >&2 "usage: $0"' [-n] [-o dir | --stdout] [--keep-subject] [--mbox] [--check] [--signoff] [-...] + [--help] ( from..to ... | upstream [ our-head ] ) Prepare each commit with its patch since our-head forked from upstream, @@ -63,6 +64,9 @@ do --output-directo|--output-director|--output-directory) case "$#" in 1) usage ;; esac; shift outdir="$1" ;; + -h|--h|--he|--hel|--help) + usage + ;; -*' '* | -*"$LF"* | -*' '*) # Ignore diff option that has whitespace for now. ;; diff --git a/git-pull.sh b/git-pull.sh old mode 100755 new mode 100644 index e23d4f5597..2358af62d5 --- a/git-pull.sh +++ b/git-pull.sh @@ -7,7 +7,14 @@ . git-sh-setup || die "Not a git archive" usage () { - die "git pull [-n] [--no-commit] [-s strategy]... ..." + echo >&2 "usage: $0"' [-n] [--no-commit] [--no-summary] [--help] + [-s strategy]... + [] + ... + +Fetch one or more remote refs and merge it/them into the current HEAD. +' + exit 1 } strategy_args= no_summary= no_commit= @@ -33,6 +40,9 @@ do esac strategy_args="${strategy_args}-s $strategy " ;; + -h|--h|--he|--hel|--help) + usage + ;; -*) # Pass thru anything that is meant for fetch. break From 44760f1d559ae2087e53be6971ad4f1a8f18f1d7 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 6 Nov 2005 23:29:35 -0800 Subject: [PATCH 2/2] Documentation: talk about guts of merge in tutorial. While discussing Jon's ASCII art on merge operations with him, I realized that the tutorial stops talking about the plumbing details halfway. So fill in the gory details, and update the examples to use 'git-merge', not 'git-resolve'. Signed-off-by: Junio C Hamano --- Documentation/tutorial.txt | 167 +++++++++++++++++++++++++++++++++++-- 1 file changed, 159 insertions(+), 8 deletions(-) diff --git a/Documentation/tutorial.txt b/Documentation/tutorial.txt index 214673db06..6d2c153cf4 100644 --- a/Documentation/tutorial.txt +++ b/Documentation/tutorial.txt @@ -301,7 +301,7 @@ all with a sequence of simple shell commands: ------------------------------------------------ tree=$(git-write-tree) commit=$(echo 'Initial commit' | git-commit-tree $tree) -git-update-ref HEAD $(commit) +git-update-ref HEAD $commit ------------------------------------------------ which will say: @@ -836,14 +836,14 @@ source. Anyway, let's exit `gitk` (`^Q` or the File menu), and decide that we want to merge the work we did on the `mybranch` branch into the `master` branch (which is currently our `HEAD` too). To do that, there's a nice -script called `git resolve`, which wants to know which branches you want +script called `git merge`, which wants to know which branches you want to resolve and what the merge is all about: ------------ -git resolve HEAD mybranch "Merge work in mybranch" +git merge "Merge work in mybranch" HEAD mybranch ------------ -where the third argument is going to be used as the commit message if +where the first argument is going to be used as the commit message if the merge can be resolved automatically. Now, in this case we've intentionally created a situation where the @@ -851,12 +851,14 @@ merge will need to be fixed up by hand, though, so git will do as much of it as it can automatically (which in this case is just merge the `example` file, which had no differences in the `mybranch` branch), and say: - Simple merge failed, trying Automatic merge - Auto-merging hello. + Trying really trivial in-index merge... + fatal: Merge requires file-level merging + Nope. + ... merge: warning: conflicts during merge ERROR: Merge conflict in hello. fatal: merge program failed - Automatic merge failed, fix up by hand + Automatic merge failed/prevented; fix up by hand which is way too verbose, but it basically tells you that it failed the really trivial merge ("Simple merge") and did an "Automatic merge" @@ -928,7 +930,7 @@ resolve to get the "upstream changes" back to your branch. ------------ git checkout mybranch -git resolve HEAD master "Merge upstream changes." +git merge "Merge upstream changes." HEAD master ------------ This outputs something like this (the actual commit object names @@ -1103,6 +1105,155 @@ the above are equivalent to: . `git pull http://www.kernel.org/pub/.../jgarzik/netdev-2.6.git e100` +How does the merge work? +------------------------ + +We said this tutorial shows what plumbing does to help you cope +with the porcelain that isn't flushing, but we so far did not +talk about how the merge really works. If you are following +this tutorial the first time, I'd suggest to skip to "Publishing +your work" section and come back here later. + +OK, still with me? To give us an example to look at, let's go +back to the earlier repository with "hello" and "example" file, +and bring ourselves back to the pre-merge state: + +------------ +$ git show-branch --more=3 master mybranch +! [master] Merge work in mybranch + * [mybranch] Merge work in mybranch +-- +++ [master] Merge work in mybranch +++ [master^2] Some work. +++ [master^] Some fun. +------------ + +Remember, before running `git merge`, our `master` head was at +"Some fun." commit, while our `mybranch` head was at "Some +work." commit. + +------------ +$ git checkout mybranch +$ git reset --hard master^2 +$ git checkout master +$ git reset --hard master^ +------------ + +After rewinding, the commit structure should look like this: + +------------ +$ git show-branch +* [master] Some fun. + ! [mybranch] Some work. +-- + + [mybranch] Some work. ++ [master] Some fun. +++ [mybranch^] New day. +------------ + +Now we are ready to experiment with the merge by hand. + +`git merge` command, when merging two branches, uses 3-way merge +algorithm. First, it finds the common ancestor between them. +The command it uses is `git-merge-base`: + +------------ +$ mb=$(git-merge-base HEAD mybranch) +------------ + +The command writes the commit object name of the common ancestor +to the standard output, so we captured its output to a variable, +because we will be using it in the next step. BTW, the common +ancestor commit is the "New day." commit in this case. You can +tell it by: + +------------ +$ git-name-rev $mb +my-first-tag +------------ + +After finding out a common ancestor commit, the second step is +this: + +------------ +$ git-read-tree -m -u $mb HEAD mybranch +------------ + +This is the same `git-read-tree` command we have already seen, +but it takes three trees, unlike previous examples. This reads +the contents of each tree into different 'stage' in the index +file (the first tree goes to stage 1, the second stage 2, +etc.). After reading three trees into three stages, the paths +that are the same in all three stages are 'collapsed' into stage +0. Also paths that are the same in two of three stages are +collapsed into stage 0, taking the SHA1 from either stage 2 or +stage 3, whichever is different from stage 1 (i.e. only one side +changed from the common ancestor). + +After 'collapsing' operation, paths that are different in three +trees are left in non-zero stages. At this point, you can +inspect the index file with this command: + +------------ +$ git-ls-files --stage +100644 7f8b141b65fdcee47321e399a2598a235a032422 0 example +100644 263414f423d0e4d70dae8fe53fa34614ff3e2860 1 hello +100644 06fa6a24256dc7e560efa5687fa84b51f0263c3a 2 hello +100644 cc44c73eb783565da5831b4d820c962954019b69 3 hello +------------ + +In our example of only two files, we did not have unchanged +files so only 'example' resulted in collapsing, but in real-life +large projects, only small number of files change in one commit, +and this 'collapsing' tends to trivially merge most of the paths +fairly quickly, leaving only the real changes in non-zero stages. + +To look at only non-zero stages, use `\--unmerged` flag: + +------------ +$ git-ls-files --unmerged +100644 263414f423d0e4d70dae8fe53fa34614ff3e2860 1 hello +100644 06fa6a24256dc7e560efa5687fa84b51f0263c3a 2 hello +100644 cc44c73eb783565da5831b4d820c962954019b69 3 hello +------------ + +The next step of merging is to merge these three versions of the +file, using 3-way merge. This is done by giving +`git-merge-one-file` command as one of the arguments to +`git-merge-index` command: + +------------ +$ git-merge-index git-merge-one-file hello +Auto-merging hello. +merge: warning: conflicts during merge +ERROR: Merge conflict in hello. +fatal: merge program failed +------------ + +`git-merge-one-file` script is called with parameters to +describe those three versions, and is responsible to leave the +merge results in the working tree and register it in the index +file. It is a fairly straightforward shell script, and +eventually calls `merge` program from RCS suite to perform the +file-level 3-way merge. In this case, `merge` detects +conflicts, and the merge result with conflict marks is left in +the working tree, while the index file is updated with the +version from the current branch (this is to make `git diff` +useful after this step). This can be seen if you run `ls-files +--stage` again at this point: + +------------ +$ git-ls-files --stage +100644 7f8b141b65fdcee47321e399a2598a235a032422 0 example +100644 06fa6a24256dc7e560efa5687fa84b51f0263c3a 0 hello +------------ + +As you can see, there is no unmerged paths in the index file. +This is the state of the index file and the working file after +`git merge` returns control back to you, leaving the conflicting +merge for you to resolve. + + Publishing your work --------------------