mirror of
https://github.com/git/git.git
synced 2026-03-13 10:23:30 +01:00
Merge commit 'v1.5.3-rc2'
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -96,6 +96,7 @@ git-push
|
||||
git-quiltimport
|
||||
git-read-tree
|
||||
git-rebase
|
||||
git-rebase--interactive
|
||||
git-receive-pack
|
||||
git-reflog
|
||||
git-relink
|
||||
@@ -123,6 +124,7 @@ git-ssh-fetch
|
||||
git-ssh-pull
|
||||
git-ssh-push
|
||||
git-ssh-upload
|
||||
git-stash
|
||||
git-status
|
||||
git-stripspace
|
||||
git-submodule
|
||||
|
||||
4
.mailmap
4
.mailmap
@@ -19,13 +19,16 @@ Horst H. von Brand <vonbrand@inf.utfsm.cl>
|
||||
Joachim Berdal Haga <cjhaga@fys.uio.no>
|
||||
Jon Loeliger <jdl@freescale.com>
|
||||
Jon Seymour <jon@blackcubes.dyndns.org>
|
||||
Junio C Hamano <junio@twinsun.com>
|
||||
Karl Hasselström <kha@treskal.com>
|
||||
Kent Engstrom <kent@lysator.liu.se>
|
||||
Lars Doelle <lars.doelle@on-line ! de>
|
||||
Lars Doelle <lars.doelle@on-line.de>
|
||||
Lukas Sandström <lukass@etek.chalmers.se>
|
||||
Martin Langhoff <martin@catalyst.net.nz>
|
||||
Michael Coleman <tutufan@gmail.com>
|
||||
Michele Ballabio <barra_cuda@katamail.com>
|
||||
Nanako Shiraishi <nanako3@bluebottle.com>
|
||||
Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
|
||||
Ramsay Allan Jones <ramsay@ramsay1.demon.co.uk>
|
||||
René Scharfe <rene.scharfe@lsrfire.ath.cx>
|
||||
@@ -41,6 +44,7 @@ Uwe Kleine-König <ukleinek@informatik.uni-freiburg.de>
|
||||
Uwe Kleine-König <uzeisberger@io.fsforth.de>
|
||||
Uwe Kleine-König <zeisberg@informatik.uni-freiburg.de>
|
||||
Ville Skyttä <scop@xemacs.org>
|
||||
William Pursell <bill.pursell@gmail.com>
|
||||
YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
|
||||
anonymous <linux@horizon.com>
|
||||
anonymous <linux@horizon.net>
|
||||
|
||||
@@ -41,6 +41,7 @@ ifdef ASCIIDOC8
|
||||
ASCIIDOC_EXTRA += -a asciidoc7compatible
|
||||
endif
|
||||
INSTALL?=install
|
||||
RM ?= rm -f
|
||||
DOC_REF = origin/man
|
||||
|
||||
-include ../config.mak.autogen
|
||||
@@ -84,7 +85,7 @@ install: man
|
||||
# Determine "include::" file references in asciidoc files.
|
||||
#
|
||||
doc.dep : $(wildcard *.txt) build-docdep.perl
|
||||
rm -f $@+ $@
|
||||
$(RM) $@+ $@
|
||||
perl ./build-docdep.perl >$@+
|
||||
mv $@+ $@
|
||||
|
||||
@@ -109,11 +110,11 @@ cmd-list.made: cmd-list.perl $(MAN1_TXT)
|
||||
git.7 git.html: git.txt core-intro.txt
|
||||
|
||||
clean:
|
||||
rm -f *.xml *.xml+ *.html *.html+ *.1 *.5 *.7 howto-index.txt howto/*.html doc.dep
|
||||
rm -f $(cmds_txt) *.made
|
||||
$(RM) *.xml *.xml+ *.html *.html+ *.1 *.5 *.7 howto-index.txt howto/*.html doc.dep
|
||||
$(RM) $(cmds_txt) *.made
|
||||
|
||||
%.html : %.txt
|
||||
rm -f $@+ $@
|
||||
$(RM) $@+ $@
|
||||
$(ASCIIDOC) -b xhtml11 -d manpage -f asciidoc.conf \
|
||||
$(ASCIIDOC_EXTRA) -agit_version=$(GIT_VERSION) -o $@+ $<
|
||||
mv $@+ $@
|
||||
@@ -122,7 +123,7 @@ clean:
|
||||
xmlto -m callouts.xsl man $<
|
||||
|
||||
%.xml : %.txt
|
||||
rm -f $@+ $@
|
||||
$(RM) $@+ $@
|
||||
$(ASCIIDOC) -b docbook -d manpage -f asciidoc.conf \
|
||||
$(ASCIIDOC_EXTRA) -agit_version=$(GIT_VERSION) -o $@+ $<
|
||||
mv $@+ $@
|
||||
@@ -137,7 +138,7 @@ user-manual.html: user-manual.xml
|
||||
xsltproc $(XSLTOPTS) -o $@ $(XSLT) $<
|
||||
|
||||
howto-index.txt: howto-index.sh $(wildcard howto/*.txt)
|
||||
rm -f $@+ $@
|
||||
$(RM) $@+ $@
|
||||
sh ./howto-index.sh $(wildcard howto/*.txt) >$@+
|
||||
mv $@+ $@
|
||||
|
||||
@@ -147,7 +148,7 @@ $(patsubst %,%.html,$(ARTICLES)) : %.html : %.txt
|
||||
WEBDOC_DEST = /pub/software/scm/git/docs
|
||||
|
||||
$(patsubst %.txt,%.html,$(wildcard howto/*.txt)): %.html : %.txt
|
||||
rm -f $@+ $@
|
||||
$(RM) $@+ $@
|
||||
sed -e '1,/^$$/d' $< | $(ASCIIDOC) -b xhtml11 - >$@+
|
||||
mv $@+ $@
|
||||
|
||||
|
||||
@@ -4,14 +4,16 @@ GIT v1.5.3 Release Notes
|
||||
Updates since v1.5.2
|
||||
--------------------
|
||||
|
||||
* An initial interation of Porcelain level superproject support
|
||||
started to take shape.
|
||||
* The commit walkers other than http are officially deprecated,
|
||||
but still supported for now.
|
||||
|
||||
* Thee are a handful pack-objects changes to help you cope better with
|
||||
repositories with pathologically large blobs in them.
|
||||
* The submodule support has Porcelain layer.
|
||||
|
||||
* There are a handful pack-objects changes to help you cope better
|
||||
with repositories with pathologically large blobs in them.
|
||||
|
||||
* For people who need to import from Perforce, a front-end for
|
||||
fast-import is in contrib/fast-import/ now.
|
||||
fast-import is in contrib/fast-import/.
|
||||
|
||||
* Comes with git-gui 0.8.0.
|
||||
|
||||
@@ -19,10 +21,30 @@ Updates since v1.5.2
|
||||
|
||||
* New commands and options.
|
||||
|
||||
- "git log" learned a new option '--follow', to follow
|
||||
- "git log --date=<format>" can use more formats: iso8601, rfc2822.
|
||||
|
||||
- The hunk header output from "git diff" family can be customized
|
||||
with the attributes mechanism. See gitattributes(5) for details.
|
||||
|
||||
- "git stash" allows you to quickly save away your work in
|
||||
progress and replay it later on an updated state.
|
||||
|
||||
- "git rebase" learned an "interactive" mode that let you
|
||||
pick and reorder which commits to rebuild.
|
||||
|
||||
- "git fsck" can save its findings in $GIT_DIR/lost-found,
|
||||
without a separate invocation of "git lost-found" command.
|
||||
|
||||
- $GIT_WORK_TREE environment variable can be used together with
|
||||
$GIT_DIR to work in a subdirectory of a working tree that is
|
||||
not located at "$GIT_DIR/..".
|
||||
|
||||
- "git log" learned a new option "--follow", to follow
|
||||
renaming history of a single file.
|
||||
|
||||
- "git-filter-branch" is a reborn cg-admin-rewritehist.
|
||||
- "git-filter-branch" lets you rewrite the revision history of
|
||||
the current branch, creating a new branch. You can specify a
|
||||
number of filters to modify the commits, files and trees.
|
||||
|
||||
- "git-cvsserver" learned new options (--base-path, --export-all,
|
||||
--strict-paths) inspired by git-daemon.
|
||||
@@ -48,6 +70,10 @@ Updates since v1.5.2
|
||||
- "git gc --aggressive" tells the command to spend more cycles
|
||||
to optimize the repository harder.
|
||||
|
||||
- "git repack" learned a "window-memory" limit which
|
||||
dynamically reduces the window size to stay within the
|
||||
specified memory usage.
|
||||
|
||||
- "git repack" can be told to split resulting packs to avoid
|
||||
exceeding limit specified with "--max-pack-size".
|
||||
|
||||
@@ -58,11 +84,15 @@ Updates since v1.5.2
|
||||
- "git format-patch" learned --numbered-files option. This
|
||||
may be useful for MH users.
|
||||
|
||||
- "git format-patch" learned format.subjectprefix configuration
|
||||
variable, which serves the same purpose as "--subject-prefix"
|
||||
option.
|
||||
|
||||
- "git tag -n -l" shows tag annotations while listing tags.
|
||||
|
||||
- "git cvsimport" can optionally use the separate-remote layout.
|
||||
|
||||
- "git blame" can be told to see through commits that changes
|
||||
- "git blame" can be told to see through commits that change
|
||||
whitespaces and indentation levels with "-w" option.
|
||||
|
||||
- "git send-email" can be told not to thread the messages when
|
||||
@@ -71,8 +101,21 @@ Updates since v1.5.2
|
||||
- "git config" learned NUL terminated output format via -z to
|
||||
help scripts.
|
||||
|
||||
- "git init -q" makes the command quieter.
|
||||
|
||||
* Updated behavior of existing commands.
|
||||
|
||||
- "git rm --cached" does not complain when removing a newly
|
||||
added file from the index anymore.
|
||||
|
||||
- "git svn dcommit" retains local merge information.
|
||||
|
||||
- "git config" to set values also honors type flags like --bool
|
||||
and --int.
|
||||
|
||||
- core.quotepath configuration can be used to make textual git
|
||||
output to emit most of the characters in the path literally.
|
||||
|
||||
- "git mergetool" chooses its backend more wisely, taking
|
||||
notice of its environment such as use of X, Gnome/KDE, etc.
|
||||
|
||||
@@ -84,7 +127,7 @@ Updates since v1.5.2
|
||||
$path/$project/.git are more useful. We use $project part
|
||||
in the filename, which we used to discard.
|
||||
|
||||
- "git cvsimort" creates lightweight tag; there is not any
|
||||
- "git cvsimport" creates lightweight tags; there is no
|
||||
interesting information we can record in an annotated tag,
|
||||
and the handcrafted ones the old code created was not
|
||||
properly formed anyway.
|
||||
@@ -99,9 +142,9 @@ Updates since v1.5.2
|
||||
- "git-apply --whitespace=strip" removes blank lines added at
|
||||
the end of the file.
|
||||
|
||||
- "git-fetch" over git native protocols with -v shows connection
|
||||
status, and the IP address of the other end, to help
|
||||
diagnosing problems.
|
||||
- "git-fetch" over git native protocols with "-v" option shows
|
||||
connection status, and the IP address of the other end, to
|
||||
help diagnosing problems.
|
||||
|
||||
- We used to have core.legacyheaders configuration, when
|
||||
set to false, allowed git to write loose objects in a format
|
||||
@@ -124,8 +167,8 @@ Updates since v1.5.2
|
||||
.gitattributes. It does not attempt to deltify blobs that
|
||||
come from paths with delta attribute set to false.
|
||||
|
||||
- new-workdir script (in contrib) can now be used with a bare
|
||||
repository.
|
||||
- "new-workdir" script (in contrib) can now be used with a
|
||||
bare repository.
|
||||
|
||||
- "git-mergetool" learned to use gvimdiff.
|
||||
|
||||
@@ -141,6 +184,11 @@ Updates since v1.5.2
|
||||
concatenate them into a single line and treat the result as
|
||||
"oneline".
|
||||
|
||||
- "git p4import" has been demoted to contrib status. For
|
||||
a superior option, checkout the git-p4 front end to
|
||||
git-fast-import (also in contrib). The man page and p4
|
||||
rpm have been removed as well.
|
||||
|
||||
* Builds
|
||||
|
||||
- old-style function definitions (most notably, a function
|
||||
@@ -153,6 +201,11 @@ Updates since v1.5.2
|
||||
small enough delta results it creates while looking for the
|
||||
best delta candidates.
|
||||
|
||||
- git-pack-objects learned a new heuristcs to prefer delta
|
||||
that is shallower in depth over the smallest delta
|
||||
possible. This improves both overall packfile access
|
||||
performance and packfile density.
|
||||
|
||||
- diff-delta code that is used for packing has been improved
|
||||
to work better on big files.
|
||||
|
||||
@@ -179,6 +232,6 @@ this release, unless otherwise noted.
|
||||
|
||||
--
|
||||
exec >/var/tmp/1
|
||||
O=v1.5.2.2-603-g7c85173
|
||||
O=v1.5.3-rc2
|
||||
echo O=`git describe refs/heads/master`
|
||||
git shortlog --no-merges $O..refs/heads/master ^refs/heads/maint
|
||||
|
||||
@@ -105,6 +105,7 @@ git-diff-tree plumbinginterrogators
|
||||
git-fast-import ancillarymanipulators
|
||||
git-fetch mainporcelain
|
||||
git-fetch-pack synchingrepositories
|
||||
git-filter-branch ancillarymanipulators
|
||||
git-fmt-merge-msg purehelpers
|
||||
git-for-each-ref plumbinginterrogators
|
||||
git-format-patch mainporcelain
|
||||
@@ -178,6 +179,7 @@ git-show-ref plumbinginterrogators
|
||||
git-sh-setup purehelpers
|
||||
git-ssh-fetch synchingrepositories
|
||||
git-ssh-upload synchingrepositories
|
||||
git-stash mainporcelain
|
||||
git-status mainporcelain
|
||||
git-stripspace purehelpers
|
||||
git-submodule mainporcelain
|
||||
|
||||
@@ -117,6 +117,18 @@ core.fileMode::
|
||||
the working copy are ignored; useful on broken filesystems like FAT.
|
||||
See gitlink:git-update-index[1]. True by default.
|
||||
|
||||
core.quotepath::
|
||||
The commands that output paths (e.g. `ls-files`,
|
||||
`diff`), when not given the `-z` option, will quote
|
||||
"unusual" characters in the pathname by enclosing the
|
||||
pathname in a double-quote pair and with backslashes the
|
||||
same way strings in C source code are quoted. If this
|
||||
variable is set to false, the bytes higher than 0x80 are
|
||||
not quoted but output as verbatim. Note that double
|
||||
quote, backslash and control characters are always
|
||||
quoted without `-z` regardless of the setting of this
|
||||
variable.
|
||||
|
||||
core.autocrlf::
|
||||
If true, makes git convert `CRLF` at the end of lines in text files to
|
||||
`LF` when reading from the filesystem, and convert in reverse when
|
||||
@@ -269,6 +281,10 @@ core.excludesfile::
|
||||
of files which are not meant to be tracked. See
|
||||
gitlink:gitignore[5].
|
||||
|
||||
core.pager::
|
||||
The command that git will use to paginate output. Can be overridden
|
||||
with the `GIT_PAGER` environment variable.
|
||||
|
||||
alias.*::
|
||||
Command aliases for the gitlink:git[1] command wrapper - e.g.
|
||||
after defining "alias.last = cat-file commit HEAD", the invocation
|
||||
@@ -432,6 +448,11 @@ gc.rerereunresolved::
|
||||
kept for this many days when `git rerere gc` is run.
|
||||
The default is 15 days. See gitlink:git-rerere[1].
|
||||
|
||||
rerere.enabled::
|
||||
Activate recording of resolved conflicts, so that identical
|
||||
conflict hunks can be resolved automatically, should they
|
||||
be encountered again. See gitlink:git-rerere[1].
|
||||
|
||||
gitcvs.enabled::
|
||||
Whether the cvs server interface is enabled for this repository.
|
||||
See gitlink:git-cvsserver[1].
|
||||
@@ -546,6 +567,7 @@ merge.verbosity::
|
||||
message if conflicts were detected. Level 1 outputs only
|
||||
conflicts, 2 outputs conflicts and file changes. Level 5 and
|
||||
above outputs debugging information. The default is level 2.
|
||||
Can be overriden by 'GIT_MERGE_VERBOSITY' environment variable.
|
||||
|
||||
merge.<driver>.name::
|
||||
Defines a human readable name for a custom low-level
|
||||
@@ -568,6 +590,12 @@ pack.depth::
|
||||
The maximum delta depth used by gitlink:git-pack-objects[1] when no
|
||||
maximum depth is given on the command line. Defaults to 50.
|
||||
|
||||
pack.windowMemory::
|
||||
The window memory size limit used by gitlink:git-pack-objects[1]
|
||||
when no limit is given on the command line. The value can be
|
||||
suffixed with "k", "m", or "g". Defaults to 0, meaning no
|
||||
limit.
|
||||
|
||||
pack.compression::
|
||||
An integer -1..9, indicating the compression level for objects
|
||||
in a pack file. -1 is the zlib default. 0 means no
|
||||
|
||||
@@ -528,7 +528,7 @@ paths that have been trivially merged.
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Sadly, many merges aren't trivial. If there are files that have
|
||||
been added.moved or removed, or if both branches have modified the
|
||||
been added, moved or removed, or if both branches have modified the
|
||||
same file, you will be left with an index tree that contains "merge
|
||||
entries" in it. Such an index tree can 'NOT' be written out to a tree
|
||||
object, and you will have to resolve any such merge clashes using
|
||||
|
||||
@@ -126,6 +126,13 @@ the file that rename/copy produces, respectively.
|
||||
If there is need for such substitution then the whole
|
||||
pathname is put in double quotes.
|
||||
|
||||
The similarity index is the percentage of unchanged lines, and
|
||||
the dissimilarity index is the percentage of changed lines. It
|
||||
is a rounded down integer, followed by a percent sign. The
|
||||
similarity index value of 100% is thus reserved for two equal
|
||||
files, while 100% dissimilarity means that no line from the old
|
||||
file made it into the new one.
|
||||
|
||||
|
||||
combined diff format
|
||||
--------------------
|
||||
|
||||
@@ -168,5 +168,13 @@
|
||||
--quiet::
|
||||
Disable all output of the program. Implies --exit-code.
|
||||
|
||||
--ext-diff::
|
||||
Allow an external diff helper to be executed. If you set an
|
||||
external diff driver with gitlink:gitattributes(5), you need
|
||||
to use this option with gitlink:git-log(1) and friends.
|
||||
|
||||
--no-ext-diff::
|
||||
Disallow external diff drivers.
|
||||
|
||||
For more detailed explanation on these common options, see also
|
||||
link:diffcore.html[diffcore documentation].
|
||||
|
||||
@@ -41,7 +41,7 @@ to happen.
|
||||
|
||||
With a `-d` or `-D` option, `<branchname>` will be deleted. You may
|
||||
specify more than one branch for deletion. If the branch currently
|
||||
has a ref log then the ref log will also be deleted. Use -r together with -d
|
||||
has a reflog then the reflog will also be deleted. Use -r together with -d
|
||||
to delete remote-tracking branches.
|
||||
|
||||
|
||||
@@ -54,9 +54,9 @@ OPTIONS
|
||||
Delete a branch irrespective of its index status.
|
||||
|
||||
-l::
|
||||
Create the branch's ref log. This activates recording of
|
||||
all changes to made the branch ref, enabling use of date
|
||||
based sha1 expressions such as "<branchname>@{yesterday}".
|
||||
Create the branch's reflog. This activates recording of
|
||||
all changes made to the branch ref, enabling use of date
|
||||
based sha1 expressions such as "<branchname>@\{yesterday}".
|
||||
|
||||
-f::
|
||||
Force the creation of a new branch even if it means deleting
|
||||
|
||||
@@ -62,9 +62,9 @@ OPTIONS
|
||||
configuration variable.
|
||||
|
||||
-l::
|
||||
Create the new branch's ref log. This activates recording of
|
||||
all changes to made the branch ref, enabling use of date
|
||||
based sha1 expressions such as "<branchname>@{yesterday}".
|
||||
Create the new branch's reflog. This activates recording of
|
||||
all changes made to the branch ref, enabling use of date
|
||||
based sha1 expressions such as "<branchname>@\{yesterday}".
|
||||
|
||||
-m::
|
||||
If you have local modifications to one or more files that
|
||||
|
||||
@@ -64,6 +64,7 @@ OPTIONS
|
||||
Operate quietly. This flag is passed to "rsync" and
|
||||
"git-fetch-pack" commands when given.
|
||||
|
||||
--no-checkout::
|
||||
-n::
|
||||
No checkout of HEAD is performed after the clone is complete.
|
||||
|
||||
@@ -106,8 +107,9 @@ OPTIONS
|
||||
as patches.
|
||||
|
||||
<repository>::
|
||||
The (possibly remote) repository to clone from. It can
|
||||
be any URL git-fetch supports.
|
||||
The (possibly remote) repository to clone from. See the
|
||||
<<URLS,URLS>> section below for more information on specifying
|
||||
repositories.
|
||||
|
||||
<directory>::
|
||||
The name of a new directory to clone into. The "humanish"
|
||||
@@ -116,6 +118,8 @@ OPTIONS
|
||||
for "host.xz:foo/.git"). Cloning into an existing directory
|
||||
is not allowed.
|
||||
|
||||
include::urls.txt[]
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ GIT_AUTHOR_EMAIL:
|
||||
name = "Your Name"
|
||||
email = "your@email.address.xz"
|
||||
|
||||
A commit comment is read from stdin (max 999 chars). If a changelog
|
||||
A commit comment is read from stdin. If a changelog
|
||||
entry is not provided via "<" redirection, "git-commit-tree" will just wait
|
||||
for one to be entered and terminated with ^D.
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ git-commit - Record changes to the repository
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git-commit' [-a | --interactive] [-s] [-v]
|
||||
'git-commit' [-a | --interactive] [-s] [-v] [-u]
|
||||
[(-c | -C) <commit> | -F <file> | -m <msg> | --amend]
|
||||
[--no-verify] [-e] [--author <author>]
|
||||
[--] [[-i | -o ]<file>...]
|
||||
@@ -71,7 +71,7 @@ OPTIONS
|
||||
Override the author name used in the commit. Use
|
||||
`A U Thor <author@example.com>` format.
|
||||
|
||||
-m <msg>::
|
||||
-m <msg>|--message=<msg>::
|
||||
Use the given <msg> as the commit message.
|
||||
|
||||
-s|--signoff::
|
||||
@@ -115,6 +115,19 @@ but can be used to amend a merge commit.
|
||||
as well. This is usually not what you want unless you
|
||||
are concluding a conflicted merge.
|
||||
|
||||
-u|--untracked-files::
|
||||
Show all untracked files, also those in uninteresting
|
||||
directories, in the "Untracked files:" section of commit
|
||||
message template. Without this option only its name and
|
||||
a trailing slash are displayed for each untracked
|
||||
directory.
|
||||
|
||||
-v|--verbose::
|
||||
Show unified diff between the HEAD commit and what
|
||||
would be committed at the bottom of the commit message
|
||||
template. Note that this diff output doesn't have its
|
||||
lines prefixed with '#'.
|
||||
|
||||
-q|--quiet::
|
||||
Suppress commit summary message.
|
||||
|
||||
|
||||
@@ -302,7 +302,7 @@ change to the project.
|
||||
data
|
||||
('from' SP <committish> LF)?
|
||||
('merge' SP <committish> LF)?
|
||||
(filemodify | filedelete | filedeleteall)*
|
||||
(filemodify | filedelete | filecopy | filerename | filedeleteall)*
|
||||
LF
|
||||
....
|
||||
|
||||
@@ -325,11 +325,13 @@ commit message use a 0 length data. Commit messages are free-form
|
||||
and are not interpreted by Git. Currently they must be encoded in
|
||||
UTF-8, as fast-import does not permit other encodings to be specified.
|
||||
|
||||
Zero or more `filemodify`, `filedelete` and `filedeleteall` commands
|
||||
Zero or more `filemodify`, `filedelete`, `filecopy`, `filerename`
|
||||
and `filedeleteall` commands
|
||||
may be included to update the contents of the branch prior to
|
||||
creating the commit. These commands may be supplied in any order.
|
||||
However it is recommended that a `filedeleteall` command preceed
|
||||
all `filemodify` commands in the same commit, as `filedeleteall`
|
||||
all `filemodify`, `filecopy` and `filerename` commands in the same
|
||||
commit, as `filedeleteall`
|
||||
wipes the branch clean (see below).
|
||||
|
||||
`author`
|
||||
@@ -495,6 +497,56 @@ here `<path>` is the complete path of the file or subdirectory to
|
||||
be removed from the branch.
|
||||
See `filemodify` above for a detailed description of `<path>`.
|
||||
|
||||
`filecopy`
|
||||
^^^^^^^^^^^^
|
||||
Recursively copies an existing file or subdirectory to a different
|
||||
location within the branch. The existing file or directory must
|
||||
exist. If the destination exists it will be completely replaced
|
||||
by the content copied from the source.
|
||||
|
||||
....
|
||||
'C' SP <path> SP <path> LF
|
||||
....
|
||||
|
||||
here the first `<path>` is the source location and the second
|
||||
`<path>` is the destination. See `filemodify` above for a detailed
|
||||
description of what `<path>` may look like. To use a source path
|
||||
that contains SP the path must be quoted.
|
||||
|
||||
A `filecopy` command takes effect immediately. Once the source
|
||||
location has been copied to the destination any future commands
|
||||
applied to the source location will not impact the destination of
|
||||
the copy.
|
||||
|
||||
`filerename`
|
||||
^^^^^^^^^^^^
|
||||
Renames an existing file or subdirectory to a different location
|
||||
within the branch. The existing file or directory must exist. If
|
||||
the destination exists it will be replaced by the source directory.
|
||||
|
||||
....
|
||||
'R' SP <path> SP <path> LF
|
||||
....
|
||||
|
||||
here the first `<path>` is the source location and the second
|
||||
`<path>` is the destination. See `filemodify` above for a detailed
|
||||
description of what `<path>` may look like. To use a source path
|
||||
that contains SP the path must be quoted.
|
||||
|
||||
A `filerename` command takes effect immediately. Once the source
|
||||
location has been renamed to the destination any future commands
|
||||
applied to the source location will create new files there and not
|
||||
impact the destination of the rename.
|
||||
|
||||
Note that a `filerename` is the same as a `filecopy` followed by a
|
||||
`filedelete` of the source location. There is a slight performance
|
||||
advantage to using `filerename`, but the advantage is so small
|
||||
that it is never worth trying to convert a delete/add pair in
|
||||
source material into a rename for fast-import. This `filerename`
|
||||
command is provided just to simplify frontends that already have
|
||||
rename information and don't want bother with decomposing it into a
|
||||
`filecopy` followed by a `filedelete`.
|
||||
|
||||
`filedeleteall`
|
||||
^^^^^^^^^^^^^^^
|
||||
Included in a `commit` command to remove all files (and also all
|
||||
|
||||
@@ -35,7 +35,7 @@ include::fetch-options.txt[]
|
||||
|
||||
include::pull-fetch-param.txt[]
|
||||
|
||||
include::urls.txt[]
|
||||
include::urls-remotes.txt[]
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
|
||||
273
Documentation/git-filter-branch.txt
Normal file
273
Documentation/git-filter-branch.txt
Normal file
@@ -0,0 +1,273 @@
|
||||
git-filter-branch(1)
|
||||
====================
|
||||
|
||||
NAME
|
||||
----
|
||||
git-filter-branch - Rewrite branches
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git-filter-branch' [--env-filter <command>] [--tree-filter <command>]
|
||||
[--index-filter <command>] [--parent-filter <command>]
|
||||
[--msg-filter <command>] [--commit-filter <command>]
|
||||
[--tag-name-filter <command>] [--subdirectory-filter <directory>]
|
||||
[-d <directory>] <new-branch-name> [<rev-list options>...]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
Lets you rewrite git revision history by creating a new branch from
|
||||
your current branch, applying custom filters on each revision.
|
||||
Those filters can modify each tree (e.g. removing a file or running
|
||||
a perl rewrite on all files) or information about each commit.
|
||||
Otherwise, all information (including original commit times or merge
|
||||
information) will be preserved.
|
||||
|
||||
The command takes the new branch name as a mandatory argument and
|
||||
the filters as optional arguments. If you specify no filters, the
|
||||
commits will be recommitted without any changes, which would normally
|
||||
have no effect and result in the new branch pointing to the same
|
||||
branch as your current branch. Nevertheless, this may be useful in
|
||||
the future for compensating for some git bugs or such, therefore
|
||||
such a usage is permitted.
|
||||
|
||||
*WARNING*! The rewritten history will have different object names for all
|
||||
the objects and will not converge with the original branch. You will not
|
||||
be able to easily push and distribute the rewritten branch on top of the
|
||||
original branch. Please do not use this command if you do not know the
|
||||
full implications, and avoid using it anyway, if a simple single commit
|
||||
would suffice to fix your problem.
|
||||
|
||||
Always verify that the rewritten version is correct before disposing
|
||||
the original branch.
|
||||
|
||||
Note that since this operation is extensively I/O expensive, it might
|
||||
be a good idea to redirect the temporary directory off-disk, e.g. on
|
||||
tmpfs. Reportedly the speedup is very noticeable.
|
||||
|
||||
|
||||
Filters
|
||||
~~~~~~~
|
||||
|
||||
The filters are applied in the order as listed below. The <command>
|
||||
argument is always evaluated in shell using the 'eval' command (with the
|
||||
notable exception of the commit filter, for technical reasons).
|
||||
Prior to that, the $GIT_COMMIT environment variable will be set to contain
|
||||
the id of the commit being rewritten. Also, GIT_AUTHOR_NAME,
|
||||
GIT_AUTHOR_EMAIL, GIT_AUTHOR_DATE, GIT_COMMITTER_NAME, GIT_COMMITTER_EMAIL,
|
||||
and GIT_COMMITTER_DATE are set according to the current commit.
|
||||
|
||||
A 'map' function is available that takes an "original sha1 id" argument
|
||||
and outputs a "rewritten sha1 id" if the commit has been already
|
||||
rewritten, and "original sha1 id" otherwise; the 'map' function can
|
||||
return several ids on separate lines if your commit filter emitted
|
||||
multiple commits.
|
||||
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
|
||||
--env-filter <command>::
|
||||
This is the filter for modifying the environment in which
|
||||
the commit will be performed. Specifically, you might want
|
||||
to rewrite the author/committer name/email/time environment
|
||||
variables (see gitlink:git-commit[1] for details). Do not forget
|
||||
to re-export the variables.
|
||||
|
||||
--tree-filter <command>::
|
||||
This is the filter for rewriting the tree and its contents.
|
||||
The argument is evaluated in shell with the working
|
||||
directory set to the root of the checked out tree. The new tree
|
||||
is then used as-is (new files are auto-added, disappeared files
|
||||
are auto-removed - neither .gitignore files nor any other ignore
|
||||
rules *HAVE ANY EFFECT*!).
|
||||
|
||||
--index-filter <command>::
|
||||
This is the filter for rewriting the index. It is similar to the
|
||||
tree filter but does not check out the tree, which makes it much
|
||||
faster. For hairy cases, see gitlink:git-update-index[1].
|
||||
|
||||
--parent-filter <command>::
|
||||
This is the filter for rewriting the commit's parent list.
|
||||
It will receive the parent string on stdin and shall output
|
||||
the new parent string on stdout. The parent string is in
|
||||
a format accepted by gitlink:git-commit-tree[1]: empty for
|
||||
the initial commit, "-p parent" for a normal commit and
|
||||
"-p parent1 -p parent2 -p parent3 ..." for a merge commit.
|
||||
|
||||
--msg-filter <command>::
|
||||
This is the filter for rewriting the commit messages.
|
||||
The argument is evaluated in the shell with the original
|
||||
commit message on standard input; its standard output is
|
||||
used as the new commit message.
|
||||
|
||||
--commit-filter <command>::
|
||||
This is the filter for performing the commit.
|
||||
If this filter is specified, it will be called instead of the
|
||||
gitlink:git-commit-tree[1] command, with arguments of the form
|
||||
"<TREE_ID> [-p <PARENT_COMMIT_ID>]..." and the log message on
|
||||
stdin. The commit id is expected on stdout.
|
||||
+
|
||||
As a special extension, the commit filter may emit multiple
|
||||
commit ids; in that case, ancestors of the original commit will
|
||||
have all of them as parents.
|
||||
|
||||
--tag-name-filter <command>::
|
||||
This is the filter for rewriting tag names. When passed,
|
||||
it will be called for every tag ref that points to a rewritten
|
||||
object (or to a tag object which points to a rewritten object).
|
||||
The original tag name is passed via standard input, and the new
|
||||
tag name is expected on standard output.
|
||||
+
|
||||
The original tags are not deleted, but can be overwritten;
|
||||
use "--tag-name-filter=cat" to simply update the tags. In this
|
||||
case, be very careful and make sure you have the old tags
|
||||
backed up in case the conversion has run afoul.
|
||||
+
|
||||
Note that there is currently no support for proper rewriting of
|
||||
tag objects; in layman terms, if the tag has a message or signature
|
||||
attached, the rewritten tag won't have it. Sorry. (It is by
|
||||
definition impossible to preserve signatures at any rate.)
|
||||
|
||||
--subdirectory-filter <directory>::
|
||||
Only look at the history which touches the given subdirectory.
|
||||
The result will contain that directory (and only that) as its
|
||||
project root.
|
||||
|
||||
-d <directory>::
|
||||
Use this option to set the path to the temporary directory used for
|
||||
rewriting. When applying a tree filter, the command needs to
|
||||
temporary checkout the tree to some directory, which may consume
|
||||
considerable space in case of large projects. By default it
|
||||
does this in the '.git-rewrite/' directory but you can override
|
||||
that choice by this parameter.
|
||||
|
||||
<rev-list-options>::
|
||||
When options are given after the new branch name, they will
|
||||
be passed to gitlink:git-rev-list[1]. Only commits in the resulting
|
||||
output will be filtered, although the filtered commits can still
|
||||
reference parents which are outside of that set.
|
||||
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
Suppose you want to remove a file (containing confidential information
|
||||
or copyright violation) from all commits:
|
||||
|
||||
-------------------------------------------------------
|
||||
git filter-branch --tree-filter 'rm filename' newbranch
|
||||
-------------------------------------------------------
|
||||
|
||||
A significantly faster version:
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
git filter-branch --index-filter 'git update-index --remove filename' newbranch
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Now, you will get the rewritten history saved in the branch 'newbranch'
|
||||
(your current branch is left untouched).
|
||||
|
||||
To set a commit (which typically is at the tip of another
|
||||
history) to be the parent of the current initial commit, in
|
||||
order to paste the other history behind the current history:
|
||||
|
||||
------------------------------------------------------------------------
|
||||
git filter-branch --parent-filter 'sed "s/^\$/-p <graft-id>/"' newbranch
|
||||
------------------------------------------------------------------------
|
||||
|
||||
(if the parent string is empty - therefore we are dealing with the
|
||||
initial commit - add graftcommit as a parent). Note that this assumes
|
||||
history with a single root (that is, no merge without common ancestors
|
||||
happened). If this is not the case, use:
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
git filter-branch --parent-filter \
|
||||
'cat; test $GIT_COMMIT = <commit-id> && echo "-p <graft-id>"' newbranch
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
or even simpler:
|
||||
|
||||
-----------------------------------------------
|
||||
echo "$commit-id $graft-id" >> .git/info/grafts
|
||||
git filter-branch newbranch $graft-id..
|
||||
-----------------------------------------------
|
||||
|
||||
To remove commits authored by "Darl McBribe" from the history:
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
git filter-branch --commit-filter '
|
||||
if [ "$GIT_AUTHOR_NAME" = "Darl McBribe" ];
|
||||
then
|
||||
shift;
|
||||
while [ -n "$1" ];
|
||||
do
|
||||
shift;
|
||||
echo "$1";
|
||||
shift;
|
||||
done;
|
||||
else
|
||||
git commit-tree "$@";
|
||||
fi' newbranch
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
The shift magic first throws away the tree id and then the -p
|
||||
parameters. Note that this handles merges properly! In case Darl
|
||||
committed a merge between P1 and P2, it will be propagated properly
|
||||
and all children of the merge will become merge commits with P1,P2
|
||||
as their parents instead of the merge commit.
|
||||
|
||||
To restrict rewriting to only part of the history, specify a revision
|
||||
range in addition to the new branch name. The new branch name will
|
||||
point to the top-most revision that a 'git rev-list' of this range
|
||||
will print.
|
||||
|
||||
Note that the changes introduced by the commits, and not reverted by
|
||||
subsequent commits, will still be in the rewritten branch. If you want
|
||||
to throw out _changes_ together with the commits, you should use the
|
||||
interactive mode of gitlink:git-rebase[1].
|
||||
|
||||
Consider this history:
|
||||
|
||||
------------------
|
||||
D--E--F--G--H
|
||||
/ /
|
||||
A--B-----C
|
||||
------------------
|
||||
|
||||
To rewrite only commits D,E,F,G,H, but leave A, B and C alone, use:
|
||||
|
||||
--------------------------------
|
||||
git filter-branch ... new-H C..H
|
||||
--------------------------------
|
||||
|
||||
To rewrite commits E,F,G,H, use one of these:
|
||||
|
||||
----------------------------------------
|
||||
git filter-branch ... new-H C..H --not D
|
||||
git filter-branch ... new-H D..H --not C
|
||||
----------------------------------------
|
||||
|
||||
To move the whole tree into a subdirectory, or remove it from there:
|
||||
|
||||
---------------------------------------------------------------
|
||||
git filter-branch --index-filter \
|
||||
'git ls-files -s | sed "s-\t-&newsubdir/-" |
|
||||
GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
|
||||
git update-index --index-info &&
|
||||
mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE' directorymoved
|
||||
---------------------------------------------------------------
|
||||
|
||||
|
||||
Author
|
||||
------
|
||||
Written by Petr "Pasky" Baudis <pasky@suse.cz>,
|
||||
and the git list <git@vger.kernel.org>
|
||||
|
||||
Documentation
|
||||
--------------
|
||||
Documentation by Petr Baudis and the git list.
|
||||
|
||||
GIT
|
||||
---
|
||||
Part of the gitlink:git[7] suite
|
||||
@@ -129,12 +129,13 @@ not add any suffix.
|
||||
CONFIGURATION
|
||||
-------------
|
||||
You can specify extra mail header lines to be added to each
|
||||
message in the repository configuration. Also you can specify
|
||||
the default suffix different from the built-in one:
|
||||
message in the repository configuration. You can also specify
|
||||
new defaults for the subject prefix and file suffix.
|
||||
|
||||
------------
|
||||
[format]
|
||||
headers = "Organization: git-foo\n"
|
||||
subjectprefix = CHANGE
|
||||
suffix = .txt
|
||||
------------
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git-fsck' [--tags] [--root] [--unreachable] [--cache] [--no-reflogs]
|
||||
[--full] [--strict] [--verbose] [<object>*]
|
||||
[--full] [--strict] [--verbose] [--lost-found] [<object>*]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@@ -64,6 +64,10 @@ index file and all SHA1 references in .git/refs/* as heads.
|
||||
--verbose::
|
||||
Be chatty.
|
||||
|
||||
--lost-found::
|
||||
Write dangling refs into .git/lost-found/commit/ or
|
||||
.git/lost-found/other/, depending on type.
|
||||
|
||||
It tests SHA1 and general object sanity, and it does full tracking of
|
||||
the resulting reachability and everything else. It prints out any
|
||||
corruption it finds (missing or bad objects), and if you use the
|
||||
|
||||
@@ -8,7 +8,7 @@ git-init-db - Creates an empty git repository
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-init-db' [--template=<template_directory>] [--shared[=<permissions>]]
|
||||
'git-init-db' [-q | --quiet] [--template=<template_directory>] [--shared[=<permissions>]]
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
@@ -8,7 +8,7 @@ git-init - Create an empty git repository or reinitialize an existing one
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-init' [--template=<template_directory>] [--shared[=<permissions>]]
|
||||
'git-init' [-q | --quiet] [--template=<template_directory>] [--shared[=<permissions>]]
|
||||
|
||||
|
||||
OPTIONS
|
||||
@@ -16,6 +16,10 @@ OPTIONS
|
||||
|
||||
--
|
||||
|
||||
-q, \--quiet::
|
||||
|
||||
Only print error and warning messages, all other output will be suppressed.
|
||||
|
||||
--template=<template_directory>::
|
||||
|
||||
Provide the directory from which templates will be used. The default template
|
||||
|
||||
@@ -14,6 +14,8 @@ SYNOPSIS
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
THIS COMMAND IS DEPRECATED.
|
||||
|
||||
Duplicates another git repository on a local system.
|
||||
|
||||
OPTIONS
|
||||
|
||||
@@ -61,6 +61,9 @@ include::pretty-options.txt[]
|
||||
the specified paths; this means that "<paths>..." limits only
|
||||
commits, and doesn't limit diff for those commits.
|
||||
|
||||
--follow::
|
||||
Continue listing the history of a file beyond renames.
|
||||
|
||||
<paths>...::
|
||||
Show only commits that affect the specified paths.
|
||||
|
||||
@@ -91,6 +94,12 @@ git log -r --name-status release..test::
|
||||
in the "release" branch, along with the list of paths
|
||||
each commit modifies.
|
||||
|
||||
git log --follow builtin-rev-list.c::
|
||||
|
||||
Shows the commits that changed builtin-rev-list.c, including
|
||||
those commits that occurred before the file was given its
|
||||
present name.
|
||||
|
||||
Discussion
|
||||
----------
|
||||
|
||||
|
||||
@@ -43,6 +43,21 @@ If you tried a merge which resulted in a complex conflicts and
|
||||
would want to start over, you can recover with
|
||||
gitlink:git-reset[1].
|
||||
|
||||
CONFIGURATION
|
||||
-------------
|
||||
|
||||
merge.summary::
|
||||
Whether to include summaries of merged commits in newly
|
||||
created merge commit. False by default.
|
||||
|
||||
merge.verbosity::
|
||||
Controls the amount of output shown by the recursive merge
|
||||
strategy. Level 0 outputs nothing except a final error
|
||||
message if conflicts were detected. Level 1 outputs only
|
||||
conflicts, 2 outputs conflicts and file changes. Level 5 and
|
||||
above outputs debugging information. The default is level 2.
|
||||
Can be overriden by 'GIT_MERGE_VERBOSITY' environment variable.
|
||||
|
||||
|
||||
HOW MERGE WORKS
|
||||
---------------
|
||||
|
||||
@@ -85,6 +85,17 @@ base-name::
|
||||
times to get to the necessary object.
|
||||
The default value for --window is 10 and --depth is 50.
|
||||
|
||||
--window-memory=[N]::
|
||||
This option provides an additional limit on top of `--window`;
|
||||
the window size will dynamically scale down so as to not take
|
||||
up more than N bytes in memory. This is useful in
|
||||
repositories with a mix of large and small objects to not run
|
||||
out of memory with a large window, but still be able to take
|
||||
advantage of the large window for the smaller objects. The
|
||||
size can be suffixed with "k", "m", or "g".
|
||||
`--window-memory=0` makes memory usage unlimited, which is the
|
||||
default.
|
||||
|
||||
--max-pack-size=<n>::
|
||||
Maximum size of each output packfile, expressed in MiB.
|
||||
If specified, multiple packfiles may be created.
|
||||
|
||||
@@ -29,7 +29,7 @@ include::fetch-options.txt[]
|
||||
|
||||
include::pull-fetch-param.txt[]
|
||||
|
||||
include::urls.txt[]
|
||||
include::urls-remotes.txt[]
|
||||
|
||||
include::merge-strategies.txt[]
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ the remote repository.
|
||||
-v::
|
||||
Run verbosely.
|
||||
|
||||
include::urls.txt[]
|
||||
include::urls-remotes.txt[]
|
||||
|
||||
|
||||
Examples
|
||||
|
||||
@@ -8,7 +8,8 @@ git-rebase - Forward-port local commits to the updated upstream head
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git-rebase' [-v] [--merge] [-C<n>] [--onto <newbase>] <upstream> [<branch>]
|
||||
'git-rebase' [-i | --interactive] [-v | --verbose] [--merge] [-C<n>]
|
||||
[-p | --preserve-merges] [--onto <newbase>] <upstream> [<branch>]
|
||||
'git-rebase' --continue | --skip | --abort
|
||||
|
||||
DESCRIPTION
|
||||
@@ -208,6 +209,14 @@ OPTIONS
|
||||
context exist they all must match. By default no context is
|
||||
ever ignored.
|
||||
|
||||
-i, \--interactive::
|
||||
Make a list of the commits which are about to be rebased. Let the
|
||||
user edit that list before rebasing.
|
||||
|
||||
-p, \--preserve-merges::
|
||||
Instead of ignoring merges, try to recreate them. This option
|
||||
only works in interactive mode.
|
||||
|
||||
include::merge-strategies.txt[]
|
||||
|
||||
NOTES
|
||||
@@ -226,9 +235,100 @@ pre-rebase hook script for an example.
|
||||
You must be in the top directory of your project to start (or continue)
|
||||
a rebase. Upon completion, <branch> will be the current branch.
|
||||
|
||||
Author
|
||||
INTERACTIVE MODE
|
||||
----------------
|
||||
|
||||
Rebasing interactively means that you have a chance to edit the commits
|
||||
which are rebased. You can reorder the commits, and you can
|
||||
remove them (weeding out bad or otherwise unwanted patches).
|
||||
|
||||
The interactive mode is meant for this type of workflow:
|
||||
|
||||
1. have a wonderful idea
|
||||
2. hack on the code
|
||||
3. prepare a series for submission
|
||||
4. submit
|
||||
|
||||
where point 2. consists of several instances of
|
||||
|
||||
a. regular use
|
||||
1. finish something worthy of a commit
|
||||
2. commit
|
||||
b. independent fixup
|
||||
1. realize that something does not work
|
||||
2. fix that
|
||||
3. commit it
|
||||
|
||||
Sometimes the thing fixed in b.2. cannot be amended to the not-quite
|
||||
perfect commit it fixes, because that commit is buried deeply in a
|
||||
patch series. That is exactly what interactive rebase is for: use it
|
||||
after plenty of "a"s and "b"s, by rearranging and editing
|
||||
commits, and squashing multiple commits into one.
|
||||
|
||||
Start it with the last commit you want to retain as-is:
|
||||
|
||||
git rebase -i <after-this-commit>
|
||||
|
||||
An editor will be fired up with all the commits in your current branch
|
||||
(ignoring merge commits), which come after the given commit. You can
|
||||
reorder the commits in this list to your heart's content, and you can
|
||||
remove them. The list looks more or less like this:
|
||||
|
||||
-------------------------------------------
|
||||
pick deadbee The oneline of this commit
|
||||
pick fa1afe1 The oneline of the next commit
|
||||
...
|
||||
-------------------------------------------
|
||||
|
||||
The oneline descriptions are purely for your pleasure; `git-rebase` will
|
||||
not look at them but at the commit names ("deadbee" and "fa1afe1" in this
|
||||
example), so do not delete or edit the names.
|
||||
|
||||
By replacing the command "pick" with the command "edit", you can tell
|
||||
`git-rebase` to stop after applying that commit, so that you can edit
|
||||
the files and/or the commit message, amend the commit, and continue
|
||||
rebasing.
|
||||
|
||||
If you want to fold two or more commits into one, replace the command
|
||||
"pick" with "squash" for the second and subsequent commit. If the
|
||||
commits had different authors, it will attribute the squashed commit to
|
||||
the author of the last commit.
|
||||
|
||||
In both cases, or when a "pick" does not succeed (because of merge
|
||||
errors), the loop will stop to let you fix things, and you can continue
|
||||
the loop with `git rebase --continue`.
|
||||
|
||||
For example, if you want to reorder the last 5 commits, such that what
|
||||
was HEAD~4 becomes the new HEAD. To achieve that, you would call
|
||||
`git-rebase` like this:
|
||||
|
||||
----------------------
|
||||
$ git rebase -i HEAD~5
|
||||
----------------------
|
||||
|
||||
And move the first patch to the end of the list.
|
||||
|
||||
You might want to preserve merges, if you have a history like this:
|
||||
|
||||
------------------
|
||||
X
|
||||
\
|
||||
A---M---B
|
||||
/
|
||||
---o---O---P---Q
|
||||
------------------
|
||||
|
||||
Suppose you want to rebase the side branch starting at "A" to "Q". Make
|
||||
sure that the current HEAD is "B", and call
|
||||
|
||||
-----------------------------
|
||||
$ git rebase -i -p --onto Q O
|
||||
-----------------------------
|
||||
|
||||
Authors
|
||||
------
|
||||
Written by Junio C Hamano <junkio@cox.net>
|
||||
Written by Junio C Hamano <junkio@cox.net> and
|
||||
Johannes E. Schindelin <johannes.schindelin@gmx.de>
|
||||
|
||||
Documentation
|
||||
--------------
|
||||
|
||||
@@ -48,8 +48,8 @@ standard input of the hook will be one line per ref to be updated:
|
||||
The refname value is relative to $GIT_DIR; e.g. for the master
|
||||
head this is "refs/heads/master". The two sha1 values before
|
||||
each refname are the object names for the refname before and after
|
||||
the update. Refs to be created will have sha1-old equal to 0{40},
|
||||
while refs to be deleted will have sha1-new equal to 0{40}, otherwise
|
||||
the update. Refs to be created will have sha1-old equal to 0\{40},
|
||||
while refs to be deleted will have sha1-new equal to 0\{40}, otherwise
|
||||
sha1-old and sha1-new should be valid objects in the repository.
|
||||
|
||||
This hook is called before any refname is updated and before any
|
||||
@@ -71,7 +71,7 @@ The refname parameter is relative to $GIT_DIR; e.g. for the master
|
||||
head this is "refs/heads/master". The two sha1 arguments are
|
||||
the object names for the refname before and after the update.
|
||||
Note that the hook is called before the refname is updated,
|
||||
so either sha1-old is 0{40} (meaning there is no such ref yet),
|
||||
so either sha1-old is 0\{40} (meaning there is no such ref yet),
|
||||
or it should match what is recorded in refname.
|
||||
|
||||
The hook should exit with non-zero status if it wants to disallow
|
||||
@@ -96,8 +96,8 @@ The refname value is relative to $GIT_DIR; e.g. for the master
|
||||
head this is "refs/heads/master". The two sha1 values before
|
||||
each refname are the object names for the refname before and after
|
||||
the update. Refs that were created will have sha1-old equal to
|
||||
0{40}, while refs that were deleted will have sha1-new equal to
|
||||
0{40}, otherwise sha1-old and sha1-new should be valid objects in
|
||||
0\{40}, while refs that were deleted will have sha1-new equal to
|
||||
0\{40}, otherwise sha1-old and sha1-new should be valid objects in
|
||||
the repository.
|
||||
|
||||
Using this hook, it is easy to generate mails describing the updates
|
||||
|
||||
@@ -68,6 +68,17 @@ OPTIONS
|
||||
to be applied that many times to get to the necessary object.
|
||||
The default value for --window is 10 and --depth is 50.
|
||||
|
||||
--window-memory=[N]::
|
||||
This option provides an additional limit on top of `--window`;
|
||||
the window size will dynamically scale down so as to not take
|
||||
up more than N bytes in memory. This is useful in
|
||||
repositories with a mix of large and small objects to not run
|
||||
out of memory with a large window, but still be able to take
|
||||
advantage of the large window for the smaller objects. The
|
||||
size can be suffixed with "k", "m", or "g".
|
||||
`--window-memory=0` makes memory usage unlimited, which is the
|
||||
default.
|
||||
|
||||
--max-pack-size=<n>::
|
||||
Maximum size of each output packfile, expressed in MiB.
|
||||
If specified, multiple packfiles may be created.
|
||||
|
||||
@@ -23,7 +23,7 @@ initial manual merge, and later by noticing the same automerge
|
||||
results and applying the previously recorded hand resolution.
|
||||
|
||||
[NOTE]
|
||||
You need to create `$GIT_DIR/rr-cache` directory to enable this
|
||||
You need to set the config variable rerere.enabled to enable this
|
||||
command.
|
||||
|
||||
|
||||
@@ -171,7 +171,7 @@ records it if it is a new conflict, or reuses the earlier hand
|
||||
resolve when it is not. `git-commit` also invokes `git-rerere`
|
||||
when recording a merge result. What this means is that you do
|
||||
not have to do anything special yourself (Note: you still have
|
||||
to create `$GIT_DIR/rr-cache` directory to enable this command).
|
||||
to set the config variable rerere.enabled to enable this command).
|
||||
|
||||
In our example, when you did the test merge, the manual
|
||||
resolution is recorded, and it will be reused when you do the
|
||||
|
||||
@@ -28,7 +28,7 @@ SYNOPSIS
|
||||
[ \--encoding[=<encoding>] ]
|
||||
[ \--(author|committer|grep)=<pattern> ]
|
||||
[ \--regexp-ignore-case ] [ \--extended-regexp ]
|
||||
[ \--date={local|relative|default} ]
|
||||
[ \--date={local|relative|default|iso|rfc|short} ]
|
||||
[ [\--objects | \--objects-edge] [ \--unpacked ] ]
|
||||
[ \--pretty | \--header ]
|
||||
[ \--bisect ]
|
||||
@@ -96,7 +96,7 @@ include::pretty-options.txt[]
|
||||
|
||||
Synonym for `--date=relative`.
|
||||
|
||||
--date={relative,local,default}::
|
||||
--date={relative,local,default,iso,rfc}::
|
||||
|
||||
Only takes effect for dates shown in human-readable format, such
|
||||
as when using "--pretty".
|
||||
@@ -106,6 +106,13 @@ e.g. "2 hours ago".
|
||||
+
|
||||
`--date=local` shows timestamps in user's local timezone.
|
||||
+
|
||||
`--date=iso` (or `--date=iso8601`) shows timestamps in ISO 8601 format.
|
||||
+
|
||||
`--date=rfc` (or `--date=rfc2822`) shows timestamps in RFC 2822
|
||||
format, often found in E-mail messages.
|
||||
+
|
||||
`--date=short` shows only date but not time, in `YYYY-MM-DD` fomat.
|
||||
+
|
||||
`--date=default` shows timestamps in the original timezone
|
||||
(either committer's or author's).
|
||||
|
||||
@@ -284,9 +291,9 @@ excluded from the output.
|
||||
+
|
||||
With '\--pretty' format other than oneline (for obvious reasons),
|
||||
this causes the output to have two extra lines of information
|
||||
taken from the reflog. By default, 'commit@{Nth}' notation is
|
||||
taken from the reflog. By default, 'commit@\{Nth}' notation is
|
||||
used in the output. When the starting commit is specified as
|
||||
'commit@{now}', output also uses 'commit@{timestamp}' notation
|
||||
'commit@{now}', output also uses 'commit@\{timestamp}' notation
|
||||
instead. Under '\--pretty=oneline', the commit message is
|
||||
prefixed with this information on the same line.
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@ DESCRIPTION
|
||||
Remove files from the working tree and from the index. The
|
||||
files have to be identical to the tip of the branch, and no
|
||||
updates to its contents must have been placed in the staging
|
||||
area (aka index).
|
||||
area (aka index). When --cached is given, the staged content has to
|
||||
match either the tip of the branch *or* the file on disk.
|
||||
|
||||
|
||||
OPTIONS
|
||||
|
||||
@@ -13,6 +13,8 @@ SYNOPSIS
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
THIS COMMAND IS DEPRECATED.
|
||||
|
||||
Pulls from a remote repository over ssh connection, invoking
|
||||
git-ssh-upload on the other end. It functions identically to
|
||||
git-ssh-upload, aside from which end you run it on.
|
||||
|
||||
@@ -12,6 +12,8 @@ SYNOPSIS
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
THIS COMMAND IS DEPRECATED.
|
||||
|
||||
Pushes from a remote repository over ssh connection, invoking
|
||||
git-ssh-fetch on the other end. It functions identically to
|
||||
git-ssh-fetch, aside from which end you run it on.
|
||||
|
||||
162
Documentation/git-stash.txt
Normal file
162
Documentation/git-stash.txt
Normal file
@@ -0,0 +1,162 @@
|
||||
git-stash(1)
|
||||
============
|
||||
|
||||
NAME
|
||||
----
|
||||
git-stash - Stash the changes in a dirty working directory away
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git-stash' (save | list | show [<stash>] | apply [<stash>] | clear)
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
||||
Use 'git-stash' when you want to record the current state of the
|
||||
working directory and the index, but want to go back to a clean
|
||||
working directory. The command saves your local modifications away
|
||||
and reverts the working directory to match the `HEAD` commit.
|
||||
|
||||
The modifications stashed away by this command can be listed with
|
||||
`git-stash list`, inspected with `git-stash show`, and restored
|
||||
(potentially on top of a different commit) with `git-stash apply`.
|
||||
Calling git-stash without any arguments is equivalent to `git-stash
|
||||
save`.
|
||||
|
||||
The latest stash you created is stored in `$GIT_DIR/refs/stash`; older
|
||||
stashes are found in the reflog of this reference and can be named using
|
||||
the usual reflog syntax (e.g. `stash@\{1}` is the most recently
|
||||
created stash, `stash@\{2}` is the one before it, `stash@\{2.hours.ago}`
|
||||
is also possible).
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
|
||||
save::
|
||||
|
||||
Save your local modifications to a new 'stash', and run `git-reset
|
||||
--hard` to revert them. This is the default action when no
|
||||
subcommand is given.
|
||||
|
||||
list::
|
||||
|
||||
List the stashes that you currently have. Each 'stash' is listed
|
||||
with its name (e.g. `stash@\{0}` is the latest stash, `stash@\{1} is
|
||||
the one before, etc.), the name of the branch that was current when the
|
||||
stash was made, and a short description of the commit the stash was
|
||||
based on.
|
||||
+
|
||||
----------------------------------------------------------------
|
||||
stash@{0}: submit: 6ebd0e2... Add git-stash
|
||||
stash@{1}: master: 9cc0589... Merge branch 'master' of gfi
|
||||
----------------------------------------------------------------
|
||||
|
||||
show [<stash>]::
|
||||
|
||||
Show the changes recorded in the stash as a diff between the the
|
||||
stashed state and its original parent. When no `<stash>` is given,
|
||||
shows the latest one. By default, the command shows the diffstat, but
|
||||
it will accept any format known to `git-diff` (e.g., `git-stash show
|
||||
-p stash@\{2}` to view the second most recent stash in patch form).
|
||||
|
||||
apply [<stash>]::
|
||||
|
||||
Restore the changes recorded in the stash on top of the current
|
||||
working tree state. When no `<stash>` is given, applies the latest
|
||||
one. The working directory must match the index.
|
||||
+
|
||||
This operation can fail with conflicts; you need to resolve them
|
||||
by hand in the working tree.
|
||||
|
||||
clear::
|
||||
Remove all the stashed states. Note that those states will then
|
||||
be subject to pruning, and may be difficult or impossible to recover.
|
||||
|
||||
|
||||
DISCUSSION
|
||||
----------
|
||||
|
||||
A stash is represented as a commit whose tree records the state of the
|
||||
working directory, and its first parent is the commit at `HEAD` when
|
||||
the stash was created. The tree of the second parent records the
|
||||
state of the index when the stash is made, and it is made a child of
|
||||
the `HEAD` commit. The ancestry graph looks like this:
|
||||
|
||||
.----W
|
||||
/ /
|
||||
-----H----I
|
||||
|
||||
where `H` is the `HEAD` commit, `I` is a commit that records the state
|
||||
of the index, and `W` is a commit that records the state of the working
|
||||
tree.
|
||||
|
||||
|
||||
EXAMPLES
|
||||
--------
|
||||
|
||||
Pulling into a dirty tree::
|
||||
|
||||
When you are in the middle of something, you learn that there are
|
||||
upstream changes that are possibly relevant to what you are
|
||||
doing. When your local changes do not conflict with the changes in
|
||||
the upstream, a simple `git pull` will let you move forward.
|
||||
+
|
||||
However, there are cases in which your local changes do conflict with
|
||||
the upstream changes, and `git pull` refuses to overwrite your
|
||||
changes. In such a case, you can stash your changes away,
|
||||
perform a pull, and then unstash, like this:
|
||||
+
|
||||
----------------------------------------------------------------
|
||||
$ git pull
|
||||
...
|
||||
file foobar not up to date, cannot merge.
|
||||
$ git stash
|
||||
$ git pull
|
||||
$ git stash apply
|
||||
----------------------------------------------------------------
|
||||
|
||||
Interrupted workflow::
|
||||
|
||||
When you are in the middle of something, your boss comes in and
|
||||
demands that you fix something immediately. Traditionally, you would
|
||||
make a commit to a temporary branch to store your changes away, and
|
||||
return to your original branch to make the emergency fix, like this:
|
||||
+
|
||||
----------------------------------------------------------------
|
||||
... hack hack hack ...
|
||||
$ git checkout -b my_wip
|
||||
$ git commit -a -m "WIP"
|
||||
$ git checkout master
|
||||
$ edit emergency fix
|
||||
$ git commit -a -m "Fix in a hurry"
|
||||
$ git checkout my_wip
|
||||
$ git reset --soft HEAD^
|
||||
... continue hacking ...
|
||||
----------------------------------------------------------------
|
||||
+
|
||||
You can use `git-stash` to simplify the above, like this:
|
||||
+
|
||||
----------------------------------------------------------------
|
||||
... hack hack hack ...
|
||||
$ git stash
|
||||
$ edit emergency fix
|
||||
$ git commit -a -m "Fix in a hurry"
|
||||
$ git stash apply
|
||||
... continue hacking ...
|
||||
----------------------------------------------------------------
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
gitlink:git-checkout[1],
|
||||
gitlink:git-commit[1],
|
||||
gitlink:git-reflog[1],
|
||||
gitlink:git-reset[1]
|
||||
|
||||
AUTHOR
|
||||
------
|
||||
Written by Nanako Shiraishi <nanako3@bluebottle.com>
|
||||
|
||||
GIT
|
||||
---
|
||||
Part of the gitlink:git[7] suite
|
||||
@@ -8,11 +8,20 @@ git-submodule - Initialize, update or inspect submodules
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git-submodule' [--quiet] [-b branch] add <repository> [<path>]
|
||||
'git-submodule' [--quiet] [--cached] [status|init|update] [--] [<path>...]
|
||||
|
||||
|
||||
COMMANDS
|
||||
--------
|
||||
add::
|
||||
Add the given repository as a submodule at the given path
|
||||
to the changeset to be committed next. In particular, the
|
||||
repository is cloned at the specified path, added to the
|
||||
changeset and registered in .gitmodules. If no path is
|
||||
specified, the path is deduced from the repository specification.
|
||||
|
||||
status::
|
||||
Show the status of the submodules. This will print the SHA-1 of the
|
||||
currently checked out commit for each submodule, along with the
|
||||
@@ -24,8 +33,8 @@ status::
|
||||
|
||||
init::
|
||||
Initialize the submodules, i.e. register in .git/config each submodule
|
||||
path and url found in .gitmodules. The key used in git/config is
|
||||
`submodule.$path.url`. This command does not alter existing information
|
||||
name and url found in .gitmodules. The key used in .git/config is
|
||||
`submodule.$name.url`. This command does not alter existing information
|
||||
in .git/config.
|
||||
|
||||
update::
|
||||
@@ -39,6 +48,9 @@ OPTIONS
|
||||
-q, --quiet::
|
||||
Only print error messages.
|
||||
|
||||
-b, --branch::
|
||||
Branch of repository to add as submodule.
|
||||
|
||||
--cached::
|
||||
Display the SHA-1 stored in the index, not the SHA-1 of the currently
|
||||
checked out submodule commit. This option is only valid for the
|
||||
@@ -53,7 +65,7 @@ FILES
|
||||
When initializing submodules, a .gitmodules file in the top-level directory
|
||||
of the containing repository is used to find the url of each submodule.
|
||||
This file should be formatted in the same way as $GIR_DIR/config. The key
|
||||
to each submodule url is "module.$path.url".
|
||||
to each submodule url is "submodule.$name.url".
|
||||
|
||||
|
||||
AUTHOR
|
||||
|
||||
@@ -42,9 +42,11 @@ unreleased) version of git, that is available from 'master'
|
||||
branch of the `git.git` repository.
|
||||
Documentation for older releases are available here:
|
||||
|
||||
* link:v1.5.2.2/git.html[documentation for release 1.5.2.2]
|
||||
* link:v1.5.2.4/git.html[documentation for release 1.5.2.4]
|
||||
|
||||
* release notes for
|
||||
link:RelNotes-1.5.2.4.txt[1.5.2.4],
|
||||
link:RelNotes-1.5.2.3.txt[1.5.2.3],
|
||||
link:RelNotes-1.5.2.2.txt[1.5.2.2],
|
||||
link:RelNotes-1.5.2.1.txt[1.5.2.1],
|
||||
link:RelNotes-1.5.2.txt[1.5.2].
|
||||
@@ -409,6 +411,11 @@ parameter, <path>.
|
||||
|
||||
other
|
||||
~~~~~
|
||||
'GIT_MERGE_VERBOSITY'::
|
||||
A number controlling the amount of output shown by
|
||||
the recursive merge strategy. Overrides merge.verbosity.
|
||||
See gitlink:git-merge[1]
|
||||
|
||||
'GIT_PAGER'::
|
||||
This environment variable overrides `$PAGER`.
|
||||
|
||||
|
||||
@@ -72,8 +72,8 @@ EFFECTS
|
||||
-------
|
||||
|
||||
Certain operations by git can be influenced by assigning
|
||||
particular attributes to a path. Currently, three operations
|
||||
are attributes-aware.
|
||||
particular attributes to a path. Currently, the following
|
||||
operations are attributes-aware.
|
||||
|
||||
Checking-out and checking-in
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -199,7 +199,9 @@ Generating diff text
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The attribute `diff` affects if `git diff` generates textual
|
||||
patch for the path or just says `Binary files differ`.
|
||||
patch for the path or just says `Binary files differ`. It also
|
||||
can affect what line is shown on the hunk header `@@ -k,l +n,m @@`
|
||||
line.
|
||||
|
||||
Set::
|
||||
|
||||
@@ -224,7 +226,8 @@ String::
|
||||
Diff is shown using the specified custom diff driver.
|
||||
The driver program is given its input using the same
|
||||
calling convention as used for GIT_EXTERNAL_DIFF
|
||||
program.
|
||||
program. This name is also used for custom hunk header
|
||||
selection.
|
||||
|
||||
|
||||
Defining a custom diff driver
|
||||
@@ -249,6 +252,50 @@ parameters, just like `GIT_EXTERNAL_DIFF` program is called.
|
||||
See gitlink:git[7] for details.
|
||||
|
||||
|
||||
Defining a custom hunk-header
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Each group of changes (called "hunk") in the textual diff output
|
||||
is prefixed with a line of the form:
|
||||
|
||||
@@ -k,l +n,m @@ TEXT
|
||||
|
||||
The text is called 'hunk header', and by default a line that
|
||||
begins with an alphabet, an underscore or a dollar sign is used,
|
||||
which matches what GNU `diff -p` output uses. This default
|
||||
selection however is not suited for some contents, and you can
|
||||
use customized pattern to make a selection.
|
||||
|
||||
First in .gitattributes, you would assign the `diff` attribute
|
||||
for paths.
|
||||
|
||||
------------------------
|
||||
*.tex diff=tex
|
||||
------------------------
|
||||
|
||||
Then, you would define "diff.tex.funcname" configuration to
|
||||
specify a regular expression that matches a line that you would
|
||||
want to appear as the hunk header, like this:
|
||||
|
||||
------------------------
|
||||
[diff "tex"]
|
||||
funcname = "^\\(\\\\\\(sub\\)*section{.*\\)$"
|
||||
------------------------
|
||||
|
||||
Note. A single level of backslashes are eaten by the
|
||||
configuration file parser, so you would need to double the
|
||||
backslashes; the pattern above picks a line that begins with a
|
||||
backslash, and zero or more occurences of `sub` followed by
|
||||
`section` followed by open brace, to the end of line.
|
||||
|
||||
There are a few built-in patterns to make this easier, and `tex`
|
||||
is one of them, so you do not have to write the above in your
|
||||
configuration file (you still need to enable this with the
|
||||
attribute mechanism, via `.gitattributes`). Another built-in
|
||||
pattern is defined for `java` that defines a pattern suitable
|
||||
for program text in Java language.
|
||||
|
||||
|
||||
Performing a three-way merge
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ USAGE='<refname> <target directory>'
|
||||
export GIT_DIR
|
||||
|
||||
test -z "$mandir" && usage
|
||||
if ! git-rev-parse --verify "$head^0" >/dev/null; then
|
||||
if ! git rev-parse --verify "$head^0" >/dev/null; then
|
||||
echo >&2 "head: $head does not exist in the current repository"
|
||||
usage
|
||||
fi
|
||||
@@ -18,12 +18,12 @@ fi
|
||||
GIT_INDEX_FILE=`pwd`/.quick-doc.index
|
||||
export GIT_INDEX_FILE
|
||||
rm -f "$GIT_INDEX_FILE"
|
||||
git-read-tree $head
|
||||
git-checkout-index -a -f --prefix="$mandir"/
|
||||
git read-tree $head
|
||||
git checkout-index -a -f --prefix="$mandir"/
|
||||
|
||||
if test -n "$GZ"; then
|
||||
cd "$mandir"
|
||||
for i in `git-ls-tree -r --name-only $head`
|
||||
for i in `git ls-tree -r --name-only $head`
|
||||
do
|
||||
gzip < $i > $i.gz && rm $i
|
||||
done
|
||||
|
||||
@@ -106,12 +106,14 @@ The placeholders are:
|
||||
- '%aD': author date, RFC2822 style
|
||||
- '%ar': author date, relative
|
||||
- '%at': author date, UNIX timestamp
|
||||
- '%ai': author date, ISO 8601 format
|
||||
- '%cn': committer name
|
||||
- '%ce': committer email
|
||||
- '%cd': committer date
|
||||
- '%cD': committer date, RFC2822 style
|
||||
- '%cr': committer date, relative
|
||||
- '%ct': committer date, UNIX timestamp
|
||||
- '%ci': committer date, ISO 8601 format
|
||||
- '%e': encoding
|
||||
- '%s': subject
|
||||
- '%b': body
|
||||
|
||||
@@ -354,7 +354,7 @@ used for pulls:
|
||||
|
||||
-------------------------------------
|
||||
$ git config --get remote.origin.url
|
||||
/home/bob/myrepo
|
||||
/home/alice/project
|
||||
-------------------------------------
|
||||
|
||||
(The complete configuration created by git-clone is visible using
|
||||
|
||||
55
Documentation/urls-remotes.txt
Normal file
55
Documentation/urls-remotes.txt
Normal file
@@ -0,0 +1,55 @@
|
||||
include::urls.txt[]
|
||||
|
||||
REMOTES
|
||||
-------
|
||||
|
||||
In addition to the above, as a short-hand, the name of a
|
||||
file in `$GIT_DIR/remotes` directory can be given; the
|
||||
named file should be in the following format:
|
||||
|
||||
------------
|
||||
URL: one of the above URL format
|
||||
Push: <refspec>
|
||||
Pull: <refspec>
|
||||
|
||||
------------
|
||||
|
||||
Then such a short-hand is specified in place of
|
||||
<repository> without <refspec> parameters on the command
|
||||
line, <refspec> specified on `Push:` lines or `Pull:`
|
||||
lines are used for `git-push` and `git-fetch`/`git-pull`,
|
||||
respectively. Multiple `Push:` and `Pull:` lines may
|
||||
be specified for additional branch mappings.
|
||||
|
||||
Or, equivalently, in the `$GIT_DIR/config` (note the use
|
||||
of `fetch` instead of `Pull:`):
|
||||
|
||||
------------
|
||||
[remote "<remote>"]
|
||||
url = <url>
|
||||
push = <refspec>
|
||||
fetch = <refspec>
|
||||
|
||||
------------
|
||||
|
||||
The name of a file in `$GIT_DIR/branches` directory can be
|
||||
specified as an older notation short-hand; the named
|
||||
file should contain a single line, a URL in one of the
|
||||
above formats, optionally followed by a hash `#` and the
|
||||
name of remote head (URL fragment notation).
|
||||
`$GIT_DIR/branches/<remote>` file that stores a <url>
|
||||
without the fragment is equivalent to have this in the
|
||||
corresponding file in the `$GIT_DIR/remotes/` directory.
|
||||
|
||||
------------
|
||||
URL: <url>
|
||||
Pull: refs/heads/master:<remote>
|
||||
|
||||
------------
|
||||
|
||||
while having `<url>#<head>` is equivalent to
|
||||
|
||||
------------
|
||||
URL: <url>
|
||||
Pull: refs/heads/<head>:<remote>
|
||||
------------
|
||||
@@ -32,57 +32,3 @@ To sync with a local directory, use:
|
||||
===============================================================
|
||||
- /path/to/repo.git/
|
||||
===============================================================
|
||||
|
||||
REMOTES
|
||||
-------
|
||||
|
||||
In addition to the above, as a short-hand, the name of a
|
||||
file in `$GIT_DIR/remotes` directory can be given; the
|
||||
named file should be in the following format:
|
||||
|
||||
------------
|
||||
URL: one of the above URL format
|
||||
Push: <refspec>
|
||||
Pull: <refspec>
|
||||
|
||||
------------
|
||||
|
||||
Then such a short-hand is specified in place of
|
||||
<repository> without <refspec> parameters on the command
|
||||
line, <refspec> specified on `Push:` lines or `Pull:`
|
||||
lines are used for `git-push` and `git-fetch`/`git-pull`,
|
||||
respectively. Multiple `Push:` and `Pull:` lines may
|
||||
be specified for additional branch mappings.
|
||||
|
||||
Or, equivalently, in the `$GIT_DIR/config` (note the use
|
||||
of `fetch` instead of `Pull:`):
|
||||
|
||||
------------
|
||||
[remote "<remote>"]
|
||||
url = <url>
|
||||
push = <refspec>
|
||||
fetch = <refspec>
|
||||
|
||||
------------
|
||||
|
||||
The name of a file in `$GIT_DIR/branches` directory can be
|
||||
specified as an older notation short-hand; the named
|
||||
file should contain a single line, a URL in one of the
|
||||
above formats, optionally followed by a hash `#` and the
|
||||
name of remote head (URL fragment notation).
|
||||
`$GIT_DIR/branches/<remote>` file that stores a <url>
|
||||
without the fragment is equivalent to have this in the
|
||||
corresponding file in the `$GIT_DIR/remotes/` directory.
|
||||
|
||||
------------
|
||||
URL: <url>
|
||||
Pull: refs/heads/master:<remote>
|
||||
|
||||
------------
|
||||
|
||||
while having `<url>#<head>` is equivalent to
|
||||
|
||||
------------
|
||||
URL: <url>
|
||||
Pull: refs/heads/<head>:<remote>
|
||||
------------
|
||||
|
||||
@@ -2974,13 +2974,13 @@ developed. If you blow the directory cache away entirely, you generally
|
||||
haven't lost any information as long as you have the name of the tree
|
||||
that it described.
|
||||
|
||||
At the same time, the index is at the same time also the
|
||||
staging area for creating new trees, and creating a new tree always
|
||||
involves a controlled modification of the index file. In particular,
|
||||
the index file can have the representation of an intermediate tree that
|
||||
has not yet been instantiated. So the index can be thought of as a
|
||||
write-back cache, which can contain dirty information that has not yet
|
||||
been written back to the backing store.
|
||||
At the same time, the index is also the staging area for creating
|
||||
new trees, and creating a new tree always involves a controlled
|
||||
modification of the index file. In particular, the index file can
|
||||
have the representation of an intermediate tree that has not yet been
|
||||
instantiated. So the index can be thought of as a write-back cache,
|
||||
which can contain dirty information that has not yet been written back
|
||||
to the backing store.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
GVF=GIT-VERSION-FILE
|
||||
DEF_VER=v1.5.2.4.GIT
|
||||
DEF_VER=v1.5.3.GIT
|
||||
|
||||
LF='
|
||||
'
|
||||
|
||||
100
Makefile
100
Makefile
@@ -112,8 +112,6 @@ all:
|
||||
# Define NO_PERL_MAKEMAKER if you cannot use Makefiles generated by perl's
|
||||
# MakeMaker (e.g. using ActiveState under Cygwin).
|
||||
#
|
||||
# Define WITH_P4IMPORT to build and install Python git-p4import script.
|
||||
#
|
||||
# Define NO_TCLTK if you do not want Tcl/Tk GUI.
|
||||
#
|
||||
# The TCL_PATH variable governs the location of the Tcl interpreter
|
||||
@@ -176,6 +174,7 @@ export prefix bindir gitexecdir sharedir template_dir sysconfdir
|
||||
|
||||
CC = gcc
|
||||
AR = ar
|
||||
RM = rm -f
|
||||
TAR = tar
|
||||
INSTALL = install
|
||||
RPMBUILD = rpmbuild
|
||||
@@ -204,7 +203,7 @@ SCRIPT_SH = \
|
||||
git-fetch.sh \
|
||||
git-ls-remote.sh \
|
||||
git-merge-one-file.sh git-mergetool.sh git-parse-remote.sh \
|
||||
git-pull.sh git-rebase.sh \
|
||||
git-pull.sh git-rebase.sh git-rebase--interactive.sh \
|
||||
git-repack.sh git-request-pull.sh git-reset.sh \
|
||||
git-sh-setup.sh \
|
||||
git-tag.sh git-verify-tag.sh \
|
||||
@@ -212,7 +211,8 @@ SCRIPT_SH = \
|
||||
git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \
|
||||
git-merge-resolve.sh git-merge-ours.sh \
|
||||
git-lost-found.sh git-quiltimport.sh git-submodule.sh \
|
||||
git-filter-branch.sh
|
||||
git-filter-branch.sh \
|
||||
git-stash.sh
|
||||
|
||||
SCRIPT_PERL = \
|
||||
git-add--interactive.perl \
|
||||
@@ -221,20 +221,9 @@ SCRIPT_PERL = \
|
||||
git-svnimport.perl git-cvsexportcommit.perl \
|
||||
git-send-email.perl git-svn.perl
|
||||
|
||||
SCRIPT_PYTHON = \
|
||||
git-p4import.py
|
||||
|
||||
ifdef WITH_P4IMPORT
|
||||
SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
|
||||
$(patsubst %.perl,%,$(SCRIPT_PERL)) \
|
||||
$(patsubst %.py,%,$(SCRIPT_PYTHON)) \
|
||||
git-status git-instaweb
|
||||
else
|
||||
SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
|
||||
$(patsubst %.perl,%,$(SCRIPT_PERL)) \
|
||||
git-status git-instaweb
|
||||
endif
|
||||
|
||||
|
||||
# ... and all the rest that could be moved out of bindir to gitexecdir
|
||||
PROGRAMS = \
|
||||
@@ -283,9 +272,6 @@ endif
|
||||
ifndef PERL_PATH
|
||||
PERL_PATH = /usr/bin/perl
|
||||
endif
|
||||
ifndef PYTHON_PATH
|
||||
PYTHON_PATH = /usr/local/bin/python
|
||||
endif
|
||||
|
||||
export PERL_PATH
|
||||
|
||||
@@ -739,7 +725,6 @@ prefix_SQ = $(subst ','\'',$(prefix))
|
||||
|
||||
SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
|
||||
PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))
|
||||
PYTHON_PATH_SQ = $(subst ','\'',$(PYTHON_PATH))
|
||||
TCLTK_PATH_SQ = $(subst ','\'',$(TCLTK_PATH))
|
||||
|
||||
LIBS = $(GITLIBS) $(EXTLIBS)
|
||||
@@ -769,7 +754,7 @@ strip: $(PROGRAMS) git$X
|
||||
$(STRIP) $(STRIP_OPTS) $(PROGRAMS) git$X
|
||||
|
||||
gitk-wish: gitk GIT-GUI-VARS
|
||||
$(QUIET_GEN)rm -f $@ $@+ && \
|
||||
$(QUIET_GEN)$(RM) $@ $@+ && \
|
||||
sed -e '1,3s|^exec .* "$$0"|exec $(subst |,'\|',$(TCLTK_PATH_SQ)) "$$0"|' <gitk >$@+ && \
|
||||
chmod +x $@+ && \
|
||||
mv -f $@+ $@
|
||||
@@ -779,17 +764,16 @@ git.o: git.c common-cmds.h GIT-CFLAGS
|
||||
$(ALL_CFLAGS) -c $(filter %.c,$^)
|
||||
|
||||
git$X: git.o $(BUILTIN_OBJS) $(GITLIBS)
|
||||
$(QUIET_LINK)$(CC) -DGIT_VERSION='"$(GIT_VERSION)"' \
|
||||
$(ALL_CFLAGS) -o $@ $(filter %.c,$^) git.o \
|
||||
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ git.o \
|
||||
$(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)
|
||||
|
||||
help.o: common-cmds.h
|
||||
|
||||
git-merge-subtree$X: git-merge-recursive$X
|
||||
$(QUIET_BUILT_IN)rm -f $@ && ln git-merge-recursive$X $@
|
||||
$(QUIET_BUILT_IN)$(RM) $@ && ln git-merge-recursive$X $@
|
||||
|
||||
$(BUILT_INS): git$X
|
||||
$(QUIET_BUILT_IN)rm -f $@ && ln git$X $@
|
||||
$(QUIET_BUILT_IN)$(RM) $@ && ln git$X $@
|
||||
|
||||
common-cmds.h: ./generate-cmdlist.sh
|
||||
|
||||
@@ -797,7 +781,7 @@ common-cmds.h: $(wildcard Documentation/git-*.txt)
|
||||
$(QUIET_GEN)./generate-cmdlist.sh > $@+ && mv $@+ $@
|
||||
|
||||
$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
|
||||
$(QUIET_GEN)rm -f $@ $@+ && \
|
||||
$(QUIET_GEN)$(RM) $@ $@+ && \
|
||||
sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
|
||||
-e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
|
||||
-e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
|
||||
@@ -808,20 +792,11 @@ $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
|
||||
|
||||
$(patsubst %.perl,%,$(SCRIPT_PERL)): perl/perl.mak
|
||||
|
||||
$(patsubst %.py,%,$(SCRIPT_PYTHON)) : % : %.py
|
||||
rm -f $@ $@+
|
||||
sed -e '1s|#!.*/python|#!$(PYTHON_PATH_SQ)|' \
|
||||
-e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
|
||||
-e 's/@@NO_CURL@@/$(NO_CURL)/g' \
|
||||
$@.py >$@+
|
||||
chmod +x $@+
|
||||
mv $@+ $@
|
||||
|
||||
perl/perl.mak: GIT-CFLAGS
|
||||
$(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' $(@F)
|
||||
|
||||
$(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl
|
||||
$(QUIET_GEN)rm -f $@ $@+ && \
|
||||
$(QUIET_GEN)$(RM) $@ $@+ && \
|
||||
INSTLIBDIR=`$(MAKE) -C perl -s --no-print-directory instlibdir` && \
|
||||
sed -e '1{' \
|
||||
-e ' s|#!.*perl|#!$(PERL_PATH_SQ)|' \
|
||||
@@ -840,7 +815,7 @@ git-status: git-commit
|
||||
$(QUIET_GEN)cp $< $@+ && mv $@+ $@
|
||||
|
||||
gitweb/gitweb.cgi: gitweb/gitweb.perl
|
||||
$(QUIET_GEN)rm -f $@ $@+ && \
|
||||
$(QUIET_GEN)$(RM) $@ $@+ && \
|
||||
sed -e '1s|#!.*perl|#!$(PERL_PATH_SQ)|' \
|
||||
-e 's|++GIT_VERSION++|$(GIT_VERSION)|g' \
|
||||
-e 's|++GIT_BINDIR++|$(bindir)|g' \
|
||||
@@ -863,7 +838,7 @@ gitweb/gitweb.cgi: gitweb/gitweb.perl
|
||||
mv $@+ $@
|
||||
|
||||
git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css
|
||||
$(QUIET_GEN)rm -f $@ $@+ && \
|
||||
$(QUIET_GEN)$(RM) $@ $@+ && \
|
||||
sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
|
||||
-e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
|
||||
-e 's/@@NO_CURL@@/$(NO_CURL)/g' \
|
||||
@@ -876,14 +851,14 @@ git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css
|
||||
mv $@+ $@
|
||||
|
||||
configure: configure.ac
|
||||
$(QUIET_GEN)rm -f $@ $<+ && \
|
||||
$(QUIET_GEN)$(RM) $@ $<+ && \
|
||||
sed -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
|
||||
$< > $<+ && \
|
||||
autoconf -o $@ $<+ && \
|
||||
rm -f $<+
|
||||
$(RM) $<+
|
||||
|
||||
# These can record GIT_VERSION
|
||||
git$X git.spec \
|
||||
git.o git.spec \
|
||||
$(patsubst %.sh,%,$(SCRIPT_SH)) \
|
||||
$(patsubst %.perl,%,$(SCRIPT_PERL)) \
|
||||
: GIT-VERSION-FILE
|
||||
@@ -938,7 +913,7 @@ $(patsubst git-%$X,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
|
||||
$(DIFF_OBJS): diffcore.h
|
||||
|
||||
$(LIB_FILE): $(LIB_OBJS)
|
||||
$(QUIET_AR)rm -f $@ && $(AR) rcs $@ $(LIB_OBJS)
|
||||
$(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS)
|
||||
|
||||
XDIFF_OBJS=xdiff/xdiffi.o xdiff/xprepare.o xdiff/xutils.o xdiff/xemit.o \
|
||||
xdiff/xmerge.o
|
||||
@@ -946,7 +921,7 @@ $(XDIFF_OBJS): xdiff/xinclude.h xdiff/xmacros.h xdiff/xdiff.h xdiff/xtypes.h \
|
||||
xdiff/xutils.h xdiff/xprepare.h xdiff/xdiffi.h xdiff/xemit.h
|
||||
|
||||
$(XDIFF_LIB): $(XDIFF_OBJS)
|
||||
$(QUIET_AR)rm -f $@ && $(AR) rcs $@ $(XDIFF_OBJS)
|
||||
$(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(XDIFF_OBJS)
|
||||
|
||||
|
||||
perl/Makefile: perl/Git.pm perl/Makefile.PL GIT-CFLAGS
|
||||
@@ -957,11 +932,11 @@ doc:
|
||||
$(MAKE) -C Documentation all
|
||||
|
||||
TAGS:
|
||||
rm -f TAGS
|
||||
$(RM) TAGS
|
||||
find . -name '*.[hcS]' -print | xargs etags -a
|
||||
|
||||
tags:
|
||||
rm -f tags
|
||||
$(RM) tags
|
||||
find . -name '*.[hcS]' -print | xargs ctags -a
|
||||
|
||||
### Detect prefix changes
|
||||
@@ -1018,7 +993,8 @@ check-sha1:: test-sha1$X
|
||||
check: common-cmds.h
|
||||
for i in *.c; do sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i || exit; done
|
||||
|
||||
|
||||
remove-dashes:
|
||||
./fixup-builtins $(BUILT_INS)
|
||||
|
||||
### Installation rules
|
||||
|
||||
@@ -1040,7 +1016,7 @@ endif
|
||||
cp '$(DESTDIR_SQ)$(bindir_SQ)/git$X' \
|
||||
'$(DESTDIR_SQ)$(gitexecdir_SQ)/git$X'; \
|
||||
fi
|
||||
$(foreach p,$(BUILT_INS), rm -f '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' && ln '$(DESTDIR_SQ)$(gitexecdir_SQ)/git$X' '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' ;)
|
||||
$(foreach p,$(BUILT_INS), $(RM) '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' && ln '$(DESTDIR_SQ)$(gitexecdir_SQ)/git$X' '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' ;)
|
||||
|
||||
install-doc:
|
||||
$(MAKE) -C Documentation install
|
||||
@@ -1069,7 +1045,7 @@ dist: git.spec git-archive configure
|
||||
$(GIT_TARNAME)/configure \
|
||||
$(GIT_TARNAME)/version \
|
||||
$(GIT_TARNAME)/git-gui/version
|
||||
@rm -rf $(GIT_TARNAME)
|
||||
@$(RM) -r $(GIT_TARNAME)
|
||||
gzip -f -9 $(GIT_TARNAME).tar
|
||||
|
||||
rpm: dist
|
||||
@@ -1078,13 +1054,13 @@ rpm: dist
|
||||
htmldocs = git-htmldocs-$(GIT_VERSION)
|
||||
manpages = git-manpages-$(GIT_VERSION)
|
||||
dist-doc:
|
||||
rm -fr .doc-tmp-dir
|
||||
$(RM) -r .doc-tmp-dir
|
||||
mkdir .doc-tmp-dir
|
||||
$(MAKE) -C Documentation WEBDOC_DEST=../.doc-tmp-dir install-webdoc
|
||||
cd .doc-tmp-dir && $(TAR) cf ../$(htmldocs).tar .
|
||||
gzip -n -9 -f $(htmldocs).tar
|
||||
:
|
||||
rm -fr .doc-tmp-dir
|
||||
$(RM) -r .doc-tmp-dir
|
||||
mkdir -p .doc-tmp-dir/man1 .doc-tmp-dir/man5 .doc-tmp-dir/man7
|
||||
$(MAKE) -C Documentation DESTDIR=./ \
|
||||
man1dir=../.doc-tmp-dir/man1 \
|
||||
@@ -1093,31 +1069,31 @@ dist-doc:
|
||||
install
|
||||
cd .doc-tmp-dir && $(TAR) cf ../$(manpages).tar .
|
||||
gzip -n -9 -f $(manpages).tar
|
||||
rm -fr .doc-tmp-dir
|
||||
$(RM) -r .doc-tmp-dir
|
||||
|
||||
### Cleaning rules
|
||||
|
||||
clean:
|
||||
rm -f *.o mozilla-sha1/*.o arm/*.o ppc/*.o compat/*.o xdiff/*.o \
|
||||
$(RM) *.o mozilla-sha1/*.o arm/*.o ppc/*.o compat/*.o xdiff/*.o \
|
||||
$(LIB_FILE) $(XDIFF_LIB)
|
||||
rm -f $(ALL_PROGRAMS) $(BUILT_INS) git$X
|
||||
rm -f $(TEST_PROGRAMS)
|
||||
rm -f *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags
|
||||
rm -rf autom4te.cache
|
||||
rm -f configure config.log config.mak.autogen config.mak.append config.status config.cache
|
||||
rm -rf $(GIT_TARNAME) .doc-tmp-dir
|
||||
rm -f $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz
|
||||
rm -f $(htmldocs).tar.gz $(manpages).tar.gz
|
||||
rm -f gitweb/gitweb.cgi
|
||||
$(RM) $(ALL_PROGRAMS) $(BUILT_INS) git$X
|
||||
$(RM) $(TEST_PROGRAMS)
|
||||
$(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags
|
||||
$(RM) -r autom4te.cache
|
||||
$(RM) configure config.log config.mak.autogen config.mak.append config.status config.cache
|
||||
$(RM) -r $(GIT_TARNAME) .doc-tmp-dir
|
||||
$(RM) $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz
|
||||
$(RM) $(htmldocs).tar.gz $(manpages).tar.gz
|
||||
$(RM) gitweb/gitweb.cgi
|
||||
$(MAKE) -C Documentation/ clean
|
||||
$(MAKE) -C perl clean
|
||||
$(MAKE) -C templates/ clean
|
||||
$(MAKE) -C t/ clean
|
||||
ifndef NO_TCLTK
|
||||
rm -f gitk-wish
|
||||
$(RM) gitk-wish
|
||||
$(MAKE) -C git-gui clean
|
||||
endif
|
||||
rm -f GIT-VERSION-FILE GIT-CFLAGS GIT-GUI-VARS
|
||||
$(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-GUI-VARS
|
||||
|
||||
.PHONY: all install clean strip
|
||||
.PHONY: .FORCE-GIT-VERSION-FILE TAGS tags .FORCE-GIT-CFLAGS
|
||||
|
||||
@@ -518,8 +518,8 @@ static struct patch *compare_buffer(mmfile_t *file_p, mmfile_t *file_o,
|
||||
xdemitcb_t ecb;
|
||||
|
||||
xpp.flags = xdl_opts;
|
||||
memset(&xecfg, 0, sizeof(xecfg));
|
||||
xecfg.ctxlen = context;
|
||||
xecfg.flags = 0;
|
||||
ecb.outf = xdiff_outf;
|
||||
ecb.priv = &state;
|
||||
memset(&state, 0, sizeof(state));
|
||||
|
||||
162
builtin-branch.c
162
builtin-branch.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Builtin "git branch"
|
||||
*
|
||||
* Copyright (c) 2006 Kristian H<EFBFBD>gsberg <krh@redhat.com>
|
||||
* Copyright (c) 2006 Kristian Høgsberg <krh@redhat.com>
|
||||
* Based on git-branch.sh by Junio C Hamano.
|
||||
*/
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "refs.h"
|
||||
#include "commit.h"
|
||||
#include "builtin.h"
|
||||
#include "remote.h"
|
||||
|
||||
static const char builtin_branch_usage[] =
|
||||
"git-branch [-r] (-d | -D) <branchname> | [--track | --no-track] [-l] [-f] <branchname> [<start-point>] | (-m | -M) [<oldbranch>] <newbranch> | [--color | --no-color] [-r | -a] [-v [--abbrev=<length> | --no-abbrev]]";
|
||||
@@ -22,7 +23,7 @@ static const char builtin_branch_usage[] =
|
||||
static const char *head;
|
||||
static unsigned char head_sha1[20];
|
||||
|
||||
static int branch_track_remotes;
|
||||
static int branch_track = 1;
|
||||
|
||||
static int branch_use_color;
|
||||
static char branch_colors[][COLOR_MAXLEN] = {
|
||||
@@ -67,7 +68,7 @@ static int git_branch_config(const char *var, const char *value)
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(var, "branch.autosetupmerge"))
|
||||
branch_track_remotes = git_config_bool(var, value);
|
||||
branch_track = git_config_bool(var, value);
|
||||
|
||||
return git_default_config(var, value);
|
||||
}
|
||||
@@ -324,125 +325,70 @@ static void print_ref_list(int kinds, int detached, int verbose, int abbrev)
|
||||
free_ref_list(&ref_list);
|
||||
}
|
||||
|
||||
static char *config_repo;
|
||||
static char *config_remote;
|
||||
static const char *start_ref;
|
||||
struct tracking {
|
||||
struct refspec spec;
|
||||
char *src;
|
||||
const char *remote;
|
||||
int matches;
|
||||
};
|
||||
|
||||
static int get_remote_branch_name(const char *value)
|
||||
static int find_tracked_branch(struct remote *remote, void *priv)
|
||||
{
|
||||
const char *colon;
|
||||
const char *end;
|
||||
struct tracking *tracking = priv;
|
||||
|
||||
if (*value == '+')
|
||||
value++;
|
||||
|
||||
colon = strchr(value, ':');
|
||||
if (!colon)
|
||||
return 0;
|
||||
|
||||
end = value + strlen(value);
|
||||
|
||||
/*
|
||||
* Try an exact match first. I.e. handle the case where the
|
||||
* value is "$anything:refs/foo/bar/baz" and start_ref is exactly
|
||||
* "refs/foo/bar/baz". Then the name at the remote is $anything.
|
||||
*/
|
||||
if (!strcmp(colon + 1, start_ref)) {
|
||||
/* Truncate the value before the colon. */
|
||||
nfasprintf(&config_repo, "%.*s", colon - value, value);
|
||||
return 1;
|
||||
if (!remote_find_tracking(remote, &tracking->spec)) {
|
||||
if (++tracking->matches == 1) {
|
||||
tracking->src = tracking->spec.src;
|
||||
tracking->remote = remote->name;
|
||||
} else {
|
||||
free(tracking->spec.src);
|
||||
if (tracking->src) {
|
||||
free(tracking->src);
|
||||
tracking->src = NULL;
|
||||
}
|
||||
}
|
||||
tracking->spec.src = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Is this a wildcard match?
|
||||
*/
|
||||
if ((end - 2 <= value) || end[-2] != '/' || end[-1] != '*' ||
|
||||
(colon - 2 <= value) || colon[-2] != '/' || colon[-1] != '*')
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Value is "refs/foo/bar/<asterisk>:refs/baz/boa/<asterisk>"
|
||||
* and start_ref begins with "refs/baz/boa/"; the name at the
|
||||
* remote is refs/foo/bar/ with the remaining part of the
|
||||
* start_ref. The length of the prefix on the RHS is (end -
|
||||
* colon - 2), including the slash immediately before the
|
||||
* asterisk.
|
||||
*/
|
||||
if ((strlen(start_ref) < end - colon - 2) ||
|
||||
memcmp(start_ref, colon + 1, end - colon - 2))
|
||||
return 0; /* does not match prefix */
|
||||
|
||||
/* Replace the asterisk with the remote branch name. */
|
||||
nfasprintf(&config_repo, "%.*s%s",
|
||||
(colon - 1) - value, value,
|
||||
start_ref + (end - colon - 2));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int get_remote_config(const char *key, const char *value)
|
||||
{
|
||||
const char *var;
|
||||
if (prefixcmp(key, "remote."))
|
||||
return 0;
|
||||
|
||||
var = strrchr(key, '.');
|
||||
if (var == key + 6 || strcmp(var, ".fetch"))
|
||||
return 0;
|
||||
/*
|
||||
* Ok, we are looking at key == "remote.$foo.fetch";
|
||||
*/
|
||||
if (get_remote_branch_name(value))
|
||||
nfasprintf(&config_remote, "%.*s", var - (key + 7), key + 7);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void set_branch_merge(const char *name, const char *config_remote,
|
||||
const char *config_repo)
|
||||
|
||||
/*
|
||||
* This is called when new_ref is branched off of orig_ref, and tries
|
||||
* to infer the settings for branch.<new_ref>.{remote,merge} from the
|
||||
* config.
|
||||
*/
|
||||
static int setup_tracking(const char *new_ref, const char *orig_ref)
|
||||
{
|
||||
char key[1024];
|
||||
if (sizeof(key) <=
|
||||
snprintf(key, sizeof(key), "branch.%s.remote", name))
|
||||
die("what a long branch name you have!");
|
||||
git_config_set(key, config_remote);
|
||||
struct tracking tracking;
|
||||
|
||||
/*
|
||||
* We do not have to check if we have enough space for
|
||||
* the 'merge' key, since it's shorter than the
|
||||
* previous 'remote' key, which we already checked.
|
||||
*/
|
||||
snprintf(key, sizeof(key), "branch.%s.merge", name);
|
||||
git_config_set(key, config_repo);
|
||||
}
|
||||
if (strlen(new_ref) > 1024 - 7 - 7 - 1)
|
||||
return error("Tracking not set up: name too long: %s",
|
||||
new_ref);
|
||||
|
||||
static void set_branch_defaults(const char *name, const char *real_ref)
|
||||
{
|
||||
/*
|
||||
* name is the name of new branch under refs/heads;
|
||||
* real_ref is typically refs/remotes/$foo/$bar, where
|
||||
* $foo is the remote name (there typically are no slashes)
|
||||
* and $bar is the branch name we map from the remote
|
||||
* (it could have slashes).
|
||||
*/
|
||||
start_ref = real_ref;
|
||||
git_config(get_remote_config);
|
||||
if (!config_repo && !config_remote &&
|
||||
!prefixcmp(real_ref, "refs/heads/")) {
|
||||
set_branch_merge(name, ".", real_ref);
|
||||
printf("Branch %s set up to track local branch %s.\n",
|
||||
name, real_ref);
|
||||
}
|
||||
memset(&tracking, 0, sizeof(tracking));
|
||||
tracking.spec.dst = (char *)orig_ref;
|
||||
if (for_each_remote(find_tracked_branch, &tracking) ||
|
||||
!tracking.matches)
|
||||
return 1;
|
||||
|
||||
if (config_repo && config_remote) {
|
||||
set_branch_merge(name, config_remote, config_repo);
|
||||
if (tracking.matches > 1)
|
||||
return error("Not tracking: ambiguous information for ref %s",
|
||||
orig_ref);
|
||||
|
||||
if (tracking.matches == 1) {
|
||||
sprintf(key, "branch.%s.remote", new_ref);
|
||||
git_config_set(key, tracking.remote ? tracking.remote : ".");
|
||||
sprintf(key, "branch.%s.merge", new_ref);
|
||||
git_config_set(key, tracking.src);
|
||||
free(tracking.src);
|
||||
printf("Branch %s set up to track remote branch %s.\n",
|
||||
name, real_ref);
|
||||
new_ref, orig_ref);
|
||||
}
|
||||
|
||||
if (config_repo)
|
||||
free(config_repo);
|
||||
if (config_remote)
|
||||
free(config_remote);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void create_branch(const char *name, const char *start_name,
|
||||
@@ -505,7 +451,7 @@ static void create_branch(const char *name, const char *start_name,
|
||||
automatically merges from there. So far, this is only done for
|
||||
remotes registered via .git/config. */
|
||||
if (real_ref && track)
|
||||
set_branch_defaults(name, real_ref);
|
||||
setup_tracking(name, real_ref);
|
||||
|
||||
if (write_ref_sha1(lock, sha1, msg) < 0)
|
||||
die("Failed to write ref: %s.", strerror(errno));
|
||||
@@ -564,7 +510,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
|
||||
int i;
|
||||
|
||||
git_config(git_branch_config);
|
||||
track = branch_track_remotes;
|
||||
track = branch_track;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "builtin.h"
|
||||
#include "cache.h"
|
||||
#include "object.h"
|
||||
#include "commit.h"
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
* of "-a" causing problems (not possible in the above example,
|
||||
* but get used to it in scripting!).
|
||||
*/
|
||||
#include "builtin.h"
|
||||
#include "cache.h"
|
||||
#include "strbuf.h"
|
||||
#include "quote.h"
|
||||
|
||||
@@ -178,14 +178,14 @@ int cmd_config(int argc, const char **argv, const char *prefix)
|
||||
char *home = getenv("HOME");
|
||||
if (home) {
|
||||
char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
|
||||
setenv("GIT_CONFIG", user_config, 1);
|
||||
setenv(CONFIG_ENVIRONMENT, user_config, 1);
|
||||
free(user_config);
|
||||
} else {
|
||||
die("$HOME not set");
|
||||
}
|
||||
}
|
||||
else if (!strcmp(argv[1], "--system"))
|
||||
setenv("GIT_CONFIG", git_etc_gitconfig(), 1);
|
||||
setenv(CONFIG_ENVIRONMENT, git_etc_gitconfig(), 1);
|
||||
else if (!strcmp(argv[1], "--null") || !strcmp(argv[1], "-z")) {
|
||||
term = '\0';
|
||||
delim = '\n';
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "builtin.h"
|
||||
#include "cache.h"
|
||||
#include "refs.h"
|
||||
#include "commit.h"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "builtin.h"
|
||||
#include "cache.h"
|
||||
#include "refs.h"
|
||||
#include "object.h"
|
||||
@@ -796,7 +797,7 @@ static struct ref_sort *default_sort(void)
|
||||
return sort;
|
||||
}
|
||||
|
||||
int cmd_for_each_ref(int ac, const char **av, char *prefix)
|
||||
int cmd_for_each_ref(int ac, const char **av, const char *prefix)
|
||||
{
|
||||
int i, num_refs;
|
||||
const char *format = NULL;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "builtin.h"
|
||||
#include "cache.h"
|
||||
#include "commit.h"
|
||||
#include "tree.h"
|
||||
@@ -20,6 +21,7 @@ static int check_strict;
|
||||
static int keep_cache_objects;
|
||||
static unsigned char head_sha1[20];
|
||||
static int errors_found;
|
||||
static int write_lost_and_found;
|
||||
static int verbose;
|
||||
#define ERROR_OBJECT 01
|
||||
#define ERROR_REACHABLE 02
|
||||
@@ -138,6 +140,21 @@ static void check_unreachable_object(struct object *obj)
|
||||
if (!obj->used) {
|
||||
printf("dangling %s %s\n", typename(obj->type),
|
||||
sha1_to_hex(obj->sha1));
|
||||
if (write_lost_and_found) {
|
||||
char *filename = git_path("lost-found/%s/%s",
|
||||
obj->type == OBJ_COMMIT ? "commit" : "other",
|
||||
sha1_to_hex(obj->sha1));
|
||||
FILE *f;
|
||||
|
||||
if (safe_create_leading_directories(filename)) {
|
||||
error("Could not create lost-found");
|
||||
return;
|
||||
}
|
||||
if (!(f = fopen(filename, "w")))
|
||||
die("Could not open %s", filename);
|
||||
fprintf(f, "%s\n", sha1_to_hex(obj->sha1));
|
||||
fclose(f);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -643,7 +660,7 @@ static const char fsck_usage[] =
|
||||
"git-fsck [--tags] [--root] [[--unreachable] [--cache] [--full] "
|
||||
"[--strict] [--verbose] <head-sha1>*]";
|
||||
|
||||
int cmd_fsck(int argc, char **argv, const char *prefix)
|
||||
int cmd_fsck(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i, heads;
|
||||
|
||||
@@ -685,6 +702,12 @@ int cmd_fsck(int argc, char **argv, const char *prefix)
|
||||
verbose = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--lost-found")) {
|
||||
check_full = 1;
|
||||
include_reflogs = 0;
|
||||
write_lost_and_found = 1;
|
||||
continue;
|
||||
}
|
||||
if (*arg == '-')
|
||||
usage(fsck_usage);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
* Copyright (c) 2006 Shawn O. Pearce
|
||||
*/
|
||||
|
||||
#include "builtin.h"
|
||||
#include "cache.h"
|
||||
#include "run-command.h"
|
||||
|
||||
|
||||
@@ -184,7 +184,36 @@ static void copy_templates(const char *git_dir, int len, const char *template_di
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
static int create_default_files(const char *git_dir, const char *template_path)
|
||||
/*
|
||||
* Get the full path to the working tree specified in $GIT_WORK_TREE
|
||||
* or NULL if no working tree is specified.
|
||||
*/
|
||||
static const char *get_work_tree(void)
|
||||
{
|
||||
const char *git_work_tree;
|
||||
char cwd[PATH_MAX];
|
||||
static char worktree[PATH_MAX];
|
||||
|
||||
git_work_tree = getenv(GIT_WORK_TREE_ENVIRONMENT);
|
||||
if (!git_work_tree)
|
||||
return NULL;
|
||||
if (!getcwd(cwd, sizeof(cwd)))
|
||||
die("Unable to read current working directory");
|
||||
if (chdir(git_work_tree))
|
||||
die("Cannot change directory to specified working tree '%s'",
|
||||
git_work_tree);
|
||||
if (git_work_tree[0] != '/') {
|
||||
if (!getcwd(worktree, sizeof(worktree)))
|
||||
die("Unable to read current working directory");
|
||||
git_work_tree = worktree;
|
||||
}
|
||||
if (chdir(cwd))
|
||||
die("Cannot come back to cwd");
|
||||
return git_work_tree;
|
||||
}
|
||||
|
||||
static int create_default_files(const char *git_dir, const char *git_work_tree,
|
||||
const char *template_path)
|
||||
{
|
||||
unsigned len = strlen(git_dir);
|
||||
static char path[PATH_MAX];
|
||||
@@ -263,7 +292,7 @@ static int create_default_files(const char *git_dir, const char *template_path)
|
||||
}
|
||||
git_config_set("core.filemode", filemode ? "true" : "false");
|
||||
|
||||
if (is_bare_repository()) {
|
||||
if (is_bare_repository() && !git_work_tree) {
|
||||
git_config_set("core.bare", "true");
|
||||
}
|
||||
else {
|
||||
@@ -271,12 +300,14 @@ static int create_default_files(const char *git_dir, const char *template_path)
|
||||
/* allow template config file to override the default */
|
||||
if (log_all_ref_updates == -1)
|
||||
git_config_set("core.logallrefupdates", "true");
|
||||
if (git_work_tree)
|
||||
git_config_set("core.worktree", git_work_tree);
|
||||
}
|
||||
return reinit;
|
||||
}
|
||||
|
||||
static const char init_db_usage[] =
|
||||
"git-init [--template=<template-directory>] [--shared]";
|
||||
"git-init [-q | --quiet] [--template=<template-directory>] [--shared]";
|
||||
|
||||
/*
|
||||
* If you want to, you can share the DB area with any number of branches.
|
||||
@@ -287,10 +318,12 @@ static const char init_db_usage[] =
|
||||
int cmd_init_db(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
const char *git_dir;
|
||||
const char *git_work_tree;
|
||||
const char *sha1_dir;
|
||||
const char *template_dir = NULL;
|
||||
char *path;
|
||||
int len, i, reinit;
|
||||
int quiet = 0;
|
||||
|
||||
for (i = 1; i < argc; i++, argv++) {
|
||||
const char *arg = argv[1];
|
||||
@@ -300,10 +333,14 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
|
||||
shared_repository = PERM_GROUP;
|
||||
else if (!prefixcmp(arg, "--shared="))
|
||||
shared_repository = git_config_perm("arg", arg+9);
|
||||
else if (!strcmp(arg, "-q") || !strcmp(arg, "--quiet"))
|
||||
quiet = 1;
|
||||
else
|
||||
usage(init_db_usage);
|
||||
}
|
||||
|
||||
git_work_tree = get_work_tree();
|
||||
|
||||
/*
|
||||
* Set up the default .git directory contents
|
||||
*/
|
||||
@@ -319,7 +356,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
|
||||
*/
|
||||
check_repository_format();
|
||||
|
||||
reinit = create_default_files(git_dir, template_dir);
|
||||
reinit = create_default_files(git_dir, git_work_tree, template_dir);
|
||||
|
||||
/*
|
||||
* And set up the object store.
|
||||
@@ -346,10 +383,11 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
|
||||
git_config_set("receive.denyNonFastforwards", "true");
|
||||
}
|
||||
|
||||
printf("%s%s Git repository in %s/\n",
|
||||
reinit ? "Reinitialized existing" : "Initialized empty",
|
||||
shared_repository ? " shared" : "",
|
||||
git_dir);
|
||||
if (!quiet)
|
||||
printf("%s%s Git repository in %s/\n",
|
||||
reinit ? "Reinitialized existing" : "Initialized empty",
|
||||
shared_repository ? " shared" : "",
|
||||
git_dir);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "refs.h"
|
||||
|
||||
static int default_show_root = 1;
|
||||
static const char *fmt_patch_subject_prefix = "PATCH";
|
||||
|
||||
/* this is in builtin-diff.c */
|
||||
void add_head(struct rev_info *revs);
|
||||
@@ -55,6 +56,7 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
|
||||
rev->commit_format = CMIT_FMT_DEFAULT;
|
||||
rev->verbose_header = 1;
|
||||
rev->show_root_diff = default_show_root;
|
||||
rev->subject_prefix = fmt_patch_subject_prefix;
|
||||
argc = setup_revisions(argc, argv, rev, "HEAD");
|
||||
if (rev->diffopt.pickaxe || rev->diffopt.filter)
|
||||
rev->always_show_header = 0;
|
||||
@@ -94,6 +96,12 @@ static int cmd_log_walk(struct rev_info *rev)
|
||||
|
||||
static int git_log_config(const char *var, const char *value)
|
||||
{
|
||||
if (!strcmp(var, "format.subjectprefix")) {
|
||||
if (!value)
|
||||
die("format.subjectprefix without value");
|
||||
fmt_patch_subject_prefix = xstrdup(value);
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(var, "log.showroot")) {
|
||||
default_show_root = git_config_bool(var, value);
|
||||
return 0;
|
||||
@@ -290,6 +298,7 @@ static int git_format_config(const char *var, const char *value)
|
||||
if (!strcmp(var, "diff.color") || !strcmp(var, "color.diff")) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return git_log_config(var, value);
|
||||
}
|
||||
|
||||
@@ -459,6 +468,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
|
||||
rev.diffopt.msg_sep = "";
|
||||
rev.diffopt.recursive = 1;
|
||||
|
||||
rev.subject_prefix = fmt_patch_subject_prefix;
|
||||
rev.extra_headers = extra_headers;
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "builtin.h"
|
||||
#include "cache.h"
|
||||
#include "commit.h"
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "builtin.h"
|
||||
#include "cache.h"
|
||||
#include "xdiff/xdiff.h"
|
||||
#include "xdiff-interface.h"
|
||||
@@ -5,9 +6,9 @@
|
||||
static const char merge_file_usage[] =
|
||||
"git merge-file [-p | --stdout] [-q | --quiet] [-L name1 [-L orig [-L name2]]] file1 orig_file file2";
|
||||
|
||||
int cmd_merge_file(int argc, char **argv, char **envp)
|
||||
int cmd_merge_file(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
char *names[3];
|
||||
const char *names[3];
|
||||
mmfile_t mmfs[3];
|
||||
mmbuffer_t result = {NULL, 0};
|
||||
xpparam_t xpp = {XDF_NEED_MINIMAL};
|
||||
@@ -51,7 +52,7 @@ int cmd_merge_file(int argc, char **argv, char **envp)
|
||||
free(mmfs[i].ptr);
|
||||
|
||||
if (ret >= 0) {
|
||||
char *filename = argv[1];
|
||||
const char *filename = argv[1];
|
||||
FILE *f = to_stdout ? stdout : fopen(filename, "wb");
|
||||
|
||||
if (!f)
|
||||
|
||||
@@ -16,8 +16,9 @@
|
||||
#include "progress.h"
|
||||
|
||||
static const char pack_usage[] = "\
|
||||
git-pack-objects [{ -q | --progress | --all-progress }] [--max-pack-size=N] \n\
|
||||
[--local] [--incremental] [--window=N] [--depth=N] \n\
|
||||
git-pack-objects [{ -q | --progress | --all-progress }] \n\
|
||||
[--max-pack-size=N] [--local] [--incremental] \n\
|
||||
[--window=N] [--window-memory=N] [--depth=N] \n\
|
||||
[--no-reuse-delta] [--no-reuse-object] [--delta-base-offset] \n\
|
||||
[--non-empty] [--revs [--unpacked | --all]*] [--reflog] \n\
|
||||
[--stdout | base-name] [<ref-list | <object-list]";
|
||||
@@ -25,9 +26,6 @@ git-pack-objects [{ -q | --progress | --all-progress }] [--max-pack-size=N] \n\
|
||||
struct object_entry {
|
||||
struct pack_idx_entry idx;
|
||||
unsigned long size; /* uncompressed size */
|
||||
|
||||
unsigned int hash; /* name hint hash */
|
||||
unsigned int depth; /* delta depth */
|
||||
struct packed_git *in_pack; /* already in pack */
|
||||
off_t in_pack_offset;
|
||||
struct object_entry *delta; /* delta base object */
|
||||
@@ -37,6 +35,7 @@ struct object_entry {
|
||||
*/
|
||||
void *delta_data; /* cached delta (uncompressed) */
|
||||
unsigned long delta_size; /* delta data size (uncompressed) */
|
||||
unsigned int hash; /* name hint hash */
|
||||
enum object_type type;
|
||||
enum object_type in_pack_type; /* could be delta */
|
||||
unsigned char in_pack_header_size;
|
||||
@@ -79,6 +78,9 @@ static unsigned long delta_cache_size = 0;
|
||||
static unsigned long max_delta_cache_size = 0;
|
||||
static unsigned long cache_max_small_delta_size = 1000;
|
||||
|
||||
static unsigned long window_memory_usage = 0;
|
||||
static unsigned long window_memory_limit = 0;
|
||||
|
||||
/*
|
||||
* The object names in objects array are hashed with this hashtable,
|
||||
* to help looking up the entry by object name.
|
||||
@@ -1270,6 +1272,7 @@ struct unpacked {
|
||||
struct object_entry *entry;
|
||||
void *data;
|
||||
struct delta_index *index;
|
||||
unsigned depth;
|
||||
};
|
||||
|
||||
static int delta_cacheable(struct unpacked *trg, struct unpacked *src,
|
||||
@@ -1303,6 +1306,7 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
|
||||
struct object_entry *trg_entry = trg->entry;
|
||||
struct object_entry *src_entry = src->entry;
|
||||
unsigned long trg_size, src_size, delta_size, sizediff, max_size, sz;
|
||||
unsigned ref_depth;
|
||||
enum object_type type;
|
||||
void *delta_buf;
|
||||
|
||||
@@ -1327,21 +1331,28 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
|
||||
return 0;
|
||||
|
||||
/* Let's not bust the allowed depth. */
|
||||
if (src_entry->depth >= max_depth)
|
||||
if (src->depth >= max_depth)
|
||||
return 0;
|
||||
|
||||
/* Now some size filtering heuristics. */
|
||||
trg_size = trg_entry->size;
|
||||
max_size = trg_size/2 - 20;
|
||||
max_size = max_size * (max_depth - src_entry->depth) / max_depth;
|
||||
if (!trg_entry->delta) {
|
||||
max_size = trg_size/2 - 20;
|
||||
ref_depth = 1;
|
||||
} else {
|
||||
max_size = trg_entry->delta_size;
|
||||
ref_depth = trg->depth;
|
||||
}
|
||||
max_size = max_size * (max_depth - src->depth) /
|
||||
(max_depth - ref_depth + 1);
|
||||
if (max_size == 0)
|
||||
return 0;
|
||||
if (trg_entry->delta && trg_entry->delta_size <= max_size)
|
||||
max_size = trg_entry->delta_size-1;
|
||||
src_size = src_entry->size;
|
||||
sizediff = src_size < trg_size ? trg_size - src_size : 0;
|
||||
if (sizediff >= max_size)
|
||||
return 0;
|
||||
if (trg_size < src_size / 32)
|
||||
return 0;
|
||||
|
||||
/* Load data if not already done */
|
||||
if (!trg->data) {
|
||||
@@ -1349,12 +1360,14 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
|
||||
if (sz != trg_size)
|
||||
die("object %s inconsistent object length (%lu vs %lu)",
|
||||
sha1_to_hex(trg_entry->idx.sha1), sz, trg_size);
|
||||
window_memory_usage += sz;
|
||||
}
|
||||
if (!src->data) {
|
||||
src->data = read_sha1_file(src_entry->idx.sha1, &type, &sz);
|
||||
if (sz != src_size)
|
||||
die("object %s inconsistent object length (%lu vs %lu)",
|
||||
sha1_to_hex(src_entry->idx.sha1), sz, src_size);
|
||||
window_memory_usage += sz;
|
||||
}
|
||||
if (!src->index) {
|
||||
src->index = create_delta_index(src->data, src_size);
|
||||
@@ -1364,6 +1377,7 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
|
||||
warning("suboptimal pack - out of memory");
|
||||
return 0;
|
||||
}
|
||||
window_memory_usage += sizeof_delta_index(src->index);
|
||||
}
|
||||
|
||||
delta_buf = create_delta(src->index, trg->data, trg_size, &delta_size, max_size);
|
||||
@@ -1371,13 +1385,19 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
|
||||
return 0;
|
||||
|
||||
if (trg_entry->delta_data) {
|
||||
/* Prefer only shallower same-sized deltas. */
|
||||
if (delta_size == trg_entry->delta_size &&
|
||||
src->depth + 1 >= trg->depth) {
|
||||
free(delta_buf);
|
||||
return 0;
|
||||
}
|
||||
delta_cache_size -= trg_entry->delta_size;
|
||||
free(trg_entry->delta_data);
|
||||
trg_entry->delta_data = NULL;
|
||||
}
|
||||
trg_entry->delta_data = 0;
|
||||
trg_entry->delta = src_entry;
|
||||
trg_entry->delta_size = delta_size;
|
||||
trg_entry->depth = src_entry->depth + 1;
|
||||
trg->depth = src->depth + 1;
|
||||
|
||||
if (delta_cacheable(src, trg, src_size, trg_size, delta_size)) {
|
||||
trg_entry->delta_data = xrealloc(delta_buf, delta_size);
|
||||
@@ -1400,9 +1420,23 @@ static unsigned int check_delta_limit(struct object_entry *me, unsigned int n)
|
||||
return m;
|
||||
}
|
||||
|
||||
static void free_unpacked(struct unpacked *n)
|
||||
{
|
||||
window_memory_usage -= sizeof_delta_index(n->index);
|
||||
free_delta_index(n->index);
|
||||
n->index = NULL;
|
||||
if (n->data) {
|
||||
free(n->data);
|
||||
n->data = NULL;
|
||||
window_memory_usage -= n->entry->size;
|
||||
}
|
||||
n->entry = NULL;
|
||||
n->depth = 0;
|
||||
}
|
||||
|
||||
static void find_deltas(struct object_entry **list, int window, int depth)
|
||||
{
|
||||
uint32_t i = nr_objects, idx = 0, processed = 0;
|
||||
uint32_t i = nr_objects, idx = 0, count = 0, processed = 0;
|
||||
unsigned int array_size = window * sizeof(struct unpacked);
|
||||
struct unpacked *array;
|
||||
int max_depth;
|
||||
@@ -1437,12 +1471,17 @@ static void find_deltas(struct object_entry **list, int window, int depth)
|
||||
if (entry->no_try_delta)
|
||||
continue;
|
||||
|
||||
free_delta_index(n->index);
|
||||
n->index = NULL;
|
||||
free(n->data);
|
||||
n->data = NULL;
|
||||
free_unpacked(n);
|
||||
n->entry = entry;
|
||||
|
||||
while (window_memory_limit &&
|
||||
window_memory_usage > window_memory_limit &&
|
||||
count > 1) {
|
||||
uint32_t tail = (idx + window - count) % window;
|
||||
free_unpacked(array + tail);
|
||||
count--;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the current object is at pack edge, take the depth the
|
||||
* objects that depend on the current object into account
|
||||
@@ -1472,11 +1511,13 @@ static void find_deltas(struct object_entry **list, int window, int depth)
|
||||
* depth, leaving it in the window is pointless. we
|
||||
* should evict it first.
|
||||
*/
|
||||
if (entry->delta && depth <= entry->depth)
|
||||
if (entry->delta && depth <= n->depth)
|
||||
continue;
|
||||
|
||||
next:
|
||||
idx++;
|
||||
if (count + 1 < window)
|
||||
count++;
|
||||
if (idx >= window)
|
||||
idx = 0;
|
||||
} while (i > 0);
|
||||
@@ -1515,7 +1556,11 @@ static int git_pack_config(const char *k, const char *v)
|
||||
window = git_config_int(k, v);
|
||||
return 0;
|
||||
}
|
||||
if(!strcmp(k, "pack.depth")) {
|
||||
if (!strcmp(k, "pack.windowmemory")) {
|
||||
window_memory_limit = git_config_ulong(k, v);
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(k, "pack.depth")) {
|
||||
depth = git_config_int(k, v);
|
||||
return 0;
|
||||
}
|
||||
@@ -1691,6 +1736,11 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
|
||||
usage(pack_usage);
|
||||
continue;
|
||||
}
|
||||
if (!prefixcmp(arg, "--window-memory=")) {
|
||||
if (!git_parse_ulong(arg+16, &window_memory_limit))
|
||||
usage(pack_usage);
|
||||
continue;
|
||||
}
|
||||
if (!prefixcmp(arg, "--depth=")) {
|
||||
char *end;
|
||||
depth = strtoul(arg+8, &end, 0);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "builtin.h"
|
||||
#include "cache.h"
|
||||
#include "refs.h"
|
||||
#include "object.h"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "builtin.h"
|
||||
#include "cache.h"
|
||||
#include "path-list.h"
|
||||
#include "xdiff/xdiff.h"
|
||||
@@ -12,6 +13,9 @@ static const char git_rerere_usage[] =
|
||||
static int cutoff_noresolve = 15;
|
||||
static int cutoff_resolve = 60;
|
||||
|
||||
/* if rerere_enabled == -1, fall back to detection of .git/rr-cache */
|
||||
static int rerere_enabled = -1;
|
||||
|
||||
static char *merge_rr_path;
|
||||
|
||||
static const char *rr_path(const char *name, const char *file)
|
||||
@@ -165,19 +169,16 @@ static int find_conflict(struct path_list *conflict)
|
||||
int i;
|
||||
if (read_cache() < 0)
|
||||
return error("Could not read index");
|
||||
for (i = 0; i + 2 < active_nr; i++) {
|
||||
struct cache_entry *e1 = active_cache[i];
|
||||
struct cache_entry *e2 = active_cache[i+1];
|
||||
struct cache_entry *e3 = active_cache[i+2];
|
||||
if (ce_stage(e1) == 1 &&
|
||||
ce_stage(e2) == 2 &&
|
||||
for (i = 0; i+1 < active_nr; i++) {
|
||||
struct cache_entry *e2 = active_cache[i];
|
||||
struct cache_entry *e3 = active_cache[i+1];
|
||||
if (ce_stage(e2) == 2 &&
|
||||
ce_stage(e3) == 3 &&
|
||||
ce_same_name(e1, e2) && ce_same_name(e1, e3) &&
|
||||
S_ISREG(ntohl(e1->ce_mode)) &&
|
||||
ce_same_name(e2, e3) &&
|
||||
S_ISREG(ntohl(e2->ce_mode)) &&
|
||||
S_ISREG(ntohl(e3->ce_mode))) {
|
||||
path_list_insert((const char *)e1->name, conflict);
|
||||
i += 2;
|
||||
path_list_insert((const char *)e2->name, conflict);
|
||||
i++; /* skip over both #2 and #3 */
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -282,8 +283,8 @@ static int diff_two(const char *file1, const char *label1,
|
||||
printf("--- a/%s\n+++ b/%s\n", label1, label2);
|
||||
fflush(stdout);
|
||||
xpp.flags = XDF_NEED_MINIMAL;
|
||||
memset(&xecfg, 0, sizeof(xecfg));
|
||||
xecfg.ctxlen = 3;
|
||||
xecfg.flags = 0;
|
||||
ecb.outf = outf;
|
||||
xdl_diff(&minus, &plus, &xpp, &xecfg, &ecb);
|
||||
|
||||
@@ -387,21 +388,41 @@ static int git_rerere_config(const char *var, const char *value)
|
||||
cutoff_resolve = git_config_int(var, value);
|
||||
else if (!strcmp(var, "gc.rerereunresolved"))
|
||||
cutoff_noresolve = git_config_int(var, value);
|
||||
else if (!strcmp(var, "rerere.enabled"))
|
||||
rerere_enabled = git_config_bool(var, value);
|
||||
else
|
||||
return git_default_config(var, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_rerere_enabled(void)
|
||||
{
|
||||
struct stat st;
|
||||
const char *rr_cache;
|
||||
int rr_cache_exists;
|
||||
|
||||
if (!rerere_enabled)
|
||||
return 0;
|
||||
|
||||
rr_cache = git_path("rr-cache");
|
||||
rr_cache_exists = !stat(rr_cache, &st) && S_ISDIR(st.st_mode);
|
||||
if (rerere_enabled < 0)
|
||||
return rr_cache_exists;
|
||||
|
||||
if (!rr_cache_exists &&
|
||||
(mkdir(rr_cache, 0777) || adjust_shared_perm(rr_cache)))
|
||||
die("Could not create directory %s", rr_cache);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cmd_rerere(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct path_list merge_rr = { NULL, 0, 0, 1 };
|
||||
int i, fd = -1;
|
||||
struct stat st;
|
||||
|
||||
if (stat(git_path("rr-cache"), &st) || !S_ISDIR(st.st_mode))
|
||||
return 0;
|
||||
|
||||
git_config(git_rerere_config);
|
||||
if (!is_rerere_enabled())
|
||||
return 0;
|
||||
|
||||
merge_rr_path = xstrdup(git_path("rr-cache/MERGE_RR"));
|
||||
fd = hold_lock_file_for_update(&write_lock, merge_rr_path, 1);
|
||||
@@ -411,6 +432,7 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)
|
||||
return do_plain_rerere(&merge_rr, fd);
|
||||
else if (!strcmp(argv[1], "clear")) {
|
||||
for (i = 0; i < merge_rr.nr; i++) {
|
||||
struct stat st;
|
||||
const char *name = (const char *)merge_rr.items[i].util;
|
||||
if (!stat(git_path("rr-cache/%s", name), &st) &&
|
||||
S_ISDIR(st.st_mode) &&
|
||||
|
||||
@@ -70,21 +70,9 @@ static void show_commit(struct commit *commit)
|
||||
if (revs.parents) {
|
||||
struct commit_list *parents = commit->parents;
|
||||
while (parents) {
|
||||
struct object *o = &(parents->item->object);
|
||||
printf(" %s", sha1_to_hex(parents->item->object.sha1));
|
||||
parents = parents->next;
|
||||
if (o->flags & TMP_MARK)
|
||||
continue;
|
||||
printf(" %s", sha1_to_hex(o->sha1));
|
||||
o->flags |= TMP_MARK;
|
||||
}
|
||||
/* TMP_MARK is a general purpose flag that can
|
||||
* be used locally, but the user should clean
|
||||
* things up after it is done with them.
|
||||
*/
|
||||
for (parents = commit->parents;
|
||||
parents;
|
||||
parents = parents->next)
|
||||
parents->item->object.flags &= ~TMP_MARK;
|
||||
}
|
||||
if (revs.commit_format == CMIT_FMT_ONELINE)
|
||||
putchar(' ');
|
||||
|
||||
32
builtin-rm.c
32
builtin-rm.c
@@ -46,7 +46,7 @@ static int remove_file(const char *name)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int check_local_mod(unsigned char *head)
|
||||
static int check_local_mod(unsigned char *head, int index_only)
|
||||
{
|
||||
/* items in list are already sorted in the cache order,
|
||||
* so we could do this a lot more efficiently by using
|
||||
@@ -65,6 +65,8 @@ static int check_local_mod(unsigned char *head)
|
||||
const char *name = list.name[i];
|
||||
unsigned char sha1[20];
|
||||
unsigned mode;
|
||||
int local_changes = 0;
|
||||
int staged_changes = 0;
|
||||
|
||||
pos = cache_name_pos(name, strlen(name));
|
||||
if (pos < 0)
|
||||
@@ -87,14 +89,32 @@ static int check_local_mod(unsigned char *head)
|
||||
continue;
|
||||
}
|
||||
if (ce_match_stat(ce, &st, 0))
|
||||
errs = error("'%s' has local modifications "
|
||||
"(hint: try -f)", ce->name);
|
||||
local_changes = 1;
|
||||
if (no_head
|
||||
|| get_tree_entry(head, name, sha1, &mode)
|
||||
|| ce->ce_mode != create_ce_mode(mode)
|
||||
|| hashcmp(ce->sha1, sha1))
|
||||
errs = error("'%s' has changes staged in the index "
|
||||
"(hint: try -f)", name);
|
||||
staged_changes = 1;
|
||||
|
||||
if (local_changes && staged_changes)
|
||||
errs = error("'%s' has staged content different "
|
||||
"from both the file and the HEAD\n"
|
||||
"(use -f to force removal)", name);
|
||||
else if (!index_only) {
|
||||
/* It's not dangerous to git-rm --cached a
|
||||
* file if the index matches the file or the
|
||||
* HEAD, since it means the deleted content is
|
||||
* still available somewhere.
|
||||
*/
|
||||
if (staged_changes)
|
||||
errs = error("'%s' has changes staged in the index\n"
|
||||
"(use --cached to keep the file, "
|
||||
"or -f to force removal)", name);
|
||||
if (local_changes)
|
||||
errs = error("'%s' has local modifications\n"
|
||||
"(use --cached to keep the file, "
|
||||
"or -f to force removal)", name);
|
||||
}
|
||||
}
|
||||
return errs;
|
||||
}
|
||||
@@ -192,7 +212,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
|
||||
unsigned char sha1[20];
|
||||
if (get_sha1("HEAD", sha1))
|
||||
hashclr(sha1);
|
||||
if (check_local_mod(sha1))
|
||||
if (check_local_mod(sha1, index_only))
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "builtin.h"
|
||||
#include "cache.h"
|
||||
#include "wt-status.h"
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "builtin.h"
|
||||
#include "cache.h"
|
||||
#include "refs.h"
|
||||
#include "object.h"
|
||||
|
||||
@@ -2,12 +2,11 @@
|
||||
#include "cache.h"
|
||||
|
||||
/*
|
||||
* Remove trailing spaces from a line.
|
||||
* Returns the length of a line, without trailing spaces.
|
||||
*
|
||||
* If the line ends with newline, it will be removed too.
|
||||
* Returns the new length of the string.
|
||||
*/
|
||||
static int cleanup(char *line, int len)
|
||||
static size_t cleanup(char *line, size_t len)
|
||||
{
|
||||
if (len) {
|
||||
if (line[len - 1] == '\n')
|
||||
@@ -19,7 +18,6 @@ static int cleanup(char *line, int len)
|
||||
break;
|
||||
len--;
|
||||
}
|
||||
line[len] = 0;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
@@ -28,52 +26,67 @@ static int cleanup(char *line, int len)
|
||||
* Remove empty lines from the beginning and end
|
||||
* and also trailing spaces from every line.
|
||||
*
|
||||
* Note that the buffer will not be NUL-terminated.
|
||||
*
|
||||
* Turn multiple consecutive empty lines between paragraphs
|
||||
* into just one empty line.
|
||||
*
|
||||
* If the input has only empty lines and spaces,
|
||||
* no output will be produced.
|
||||
*
|
||||
* If last line has a newline at the end, it will be removed.
|
||||
*
|
||||
* Enable skip_comments to skip every line starting with "#".
|
||||
*/
|
||||
void stripspace(FILE *in, FILE *out, int skip_comments)
|
||||
size_t stripspace(char *buffer, size_t length, int skip_comments)
|
||||
{
|
||||
int empties = -1;
|
||||
int alloc = 1024;
|
||||
char *line = xmalloc(alloc);
|
||||
size_t i, j, len, newlen;
|
||||
char *eol;
|
||||
|
||||
while (fgets(line, alloc, in)) {
|
||||
int len = strlen(line);
|
||||
for (i = j = 0; i < length; i += len, j += newlen) {
|
||||
eol = memchr(buffer + i, '\n', length - i);
|
||||
len = eol ? eol - (buffer + i) + 1 : length - i;
|
||||
|
||||
while (len == alloc - 1 && line[len - 1] != '\n') {
|
||||
alloc = alloc_nr(alloc);
|
||||
line = xrealloc(line, alloc);
|
||||
fgets(line + len, alloc - len, in);
|
||||
len += strlen(line + len);
|
||||
}
|
||||
|
||||
if (skip_comments && line[0] == '#')
|
||||
if (skip_comments && len && buffer[i] == '#') {
|
||||
newlen = 0;
|
||||
continue;
|
||||
len = cleanup(line, len);
|
||||
}
|
||||
newlen = cleanup(buffer + i, len);
|
||||
|
||||
/* Not just an empty line? */
|
||||
if (len) {
|
||||
if (newlen) {
|
||||
if (empties != -1)
|
||||
buffer[j++] = '\n';
|
||||
if (empties > 0)
|
||||
fputc('\n', out);
|
||||
buffer[j++] = '\n';
|
||||
empties = 0;
|
||||
fputs(line, out);
|
||||
fputc('\n', out);
|
||||
memmove(buffer + j, buffer + i, newlen);
|
||||
continue;
|
||||
}
|
||||
if (empties < 0)
|
||||
continue;
|
||||
empties++;
|
||||
}
|
||||
free(line);
|
||||
|
||||
return j;
|
||||
}
|
||||
|
||||
int cmd_stripspace(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
stripspace(stdin, stdout, 0);
|
||||
char *buffer;
|
||||
unsigned long size;
|
||||
|
||||
size = 1024;
|
||||
buffer = xmalloc(size);
|
||||
if (read_pipe(0, &buffer, &size))
|
||||
die("could not read the input");
|
||||
|
||||
size = stripspace(buffer, size, 0);
|
||||
write_or_die(1, buffer, size);
|
||||
if (size)
|
||||
putc('\n', stdout);
|
||||
|
||||
free(buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ extern const char git_version_string[];
|
||||
extern const char git_usage_string[];
|
||||
|
||||
extern void help_unknown_cmd(const char *cmd);
|
||||
extern void stripspace(FILE *in, FILE *out, int skip_comments);
|
||||
extern size_t stripspace(char *buffer, size_t length, int skip_comments);
|
||||
extern int write_tree(unsigned char *sha1, int missing_ok, const char *prefix);
|
||||
extern void prune_packed_objects(int);
|
||||
|
||||
|
||||
16
cache.h
16
cache.h
@@ -295,6 +295,7 @@ extern int delete_ref(const char *, const unsigned char *sha1);
|
||||
|
||||
/* Environment bits from configuration mechanism */
|
||||
extern int trust_executable_bit;
|
||||
extern int quote_path_fully;
|
||||
extern int has_symlinks;
|
||||
extern int assume_unchanged;
|
||||
extern int prefer_symlink_refs;
|
||||
@@ -409,9 +410,16 @@ extern void *read_object_with_reference(const unsigned char *sha1,
|
||||
unsigned long *size,
|
||||
unsigned char *sha1_ret);
|
||||
|
||||
enum date_mode { DATE_NORMAL = 0, DATE_RELATIVE, DATE_SHORT, DATE_LOCAL };
|
||||
enum date_mode {
|
||||
DATE_NORMAL = 0,
|
||||
DATE_RELATIVE,
|
||||
DATE_SHORT,
|
||||
DATE_LOCAL,
|
||||
DATE_ISO8601,
|
||||
DATE_RFC2822
|
||||
};
|
||||
|
||||
const char *show_date(unsigned long time, int timezone, enum date_mode mode);
|
||||
const char *show_rfc2822_date(unsigned long time, int timezone);
|
||||
int parse_date(const char *date, char *buf, int bufsize);
|
||||
void datestamp(char *buf, int bufsize);
|
||||
unsigned long approxidate(const char *);
|
||||
@@ -521,7 +529,10 @@ typedef int (*config_fn_t)(const char *, const char *);
|
||||
extern int git_default_config(const char *, const char *);
|
||||
extern int git_config_from_file(config_fn_t fn, const char *);
|
||||
extern int git_config(config_fn_t fn);
|
||||
extern int git_parse_long(const char *, long *);
|
||||
extern int git_parse_ulong(const char *, unsigned long *);
|
||||
extern int git_config_int(const char *, const char *);
|
||||
extern unsigned long git_config_ulong(const char *, const char *);
|
||||
extern int git_config_bool(const char *, const char *);
|
||||
extern int git_config_set(const char *, const char *);
|
||||
extern int git_config_set_multivar(const char *, const char *, const char *, int);
|
||||
@@ -547,6 +558,7 @@ extern int write_or_whine_pipe(int fd, const void *buf, size_t count, const char
|
||||
|
||||
/* pager.c */
|
||||
extern void setup_pager(void);
|
||||
extern char *pager_program;
|
||||
extern int pager_in_use;
|
||||
extern int pager_use_color;
|
||||
|
||||
|
||||
@@ -215,8 +215,7 @@ static void combine_diff(const unsigned char *parent, mmfile_t *result_file,
|
||||
parent_file.ptr = grab_blob(parent, &sz);
|
||||
parent_file.size = sz;
|
||||
xpp.flags = XDF_NEED_MINIMAL;
|
||||
xecfg.ctxlen = 0;
|
||||
xecfg.flags = 0;
|
||||
memset(&xecfg, 0, sizeof(xecfg));
|
||||
ecb.outf = xdiff_outf;
|
||||
ecb.priv = &state;
|
||||
memset(&state, 0, sizeof(state));
|
||||
|
||||
14
commit.c
14
commit.c
@@ -585,7 +585,7 @@ static int add_user_info(const char *what, enum cmit_fmt fmt, char *buf,
|
||||
break;
|
||||
case CMIT_FMT_EMAIL:
|
||||
ret += sprintf(buf + ret, "Date: %s\n",
|
||||
show_rfc2822_date(time, tz));
|
||||
show_date(time, tz, DATE_RFC2822));
|
||||
break;
|
||||
case CMIT_FMT_FULLER:
|
||||
ret += sprintf(buf + ret, "%sDate: %s\n", what,
|
||||
@@ -778,9 +778,10 @@ static void fill_person(struct interp *table, const char *msg, int len)
|
||||
tz = -tz;
|
||||
}
|
||||
|
||||
interp_set_entry(table, 2, show_date(date, tz, 0));
|
||||
interp_set_entry(table, 3, show_rfc2822_date(date, tz));
|
||||
interp_set_entry(table, 4, show_date(date, tz, 1));
|
||||
interp_set_entry(table, 2, show_date(date, tz, DATE_NORMAL));
|
||||
interp_set_entry(table, 3, show_date(date, tz, DATE_RFC2822));
|
||||
interp_set_entry(table, 4, show_date(date, tz, DATE_RELATIVE));
|
||||
interp_set_entry(table, 6, show_date(date, tz, DATE_ISO8601));
|
||||
}
|
||||
|
||||
static long format_commit_message(const struct commit *commit,
|
||||
@@ -799,12 +800,14 @@ static long format_commit_message(const struct commit *commit,
|
||||
{ "%aD" }, /* author date, RFC2822 style */
|
||||
{ "%ar" }, /* author date, relative */
|
||||
{ "%at" }, /* author date, UNIX timestamp */
|
||||
{ "%ai" }, /* author date, ISO 8601 */
|
||||
{ "%cn" }, /* committer name */
|
||||
{ "%ce" }, /* committer email */
|
||||
{ "%cd" }, /* committer date */
|
||||
{ "%cD" }, /* committer date, RFC2822 style */
|
||||
{ "%cr" }, /* committer date, relative */
|
||||
{ "%ct" }, /* committer date, UNIX timestamp */
|
||||
{ "%ci" }, /* committer date, ISO 8601 */
|
||||
{ "%e" }, /* encoding */
|
||||
{ "%s" }, /* subject */
|
||||
{ "%b" }, /* body */
|
||||
@@ -821,10 +824,11 @@ static long format_commit_message(const struct commit *commit,
|
||||
IPARENTS, IPARENTS_ABBREV,
|
||||
IAUTHOR_NAME, IAUTHOR_EMAIL,
|
||||
IAUTHOR_DATE, IAUTHOR_DATE_RFC2822, IAUTHOR_DATE_RELATIVE,
|
||||
IAUTHOR_TIMESTAMP,
|
||||
IAUTHOR_TIMESTAMP, IAUTHOR_ISO8601,
|
||||
ICOMMITTER_NAME, ICOMMITTER_EMAIL,
|
||||
ICOMMITTER_DATE, ICOMMITTER_DATE_RFC2822,
|
||||
ICOMMITTER_DATE_RELATIVE, ICOMMITTER_TIMESTAMP,
|
||||
ICOMMITTER_ISO8601,
|
||||
IENCODING,
|
||||
ISUBJECT,
|
||||
IBODY,
|
||||
|
||||
66
config.c
66
config.c
@@ -234,21 +234,55 @@ static int git_parse_file(config_fn_t fn)
|
||||
die("bad config file line %d in %s", config_linenr, config_file_name);
|
||||
}
|
||||
|
||||
int git_config_int(const char *name, const char *value)
|
||||
static unsigned long get_unit_factor(const char *end)
|
||||
{
|
||||
if (!*end)
|
||||
return 1;
|
||||
else if (!strcasecmp(end, "k"))
|
||||
return 1024;
|
||||
else if (!strcasecmp(end, "m"))
|
||||
return 1024 * 1024;
|
||||
else if (!strcasecmp(end, "g"))
|
||||
return 1024 * 1024 * 1024;
|
||||
die("unknown unit: '%s'", end);
|
||||
}
|
||||
|
||||
int git_parse_long(const char *value, long *ret)
|
||||
{
|
||||
if (value && *value) {
|
||||
char *end;
|
||||
int val = strtol(value, &end, 0);
|
||||
if (!*end)
|
||||
return val;
|
||||
if (!strcasecmp(end, "k"))
|
||||
return val * 1024;
|
||||
if (!strcasecmp(end, "m"))
|
||||
return val * 1024 * 1024;
|
||||
if (!strcasecmp(end, "g"))
|
||||
return val * 1024 * 1024 * 1024;
|
||||
long val = strtol(value, &end, 0);
|
||||
*ret = val * get_unit_factor(end);
|
||||
return 1;
|
||||
}
|
||||
die("bad config value for '%s' in %s", name, config_file_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_parse_ulong(const char *value, unsigned long *ret)
|
||||
{
|
||||
if (value && *value) {
|
||||
char *end;
|
||||
unsigned long val = strtoul(value, &end, 0);
|
||||
*ret = val * get_unit_factor(end);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_config_int(const char *name, const char *value)
|
||||
{
|
||||
long ret;
|
||||
if (!git_parse_long(value, &ret))
|
||||
die("bad config value for '%s' in %s", name, config_file_name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned long git_config_ulong(const char *name, const char *value)
|
||||
{
|
||||
unsigned long ret;
|
||||
if (!git_parse_ulong(value, &ret))
|
||||
die("bad config value for '%s' in %s", name, config_file_name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int git_config_bool(const char *name, const char *value)
|
||||
@@ -272,6 +306,11 @@ int git_default_config(const char *var, const char *value)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(var, "core.quotepath")) {
|
||||
quote_path_fully = git_config_bool(var, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(var, "core.symlinks")) {
|
||||
has_symlinks = git_config_bool(var, value);
|
||||
return 0;
|
||||
@@ -383,6 +422,11 @@ int git_default_config(const char *var, const char *value)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(var, "core.pager")) {
|
||||
pager_program = xstrdup(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Add other config variables here and to Documentation/config.txt. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ struct ref **get_remote_heads(int in, struct ref **list,
|
||||
continue;
|
||||
if (nr_match && !path_match(name, nr_match, match))
|
||||
continue;
|
||||
ref = xcalloc(1, sizeof(*ref) + len - 40);
|
||||
ref = alloc_ref(len - 40);
|
||||
hashcpy(ref->old_sha1, old_sha1);
|
||||
memcpy(ref->name, buffer + 41, len - 40);
|
||||
*list = ref;
|
||||
|
||||
@@ -7,6 +7,7 @@ INSTALL ?= install
|
||||
INSTALL_ELC = $(INSTALL) -m 644
|
||||
prefix ?= $(HOME)
|
||||
emacsdir = $(prefix)/share/emacs/site-lisp
|
||||
RM ?= rm -f
|
||||
|
||||
all: $(ELC)
|
||||
|
||||
@@ -17,4 +18,4 @@ install: all
|
||||
%.elc: %.el
|
||||
$(EMACS) -batch -f batch-byte-compile $<
|
||||
|
||||
clean:; rm -f $(ELC)
|
||||
clean:; $(RM) $(ELC)
|
||||
|
||||
@@ -681,8 +681,7 @@ and returns the process output as a string."
|
||||
(condition-case nil (delete-file ".git/MERGE_MSG") (error nil))
|
||||
(with-current-buffer buffer (erase-buffer))
|
||||
(git-set-files-state files 'uptodate)
|
||||
(when (file-directory-p ".git/rr-cache")
|
||||
(git-run-command nil nil "rerere"))
|
||||
(git-run-command nil nil "rerere")
|
||||
(git-refresh-files)
|
||||
(git-refresh-ewoc-hf git-status)
|
||||
(message "Committed %s." commit)
|
||||
|
||||
@@ -81,6 +81,71 @@
|
||||
(match-string 2 str)
|
||||
str)))
|
||||
|
||||
(defun vc-git-symbolic-commit (commit)
|
||||
"Translate COMMIT string into symbolic form.
|
||||
Returns nil if not possible."
|
||||
(and commit
|
||||
(with-temp-buffer
|
||||
(and
|
||||
(zerop
|
||||
(call-process "git" nil '(t nil) nil "name-rev"
|
||||
"--name-only" "--tags"
|
||||
commit))
|
||||
(goto-char (point-min))
|
||||
(= (forward-line 2) 1)
|
||||
(bolp)
|
||||
(buffer-substring-no-properties (point-min) (1- (point-max)))))))
|
||||
|
||||
(defun vc-git-previous-version (file rev)
|
||||
"git-specific version of `vc-previous-version'."
|
||||
(let ((default-directory (file-name-directory (expand-file-name file)))
|
||||
(file (file-name-nondirectory file)))
|
||||
(vc-git-symbolic-commit
|
||||
(with-temp-buffer
|
||||
(and
|
||||
(zerop
|
||||
(call-process "git" nil '(t nil) nil "rev-list"
|
||||
"-2" rev "--" file))
|
||||
(goto-char (point-max))
|
||||
(bolp)
|
||||
(zerop (forward-line -1))
|
||||
(not (bobp))
|
||||
(buffer-substring-no-properties
|
||||
(point)
|
||||
(1- (point-max))))))))
|
||||
|
||||
(defun vc-git-next-version (file rev)
|
||||
"git-specific version of `vc-next-version'."
|
||||
(let* ((default-directory (file-name-directory
|
||||
(expand-file-name file)))
|
||||
(file (file-name-nondirectory file))
|
||||
(current-rev
|
||||
(with-temp-buffer
|
||||
(and
|
||||
(zerop
|
||||
(call-process "git" nil '(t nil) nil "rev-list"
|
||||
"-1" rev "--" file))
|
||||
(goto-char (point-max))
|
||||
(bolp)
|
||||
(zerop (forward-line -1))
|
||||
(bobp)
|
||||
(buffer-substring-no-properties
|
||||
(point)
|
||||
(1- (point-max)))))))
|
||||
(and current-rev
|
||||
(vc-git-symbolic-commit
|
||||
(with-temp-buffer
|
||||
(and
|
||||
(zerop
|
||||
(call-process "git" nil '(t nil) nil "rev-list"
|
||||
"HEAD" "--" file))
|
||||
(goto-char (point-min))
|
||||
(search-forward current-rev nil t)
|
||||
(zerop (forward-line -1))
|
||||
(buffer-substring-no-properties
|
||||
(point)
|
||||
(progn (forward-line 1) (1- (point))))))))))
|
||||
|
||||
(defun vc-git-revert (file &optional contents-done)
|
||||
"Revert FILE to the version stored in the git repository."
|
||||
(if contents-done
|
||||
|
||||
@@ -30,8 +30,8 @@ notbare|"")
|
||||
esac
|
||||
|
||||
test "true" != "$pack_refs" ||
|
||||
git-pack-refs --prune &&
|
||||
git-reflog expire --all &&
|
||||
git pack-refs --prune &&
|
||||
git reflog expire --all &&
|
||||
git-repack -a -d -l &&
|
||||
$no_prune git-prune &&
|
||||
git-rerere gc || exit
|
||||
$no_prune git prune &&
|
||||
git rerere gc || exit
|
||||
|
||||
@@ -17,8 +17,8 @@ dropheads() {
|
||||
"$GIT_DIR/LAST_MERGE" || exit 1
|
||||
}
|
||||
|
||||
head=$(git-rev-parse --verify "$1"^0) &&
|
||||
merge=$(git-rev-parse --verify "$2"^0) &&
|
||||
head=$(git rev-parse --verify "$1"^0) &&
|
||||
merge=$(git rev-parse --verify "$2"^0) &&
|
||||
merge_name="$2" &&
|
||||
merge_msg="$3" || usage
|
||||
|
||||
@@ -34,7 +34,7 @@ dropheads
|
||||
echo $head > "$GIT_DIR"/ORIG_HEAD
|
||||
echo $merge > "$GIT_DIR"/LAST_MERGE
|
||||
|
||||
common=$(git-merge-base $head $merge)
|
||||
common=$(git merge-base $head $merge)
|
||||
if [ -z "$common" ]; then
|
||||
die "Unable to find common commit between" $merge $head
|
||||
fi
|
||||
@@ -46,11 +46,11 @@ case "$common" in
|
||||
exit 0
|
||||
;;
|
||||
"$head")
|
||||
echo "Updating $(git-rev-parse --short $head)..$(git-rev-parse --short $merge)"
|
||||
git-read-tree -u -m $head $merge || exit 1
|
||||
git-update-ref -m "resolve $merge_name: Fast forward" \
|
||||
echo "Updating $(git rev-parse --short $head)..$(git rev-parse --short $merge)"
|
||||
git read-tree -u -m $head $merge || exit 1
|
||||
git update-ref -m "resolve $merge_name: Fast forward" \
|
||||
HEAD "$merge" "$head"
|
||||
git-diff-tree -p $head $merge | git-apply --stat
|
||||
git diff-tree -p $head $merge | git apply --stat
|
||||
dropheads
|
||||
exit 0
|
||||
;;
|
||||
@@ -62,7 +62,7 @@ git var GIT_COMMITTER_IDENT >/dev/null || exit
|
||||
# Find an optimum merge base if there are more than one candidates.
|
||||
LF='
|
||||
'
|
||||
common=$(git-merge-base -a $head $merge)
|
||||
common=$(git merge-base -a $head $merge)
|
||||
case "$common" in
|
||||
?*"$LF"?*)
|
||||
echo "Trying to find the optimum merge base."
|
||||
@@ -72,10 +72,10 @@ case "$common" in
|
||||
for c in $common
|
||||
do
|
||||
rm -f $G
|
||||
GIT_INDEX_FILE=$G git-read-tree -m $c $head $merge \
|
||||
GIT_INDEX_FILE=$G git read-tree -m $c $head $merge \
|
||||
2>/dev/null || continue
|
||||
# Count the paths that are unmerged.
|
||||
cnt=`GIT_INDEX_FILE=$G git-ls-files --unmerged | wc -l`
|
||||
cnt=`GIT_INDEX_FILE=$G git ls-files --unmerged | wc -l`
|
||||
if test $best_cnt -le 0 -o $cnt -le $best_cnt
|
||||
then
|
||||
best=$c
|
||||
@@ -92,9 +92,9 @@ case "$common" in
|
||||
esac
|
||||
|
||||
echo "Trying to merge $merge into $head using $common."
|
||||
git-update-index --refresh 2>/dev/null
|
||||
git-read-tree -u -m $common $head $merge || exit 1
|
||||
result_tree=$(git-write-tree 2> /dev/null)
|
||||
git update-index --refresh 2>/dev/null
|
||||
git read-tree -u -m $common $head $merge || exit 1
|
||||
result_tree=$(git write-tree 2> /dev/null)
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Simple merge failed, trying Automatic merge"
|
||||
git-merge-index -o git-merge-one-file -a
|
||||
@@ -102,11 +102,11 @@ if [ $? -ne 0 ]; then
|
||||
echo $merge > "$GIT_DIR"/MERGE_HEAD
|
||||
die "Automatic merge failed, fix up by hand"
|
||||
fi
|
||||
result_tree=$(git-write-tree) || exit 1
|
||||
result_tree=$(git write-tree) || exit 1
|
||||
fi
|
||||
result_commit=$(echo "$merge_msg" | git-commit-tree $result_tree -p $head -p $merge)
|
||||
result_commit=$(echo "$merge_msg" | git commit-tree $result_tree -p $head -p $merge)
|
||||
echo "Committed merge $result_commit"
|
||||
git-update-ref -m "resolve $merge_name: In-index merge" \
|
||||
git update-ref -m "resolve $merge_name: In-index merge" \
|
||||
HEAD "$result_commit" "$head"
|
||||
git-diff-tree -p $head $result_commit | git-apply --stat
|
||||
git diff-tree -p $head $result_commit | git apply --stat
|
||||
dropheads
|
||||
|
||||
@@ -717,7 +717,11 @@ class P4Sync(Command):
|
||||
# POSIX says it's 4096 bytes, default for Linux seems to be 130 K.
|
||||
# and all OS from the table below seems to be higher than POSIX.
|
||||
# See http://www.in-ulm.de/~mascheck/various/argmax/
|
||||
argmax = min(4000, os.sysconf('SC_ARG_MAX'))
|
||||
if (self.isWindows):
|
||||
argmax = 2000
|
||||
else:
|
||||
argmax = min(4000, os.sysconf('SC_ARG_MAX'))
|
||||
|
||||
chunk = ''
|
||||
filedata = []
|
||||
for i in xrange(len(files)):
|
||||
|
||||
1
contrib/p4import/README
Normal file
1
contrib/p4import/README
Normal file
@@ -0,0 +1 @@
|
||||
Please see contrib/fast-import/git-p4 for a better Perforce importer.
|
||||
@@ -26,8 +26,8 @@ if [ -d "$GIT_DIR"/remotes ]; then
|
||||
mv "$GIT_DIR"/remotes "$GIT_DIR"/remotes.old
|
||||
fi ;;
|
||||
*)
|
||||
echo "git-config $key "$value" $regex"
|
||||
git-config $key "$value" $regex || error=1 ;;
|
||||
echo "git config $key "$value" $regex"
|
||||
git config $key "$value" $regex || error=1 ;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
26
contrib/stats/git-common-hash
Executable file
26
contrib/stats/git-common-hash
Executable file
@@ -0,0 +1,26 @@
|
||||
#!/bin/sh
|
||||
|
||||
# This script displays the distribution of longest common hash prefixes.
|
||||
# This can be used to determine the minimum prefix length to use
|
||||
# for object names to be unique.
|
||||
|
||||
git rev-list --objects --all | sort | perl -lne '
|
||||
substr($_, 40) = "";
|
||||
# uncomment next line for a distribution of bits instead of hex chars
|
||||
# $_ = unpack("B*",pack("H*",$_));
|
||||
if (defined $p) {
|
||||
($p ^ $_) =~ /^(\0*)/;
|
||||
$common = length $1;
|
||||
if (defined $pcommon) {
|
||||
$count[$pcommon > $common ? $pcommon : $common]++;
|
||||
} else {
|
||||
$count[$common]++; # first item
|
||||
}
|
||||
}
|
||||
$p = $_;
|
||||
$pcommon = $common;
|
||||
END {
|
||||
$count[$common]++; # last item
|
||||
print "$_: $count[$_]" for 0..$#count;
|
||||
}
|
||||
'
|
||||
38
contrib/stats/mailmap.pl
Executable file
38
contrib/stats/mailmap.pl
Executable file
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/perl -w
|
||||
my %mailmap = ();
|
||||
open I, "<", ".mailmap";
|
||||
while (<I>) {
|
||||
chomp;
|
||||
next if /^#/;
|
||||
if (my ($author, $mail) = /^(.*?)\s+<(.+)>$/) {
|
||||
$mailmap{$mail} = $author;
|
||||
}
|
||||
}
|
||||
close I;
|
||||
|
||||
my %mail2author = ();
|
||||
open I, "git log --pretty='format:%ae %an' |";
|
||||
while (<I>) {
|
||||
chomp;
|
||||
my ($mail, $author) = split(/\t/, $_);
|
||||
next if exists $mailmap{$mail};
|
||||
$mail2author{$mail} ||= {};
|
||||
$mail2author{$mail}{$author} ||= 0;
|
||||
$mail2author{$mail}{$author}++;
|
||||
}
|
||||
close I;
|
||||
|
||||
while (my ($mail, $authorcount) = each %mail2author) {
|
||||
# %$authorcount is ($author => $count);
|
||||
# sort and show the names from the most frequent ones.
|
||||
my @names = (map { $_->[0] }
|
||||
sort { $b->[1] <=> $a->[1] }
|
||||
map { [$_, $authorcount->{$_}] }
|
||||
keys %$authorcount);
|
||||
if (1 < @names) {
|
||||
for (@names) {
|
||||
print "$_ <$mail>\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
212
contrib/stats/packinfo.pl
Executable file
212
contrib/stats/packinfo.pl
Executable file
@@ -0,0 +1,212 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
# This tool will print vaguely pretty information about a pack. It
|
||||
# expects the output of "git-verify-pack -v" as input on stdin.
|
||||
#
|
||||
# $ git-verify-pack -v | packinfo.pl
|
||||
#
|
||||
# This prints some full-pack statistics; currently "all sizes", "all
|
||||
# path sizes", "tree sizes", "tree path sizes", and "depths".
|
||||
#
|
||||
# * "all sizes" stats are across every object size in the file;
|
||||
# full sizes for base objects, and delta size for deltas.
|
||||
# * "all path sizes" stats are across all object's "path sizes".
|
||||
# A path size is the sum of the size of the delta chain, including the
|
||||
# base object. In other words, it's how many bytes need be read to
|
||||
# reassemble the file from deltas.
|
||||
# * "tree sizes" are object sizes grouped into delta trees.
|
||||
# * "tree path sizes" are path sizes grouped into delta trees.
|
||||
# * "depths" should be obvious.
|
||||
#
|
||||
# When run as:
|
||||
#
|
||||
# $ git-verify-pack -v | packinfo.pl -tree
|
||||
#
|
||||
# the trees of objects are output along with the stats. This looks
|
||||
# like:
|
||||
#
|
||||
# 0 commit 031321c6... 803 803
|
||||
#
|
||||
# 0 blob 03156f21... 1767 1767
|
||||
# 1 blob f52a9d7f... 10 1777
|
||||
# 2 blob a8cc5739... 51 1828
|
||||
# 3 blob 660e90b1... 15 1843
|
||||
# 4 blob 0cb8e3bb... 33 1876
|
||||
# 2 blob e48607f0... 311 2088
|
||||
# size: count 6 total 2187 min 10 max 1767 mean 364.50 median 51 std_dev 635.85
|
||||
# path size: count 6 total 11179 min 1767 max 2088 mean 1863.17 median 1843 std_dev 107.26
|
||||
#
|
||||
# The first number after the sha1 is the object size, the second
|
||||
# number is the path size. The statistics are across all objects in
|
||||
# the previous delta tree. Obviously they are omitted for trees of
|
||||
# one object.
|
||||
#
|
||||
# When run as:
|
||||
#
|
||||
# $ git-verify-pack -v | packinfo.pl -tree -filenames
|
||||
#
|
||||
# it adds filenames to the tree. Getting this information is slow:
|
||||
#
|
||||
# 0 blob 03156f21... 1767 1767 Documentation/git-lost-found.txt @ tags/v1.2.0~142
|
||||
# 1 blob f52a9d7f... 10 1777 Documentation/git-lost-found.txt @ tags/v1.5.0-rc1~74
|
||||
# 2 blob a8cc5739... 51 1828 Documentation/git-lost+found.txt @ tags/v0.99.9h^0
|
||||
# 3 blob 660e90b1... 15 1843 Documentation/git-lost+found.txt @ master~3222^2~2
|
||||
# 4 blob 0cb8e3bb... 33 1876 Documentation/git-lost+found.txt @ master~3222^2~3
|
||||
# 2 blob e48607f0... 311 2088 Documentation/git-lost-found.txt @ tags/v1.5.2-rc3~4
|
||||
# size: count 6 total 2187 min 10 max 1767 mean 364.50 median 51 std_dev 635.85
|
||||
# path size: count 6 total 11179 min 1767 max 2088 mean 1863.17 median 1843 std_dev 107.26
|
||||
#
|
||||
# When run as:
|
||||
#
|
||||
# $ git-verify-pack -v | packinfo.pl -dump
|
||||
#
|
||||
# it prints out "sha1 size pathsize depth" for each sha1 in lexical
|
||||
# order.
|
||||
#
|
||||
# 000079a2eaef17b7eae70e1f0f635557ea67b644 30 472 7
|
||||
# 00013cafe6980411aa6fdd940784917b5ff50f0a 44 1542 4
|
||||
# 000182eacf99cde27d5916aa415921924b82972c 499 499 0
|
||||
# ...
|
||||
#
|
||||
# This is handy for comparing two packs. Adding "-filenames" will add
|
||||
# filenames, as per "-tree -filenames" above.
|
||||
|
||||
use strict;
|
||||
use Getopt::Long;
|
||||
|
||||
my $filenames = 0;
|
||||
my $tree = 0;
|
||||
my $dump = 0;
|
||||
GetOptions("tree" => \$tree,
|
||||
"filenames" => \$filenames,
|
||||
"dump" => \$dump);
|
||||
|
||||
my %parents;
|
||||
my %children;
|
||||
my %sizes;
|
||||
my @roots;
|
||||
my %paths;
|
||||
my %types;
|
||||
my @commits;
|
||||
my %names;
|
||||
my %depths;
|
||||
my @depths;
|
||||
|
||||
while (<STDIN>) {
|
||||
my ($sha1, $type, $size, $offset, $depth, $parent) = split(/\s+/, $_);
|
||||
next unless ($sha1 =~ /^[0-9a-f]{40}$/);
|
||||
$depths{$sha1} = $depth || 0;
|
||||
push(@depths, $depth || 0);
|
||||
push(@commits, $sha1) if ($type eq 'commit');
|
||||
push(@roots, $sha1) unless $parent;
|
||||
$parents{$sha1} = $parent;
|
||||
$types{$sha1} = $type;
|
||||
push(@{$children{$parent}}, $sha1);
|
||||
$sizes{$sha1} = $size;
|
||||
}
|
||||
|
||||
if ($filenames && ($tree || $dump)) {
|
||||
open(NAMES, "git-name-rev --all|");
|
||||
while (<NAMES>) {
|
||||
if (/^(\S+)\s+(.*)$/) {
|
||||
my ($sha1, $name) = ($1, $2);
|
||||
$names{$sha1} = $name;
|
||||
}
|
||||
}
|
||||
close NAMES;
|
||||
|
||||
for my $commit (@commits) {
|
||||
my $name = $names{$commit};
|
||||
open(TREE, "git-ls-tree -t -r $commit|");
|
||||
print STDERR "Plumbing tree $name\n";
|
||||
while (<TREE>) {
|
||||
if (/^(\S+)\s+(\S+)\s+(\S+)\s+(.*)$/) {
|
||||
my ($mode, $type, $sha1, $path) = ($1, $2, $3, $4);
|
||||
$paths{$sha1} = "$path @ $name";
|
||||
}
|
||||
}
|
||||
close TREE;
|
||||
}
|
||||
}
|
||||
|
||||
sub stats {
|
||||
my @data = sort {$a <=> $b} @_;
|
||||
my $min = $data[0];
|
||||
my $max = $data[$#data];
|
||||
my $total = 0;
|
||||
my $count = scalar @data;
|
||||
for my $datum (@data) {
|
||||
$total += $datum;
|
||||
}
|
||||
my $mean = $total / $count;
|
||||
my $median = $data[int(@data / 2)];
|
||||
my $diff_sum = 0;
|
||||
for my $datum (@data) {
|
||||
$diff_sum += ($datum - $mean)**2;
|
||||
}
|
||||
my $std_dev = sqrt($diff_sum / $count);
|
||||
return ($count, $total, $min, $max, $mean, $median, $std_dev);
|
||||
}
|
||||
|
||||
sub print_stats {
|
||||
my $name = shift;
|
||||
my ($count, $total, $min, $max, $mean, $median, $std_dev) = stats(@_);
|
||||
printf("%s: count %s total %s min %s max %s mean %.2f median %s std_dev %.2f\n",
|
||||
$name, $count, $total, $min, $max, $mean, $median, $std_dev);
|
||||
}
|
||||
|
||||
my @sizes;
|
||||
my @path_sizes;
|
||||
my @all_sizes;
|
||||
my @all_path_sizes;
|
||||
my %path_sizes;
|
||||
|
||||
sub dig {
|
||||
my ($sha1, $depth, $path_size) = @_;
|
||||
$path_size += $sizes{$sha1};
|
||||
push(@sizes, $sizes{$sha1});
|
||||
push(@all_sizes, $sizes{$sha1});
|
||||
push(@path_sizes, $path_size);
|
||||
push(@all_path_sizes, $path_size);
|
||||
$path_sizes{$sha1} = $path_size;
|
||||
if ($tree) {
|
||||
printf("%3d%s %6s %s %8d %8d %s\n",
|
||||
$depth, (" " x $depth), $types{$sha1},
|
||||
$sha1, $sizes{$sha1}, $path_size, $paths{$sha1});
|
||||
}
|
||||
for my $child (@{$children{$sha1}}) {
|
||||
dig($child, $depth + 1, $path_size);
|
||||
}
|
||||
}
|
||||
|
||||
my @tree_sizes;
|
||||
my @tree_path_sizes;
|
||||
|
||||
for my $root (@roots) {
|
||||
undef @sizes;
|
||||
undef @path_sizes;
|
||||
dig($root, 0, 0);
|
||||
my ($aa, $sz_total) = stats(@sizes);
|
||||
my ($bb, $psz_total) = stats(@path_sizes);
|
||||
push(@tree_sizes, $sz_total);
|
||||
push(@tree_path_sizes, $psz_total);
|
||||
if ($tree) {
|
||||
if (@sizes > 1) {
|
||||
print_stats(" size", @sizes);
|
||||
print_stats("path size", @path_sizes);
|
||||
}
|
||||
print "\n";
|
||||
}
|
||||
}
|
||||
|
||||
if ($dump) {
|
||||
for my $sha1 (sort keys %sizes) {
|
||||
print "$sha1 $sizes{$sha1} $path_sizes{$sha1} $depths{$sha1} $paths{$sha1}\n";
|
||||
}
|
||||
} else {
|
||||
print_stats(" all sizes", @all_sizes);
|
||||
print_stats(" all path sizes", @all_path_sizes);
|
||||
print_stats(" tree sizes", @tree_sizes);
|
||||
print_stats("tree path sizes", @tree_path_sizes);
|
||||
print_stats(" depths", @depths);
|
||||
}
|
||||
27
date.c
27
date.c
@@ -137,6 +137,18 @@ const char *show_date(unsigned long time, int tz, enum date_mode mode)
|
||||
if (mode == DATE_SHORT)
|
||||
sprintf(timebuf, "%04d-%02d-%02d", tm->tm_year + 1900,
|
||||
tm->tm_mon + 1, tm->tm_mday);
|
||||
else if (mode == DATE_ISO8601)
|
||||
sprintf(timebuf, "%04d-%02d-%02d %02d:%02d:%02d %+05d",
|
||||
tm->tm_year + 1900,
|
||||
tm->tm_mon + 1,
|
||||
tm->tm_mday,
|
||||
tm->tm_hour, tm->tm_min, tm->tm_sec,
|
||||
tz);
|
||||
else if (mode == DATE_RFC2822)
|
||||
sprintf(timebuf, "%.3s, %d %.3s %d %02d:%02d:%02d %+05d",
|
||||
weekday_names[tm->tm_wday], tm->tm_mday,
|
||||
month_names[tm->tm_mon], tm->tm_year + 1900,
|
||||
tm->tm_hour, tm->tm_min, tm->tm_sec, tz);
|
||||
else
|
||||
sprintf(timebuf, "%.3s %.3s %d %02d:%02d:%02d %d%c%+05d",
|
||||
weekday_names[tm->tm_wday],
|
||||
@@ -149,21 +161,6 @@ const char *show_date(unsigned long time, int tz, enum date_mode mode)
|
||||
return timebuf;
|
||||
}
|
||||
|
||||
const char *show_rfc2822_date(unsigned long time, int tz)
|
||||
{
|
||||
struct tm *tm;
|
||||
static char timebuf[200];
|
||||
|
||||
tm = time_to_tm(time, tz);
|
||||
if (!tm)
|
||||
return NULL;
|
||||
sprintf(timebuf, "%.3s, %d %.3s %d %02d:%02d:%02d %+05d",
|
||||
weekday_names[tm->tm_wday], tm->tm_mday,
|
||||
month_names[tm->tm_mon], tm->tm_year + 1900,
|
||||
tm->tm_hour, tm->tm_min, tm->tm_sec, tz);
|
||||
return timebuf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check these. And note how it doesn't do the summer-time conversion.
|
||||
*
|
||||
|
||||
7
delta.h
7
delta.h
@@ -23,6 +23,13 @@ create_delta_index(const void *buf, unsigned long bufsize);
|
||||
*/
|
||||
extern void free_delta_index(struct delta_index *index);
|
||||
|
||||
/*
|
||||
* sizeof_delta_index: returns memory usage of delta index
|
||||
*
|
||||
* Given pointer must be what create_delta_index() returned, or NULL.
|
||||
*/
|
||||
extern unsigned long sizeof_delta_index(struct delta_index *index);
|
||||
|
||||
/*
|
||||
* create_delta: create a delta from given index for the given buffer
|
||||
*
|
||||
|
||||
10
diff-delta.c
10
diff-delta.c
@@ -119,6 +119,7 @@ struct index_entry {
|
||||
};
|
||||
|
||||
struct delta_index {
|
||||
unsigned long memsize;
|
||||
const void *src_buf;
|
||||
unsigned long src_size;
|
||||
unsigned int hash_mask;
|
||||
@@ -159,6 +160,7 @@ struct delta_index * create_delta_index(const void *buf, unsigned long bufsize)
|
||||
mem = hash + hsize;
|
||||
entry = mem;
|
||||
|
||||
index->memsize = memsize;
|
||||
index->src_buf = buf;
|
||||
index->src_size = bufsize;
|
||||
index->hash_mask = hmask;
|
||||
@@ -228,6 +230,14 @@ void free_delta_index(struct delta_index *index)
|
||||
free(index);
|
||||
}
|
||||
|
||||
unsigned long sizeof_delta_index(struct delta_index *index)
|
||||
{
|
||||
if (index)
|
||||
return index->memsize;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The maximum size for any opcode sequence, including the initial header
|
||||
* plus Rabin window plus biggest copy.
|
||||
|
||||
@@ -24,7 +24,7 @@ static int read_directory(const char *path, struct path_list *list)
|
||||
|
||||
while ((e = readdir(dir)))
|
||||
if (strcmp(".", e->d_name) && strcmp("..", e->d_name))
|
||||
path_list_insert(xstrdup(e->d_name), list);
|
||||
path_list_insert(e->d_name, list);
|
||||
|
||||
closedir(dir);
|
||||
return 0;
|
||||
|
||||
220
diff.c
220
diff.c
@@ -57,6 +57,14 @@ static struct ll_diff_driver {
|
||||
char *cmd;
|
||||
} *user_diff, **user_diff_tail;
|
||||
|
||||
static void read_config_if_needed(void)
|
||||
{
|
||||
if (!user_diff_tail) {
|
||||
user_diff_tail = &user_diff;
|
||||
git_config(git_diff_ui_config);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Currently there is only "diff.<drivername>.command" variable;
|
||||
* because there are "diff.color.<slot>" variables, we are parsing
|
||||
@@ -94,6 +102,45 @@ static int parse_lldiff_command(const char *var, const char *ep, const char *val
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 'diff.<what>.funcname' attribute can be specified in the configuration
|
||||
* to define a customized regexp to find the beginning of a function to
|
||||
* be used for hunk header lines of "diff -p" style output.
|
||||
*/
|
||||
static struct funcname_pattern {
|
||||
char *name;
|
||||
char *pattern;
|
||||
struct funcname_pattern *next;
|
||||
} *funcname_pattern_list;
|
||||
|
||||
static int parse_funcname_pattern(const char *var, const char *ep, const char *value)
|
||||
{
|
||||
const char *name;
|
||||
int namelen;
|
||||
struct funcname_pattern *pp;
|
||||
|
||||
name = var + 5; /* "diff." */
|
||||
namelen = ep - name;
|
||||
|
||||
for (pp = funcname_pattern_list; pp; pp = pp->next)
|
||||
if (!strncmp(pp->name, name, namelen) && !pp->name[namelen])
|
||||
break;
|
||||
if (!pp) {
|
||||
char *namebuf;
|
||||
pp = xcalloc(1, sizeof(*pp));
|
||||
namebuf = xmalloc(namelen + 1);
|
||||
memcpy(namebuf, name, namelen);
|
||||
namebuf[namelen] = 0;
|
||||
pp->name = namebuf;
|
||||
pp->next = funcname_pattern_list;
|
||||
funcname_pattern_list = pp;
|
||||
}
|
||||
if (pp->pattern)
|
||||
free(pp->pattern);
|
||||
pp->pattern = xstrdup(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* These are to give UI layer defaults.
|
||||
* The core-level commands such as git-diff-files should
|
||||
@@ -123,8 +170,12 @@ int git_diff_ui_config(const char *var, const char *value)
|
||||
if (!prefixcmp(var, "diff.")) {
|
||||
const char *ep = strrchr(var, '.');
|
||||
|
||||
if (ep != var + 4 && !strcmp(ep, ".command"))
|
||||
return parse_lldiff_command(var, ep, value);
|
||||
if (ep != var + 4) {
|
||||
if (!strcmp(ep, ".command"))
|
||||
return parse_lldiff_command(var, ep, value);
|
||||
if (!strcmp(ep, ".funcname"))
|
||||
return parse_funcname_pattern(var, ep, value);
|
||||
}
|
||||
}
|
||||
if (!prefixcmp(var, "diff.color.") || !prefixcmp(var, "color.diff.")) {
|
||||
int slot = parse_diff_color_slot(var, 11);
|
||||
@@ -391,6 +442,7 @@ static void diff_words_show(struct diff_words_data *diff_words)
|
||||
mmfile_t minus, plus;
|
||||
int i;
|
||||
|
||||
memset(&xecfg, 0, sizeof(xecfg));
|
||||
minus.size = diff_words->minus.text.size;
|
||||
minus.ptr = xmalloc(minus.size);
|
||||
memcpy(minus.ptr, diff_words->minus.text.ptr, minus.size);
|
||||
@@ -409,7 +461,6 @@ static void diff_words_show(struct diff_words_data *diff_words)
|
||||
|
||||
xpp.flags = XDF_NEED_MINIMAL;
|
||||
xecfg.ctxlen = diff_words->minus.alloc + diff_words->plus.alloc;
|
||||
xecfg.flags = 0;
|
||||
ecb.outf = xdiff_outf;
|
||||
ecb.priv = diff_words;
|
||||
diff_words->xm.consume = fn_out_diff_words_aux;
|
||||
@@ -1103,30 +1154,111 @@ static void setup_diff_attr_check(struct git_attr_check *check)
|
||||
{
|
||||
static struct git_attr *attr_diff;
|
||||
|
||||
if (!attr_diff)
|
||||
if (!attr_diff) {
|
||||
attr_diff = git_attr("diff", 4);
|
||||
check->attr = attr_diff;
|
||||
}
|
||||
check[0].attr = attr_diff;
|
||||
}
|
||||
|
||||
static int file_is_binary(struct diff_filespec *one)
|
||||
static void diff_filespec_check_attr(struct diff_filespec *one)
|
||||
{
|
||||
struct git_attr_check attr_diff_check;
|
||||
int check_from_data = 0;
|
||||
|
||||
if (one->checked_attr)
|
||||
return;
|
||||
|
||||
setup_diff_attr_check(&attr_diff_check);
|
||||
one->is_binary = 0;
|
||||
one->funcname_pattern_ident = NULL;
|
||||
|
||||
if (!git_checkattr(one->path, 1, &attr_diff_check)) {
|
||||
const char *value = attr_diff_check.value;
|
||||
const char *value;
|
||||
|
||||
/* binaryness */
|
||||
value = attr_diff_check.value;
|
||||
if (ATTR_TRUE(value))
|
||||
return 0;
|
||||
;
|
||||
else if (ATTR_FALSE(value))
|
||||
return 1;
|
||||
one->is_binary = 1;
|
||||
else
|
||||
check_from_data = 1;
|
||||
|
||||
/* funcname pattern ident */
|
||||
if (ATTR_TRUE(value) || ATTR_FALSE(value) || ATTR_UNSET(value))
|
||||
;
|
||||
else
|
||||
one->funcname_pattern_ident = value;
|
||||
}
|
||||
|
||||
if (!one->data) {
|
||||
if (!DIFF_FILE_VALID(one))
|
||||
return 0;
|
||||
diff_populate_filespec(one, 0);
|
||||
if (check_from_data) {
|
||||
if (!one->data && DIFF_FILE_VALID(one))
|
||||
diff_populate_filespec(one, 0);
|
||||
|
||||
if (one->data)
|
||||
one->is_binary = buffer_is_binary(one->data, one->size);
|
||||
}
|
||||
return buffer_is_binary(one->data, one->size);
|
||||
}
|
||||
|
||||
int diff_filespec_is_binary(struct diff_filespec *one)
|
||||
{
|
||||
diff_filespec_check_attr(one);
|
||||
return one->is_binary;
|
||||
}
|
||||
|
||||
static const char *funcname_pattern(const char *ident)
|
||||
{
|
||||
struct funcname_pattern *pp;
|
||||
|
||||
read_config_if_needed();
|
||||
for (pp = funcname_pattern_list; pp; pp = pp->next)
|
||||
if (!strcmp(ident, pp->name))
|
||||
return pp->pattern;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct builtin_funcname_pattern {
|
||||
const char *name;
|
||||
const char *pattern;
|
||||
} builtin_funcname_pattern[] = {
|
||||
{ "java", "!^[ ]*\\(catch\\|do\\|for\\|if\\|instanceof\\|"
|
||||
"new\\|return\\|switch\\|throw\\|while\\)\n"
|
||||
"^[ ]*\\(\\([ ]*"
|
||||
"[A-Za-z_][A-Za-z_0-9]*\\)\\{2,\\}"
|
||||
"[ ]*([^;]*$\\)" },
|
||||
{ "tex", "^\\(\\\\\\(sub\\)*section{.*\\)$" },
|
||||
};
|
||||
|
||||
static const char *diff_funcname_pattern(struct diff_filespec *one)
|
||||
{
|
||||
const char *ident, *pattern;
|
||||
int i;
|
||||
|
||||
diff_filespec_check_attr(one);
|
||||
ident = one->funcname_pattern_ident;
|
||||
|
||||
if (!ident)
|
||||
/*
|
||||
* If the config file has "funcname.default" defined, that
|
||||
* regexp is used; otherwise NULL is returned and xemit uses
|
||||
* the built-in default.
|
||||
*/
|
||||
return funcname_pattern("default");
|
||||
|
||||
/* Look up custom "funcname.$ident" regexp from config. */
|
||||
pattern = funcname_pattern(ident);
|
||||
if (pattern)
|
||||
return pattern;
|
||||
|
||||
/*
|
||||
* And define built-in fallback patterns here. Note that
|
||||
* these can be overriden by the user's config settings.
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(builtin_funcname_pattern); i++)
|
||||
if (!strcmp(ident, builtin_funcname_pattern[i].name))
|
||||
return builtin_funcname_pattern[i].pattern;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void builtin_diff(const char *name_a,
|
||||
@@ -1183,7 +1315,8 @@ static void builtin_diff(const char *name_a,
|
||||
if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
|
||||
die("unable to read files to diff");
|
||||
|
||||
if (!o->text && (file_is_binary(one) || file_is_binary(two))) {
|
||||
if (!o->text &&
|
||||
(diff_filespec_is_binary(one) || diff_filespec_is_binary(two))) {
|
||||
/* Quite common confusing case */
|
||||
if (mf1.size == mf2.size &&
|
||||
!memcmp(mf1.ptr, mf2.ptr, mf1.size))
|
||||
@@ -1202,7 +1335,13 @@ static void builtin_diff(const char *name_a,
|
||||
xdemitconf_t xecfg;
|
||||
xdemitcb_t ecb;
|
||||
struct emit_callback ecbdata;
|
||||
const char *funcname_pattern;
|
||||
|
||||
funcname_pattern = diff_funcname_pattern(one);
|
||||
if (!funcname_pattern)
|
||||
funcname_pattern = diff_funcname_pattern(two);
|
||||
|
||||
memset(&xecfg, 0, sizeof(xecfg));
|
||||
memset(&ecbdata, 0, sizeof(ecbdata));
|
||||
ecbdata.label_path = lbl;
|
||||
ecbdata.color_diff = o->color_diff;
|
||||
@@ -1210,6 +1349,8 @@ static void builtin_diff(const char *name_a,
|
||||
xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
|
||||
xecfg.ctxlen = o->context;
|
||||
xecfg.flags = XDL_EMIT_FUNCNAMES;
|
||||
if (funcname_pattern)
|
||||
xdiff_set_find_func(&xecfg, funcname_pattern);
|
||||
if (!diffopts)
|
||||
;
|
||||
else if (!prefixcmp(diffopts, "--unified="))
|
||||
@@ -1261,7 +1402,7 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
|
||||
if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
|
||||
die("unable to read files to diff");
|
||||
|
||||
if (file_is_binary(one) || file_is_binary(two)) {
|
||||
if (diff_filespec_is_binary(one) || diff_filespec_is_binary(two)) {
|
||||
data->is_binary = 1;
|
||||
data->added = mf2.size;
|
||||
data->deleted = mf1.size;
|
||||
@@ -1271,9 +1412,8 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
|
||||
xdemitconf_t xecfg;
|
||||
xdemitcb_t ecb;
|
||||
|
||||
memset(&xecfg, 0, sizeof(xecfg));
|
||||
xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
|
||||
xecfg.ctxlen = 0;
|
||||
xecfg.flags = 0;
|
||||
ecb.outf = xdiff_outf;
|
||||
ecb.priv = diffstat;
|
||||
xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
|
||||
@@ -1303,7 +1443,7 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,
|
||||
if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
|
||||
die("unable to read files to diff");
|
||||
|
||||
if (file_is_binary(two))
|
||||
if (diff_filespec_is_binary(two))
|
||||
goto free_and_return;
|
||||
else {
|
||||
/* Crazy xdl interfaces.. */
|
||||
@@ -1311,9 +1451,8 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,
|
||||
xdemitconf_t xecfg;
|
||||
xdemitcb_t ecb;
|
||||
|
||||
memset(&xecfg, 0, sizeof(xecfg));
|
||||
xpp.flags = XDF_NEED_MINIMAL;
|
||||
xecfg.ctxlen = 0;
|
||||
xecfg.flags = 0;
|
||||
ecb.outf = xdiff_outf;
|
||||
ecb.priv = &data;
|
||||
xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
|
||||
@@ -1748,10 +1887,7 @@ static const char *external_diff_attr(const char *name)
|
||||
!ATTR_UNSET(value)) {
|
||||
struct ll_diff_driver *drv;
|
||||
|
||||
if (!user_diff_tail) {
|
||||
user_diff_tail = &user_diff;
|
||||
git_config(git_diff_ui_config);
|
||||
}
|
||||
read_config_if_needed();
|
||||
for (drv = user_diff; drv; drv = drv->next)
|
||||
if (!strcmp(drv->name, value))
|
||||
return drv->cmd;
|
||||
@@ -1808,6 +1944,11 @@ static void diff_fill_sha1_info(struct diff_filespec *one)
|
||||
hashclr(one->sha1);
|
||||
}
|
||||
|
||||
static int similarity_index(struct diff_filepair *p)
|
||||
{
|
||||
return p->score * 100 / MAX_SCORE;
|
||||
}
|
||||
|
||||
static void run_diff(struct diff_filepair *p, struct diff_options *o)
|
||||
{
|
||||
const char *pgm = external_diff();
|
||||
@@ -1842,23 +1983,20 @@ static void run_diff(struct diff_filepair *p, struct diff_options *o)
|
||||
"similarity index %d%%\n"
|
||||
"copy from %s\n"
|
||||
"copy to %s\n",
|
||||
(int)(0.5 + p->score * 100.0/MAX_SCORE),
|
||||
name_munged, other_munged);
|
||||
similarity_index(p), name_munged, other_munged);
|
||||
break;
|
||||
case DIFF_STATUS_RENAMED:
|
||||
len += snprintf(msg + len, sizeof(msg) - len,
|
||||
"similarity index %d%%\n"
|
||||
"rename from %s\n"
|
||||
"rename to %s\n",
|
||||
(int)(0.5 + p->score * 100.0/MAX_SCORE),
|
||||
name_munged, other_munged);
|
||||
similarity_index(p), name_munged, other_munged);
|
||||
break;
|
||||
case DIFF_STATUS_MODIFIED:
|
||||
if (p->score) {
|
||||
len += snprintf(msg + len, sizeof(msg) - len,
|
||||
"dissimilarity index %d%%\n",
|
||||
(int)(0.5 + p->score *
|
||||
100.0/MAX_SCORE));
|
||||
similarity_index(p));
|
||||
complete_rewrite = 1;
|
||||
break;
|
||||
}
|
||||
@@ -1873,8 +2011,8 @@ static void run_diff(struct diff_filepair *p, struct diff_options *o)
|
||||
|
||||
if (o->binary) {
|
||||
mmfile_t mf;
|
||||
if ((!fill_mmfile(&mf, one) && file_is_binary(one)) ||
|
||||
(!fill_mmfile(&mf, two) && file_is_binary(two)))
|
||||
if ((!fill_mmfile(&mf, one) && diff_filespec_is_binary(one)) ||
|
||||
(!fill_mmfile(&mf, two) && diff_filespec_is_binary(two)))
|
||||
abbrev = 40;
|
||||
}
|
||||
len += snprintf(msg + len, sizeof(msg) - len,
|
||||
@@ -2234,6 +2372,10 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
|
||||
options->exit_with_status = 1;
|
||||
else if (!strcmp(arg, "--quiet"))
|
||||
options->quiet = 1;
|
||||
else if (!strcmp(arg, "--ext-diff"))
|
||||
options->allow_external = 1;
|
||||
else if (!strcmp(arg, "--no-ext-diff"))
|
||||
options->allow_external = 0;
|
||||
else
|
||||
return 0;
|
||||
return 1;
|
||||
@@ -2382,8 +2524,7 @@ static void diff_flush_raw(struct diff_filepair *p,
|
||||
}
|
||||
|
||||
if (p->score)
|
||||
sprintf(status, "%c%03d", p->status,
|
||||
(int)(0.5 + p->score * 100.0/MAX_SCORE));
|
||||
sprintf(status, "%c%03d", p->status, similarity_index(p));
|
||||
else {
|
||||
status[0] = p->status;
|
||||
status[1] = 0;
|
||||
@@ -2666,8 +2807,7 @@ static void show_rename_copy(const char *renamecopy, struct diff_filepair *p)
|
||||
{
|
||||
char *names = pprint_rename(p->one->path, p->two->path);
|
||||
|
||||
printf(" %s %s (%d%%)\n", renamecopy, names,
|
||||
(int)(0.5 + p->score * 100.0/MAX_SCORE));
|
||||
printf(" %s %s (%d%%)\n", renamecopy, names, similarity_index(p));
|
||||
free(names);
|
||||
show_mode_change(p, 0);
|
||||
}
|
||||
@@ -2691,7 +2831,7 @@ static void diff_summary(struct diff_filepair *p)
|
||||
if (p->score) {
|
||||
char *name = quote_one(p->two->path);
|
||||
printf(" rewrite %s (%d%%)\n", name,
|
||||
(int)(0.5 + p->score * 100.0/MAX_SCORE));
|
||||
similarity_index(p));
|
||||
free(name);
|
||||
show_mode_change(p, 0);
|
||||
} else show_mode_change(p, 1);
|
||||
@@ -2755,6 +2895,7 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1)
|
||||
struct diff_filepair *p = q->queue[i];
|
||||
int len1, len2;
|
||||
|
||||
memset(&xecfg, 0, sizeof(xecfg));
|
||||
if (p->status == 0)
|
||||
return error("internal diff status error");
|
||||
if (p->status == DIFF_STATUS_UNKNOWN)
|
||||
@@ -2774,7 +2915,7 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1)
|
||||
return error("unable to read files to diff");
|
||||
|
||||
/* Maybe hash p->two? into the patch id? */
|
||||
if (file_is_binary(p->two))
|
||||
if (diff_filespec_is_binary(p->two))
|
||||
continue;
|
||||
|
||||
len1 = remove_space(p->one->path, strlen(p->one->path));
|
||||
@@ -3001,6 +3142,7 @@ void diffcore_std(struct diff_options *options)
|
||||
{
|
||||
if (options->quiet)
|
||||
return;
|
||||
|
||||
if (options->break_opt != -1)
|
||||
diffcore_break(options->break_opt);
|
||||
if (options->detect_rename)
|
||||
|
||||
@@ -66,8 +66,7 @@ static int should_break(struct diff_filespec *src,
|
||||
if (base_size < MINIMUM_BREAK_SIZE)
|
||||
return 0; /* we do not break too small filepair */
|
||||
|
||||
if (diffcore_count_changes(src->data, src->size,
|
||||
dst->data, dst->size,
|
||||
if (diffcore_count_changes(src, dst,
|
||||
NULL, NULL,
|
||||
0,
|
||||
&src_copied, &literal_added))
|
||||
|
||||
@@ -5,23 +5,20 @@
|
||||
/*
|
||||
* Idea here is very simple.
|
||||
*
|
||||
* We have total of (sz-N+1) N-byte overlapping sequences in buf whose
|
||||
* size is sz. If the same N-byte sequence appears in both source and
|
||||
* destination, we say the byte that starts that sequence is shared
|
||||
* between them (i.e. copied from source to destination).
|
||||
* Almost all data we are interested in are text, but sometimes we have
|
||||
* to deal with binary data. So we cut them into chunks delimited by
|
||||
* LF byte, or 64-byte sequence, whichever comes first, and hash them.
|
||||
*
|
||||
* For each possible N-byte sequence, if the source buffer has more
|
||||
* instances of it than the destination buffer, that means the
|
||||
* difference are the number of bytes not copied from source to
|
||||
* destination. If the counts are the same, everything was copied
|
||||
* from source to destination. If the destination has more,
|
||||
* everything was copied, and destination added more.
|
||||
* For those chunks, if the source buffer has more instances of it
|
||||
* than the destination buffer, that means the difference are the
|
||||
* number of bytes not copied from source to destination. If the
|
||||
* counts are the same, everything was copied from source to
|
||||
* destination. If the destination has more, everything was copied,
|
||||
* and destination added more.
|
||||
*
|
||||
* We are doing an approximation so we do not really have to waste
|
||||
* memory by actually storing the sequence. We just hash them into
|
||||
* somewhere around 2^16 hashbuckets and count the occurrences.
|
||||
*
|
||||
* The length of the sequence is arbitrarily set to 8 for now.
|
||||
*/
|
||||
|
||||
/* Wild guess at the initial hash size */
|
||||
@@ -125,11 +122,14 @@ static struct spanhash_top *add_spanhash(struct spanhash_top *top,
|
||||
}
|
||||
}
|
||||
|
||||
static struct spanhash_top *hash_chars(unsigned char *buf, unsigned int sz)
|
||||
static struct spanhash_top *hash_chars(struct diff_filespec *one)
|
||||
{
|
||||
int i, n;
|
||||
unsigned int accum1, accum2, hashval;
|
||||
struct spanhash_top *hash;
|
||||
unsigned char *buf = one->data;
|
||||
unsigned int sz = one->size;
|
||||
int is_text = !diff_filespec_is_binary(one);
|
||||
|
||||
i = INITIAL_HASH_SIZE;
|
||||
hash = xmalloc(sizeof(*hash) + sizeof(struct spanhash) * (1<<i));
|
||||
@@ -143,6 +143,11 @@ static struct spanhash_top *hash_chars(unsigned char *buf, unsigned int sz)
|
||||
unsigned int c = *buf++;
|
||||
unsigned int old_1 = accum1;
|
||||
sz--;
|
||||
|
||||
/* Ignore CR in CRLF sequence if text */
|
||||
if (is_text && c == '\r' && sz && *buf == '\n')
|
||||
continue;
|
||||
|
||||
accum1 = (accum1 << 7) ^ (accum2 >> 25);
|
||||
accum2 = (accum2 << 7) ^ (old_1 >> 25);
|
||||
accum1 += c;
|
||||
@@ -156,8 +161,8 @@ static struct spanhash_top *hash_chars(unsigned char *buf, unsigned int sz)
|
||||
return hash;
|
||||
}
|
||||
|
||||
int diffcore_count_changes(void *src, unsigned long src_size,
|
||||
void *dst, unsigned long dst_size,
|
||||
int diffcore_count_changes(struct diff_filespec *src,
|
||||
struct diff_filespec *dst,
|
||||
void **src_count_p,
|
||||
void **dst_count_p,
|
||||
unsigned long delta_limit,
|
||||
@@ -172,14 +177,14 @@ int diffcore_count_changes(void *src, unsigned long src_size,
|
||||
if (src_count_p)
|
||||
src_count = *src_count_p;
|
||||
if (!src_count) {
|
||||
src_count = hash_chars(src, src_size);
|
||||
src_count = hash_chars(src);
|
||||
if (src_count_p)
|
||||
*src_count_p = src_count;
|
||||
}
|
||||
if (dst_count_p)
|
||||
dst_count = *dst_count_p;
|
||||
if (!dst_count) {
|
||||
dst_count = hash_chars(dst, dst_size);
|
||||
dst_count = hash_chars(dst);
|
||||
if (dst_count_p)
|
||||
*dst_count_p = dst_count;
|
||||
}
|
||||
|
||||
@@ -138,6 +138,7 @@ struct diff_score {
|
||||
int src; /* index in rename_src */
|
||||
int dst; /* index in rename_dst */
|
||||
int score;
|
||||
int name_score;
|
||||
};
|
||||
|
||||
static int estimate_similarity(struct diff_filespec *src,
|
||||
@@ -189,8 +190,7 @@ static int estimate_similarity(struct diff_filespec *src,
|
||||
|
||||
delta_limit = (unsigned long)
|
||||
(base_size * (MAX_SCORE-minimum_score) / MAX_SCORE);
|
||||
if (diffcore_count_changes(src->data, src->size,
|
||||
dst->data, dst->size,
|
||||
if (diffcore_count_changes(src, dst,
|
||||
&src->cnt_data, &dst->cnt_data,
|
||||
delta_limit,
|
||||
&src_copied, &literal_added))
|
||||
@@ -201,11 +201,8 @@ static int estimate_similarity(struct diff_filespec *src,
|
||||
*/
|
||||
if (!dst->size)
|
||||
score = 0; /* should not happen */
|
||||
else {
|
||||
else
|
||||
score = (int)(src_copied * MAX_SCORE / max_size);
|
||||
if (basename_same(src, dst))
|
||||
score++;
|
||||
}
|
||||
return score;
|
||||
}
|
||||
|
||||
@@ -242,6 +239,10 @@ static void record_rename_pair(int dst_index, int src_index, int score)
|
||||
static int score_compare(const void *a_, const void *b_)
|
||||
{
|
||||
const struct diff_score *a = a_, *b = b_;
|
||||
|
||||
if (a->score == b->score)
|
||||
return b->name_score - a->name_score;
|
||||
|
||||
return b->score - a->score;
|
||||
}
|
||||
|
||||
@@ -360,6 +361,7 @@ void diffcore_rename(struct diff_options *options)
|
||||
m->dst = i;
|
||||
m->score = estimate_similarity(one, two,
|
||||
minimum_score);
|
||||
m->name_score = basename_same(one, two);
|
||||
diff_free_filespec_data(one);
|
||||
}
|
||||
/* We do not need the text anymore */
|
||||
|
||||
@@ -27,6 +27,7 @@ struct diff_filespec {
|
||||
char *path;
|
||||
void *data;
|
||||
void *cnt_data;
|
||||
const char *funcname_pattern_ident;
|
||||
unsigned long size;
|
||||
int xfrm_flags; /* for use by the xfrm */
|
||||
unsigned short mode; /* file mode */
|
||||
@@ -37,6 +38,8 @@ struct diff_filespec {
|
||||
#define DIFF_FILE_VALID(spec) (((spec)->mode) != 0)
|
||||
unsigned should_free : 1; /* data should be free()'ed */
|
||||
unsigned should_munmap : 1; /* data should be munmap()'ed */
|
||||
unsigned checked_attr : 1;
|
||||
unsigned is_binary : 1; /* data should be considered "binary" */
|
||||
};
|
||||
|
||||
extern struct diff_filespec *alloc_filespec(const char *);
|
||||
@@ -45,6 +48,7 @@ extern void fill_filespec(struct diff_filespec *, const unsigned char *,
|
||||
|
||||
extern int diff_populate_filespec(struct diff_filespec *, int);
|
||||
extern void diff_free_filespec_data(struct diff_filespec *);
|
||||
extern int diff_filespec_is_binary(struct diff_filespec *);
|
||||
|
||||
struct diff_filepair {
|
||||
struct diff_filespec *one;
|
||||
@@ -103,8 +107,8 @@ void diff_debug_queue(const char *, struct diff_queue_struct *);
|
||||
#define diff_debug_queue(a,b) do {} while(0)
|
||||
#endif
|
||||
|
||||
extern int diffcore_count_changes(void *src, unsigned long src_size,
|
||||
void *dst, unsigned long dst_size,
|
||||
extern int diffcore_count_changes(struct diff_filespec *src,
|
||||
struct diff_filespec *dst,
|
||||
void **src_count_p,
|
||||
void **dst_count_p,
|
||||
unsigned long delta_limit,
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
char git_default_email[MAX_GITNAME];
|
||||
char git_default_name[MAX_GITNAME];
|
||||
int trust_executable_bit = 1;
|
||||
int quote_path_fully = 1;
|
||||
int has_symlinks = 1;
|
||||
int assume_unchanged;
|
||||
int prefer_symlink_refs;
|
||||
@@ -29,6 +30,7 @@ int core_compression_seen;
|
||||
size_t packed_git_window_size = DEFAULT_PACKED_GIT_WINDOW_SIZE;
|
||||
size_t packed_git_limit = DEFAULT_PACKED_GIT_LIMIT;
|
||||
size_t delta_base_cache_limit = 16 * 1024 * 1024;
|
||||
char *pager_program;
|
||||
int pager_in_use;
|
||||
int pager_use_color = 1;
|
||||
int auto_crlf = 0; /* 1: both ways, -1: only when adding git objects */
|
||||
|
||||
164
fast-import.c
164
fast-import.c
@@ -26,9 +26,16 @@ Format of STDIN stream:
|
||||
lf;
|
||||
commit_msg ::= data;
|
||||
|
||||
file_change ::= file_clr | file_del | file_obm | file_inm;
|
||||
file_change ::= file_clr
|
||||
| file_del
|
||||
| file_rnm
|
||||
| file_cpy
|
||||
| file_obm
|
||||
| file_inm;
|
||||
file_clr ::= 'deleteall' lf;
|
||||
file_del ::= 'D' sp path_str lf;
|
||||
file_rnm ::= 'R' sp path_str sp path_str lf;
|
||||
file_cpy ::= 'C' sp path_str sp path_str lf;
|
||||
file_obm ::= 'M' sp mode sp (hexsha1 | idnum) sp path_str lf;
|
||||
file_inm ::= 'M' sp mode sp 'inline' sp path_str lf
|
||||
data;
|
||||
@@ -622,6 +629,31 @@ static void release_tree_entry(struct tree_entry *e)
|
||||
avail_tree_entry = e;
|
||||
}
|
||||
|
||||
static struct tree_content *dup_tree_content(struct tree_content *s)
|
||||
{
|
||||
struct tree_content *d;
|
||||
struct tree_entry *a, *b;
|
||||
unsigned int i;
|
||||
|
||||
if (!s)
|
||||
return NULL;
|
||||
d = new_tree_content(s->entry_count);
|
||||
for (i = 0; i < s->entry_count; i++) {
|
||||
a = s->entries[i];
|
||||
b = new_tree_entry();
|
||||
memcpy(b, a, sizeof(*a));
|
||||
if (a->tree && is_null_sha1(b->versions[1].sha1))
|
||||
b->tree = dup_tree_content(a->tree);
|
||||
else
|
||||
b->tree = NULL;
|
||||
d->entries[i] = b;
|
||||
}
|
||||
d->entry_count = s->entry_count;
|
||||
d->delta_depth = s->delta_depth;
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
static void start_packfile(void)
|
||||
{
|
||||
static char tmpfile[PATH_MAX];
|
||||
@@ -1154,7 +1186,8 @@ static int tree_content_set(
|
||||
struct tree_entry *root,
|
||||
const char *p,
|
||||
const unsigned char *sha1,
|
||||
const uint16_t mode)
|
||||
const uint16_t mode,
|
||||
struct tree_content *subtree)
|
||||
{
|
||||
struct tree_content *t = root->tree;
|
||||
const char *slash1;
|
||||
@@ -1168,20 +1201,22 @@ static int tree_content_set(
|
||||
n = strlen(p);
|
||||
if (!n)
|
||||
die("Empty path component found in input");
|
||||
if (!slash1 && !S_ISDIR(mode) && subtree)
|
||||
die("Non-directories cannot have subtrees");
|
||||
|
||||
for (i = 0; i < t->entry_count; i++) {
|
||||
e = t->entries[i];
|
||||
if (e->name->str_len == n && !strncmp(p, e->name->str_dat, n)) {
|
||||
if (!slash1) {
|
||||
if (e->versions[1].mode == mode
|
||||
if (!S_ISDIR(mode)
|
||||
&& e->versions[1].mode == mode
|
||||
&& !hashcmp(e->versions[1].sha1, sha1))
|
||||
return 0;
|
||||
e->versions[1].mode = mode;
|
||||
hashcpy(e->versions[1].sha1, sha1);
|
||||
if (e->tree) {
|
||||
if (e->tree)
|
||||
release_tree_content_recursive(e->tree);
|
||||
e->tree = NULL;
|
||||
}
|
||||
e->tree = subtree;
|
||||
hashclr(root->versions[1].sha1);
|
||||
return 1;
|
||||
}
|
||||
@@ -1191,7 +1226,7 @@ static int tree_content_set(
|
||||
}
|
||||
if (!e->tree)
|
||||
load_tree(e);
|
||||
if (tree_content_set(e, slash1 + 1, sha1, mode)) {
|
||||
if (tree_content_set(e, slash1 + 1, sha1, mode, subtree)) {
|
||||
hashclr(root->versions[1].sha1);
|
||||
return 1;
|
||||
}
|
||||
@@ -1209,9 +1244,9 @@ static int tree_content_set(
|
||||
if (slash1) {
|
||||
e->tree = new_tree_content(8);
|
||||
e->versions[1].mode = S_IFDIR;
|
||||
tree_content_set(e, slash1 + 1, sha1, mode);
|
||||
tree_content_set(e, slash1 + 1, sha1, mode, subtree);
|
||||
} else {
|
||||
e->tree = NULL;
|
||||
e->tree = subtree;
|
||||
e->versions[1].mode = mode;
|
||||
hashcpy(e->versions[1].sha1, sha1);
|
||||
}
|
||||
@@ -1219,7 +1254,10 @@ static int tree_content_set(
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int tree_content_remove(struct tree_entry *root, const char *p)
|
||||
static int tree_content_remove(
|
||||
struct tree_entry *root,
|
||||
const char *p,
|
||||
struct tree_entry *backup_leaf)
|
||||
{
|
||||
struct tree_content *t = root->tree;
|
||||
const char *slash1;
|
||||
@@ -1239,13 +1277,14 @@ static int tree_content_remove(struct tree_entry *root, const char *p)
|
||||
goto del_entry;
|
||||
if (!e->tree)
|
||||
load_tree(e);
|
||||
if (tree_content_remove(e, slash1 + 1)) {
|
||||
if (tree_content_remove(e, slash1 + 1, backup_leaf)) {
|
||||
for (n = 0; n < e->tree->entry_count; n++) {
|
||||
if (e->tree->entries[n]->versions[1].mode) {
|
||||
hashclr(root->versions[1].sha1);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
backup_leaf = NULL;
|
||||
goto del_entry;
|
||||
}
|
||||
return 0;
|
||||
@@ -1254,16 +1293,54 @@ static int tree_content_remove(struct tree_entry *root, const char *p)
|
||||
return 0;
|
||||
|
||||
del_entry:
|
||||
if (e->tree) {
|
||||
if (backup_leaf)
|
||||
memcpy(backup_leaf, e, sizeof(*backup_leaf));
|
||||
else if (e->tree)
|
||||
release_tree_content_recursive(e->tree);
|
||||
e->tree = NULL;
|
||||
}
|
||||
e->tree = NULL;
|
||||
e->versions[1].mode = 0;
|
||||
hashclr(e->versions[1].sha1);
|
||||
hashclr(root->versions[1].sha1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int tree_content_get(
|
||||
struct tree_entry *root,
|
||||
const char *p,
|
||||
struct tree_entry *leaf)
|
||||
{
|
||||
struct tree_content *t = root->tree;
|
||||
const char *slash1;
|
||||
unsigned int i, n;
|
||||
struct tree_entry *e;
|
||||
|
||||
slash1 = strchr(p, '/');
|
||||
if (slash1)
|
||||
n = slash1 - p;
|
||||
else
|
||||
n = strlen(p);
|
||||
|
||||
for (i = 0; i < t->entry_count; i++) {
|
||||
e = t->entries[i];
|
||||
if (e->name->str_len == n && !strncmp(p, e->name->str_dat, n)) {
|
||||
if (!slash1) {
|
||||
memcpy(leaf, e, sizeof(*leaf));
|
||||
if (e->tree && is_null_sha1(e->versions[1].sha1))
|
||||
leaf->tree = dup_tree_content(e->tree);
|
||||
else
|
||||
leaf->tree = NULL;
|
||||
return 1;
|
||||
}
|
||||
if (!S_ISDIR(e->versions[1].mode))
|
||||
return 0;
|
||||
if (!e->tree)
|
||||
load_tree(e);
|
||||
return tree_content_get(e, slash1 + 1, leaf);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int update_branch(struct branch *b)
|
||||
{
|
||||
static const char *msg = "fast-import";
|
||||
@@ -1629,7 +1706,7 @@ static void file_change_m(struct branch *b)
|
||||
typename(type), command_buf.buf);
|
||||
}
|
||||
|
||||
tree_content_set(&b->branch_tree, p, sha1, S_IFREG | mode);
|
||||
tree_content_set(&b->branch_tree, p, sha1, S_IFREG | mode, NULL);
|
||||
free(p_uq);
|
||||
}
|
||||
|
||||
@@ -1645,10 +1722,61 @@ static void file_change_d(struct branch *b)
|
||||
die("Garbage after path in: %s", command_buf.buf);
|
||||
p = p_uq;
|
||||
}
|
||||
tree_content_remove(&b->branch_tree, p);
|
||||
tree_content_remove(&b->branch_tree, p, NULL);
|
||||
free(p_uq);
|
||||
}
|
||||
|
||||
static void file_change_cr(struct branch *b, int rename)
|
||||
{
|
||||
const char *s, *d;
|
||||
char *s_uq, *d_uq;
|
||||
const char *endp;
|
||||
struct tree_entry leaf;
|
||||
|
||||
s = command_buf.buf + 2;
|
||||
s_uq = unquote_c_style(s, &endp);
|
||||
if (s_uq) {
|
||||
if (*endp != ' ')
|
||||
die("Missing space after source: %s", command_buf.buf);
|
||||
}
|
||||
else {
|
||||
endp = strchr(s, ' ');
|
||||
if (!endp)
|
||||
die("Missing space after source: %s", command_buf.buf);
|
||||
s_uq = xmalloc(endp - s + 1);
|
||||
memcpy(s_uq, s, endp - s);
|
||||
s_uq[endp - s] = 0;
|
||||
}
|
||||
s = s_uq;
|
||||
|
||||
endp++;
|
||||
if (!*endp)
|
||||
die("Missing dest: %s", command_buf.buf);
|
||||
|
||||
d = endp;
|
||||
d_uq = unquote_c_style(d, &endp);
|
||||
if (d_uq) {
|
||||
if (*endp)
|
||||
die("Garbage after dest in: %s", command_buf.buf);
|
||||
d = d_uq;
|
||||
}
|
||||
|
||||
memset(&leaf, 0, sizeof(leaf));
|
||||
if (rename)
|
||||
tree_content_remove(&b->branch_tree, s, &leaf);
|
||||
else
|
||||
tree_content_get(&b->branch_tree, s, &leaf);
|
||||
if (!leaf.versions[1].mode)
|
||||
die("Path %s not in branch", s);
|
||||
tree_content_set(&b->branch_tree, d,
|
||||
leaf.versions[1].sha1,
|
||||
leaf.versions[1].mode,
|
||||
leaf.tree);
|
||||
|
||||
free(s_uq);
|
||||
free(d_uq);
|
||||
}
|
||||
|
||||
static void file_change_deleteall(struct branch *b)
|
||||
{
|
||||
release_tree_content_recursive(b->branch_tree.tree);
|
||||
@@ -1816,6 +1944,10 @@ static void cmd_new_commit(void)
|
||||
file_change_m(b);
|
||||
else if (!prefixcmp(command_buf.buf, "D "))
|
||||
file_change_d(b);
|
||||
else if (!prefixcmp(command_buf.buf, "R "))
|
||||
file_change_cr(b, 1);
|
||||
else if (!prefixcmp(command_buf.buf, "C "))
|
||||
file_change_cr(b, 0);
|
||||
else if (!strcmp("deleteall", command_buf.buf))
|
||||
file_change_deleteall(b);
|
||||
else
|
||||
|
||||
16
fixup-builtins
Executable file
16
fixup-builtins
Executable file
@@ -0,0 +1,16 @@
|
||||
#!/bin/sh
|
||||
while [ "$1" ]
|
||||
do
|
||||
old="$1"
|
||||
new=$(echo "$1" | sed 's/git-/git /')
|
||||
echo "Converting '$old' to '$new'"
|
||||
git ls-files '*.sh' | while read file
|
||||
do
|
||||
sed "s/\\<$old\\>/$new/g" < $file > $file.new
|
||||
chmod --reference=$file $file.new
|
||||
mv $file.new $file
|
||||
done
|
||||
shift
|
||||
done
|
||||
git update-index --refresh >& /dev/null
|
||||
exit 0
|
||||
51
git-am.sh
51
git-am.sh
@@ -60,17 +60,17 @@ fall_back_3way () {
|
||||
mkdir "$dotest/patch-merge-tmp-dir"
|
||||
|
||||
# First see if the patch records the index info that we can use.
|
||||
git-apply -z --index-info "$dotest/patch" \
|
||||
git apply -z --index-info "$dotest/patch" \
|
||||
>"$dotest/patch-merge-index-info" &&
|
||||
GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \
|
||||
git-update-index -z --index-info <"$dotest/patch-merge-index-info" &&
|
||||
git update-index -z --index-info <"$dotest/patch-merge-index-info" &&
|
||||
GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \
|
||||
git-write-tree >"$dotest/patch-merge-base+" ||
|
||||
git write-tree >"$dotest/patch-merge-base+" ||
|
||||
cannot_fallback "Repository lacks necessary blobs to fall back on 3-way merge."
|
||||
|
||||
echo Using index info to reconstruct a base tree...
|
||||
if GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \
|
||||
git-apply $binary --cached <"$dotest/patch"
|
||||
git apply $binary --cached <"$dotest/patch"
|
||||
then
|
||||
mv "$dotest/patch-merge-base+" "$dotest/patch-merge-base"
|
||||
mv "$dotest/patch-merge-tmp-index" "$dotest/patch-merge-index"
|
||||
@@ -80,7 +80,7 @@ It does not apply to blobs recorded in its index."
|
||||
fi
|
||||
|
||||
test -f "$dotest/patch-merge-index" &&
|
||||
his_tree=$(GIT_INDEX_FILE="$dotest/patch-merge-index" git-write-tree) &&
|
||||
his_tree=$(GIT_INDEX_FILE="$dotest/patch-merge-index" git write-tree) &&
|
||||
orig_tree=$(cat "$dotest/patch-merge-base") &&
|
||||
rm -fr "$dotest"/patch-merge-* || exit 1
|
||||
|
||||
@@ -95,10 +95,7 @@ It does not apply to blobs recorded in its index."
|
||||
eval GITHEAD_$his_tree='"$SUBJECT"'
|
||||
export GITHEAD_$his_tree
|
||||
git-merge-recursive $orig_tree -- HEAD $his_tree || {
|
||||
if test -d "$GIT_DIR/rr-cache"
|
||||
then
|
||||
git-rerere
|
||||
fi
|
||||
git rerere
|
||||
echo Failed to merge in the changes.
|
||||
exit 1
|
||||
}
|
||||
@@ -198,7 +195,7 @@ else
|
||||
# Start afresh.
|
||||
mkdir -p "$dotest" || exit
|
||||
|
||||
git-mailsplit -d"$prec" -o"$dotest" -b -- "$@" > "$dotest/last" || {
|
||||
git mailsplit -d"$prec" -o"$dotest" -b -- "$@" > "$dotest/last" || {
|
||||
rm -fr "$dotest"
|
||||
exit 1
|
||||
}
|
||||
@@ -216,7 +213,7 @@ fi
|
||||
|
||||
case "$resolved" in
|
||||
'')
|
||||
files=$(git-diff-index --cached --name-only HEAD) || exit
|
||||
files=$(git diff-index --cached --name-only HEAD) || exit
|
||||
if [ "$files" ]; then
|
||||
echo "Dirty index: cannot apply patches (dirty: $files)" >&2
|
||||
exit 1
|
||||
@@ -252,10 +249,7 @@ last=`cat "$dotest/last"`
|
||||
this=`cat "$dotest/next"`
|
||||
if test "$skip" = t
|
||||
then
|
||||
if test -d "$GIT_DIR/rr-cache"
|
||||
then
|
||||
git-rerere clear
|
||||
fi
|
||||
git rerere clear
|
||||
this=`expr "$this" + 1`
|
||||
resume=
|
||||
fi
|
||||
@@ -287,14 +281,14 @@ do
|
||||
# by the user, or the user can tell us to do so by --resolved flag.
|
||||
case "$resume" in
|
||||
'')
|
||||
git-mailinfo $keep $utf8 "$dotest/msg" "$dotest/patch" \
|
||||
git mailinfo $keep $utf8 "$dotest/msg" "$dotest/patch" \
|
||||
<"$dotest/$msgnum" >"$dotest/info" ||
|
||||
stop_here $this
|
||||
test -s $dotest/patch || {
|
||||
echo "Patch is empty. Was it split wrong?"
|
||||
stop_here $this
|
||||
}
|
||||
git-stripspace < "$dotest/msg" > "$dotest/msg-clean"
|
||||
git stripspace < "$dotest/msg" > "$dotest/msg-clean"
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -347,7 +341,7 @@ do
|
||||
case "$resolved$interactive" in
|
||||
tt)
|
||||
# This is used only for interactive view option.
|
||||
git-diff-index -p --cached HEAD >"$dotest/patch"
|
||||
git diff-index -p --cached HEAD >"$dotest/patch"
|
||||
;;
|
||||
esac
|
||||
esac
|
||||
@@ -399,7 +393,7 @@ do
|
||||
|
||||
case "$resolved" in
|
||||
'')
|
||||
git-apply $git_apply_opt $binary --index "$dotest/patch"
|
||||
git apply $git_apply_opt $binary --index "$dotest/patch"
|
||||
apply_status=$?
|
||||
;;
|
||||
t)
|
||||
@@ -408,11 +402,11 @@ do
|
||||
# trust what the user has in the index file and the
|
||||
# working tree.
|
||||
resolved=
|
||||
git-diff-index --quiet --cached HEAD && {
|
||||
git diff-index --quiet --cached HEAD && {
|
||||
echo "No changes - did you forget to use 'git add'?"
|
||||
stop_here_user_resolve $this
|
||||
}
|
||||
unmerged=$(git-ls-files -u)
|
||||
unmerged=$(git ls-files -u)
|
||||
if test -n "$unmerged"
|
||||
then
|
||||
echo "You still have unmerged paths in your index"
|
||||
@@ -420,10 +414,7 @@ do
|
||||
stop_here_user_resolve $this
|
||||
fi
|
||||
apply_status=0
|
||||
if test -d "$GIT_DIR/rr-cache"
|
||||
then
|
||||
git rerere
|
||||
fi
|
||||
git rerere
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -433,7 +424,7 @@ do
|
||||
then
|
||||
# Applying the patch to an earlier tree and merging the
|
||||
# result may have produced the same tree as ours.
|
||||
git-diff-index --quiet --cached HEAD && {
|
||||
git diff-index --quiet --cached HEAD && {
|
||||
echo No changes -- Patch already applied.
|
||||
go_next
|
||||
continue
|
||||
@@ -453,12 +444,12 @@ do
|
||||
"$GIT_DIR"/hooks/pre-applypatch || stop_here $this
|
||||
fi
|
||||
|
||||
tree=$(git-write-tree) &&
|
||||
tree=$(git write-tree) &&
|
||||
echo Wrote tree $tree &&
|
||||
parent=$(git-rev-parse --verify HEAD) &&
|
||||
commit=$(git-commit-tree $tree -p $parent <"$dotest/final-commit") &&
|
||||
parent=$(git rev-parse --verify HEAD) &&
|
||||
commit=$(git commit-tree $tree -p $parent <"$dotest/final-commit") &&
|
||||
echo Committed: $commit &&
|
||||
git-update-ref -m "$GIT_REFLOG_ACTION: $SUBJECT" HEAD $commit $parent ||
|
||||
git update-ref -m "$GIT_REFLOG_ACTION: $SUBJECT" HEAD $commit $parent ||
|
||||
stop_here $this
|
||||
|
||||
if test -x "$GIT_DIR"/hooks/post-applypatch
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user