mirror of
https://github.com/git/git.git
synced 2026-03-13 10:23:30 +01:00
Merge v1.5.0.
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -36,6 +36,7 @@ git-diff-index
|
||||
git-diff-stages
|
||||
git-diff-tree
|
||||
git-describe
|
||||
git-fast-import
|
||||
git-fetch
|
||||
git-fetch-pack
|
||||
git-findtags
|
||||
@@ -71,7 +72,6 @@ git-merge-tree
|
||||
git-merge-octopus
|
||||
git-merge-one-file
|
||||
git-merge-ours
|
||||
git-merge-recur
|
||||
git-merge-recursive
|
||||
git-merge-resolve
|
||||
git-merge-stupid
|
||||
|
||||
@@ -31,6 +31,8 @@ man1dir=$(mandir)/man1
|
||||
man7dir=$(mandir)/man7
|
||||
# DESTDIR=
|
||||
|
||||
ASCIIDOC=asciidoc
|
||||
ASCIIDOC_EXTRA =
|
||||
INSTALL?=install
|
||||
DOC_REF = origin/man
|
||||
|
||||
@@ -91,16 +93,16 @@ clean:
|
||||
rm -f $(cmds_txt)
|
||||
|
||||
%.html : %.txt
|
||||
asciidoc -b xhtml11 -d manpage -f asciidoc.conf $<
|
||||
$(ASCIIDOC) -b xhtml11 -d manpage -f asciidoc.conf $(ASCIIDOC_EXTRA) $<
|
||||
|
||||
%.1 %.7 : %.xml
|
||||
xmlto -m callouts.xsl man $<
|
||||
|
||||
%.xml : %.txt
|
||||
asciidoc -b docbook -d manpage -f asciidoc.conf $<
|
||||
$(ASCIIDOC) -b docbook -d manpage -f asciidoc.conf $<
|
||||
|
||||
user-manual.xml: user-manual.txt user-manual.conf
|
||||
asciidoc -b docbook -d book $<
|
||||
$(ASCIIDOC) -b docbook -d book $<
|
||||
|
||||
user-manual.html: user-manual.xml
|
||||
xmlto html-nochunks $<
|
||||
@@ -108,7 +110,7 @@ user-manual.html: user-manual.xml
|
||||
glossary.html : glossary.txt sort_glossary.pl
|
||||
cat $< | \
|
||||
perl sort_glossary.pl | \
|
||||
asciidoc -b xhtml11 - > glossary.html
|
||||
$(ASCIIDOC) -b xhtml11 - > glossary.html
|
||||
|
||||
howto-index.txt: howto-index.sh $(wildcard howto/*.txt)
|
||||
rm -f $@+ $@
|
||||
@@ -116,13 +118,13 @@ howto-index.txt: howto-index.sh $(wildcard howto/*.txt)
|
||||
mv $@+ $@
|
||||
|
||||
$(patsubst %,%.html,$(ARTICLES)) : %.html : %.txt
|
||||
asciidoc -b xhtml11 $*.txt
|
||||
$(ASCIIDOC) -b xhtml11 $*.txt
|
||||
|
||||
WEBDOC_DEST = /pub/software/scm/git/docs
|
||||
|
||||
$(patsubst %.txt,%.html,$(wildcard howto/*.txt)): %.html : %.txt
|
||||
rm -f $@+ $@
|
||||
sed -e '1,/^$$/d' $< | asciidoc -b xhtml11 - >$@+
|
||||
sed -e '1,/^$$/d' $< | $(ASCIIDOC) -b xhtml11 - >$@+
|
||||
mv $@+ $@
|
||||
|
||||
install-webdoc : html
|
||||
|
||||
468
Documentation/RelNotes-1.5.0.txt
Normal file
468
Documentation/RelNotes-1.5.0.txt
Normal file
@@ -0,0 +1,468 @@
|
||||
GIT v1.5.0 Release Notes
|
||||
========================
|
||||
|
||||
Old news
|
||||
--------
|
||||
|
||||
This section is for people who are upgrading from ancient
|
||||
versions of git. Although all of the changes in this section
|
||||
happened before the current v1.4.4 release, they are summarized
|
||||
here in the v1.5.0 release notes for people who skipped earlier
|
||||
versions.
|
||||
|
||||
As of git v1.5.0 there are some optional features that changes
|
||||
the repository to allow data to be stored and transferred more
|
||||
efficiently. These features are not enabled by default, as they
|
||||
will make the repository unusable with older versions of git.
|
||||
Specifically, the available options are:
|
||||
|
||||
- There is a configuration variable core.legacyheaders that
|
||||
changes the format of loose objects so that they are more
|
||||
efficient to pack and to send out of the repository over git
|
||||
native protocol, since v1.4.2. However, loose objects
|
||||
written in the new format cannot be read by git older than
|
||||
that version; people fetching from your repository using
|
||||
older clients over dumb transports (e.g. http) using older
|
||||
versions of git will also be affected.
|
||||
|
||||
- Since v1.4.3, configuration repack.usedeltabaseoffset allows
|
||||
packfile to be created in more space efficient format, which
|
||||
cannot be read by git older than that version.
|
||||
|
||||
The above two are not enabled by default and you explicitly have
|
||||
to ask for them, because these two features make repositories
|
||||
unreadable by older versions of git, and in v1.5.0 we still do
|
||||
not enable them by default for the same reason. We will change
|
||||
this default probably 1 year after 1.4.2's release, when it is
|
||||
reasonable to expect everybody to have new enough version of
|
||||
git.
|
||||
|
||||
- 'git pack-refs' appeared in v1.4.4; this command allows tags
|
||||
to be accessed much more efficiently than the traditional
|
||||
'one-file-per-tag' format. Older git-native clients can
|
||||
still fetch from a repository that packed and pruned refs
|
||||
(the server side needs to run the up-to-date version of git),
|
||||
but older dumb transports cannot. Packing of refs is done by
|
||||
an explicit user action, either by use of "git pack-refs
|
||||
--prune" command or by use of "git gc" command.
|
||||
|
||||
- 'git -p' to paginate anything -- many commands do pagination
|
||||
by default on a tty. Introduced between v1.4.1 and v1.4.2;
|
||||
this may surprise old timers.
|
||||
|
||||
- 'git archive' superseded 'git tar-tree' in v1.4.3;
|
||||
|
||||
- 'git cvsserver' was new invention in v1.3.0;
|
||||
|
||||
- 'git repo-config', 'git grep', 'git rebase' and 'gitk' were
|
||||
seriously enhanced during v1.4.0 timeperiod.
|
||||
|
||||
- 'gitweb' became part of git.git during v1.4.0 timeperiod and
|
||||
seriously modified since then.
|
||||
|
||||
- reflog is an v1.4.0 invention. This allows you to name a
|
||||
revision that a branch used to be at (e.g. "git diff
|
||||
master@{yesterday} master" allows you to see changes since
|
||||
yesterday's tip of the branch).
|
||||
|
||||
|
||||
Updates in v1.5.0 since v1.4.4 series
|
||||
-------------------------------------
|
||||
|
||||
* Index manipulation
|
||||
|
||||
- git-add is to add contents to the index (aka "staging area"
|
||||
for the next commit), whether the file the contents happen to
|
||||
be is an existing one or a newly created one.
|
||||
|
||||
- git-add without any argument does not add everything
|
||||
anymore. Use 'git-add .' instead. Also you can add
|
||||
otherwise ignored files with an -f option.
|
||||
|
||||
- git-add tries to be more friendly to users by offering an
|
||||
interactive mode ("git-add -i").
|
||||
|
||||
- git-commit <path> used to refuse to commit if <path> was
|
||||
different between HEAD and the index (i.e. update-index was
|
||||
used on it earlier). This check was removed.
|
||||
|
||||
- git-rm is much saner and safer. It is used to remove paths
|
||||
from both the index file and the working tree, and makes sure
|
||||
you are not losing any local modification before doing so.
|
||||
|
||||
- git-reset <tree> <paths>... can be used to revert index
|
||||
entries for selected paths.
|
||||
|
||||
- git-update-index is much less visible. Many suggestions to
|
||||
use the command in git output and documentation have now been
|
||||
replaced by simpler commands such as "git add" or "git rm".
|
||||
|
||||
|
||||
* Repository layout and objects transfer
|
||||
|
||||
- The data for origin repository is stored in the configuration
|
||||
file $GIT_DIR/config, not in $GIT_DIR/remotes/, for newly
|
||||
created clones. The latter is still supported and there is
|
||||
no need to convert your existing repository if you are
|
||||
already comfortable with your workflow with the layout.
|
||||
|
||||
- git-clone always uses what is known as "separate remote"
|
||||
layout for a newly created repository with a working tree.
|
||||
|
||||
A repository with the separate remote layout starts with only
|
||||
one default branch, 'master', to be used for your own
|
||||
development. Unlike the traditional layout that copied all
|
||||
the upstream branches into your branch namespace (while
|
||||
renaming their 'master' to your 'origin'), the new layout
|
||||
puts upstream branches into local "remote-tracking branches"
|
||||
with their own namespace. These can be referenced with names
|
||||
such as "origin/$upstream_branch_name" and are stored in
|
||||
.git/refs/remotes rather than .git/refs/heads where normal
|
||||
branches are stored.
|
||||
|
||||
This layout keeps your own branch namespace less cluttered,
|
||||
avoids name collision with your upstream, makes it possible
|
||||
to automatically track new branches created at the remote
|
||||
after you clone from it, and makes it easier to interact with
|
||||
more than one remote repository (you can use "git remote" to
|
||||
add other repositories to track). There might be some
|
||||
surprises:
|
||||
|
||||
* 'git branch' does not show the remote tracking branches.
|
||||
It only lists your own branches. Use '-r' option to view
|
||||
the tracking branches.
|
||||
|
||||
* If you are forking off of a branch obtained from the
|
||||
upstream, you would have done something like 'git branch
|
||||
my-next next', because traditional layout dropped the
|
||||
tracking branch 'next' into your own branch namespace.
|
||||
With the separate remote layout, you say 'git branch next
|
||||
origin/next', which allows you to use the matching name
|
||||
'next' for your own branch. It also allows you to track a
|
||||
remote other than 'origin' (i.e. where you initially cloned
|
||||
from) and fork off of a branch from there the same way
|
||||
(e.g. "git branch mingw j6t/master").
|
||||
|
||||
Repositories initialized with the traditional layout continue
|
||||
to work.
|
||||
|
||||
- New branches that appear on the origin side after a clone is
|
||||
made are also tracked automatically. This is done with an
|
||||
wildcard refspec "refs/heads/*:refs/remotes/origin/*", which
|
||||
older git does not understand, so if you clone with 1.5.0,
|
||||
you would need to downgrade remote.*.fetch in the
|
||||
configuration file to specify each branch you are interested
|
||||
in individually if you plan to fetch into the repository with
|
||||
older versions of git (but why would you?).
|
||||
|
||||
- Similarly, wildcard refspec "refs/heads/*:refs/remotes/me/*"
|
||||
can be given to "git-push" command to update the tracking
|
||||
branches that is used to track the repository you are pushing
|
||||
from on the remote side.
|
||||
|
||||
- git-branch and git-show-branch know remote tracking branches
|
||||
(use the command line switch "-r" to list only tracked branches).
|
||||
|
||||
- git-push can now be used to delete a remote branch or a tag.
|
||||
This requires the updated git on the remote side (use "git
|
||||
push <remote> :refs/heads/<branch>" to delete "branch").
|
||||
|
||||
- git-push more aggressively keeps the transferred objects
|
||||
packed. Earlier we recommended to monitor amount of loose
|
||||
objects and repack regularly, but you should repack when you
|
||||
accumulated too many small packs this way as well. Updated
|
||||
git-count-objects helps you with this.
|
||||
|
||||
- git-fetch also more aggressively keeps the transferred objects
|
||||
packed. This behavior of git-push and git-fetch can be
|
||||
tweaked with a single configuration transfer.unpacklimit (but
|
||||
usually there should not be any need for a user to tweak it).
|
||||
|
||||
- A new command, git-remote, can help you manage your remote
|
||||
tracking branch definitions.
|
||||
|
||||
- You may need to specify explicit paths for upload-pack and/or
|
||||
receive-pack due to your ssh daemon configuration on the
|
||||
other end. This can now be done via remote.*.uploadpack and
|
||||
remote.*.receivepack configuration.
|
||||
|
||||
|
||||
* Bare repositories
|
||||
|
||||
- Certain commands change their behavior in a bare repository
|
||||
(i.e. a repository without associated working tree). We use
|
||||
a fairly conservative heuristic (if $GIT_DIR is ".git", or
|
||||
ends with "/.git", the repository is not bare) to decide if a
|
||||
repository is bare, but "core.bare" configuration variable
|
||||
can be used to override the heuristic when it misidentifies
|
||||
your repository.
|
||||
|
||||
- git-fetch used to complain updating the current branch but
|
||||
this is now allowed for a bare repository. So is the use of
|
||||
'git-branch -f' to update the current branch.
|
||||
|
||||
- Porcelain-ish commands that require a working tree refuses to
|
||||
work in a bare repository.
|
||||
|
||||
|
||||
* Reflog
|
||||
|
||||
- Reflog records the history from the view point of the local
|
||||
repository. In other words, regardless of the real history,
|
||||
the reflog shows the history as seen by one particular
|
||||
repository (this enables you to ask "what was the current
|
||||
revision in _this_ repository, yesterday at 1pm?"). This
|
||||
facility is enabled by default for repositories with working
|
||||
trees, and can be accessed with the "branch@{time}" and
|
||||
"branch@{Nth}" notation.
|
||||
|
||||
- "git show-branch" learned showing the reflog data with the
|
||||
new -g option. "git log" has -s option to view reflog
|
||||
entries in a more verbose manner.
|
||||
|
||||
- git-branch knows how to rename branches and moves existing
|
||||
reflog data from the old branch to the new one.
|
||||
|
||||
- In addition to the reflog support in v1.4.4 series, HEAD
|
||||
reference maintains its own log. "HEAD@{5.minutes.ago}"
|
||||
means the commit you were at 5 minutes ago, which takes
|
||||
branch switching into account. If you want to know where the
|
||||
tip of your current branch was at 5 minutes ago, you need to
|
||||
explicitly say its name (e.g. "master@{5.minutes.ago}") or
|
||||
omit the refname altogether i.e. "@{5.minutes.ago}".
|
||||
|
||||
- The commits referred to by reflog entries are now protected
|
||||
against pruning. The new command "git reflog expire" can be
|
||||
used to truncate older reflog entries and entries that refer
|
||||
to commits that have been pruned away previously with older
|
||||
versions of git.
|
||||
|
||||
Existing repositories that have been using reflog may get
|
||||
complaints from fsck-objects and may not be able to run
|
||||
git-repack, if you had run git-prune from older git; please
|
||||
run "git reflog expire --stale-fix --all" first to remove
|
||||
reflog entries that refer to commits that are no longer in
|
||||
the repository when that happens.
|
||||
|
||||
|
||||
* Crufts removal
|
||||
|
||||
- We used to say "old commits are retrievable using reflog and
|
||||
'master@{yesterday}' syntax as long as you haven't run
|
||||
git-prune". We no longer have to say the latter half of the
|
||||
above sentence, as git-prune does not remove things reachable
|
||||
from reflog entries.
|
||||
|
||||
- 'git-prune' by default does not remove _everything_
|
||||
unreachable, as there is a one-day grace period built-in.
|
||||
|
||||
- There is a toplevel garbage collector script, 'git-gc', that
|
||||
runs periodic cleanup functions, including 'git-repack -a -d',
|
||||
'git-reflog expire', 'git-pack-refs --prune', and 'git-rerere
|
||||
gc'.
|
||||
|
||||
- The output from fsck ("fsck-objects" is called just "fsck"
|
||||
now, but the old name continues to work) was needlessly
|
||||
alarming in that it warned missing objects that are reachable
|
||||
only from dangling objects. This has been corrected and the
|
||||
output is much more useful.
|
||||
|
||||
|
||||
* Detached HEAD
|
||||
|
||||
- You can use 'git-checkout' to check out an arbitrary revision
|
||||
or a tag as well, instead of named branches. This will
|
||||
dissociate your HEAD from the branch you are currently on.
|
||||
|
||||
A typical use of this feature is to "look around". E.g.
|
||||
|
||||
$ git checkout v2.6.16
|
||||
... compile, test, etc.
|
||||
$ git checkout v2.6.17
|
||||
... compile, test, etc.
|
||||
|
||||
- After detaching your HEAD, you can go back to an existing
|
||||
branch with usual "git checkout $branch". Also you can
|
||||
start a new branch using "git checkout -b $newbranch" to
|
||||
start a new branch at that commit.
|
||||
|
||||
- You can even pull from other repositories, make merges and
|
||||
commits while your HEAD is detached. Also you can use "git
|
||||
reset" to jump to arbitrary commit, while still keeping your
|
||||
HEAD detached.
|
||||
|
||||
Going back to attached state (i.e. on a particular branch) by
|
||||
"git checkout $branch" can lose the current stat you arrived
|
||||
in these ways, and "git checkout" refuses when the detached
|
||||
HEAD is not pointed by any existing ref (an existing branch,
|
||||
a remote tracking branch or a tag). This safety can be
|
||||
overridden with "git checkout -f $branch".
|
||||
|
||||
|
||||
* Packed refs
|
||||
|
||||
- Repositories with hundreds of tags have been paying large
|
||||
overhead, both in storage and in runtime, due to the
|
||||
traditional one-ref-per-file format. A new command,
|
||||
git-pack-refs, can be used to "pack" them in more efficient
|
||||
representation (you can let git-gc do this for you).
|
||||
|
||||
- Clones and fetches over dumb transports are now aware of
|
||||
packed refs and can download from repositories that use
|
||||
them.
|
||||
|
||||
|
||||
* Configuration
|
||||
|
||||
- configuration related to color setting are consolidated under
|
||||
color.* namespace (older diff.color.*, status.color.* are
|
||||
still supported).
|
||||
|
||||
- 'git-repo-config' command is accessible as 'git-config' now.
|
||||
|
||||
|
||||
* Updated features
|
||||
|
||||
- git-describe uses better criteria to pick a base ref. It
|
||||
used to pick the one with the newest timestamp, but now it
|
||||
picks the one that is topologically the closest (that is,
|
||||
among ancestors of commit C, the ref T that has the shortest
|
||||
output from "git-rev-list T..C" is chosen).
|
||||
|
||||
- git-describe gives the number of commits since the base ref
|
||||
between the refname and the hash suffix. E.g. the commit one
|
||||
before v2.6.20-rc6 in the kernel repository is:
|
||||
|
||||
v2.6.20-rc5-306-ga21b069
|
||||
|
||||
which tells you that its object name begins with a21b069,
|
||||
v2.6.20-rc5 is an ancestor of it (meaning, the commit
|
||||
contains everything -rc5 has), and there are 306 commits
|
||||
since v2.6.20-rc5.
|
||||
|
||||
- git-describe with --abbrev=0 can be used to show only the
|
||||
name of the base ref.
|
||||
|
||||
- git-blame learned a new option, --incremental, that tells it
|
||||
to output the blames as they are assigned. A sample script
|
||||
to use it is also included as contrib/blameview.
|
||||
|
||||
- git-blame starts annotating from the working tree by default.
|
||||
|
||||
|
||||
* Less external dependency
|
||||
|
||||
- We no longer require the "merge" program from the RCS suite.
|
||||
All 3-way file-level merges are now done internally.
|
||||
|
||||
- The original implementation of git-merge-recursive which was
|
||||
in Python has been removed; we have a C implementation of it
|
||||
now.
|
||||
|
||||
- git-shortlog is no longer a Perl script. It no longer
|
||||
requires output piped from git-log; it can accept revision
|
||||
parameters directly on the command line.
|
||||
|
||||
|
||||
* I18n
|
||||
|
||||
- We have always encouraged the commit message to be encoded in
|
||||
UTF-8, but the users are allowed to use legacy encoding as
|
||||
appropriate for their projects. This will continue to be the
|
||||
case. However, a non UTF-8 commit encoding _must_ be
|
||||
explicitly set with i18n.commitencoding in the repository
|
||||
where a commit is made; otherwise git-commit-tree will
|
||||
complain if the log message does not look like a valid UTF-8
|
||||
string.
|
||||
|
||||
- The value of i18n.commitencoding in the originating
|
||||
repository is recorded in the commit object on the "encoding"
|
||||
header, if it is not UTF-8. git-log and friends notice this,
|
||||
and reencodes the message to the log output encoding when
|
||||
displaying, if they are different. The log output encoding
|
||||
is determined by "git log --encoding=<encoding>",
|
||||
i18n.logoutputencoding configuration, or i18n.commitencoding
|
||||
configuration, in the decreasing order of preference, and
|
||||
defaults to UTF-8.
|
||||
|
||||
- Tools for e-mailed patch application now default to -u
|
||||
behavior; i.e. it always re-codes from the e-mailed encoding
|
||||
to the encoding specified with i18n.commitencoding. This
|
||||
unfortunately forces projects that have happily been using a
|
||||
legacy encoding without setting i18n.commitencoding to set
|
||||
the configuration, but taken with other improvement, please
|
||||
excuse us for this very minor one-time inconvenience.
|
||||
|
||||
|
||||
* e-mailed patches
|
||||
|
||||
- See the above I18n section.
|
||||
|
||||
- git-format-patch now enables --binary without being asked.
|
||||
git-am does _not_ default to it, as sending binary patch via
|
||||
e-mail is unusual and is harder to review than textual
|
||||
patches and it is prudent to require the person who is
|
||||
applying the patch to explicitly ask for it.
|
||||
|
||||
- The default suffix for git-format-patch output is now ".patch",
|
||||
not ".txt". This can be changed with --suffix=.txt option,
|
||||
or setting the config variable "format.suffix" to ".txt".
|
||||
|
||||
|
||||
* Foreign SCM interfaces
|
||||
|
||||
- git-svn now requires the Perl SVN:: libraries, the
|
||||
command-line backend was too slow and limited.
|
||||
|
||||
- the 'commit' subcommand of git-svn has been renamed to
|
||||
'set-tree', and 'dcommit' is the recommended replacement for
|
||||
day-to-day work.
|
||||
|
||||
- git fast-import backend.
|
||||
|
||||
|
||||
* User support
|
||||
|
||||
- Quite a lot of documentation updates.
|
||||
|
||||
- Bash completion scripts have been updated heavily.
|
||||
|
||||
- Better error messages for often used Porcelainish commands.
|
||||
|
||||
- Git GUI. This is a simple Tk based graphical interface for
|
||||
common Git operations.
|
||||
|
||||
|
||||
* Sliding mmap
|
||||
|
||||
- We used to assume that we can mmap the whole packfile while
|
||||
in use, but with a large project this consumes huge virtual
|
||||
memory space and truly huge ones would not fit in the
|
||||
userland address space on 32-bit platforms. We now mmap huge
|
||||
packfile in pieces to avoid this problem.
|
||||
|
||||
|
||||
* Shallow clones
|
||||
|
||||
- There is a partial support for 'shallow' repositories that
|
||||
keeps only recent history. A 'shallow clone' is created by
|
||||
specifying how deep that truncated history should be
|
||||
(e.g. "git clone --depth=5 git://some.where/repo.git").
|
||||
|
||||
Currently a shallow repository has number of limitations:
|
||||
|
||||
- Cloning and fetching _from_ a shallow clone are not
|
||||
supported (nor tested -- so they might work by accident but
|
||||
they are not expected to).
|
||||
|
||||
- Pushing from nor into a shallow clone are not expected to
|
||||
work.
|
||||
|
||||
- Merging inside a shallow repository would work as long as a
|
||||
merge base is found in the recent history, but otherwise it
|
||||
will be like merging unrelated histories and may result in
|
||||
huge conflicts.
|
||||
|
||||
but this would be more than adequate for people who want to
|
||||
look at near the tip of a big project with a deep history and
|
||||
send patches in e-mail format.
|
||||
@@ -316,7 +316,6 @@ settings but I haven't tried, yet.
|
||||
mail.identity.id?.compose_html => false
|
||||
|
||||
|
||||
|
||||
Gnus
|
||||
----
|
||||
|
||||
@@ -331,3 +330,20 @@ whitespaces (fatal in patches). Running 'C-u g' to display the
|
||||
message in raw form before using '|' to run the pipe can work
|
||||
this problem around.
|
||||
|
||||
|
||||
KMail
|
||||
-----
|
||||
|
||||
This should help you to submit patches inline using KMail.
|
||||
|
||||
1) Prepare the patch as a text file.
|
||||
|
||||
2) Click on New Mail.
|
||||
|
||||
3) Go under "Options" in the Composer window and be sure that
|
||||
"Word wrap" is not set.
|
||||
|
||||
4) Use Message -> Insert file... and insert the patch.
|
||||
|
||||
5) Back in the compose window: add whatever other text you wish to the
|
||||
message, complete the addressing and subject fields, and press send.
|
||||
|
||||
@@ -92,6 +92,7 @@ git-diff-index plumbinginterrogators
|
||||
git-diff mainporcelain
|
||||
git-diff-stages plumbinginterrogators
|
||||
git-diff-tree plumbinginterrogators
|
||||
git-fast-import ancillarymanipulators
|
||||
git-fetch mainporcelain
|
||||
git-fetch-pack synchingrepositories
|
||||
git-fmt-merge-msg purehelpers
|
||||
|
||||
@@ -39,7 +39,7 @@ in the section header, like in example below:
|
||||
|
||||
Subsection names can contain any characters except newline (doublequote
|
||||
'`"`' and backslash have to be escaped as '`\"`' and '`\\`',
|
||||
respecitvely) and are case sensitive. Section header cannot span multiple
|
||||
respectively) and are case sensitive. Section header cannot span multiple
|
||||
lines. Variables may belong directly to a section or to a given subsection.
|
||||
You can have `[section]` if you have `[section "subsection"]`, but you
|
||||
don't need to.
|
||||
@@ -222,6 +222,12 @@ alias.*::
|
||||
spaces, the usual shell quoting and escaping is supported.
|
||||
quote pair and a backslash can be used to quote them.
|
||||
|
||||
If the alias expansion is prefixed with an exclamation point,
|
||||
it will be treated as a shell command. For example, defining
|
||||
"alias.new = !gitk --all --not ORIG_HEAD", the invocation
|
||||
"git new" is equivalent to running the shell command
|
||||
"gitk --all --not ORIG_HEAD".
|
||||
|
||||
apply.whitespace::
|
||||
Tells `git-apply` how to handle whitespaces, in the same way
|
||||
as the '--whitespace' option. See gitlink:git-apply[1].
|
||||
@@ -315,6 +321,17 @@ format.headers::
|
||||
Additional email headers to include in a patch to be submitted
|
||||
by mail. See gitlink:git-format-patch[1].
|
||||
|
||||
gc.packrefs::
|
||||
`git gc` does not run `git pack-refs` in a bare repository by
|
||||
default so that older dumb-transport clients can still fetch
|
||||
from the repository. Setting this to `true` lets `git
|
||||
gc` to run `git pack-refs`. Setting this to `false` tells
|
||||
`git gc` never to run `git pack-refs`. The default setting is
|
||||
`notbare`. Enable it only when you know you do not have to
|
||||
support such clients. The default setting will change to `true`
|
||||
at some stage, and setting this to `false` will continue to
|
||||
prevent `git pack-refs` from being run from `git gc`.
|
||||
|
||||
gc.reflogexpire::
|
||||
`git reflog expire` removes reflog entries older than
|
||||
this time; defaults to 90 days.
|
||||
|
||||
@@ -624,7 +624,7 @@ name for the state at that point.
|
||||
Copying repositories
|
||||
--------------------
|
||||
|
||||
git repositories are normally totally self-sufficient and relocatable
|
||||
git repositories are normally totally self-sufficient and relocatable.
|
||||
Unlike CVS, for example, there is no separate notion of
|
||||
"repository" and "working tree". A git repository normally *is* the
|
||||
working tree, with the local git information hidden in the `.git`
|
||||
@@ -1118,7 +1118,7 @@ You could do without using any branches at all, by
|
||||
keeping as many local repositories as you would like to have
|
||||
branches, and merging between them with `git pull`, just like
|
||||
you merge between branches. The advantage of this approach is
|
||||
that it lets you keep set of files for each `branch` checked
|
||||
that it lets you keep a set of files for each `branch` checked
|
||||
out and you may find it easier to switch back and forth if you
|
||||
juggle multiple lines of development simultaneously. Of
|
||||
course, you will pay the price of more disk usage to hold
|
||||
@@ -1300,7 +1300,7 @@ differences since stage 2 (i.e. your version).
|
||||
Publishing your work
|
||||
--------------------
|
||||
|
||||
So we can use somebody else's work from a remote repository; but
|
||||
So, we can use somebody else's work from a remote repository, but
|
||||
how can *you* prepare a repository to let other people pull from
|
||||
it?
|
||||
|
||||
@@ -1469,8 +1469,8 @@ Working with Others
|
||||
Although git is a truly distributed system, it is often
|
||||
convenient to organize your project with an informal hierarchy
|
||||
of developers. Linux kernel development is run this way. There
|
||||
is a nice illustration (page 17, "Merges to Mainline") in Randy
|
||||
Dunlap's presentation (`http://tinyurl.com/a2jdg`).
|
||||
is a nice illustration (page 17, "Merges to Mainline") in
|
||||
link:http://tinyurl.com/a2jdg[Randy Dunlap's presentation].
|
||||
|
||||
It should be stressed that this hierarchy is purely *informal*.
|
||||
There is nothing fundamental in git that enforces the "chain of
|
||||
|
||||
@@ -159,7 +159,7 @@ or like this (when '--cc' option is used):
|
||||
deleted file mode <mode>,<mode>
|
||||
+
|
||||
The `mode <mode>,<mode>..<mode>` line appears only if at least one of
|
||||
the <mode> is diferent from the rest. Extended headers with
|
||||
the <mode> is different from the rest. Extended headers with
|
||||
information about detected contents movement (renames and
|
||||
copying detection) are designed to work with diff of two
|
||||
<tree-ish> and are not used by combined diff format.
|
||||
|
||||
@@ -10,7 +10,8 @@ SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git-am' [--signoff] [--dotest=<dir>] [--utf8 | --no-utf8] [--binary] [--3way]
|
||||
[--interactive] [--whitespace=<option>] <mbox>...
|
||||
[--interactive] [--whitespace=<option>] [-C<n>] [-p<n>]
|
||||
<mbox>...
|
||||
'git-am' [--skip | --resolved]
|
||||
|
||||
DESCRIPTION
|
||||
@@ -21,6 +22,10 @@ current branch.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
<mbox>...::
|
||||
The list of mailbox files to read patches from. If you do not
|
||||
supply this argument, reads from the standard input.
|
||||
|
||||
--signoff::
|
||||
Add `Signed-off-by:` line to the commit message, using
|
||||
the committer identity of yourself.
|
||||
@@ -64,6 +69,10 @@ default. You could use `--no-utf8` to override this.
|
||||
This flag is passed to the `git-apply` program that applies
|
||||
the patch.
|
||||
|
||||
-C<n>, -p<n>::
|
||||
These flag are passed to the `git-apply` program that applies
|
||||
the patch.
|
||||
|
||||
--interactive::
|
||||
Run interactively, just like git-applymbox.
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git-blame' [-c] [-l] [-t] [-f] [-n] [-p] [--incremental] [-L n,m] [-S <revs-file>]
|
||||
[-M] [-C] [-C] [--since=<date>] [<rev>] [--] <file>
|
||||
[-M] [-C] [-C] [--since=<date>] [<rev> | --contents <file>] [--] <file>
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@@ -67,6 +67,13 @@ OPTIONS
|
||||
Show the result incrementally in a format designed for
|
||||
machine consumption.
|
||||
|
||||
--contents <file>::
|
||||
When <rev> is not specified, the command annotates the
|
||||
changes starting backwards from the working tree copy.
|
||||
This flag makes the command pretend as if the working
|
||||
tree copy has the contents of he named file (specify
|
||||
`-` to make the command read from the standard input).
|
||||
|
||||
-M::
|
||||
Detect moving lines in the file as well. When a commit
|
||||
moves a block of lines in a file (e.g. the original file
|
||||
|
||||
@@ -8,7 +8,7 @@ git-checkout - Checkout and switch to a branch
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git-checkout' [-f] [-b <new_branch> [-l]] [-m] [<branch>]
|
||||
'git-checkout' [-q] [-f] [-b <new_branch> [-l]] [-m] [<branch>]
|
||||
'git-checkout' [<tree-ish>] <paths>...
|
||||
|
||||
DESCRIPTION
|
||||
@@ -33,6 +33,9 @@ working tree.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
-q::
|
||||
Quiet, supress feedback messages.
|
||||
|
||||
-f::
|
||||
Force a re-read of everything.
|
||||
|
||||
@@ -100,22 +103,12 @@ by any branch (which is natural --- you are not on any branch).
|
||||
What this means is that you can discard your temporary commits
|
||||
and merges by switching back to an existing branch (e.g. `git
|
||||
checkout master`), and a later `git prune` or `git gc` would
|
||||
garbage-collect them.
|
||||
garbage-collect them. If you did this by mistake, you can ask
|
||||
the reflog for HEAD where you were, e.g.
|
||||
|
||||
The command would refuse to switch back to make sure that you do
|
||||
not discard your temporary state by mistake when your detached
|
||||
HEAD is not pointed at by any existing ref. If you did want to
|
||||
save your state (e.g. "I was interested in the fifth commit from
|
||||
the top of 'master' branch", or "I made two commits to fix minor
|
||||
bugs while on a detached HEAD" -- and if you do not want to lose
|
||||
these facts), you can create a new branch and switch to it with
|
||||
`git checkout -b newbranch` so that you can keep building on
|
||||
that state, or tag it first so that you can come back to it
|
||||
later and switch to the branch you wanted to switch to with `git
|
||||
tag that_state; git checkout master`. On the other hand, if you
|
||||
did want to discard the temporary state, you can give `-f`
|
||||
option (e.g. `git checkout -f master`) to override this
|
||||
behaviour.
|
||||
------------
|
||||
$ git log -g -2 HEAD
|
||||
------------
|
||||
|
||||
|
||||
EXAMPLES
|
||||
|
||||
@@ -8,7 +8,7 @@ git-cvsexportcommit - Export a single commit to a CVS checkout
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-cvsexportcommit' [-h] [-v] [-c] [-p] [-a] [-f] [-m msgprefix] [PARENTCOMMIT] COMMITID
|
||||
'git-cvsexportcommit' [-h] [-v] [-c] [-P] [-p] [-a] [-f] [-m msgprefix] [PARENTCOMMIT] COMMITID
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
@@ -46,6 +46,9 @@ OPTIONS
|
||||
-f::
|
||||
Force the merge even if the files are not up to date.
|
||||
|
||||
-P::
|
||||
Force the parent commit, even if it is not a direct parent.
|
||||
|
||||
-m::
|
||||
Prepend the commit message with the provided prefix.
|
||||
Useful for patch series and the like.
|
||||
|
||||
@@ -12,6 +12,8 @@ SYNOPSIS
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
DEPRECATED and will be removed in 1.5.1.
|
||||
|
||||
Compares the content and mode of the blobs in two stages in an
|
||||
unmerged index file.
|
||||
|
||||
|
||||
901
Documentation/git-fast-import.txt
Normal file
901
Documentation/git-fast-import.txt
Normal file
@@ -0,0 +1,901 @@
|
||||
git-fast-import(1)
|
||||
==================
|
||||
|
||||
NAME
|
||||
----
|
||||
git-fast-import - Backend for fast Git data importers.
|
||||
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
frontend | 'git-fast-import' [options]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
This program is usually not what the end user wants to run directly.
|
||||
Most end users want to use one of the existing frontend programs,
|
||||
which parses a specific type of foreign source and feeds the contents
|
||||
stored there to git-fast-import.
|
||||
|
||||
fast-import reads a mixed command/data stream from standard input and
|
||||
writes one or more packfiles directly into the current repository.
|
||||
When EOF is received on standard input, fast import writes out
|
||||
updated branch and tag refs, fully updating the current repository
|
||||
with the newly imported data.
|
||||
|
||||
The fast-import backend itself can import into an empty repository (one that
|
||||
has already been initialized by gitlink:git-init[1]) or incrementally
|
||||
update an existing populated repository. Whether or not incremental
|
||||
imports are supported from a particular foreign source depends on
|
||||
the frontend program in use.
|
||||
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
--date-format=<fmt>::
|
||||
Specify the type of dates the frontend will supply to
|
||||
fast-import within `author`, `committer` and `tagger` commands.
|
||||
See ``Date Formats'' below for details about which formats
|
||||
are supported, and their syntax.
|
||||
|
||||
--force::
|
||||
Force updating modified existing branches, even if doing
|
||||
so would cause commits to be lost (as the new commit does
|
||||
not contain the old commit).
|
||||
|
||||
--max-pack-size=<n>::
|
||||
Maximum size of each output packfile, expressed in MiB.
|
||||
The default is 4096 (4 GiB) as that is the maximum allowed
|
||||
packfile size (due to file format limitations). Some
|
||||
importers may wish to lower this, such as to ensure the
|
||||
resulting packfiles fit on CDs.
|
||||
|
||||
--depth=<n>::
|
||||
Maximum delta depth, for blob and tree deltification.
|
||||
Default is 10.
|
||||
|
||||
--active-branches=<n>::
|
||||
Maximum number of branches to maintain active at once.
|
||||
See ``Memory Utilization'' below for details. Default is 5.
|
||||
|
||||
--export-marks=<file>::
|
||||
Dumps the internal marks table to <file> when complete.
|
||||
Marks are written one per line as `:markid SHA-1`.
|
||||
Frontends can use this file to validate imports after they
|
||||
have been completed.
|
||||
|
||||
--export-pack-edges=<file>::
|
||||
After creating a packfile, print a line of data to
|
||||
<file> listing the filename of the packfile and the last
|
||||
commit on each branch that was written to that packfile.
|
||||
This information may be useful after importing projects
|
||||
whose total object set exceeds the 4 GiB packfile limit,
|
||||
as these commits can be used as edge points during calls
|
||||
to gitlink:git-pack-objects[1].
|
||||
|
||||
--quiet::
|
||||
Disable all non-fatal output, making fast-import silent when it
|
||||
is successful. This option disables the output shown by
|
||||
\--stats.
|
||||
|
||||
--stats::
|
||||
Display some basic statistics about the objects fast-import has
|
||||
created, the packfiles they were stored into, and the
|
||||
memory used by fast-import during this run. Showing this output
|
||||
is currently the default, but can be disabled with \--quiet.
|
||||
|
||||
|
||||
Performance
|
||||
-----------
|
||||
The design of fast-import allows it to import large projects in a minimum
|
||||
amount of memory usage and processing time. Assuming the frontend
|
||||
is able to keep up with fast-import and feed it a constant stream of data,
|
||||
import times for projects holding 10+ years of history and containing
|
||||
100,000+ individual commits are generally completed in just 1-2
|
||||
hours on quite modest (~$2,000 USD) hardware.
|
||||
|
||||
Most bottlenecks appear to be in foreign source data access (the
|
||||
source just cannot extract revisions fast enough) or disk IO (fast-import
|
||||
writes as fast as the disk will take the data). Imports will run
|
||||
faster if the source data is stored on a different drive than the
|
||||
destination Git repository (due to less IO contention).
|
||||
|
||||
|
||||
Development Cost
|
||||
----------------
|
||||
A typical frontend for fast-import tends to weigh in at approximately 200
|
||||
lines of Perl/Python/Ruby code. Most developers have been able to
|
||||
create working importers in just a couple of hours, even though it
|
||||
is their first exposure to fast-import, and sometimes even to Git. This is
|
||||
an ideal situation, given that most conversion tools are throw-away
|
||||
(use once, and never look back).
|
||||
|
||||
|
||||
Parallel Operation
|
||||
------------------
|
||||
Like `git-push` or `git-fetch`, imports handled by fast-import are safe to
|
||||
run alongside parallel `git repack -a -d` or `git gc` invocations,
|
||||
or any other Git operation (including `git prune`, as loose objects
|
||||
are never used by fast-import).
|
||||
|
||||
fast-import does not lock the branch or tag refs it is actively importing.
|
||||
After the import, during its ref update phase, fast-import tests each
|
||||
existing branch ref to verify the update will be a fast-forward
|
||||
update (the commit stored in the ref is contained in the new
|
||||
history of the commit to be written). If the update is not a
|
||||
fast-forward update, fast-import will skip updating that ref and instead
|
||||
prints a warning message. fast-import will always attempt to update all
|
||||
branch refs, and does not stop on the first failure.
|
||||
|
||||
Branch updates can be forced with \--force, but its recommended that
|
||||
this only be used on an otherwise quiet repository. Using \--force
|
||||
is not necessary for an initial import into an empty repository.
|
||||
|
||||
|
||||
Technical Discussion
|
||||
--------------------
|
||||
fast-import tracks a set of branches in memory. Any branch can be created
|
||||
or modified at any point during the import process by sending a
|
||||
`commit` command on the input stream. This design allows a frontend
|
||||
program to process an unlimited number of branches simultaneously,
|
||||
generating commits in the order they are available from the source
|
||||
data. It also simplifies the frontend programs considerably.
|
||||
|
||||
fast-import does not use or alter the current working directory, or any
|
||||
file within it. (It does however update the current Git repository,
|
||||
as referenced by `GIT_DIR`.) Therefore an import frontend may use
|
||||
the working directory for its own purposes, such as extracting file
|
||||
revisions from the foreign source. This ignorance of the working
|
||||
directory also allows fast-import to run very quickly, as it does not
|
||||
need to perform any costly file update operations when switching
|
||||
between branches.
|
||||
|
||||
Input Format
|
||||
------------
|
||||
With the exception of raw file data (which Git does not interpret)
|
||||
the fast-import input format is text (ASCII) based. This text based
|
||||
format simplifies development and debugging of frontend programs,
|
||||
especially when a higher level language such as Perl, Python or
|
||||
Ruby is being used.
|
||||
|
||||
fast-import is very strict about its input. Where we say SP below we mean
|
||||
*exactly* one space. Likewise LF means one (and only one) linefeed.
|
||||
Supplying additional whitespace characters will cause unexpected
|
||||
results, such as branch names or file names with leading or trailing
|
||||
spaces in their name, or early termination of fast-import when it encounters
|
||||
unexpected input.
|
||||
|
||||
Date Formats
|
||||
~~~~~~~~~~~~
|
||||
The following date formats are supported. A frontend should select
|
||||
the format it will use for this import by passing the format name
|
||||
in the \--date-format=<fmt> command line option.
|
||||
|
||||
`raw`::
|
||||
This is the Git native format and is `<time> SP <offutc>`.
|
||||
It is also fast-import's default format, if \--date-format was
|
||||
not specified.
|
||||
+
|
||||
The time of the event is specified by `<time>` as the number of
|
||||
seconds since the UNIX epoch (midnight, Jan 1, 1970, UTC) and is
|
||||
written as an ASCII decimal integer.
|
||||
+
|
||||
The local offset is specified by `<offutc>` as a positive or negative
|
||||
offset from UTC. For example EST (which is 5 hours behind UTC)
|
||||
would be expressed in `<tz>` by ``-0500'' while UTC is ``+0000''.
|
||||
The local offset does not affect `<time>`; it is used only as an
|
||||
advisement to help formatting routines display the timestamp.
|
||||
+
|
||||
If the local offset is not available in the source material, use
|
||||
``+0000'', or the most common local offset. For example many
|
||||
organizations have a CVS repository which has only ever been accessed
|
||||
by users who are located in the same location and timezone. In this
|
||||
case a reasonable offset from UTC could be assumed.
|
||||
+
|
||||
Unlike the `rfc2822` format, this format is very strict. Any
|
||||
variation in formatting will cause fast-import to reject the value.
|
||||
|
||||
`rfc2822`::
|
||||
This is the standard email format as described by RFC 2822.
|
||||
+
|
||||
An example value is ``Tue Feb 6 11:22:18 2007 -0500''. The Git
|
||||
parser is accurate, but a little on the lenient side. It is the
|
||||
same parser used by gitlink:git-am[1] when applying patches
|
||||
received from email.
|
||||
+
|
||||
Some malformed strings may be accepted as valid dates. In some of
|
||||
these cases Git will still be able to obtain the correct date from
|
||||
the malformed string. There are also some types of malformed
|
||||
strings which Git will parse wrong, and yet consider valid.
|
||||
Seriously malformed strings will be rejected.
|
||||
+
|
||||
Unlike the `raw` format above, the timezone/UTC offset information
|
||||
contained in an RFC 2822 date string is used to adjust the date
|
||||
value to UTC prior to storage. Therefore it is important that
|
||||
this information be as accurate as possible.
|
||||
+
|
||||
If the source material uses RFC 2822 style dates,
|
||||
the frontend should let fast-import handle the parsing and conversion
|
||||
(rather than attempting to do it itself) as the Git parser has
|
||||
been well tested in the wild.
|
||||
+
|
||||
Frontends should prefer the `raw` format if the source material
|
||||
already uses UNIX-epoch format, can be coaxed to give dates in that
|
||||
format, or its format is easiliy convertible to it, as there is no
|
||||
ambiguity in parsing.
|
||||
|
||||
`now`::
|
||||
Always use the current time and timezone. The literal
|
||||
`now` must always be supplied for `<when>`.
|
||||
+
|
||||
This is a toy format. The current time and timezone of this system
|
||||
is always copied into the identity string at the time it is being
|
||||
created by fast-import. There is no way to specify a different time or
|
||||
timezone.
|
||||
+
|
||||
This particular format is supplied as its short to implement and
|
||||
may be useful to a process that wants to create a new commit
|
||||
right now, without needing to use a working directory or
|
||||
gitlink:git-update-index[1].
|
||||
+
|
||||
If separate `author` and `committer` commands are used in a `commit`
|
||||
the timestamps may not match, as the system clock will be polled
|
||||
twice (once for each command). The only way to ensure that both
|
||||
author and committer identity information has the same timestamp
|
||||
is to omit `author` (thus copying from `committer`) or to use a
|
||||
date format other than `now`.
|
||||
|
||||
Commands
|
||||
~~~~~~~~
|
||||
fast-import accepts several commands to update the current repository
|
||||
and control the current import process. More detailed discussion
|
||||
(with examples) of each command follows later.
|
||||
|
||||
`commit`::
|
||||
Creates a new branch or updates an existing branch by
|
||||
creating a new commit and updating the branch to point at
|
||||
the newly created commit.
|
||||
|
||||
`tag`::
|
||||
Creates an annotated tag object from an existing commit or
|
||||
branch. Lightweight tags are not supported by this command,
|
||||
as they are not recommended for recording meaningful points
|
||||
in time.
|
||||
|
||||
`reset`::
|
||||
Reset an existing branch (or a new branch) to a specific
|
||||
revision. This command must be used to change a branch to
|
||||
a specific revision without making a commit on it.
|
||||
|
||||
`blob`::
|
||||
Convert raw file data into a blob, for future use in a
|
||||
`commit` command. This command is optional and is not
|
||||
needed to perform an import.
|
||||
|
||||
`checkpoint`::
|
||||
Forces fast-import to close the current packfile, generate its
|
||||
unique SHA-1 checksum and index, and start a new packfile.
|
||||
This command is optional and is not needed to perform
|
||||
an import.
|
||||
|
||||
`commit`
|
||||
~~~~~~~~
|
||||
Create or update a branch with a new commit, recording one logical
|
||||
change to the project.
|
||||
|
||||
....
|
||||
'commit' SP <ref> LF
|
||||
mark?
|
||||
('author' SP <name> SP LT <email> GT SP <when> LF)?
|
||||
'committer' SP <name> SP LT <email> GT SP <when> LF
|
||||
data
|
||||
('from' SP <committish> LF)?
|
||||
('merge' SP <committish> LF)?
|
||||
(filemodify | filedelete | filedeleteall)*
|
||||
LF
|
||||
....
|
||||
|
||||
where `<ref>` is the name of the branch to make the commit on.
|
||||
Typically branch names are prefixed with `refs/heads/` in
|
||||
Git, so importing the CVS branch symbol `RELENG-1_0` would use
|
||||
`refs/heads/RELENG-1_0` for the value of `<ref>`. The value of
|
||||
`<ref>` must be a valid refname in Git. As `LF` is not valid in
|
||||
a Git refname, no quoting or escaping syntax is supported here.
|
||||
|
||||
A `mark` command may optionally appear, requesting fast-import to save a
|
||||
reference to the newly created commit for future use by the frontend
|
||||
(see below for format). It is very common for frontends to mark
|
||||
every commit they create, thereby allowing future branch creation
|
||||
from any imported commit.
|
||||
|
||||
The `data` command following `committer` must supply the commit
|
||||
message (see below for `data` command syntax). To import an empty
|
||||
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
|
||||
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`
|
||||
wipes the branch clean (see below).
|
||||
|
||||
`author`
|
||||
^^^^^^^^
|
||||
An `author` command may optionally appear, if the author information
|
||||
might differ from the committer information. If `author` is omitted
|
||||
then fast-import will automatically use the committer's information for
|
||||
the author portion of the commit. See below for a description of
|
||||
the fields in `author`, as they are identical to `committer`.
|
||||
|
||||
`committer`
|
||||
^^^^^^^^^^^
|
||||
The `committer` command indicates who made this commit, and when
|
||||
they made it.
|
||||
|
||||
Here `<name>` is the person's display name (for example
|
||||
``Com M Itter'') and `<email>` is the person's email address
|
||||
(``cm@example.com''). `LT` and `GT` are the literal less-than (\x3c)
|
||||
and greater-than (\x3e) symbols. These are required to delimit
|
||||
the email address from the other fields in the line. Note that
|
||||
`<name>` is free-form and may contain any sequence of bytes, except
|
||||
`LT` and `LF`. It is typically UTF-8 encoded.
|
||||
|
||||
The time of the change is specified by `<when>` using the date format
|
||||
that was selected by the \--date-format=<fmt> command line option.
|
||||
See ``Date Formats'' above for the set of supported formats, and
|
||||
their syntax.
|
||||
|
||||
`from`
|
||||
^^^^^^
|
||||
The `from` command is used to specify the commit to initialize
|
||||
this branch from. This revision will be the first ancestor of the
|
||||
new commit.
|
||||
|
||||
Omitting the `from` command in the first commit of a new branch
|
||||
will cause fast-import to create that commit with no ancestor. This
|
||||
tends to be desired only for the initial commit of a project.
|
||||
Omitting the `from` command on existing branches is usually desired,
|
||||
as the current commit on that branch is automatically assumed to
|
||||
be the first ancestor of the new commit.
|
||||
|
||||
As `LF` is not valid in a Git refname or SHA-1 expression, no
|
||||
quoting or escaping syntax is supported within `<committish>`.
|
||||
|
||||
Here `<committish>` is any of the following:
|
||||
|
||||
* The name of an existing branch already in fast-import's internal branch
|
||||
table. If fast-import doesn't know the name, its treated as a SHA-1
|
||||
expression.
|
||||
|
||||
* A mark reference, `:<idnum>`, where `<idnum>` is the mark number.
|
||||
+
|
||||
The reason fast-import uses `:` to denote a mark reference is this character
|
||||
is not legal in a Git branch name. The leading `:` makes it easy
|
||||
to distingush between the mark 42 (`:42`) and the branch 42 (`42`
|
||||
or `refs/heads/42`), or an abbreviated SHA-1 which happened to
|
||||
consist only of base-10 digits.
|
||||
+
|
||||
Marks must be declared (via `mark`) before they can be used.
|
||||
|
||||
* A complete 40 byte or abbreviated commit SHA-1 in hex.
|
||||
|
||||
* Any valid Git SHA-1 expression that resolves to a commit. See
|
||||
``SPECIFYING REVISIONS'' in gitlink:git-rev-parse[1] for details.
|
||||
|
||||
The special case of restarting an incremental import from the
|
||||
current branch value should be written as:
|
||||
----
|
||||
from refs/heads/branch^0
|
||||
----
|
||||
The `{caret}0` suffix is necessary as fast-import does not permit a branch to
|
||||
start from itself, and the branch is created in memory before the
|
||||
`from` command is even read from the input. Adding `{caret}0` will force
|
||||
fast-import to resolve the commit through Git's revision parsing library,
|
||||
rather than its internal branch table, thereby loading in the
|
||||
existing value of the branch.
|
||||
|
||||
`merge`
|
||||
^^^^^^^
|
||||
Includes one additional ancestor commit, and makes the current
|
||||
commit a merge commit. An unlimited number of `merge` commands per
|
||||
commit are permitted by fast-import, thereby establishing an n-way merge.
|
||||
However Git's other tools never create commits with more than 15
|
||||
additional ancestors (forming a 16-way merge). For this reason
|
||||
it is suggested that frontends do not use more than 15 `merge`
|
||||
commands per commit.
|
||||
|
||||
Here `<committish>` is any of the commit specification expressions
|
||||
also accepted by `from` (see above).
|
||||
|
||||
`filemodify`
|
||||
^^^^^^^^^^^^
|
||||
Included in a `commit` command to add a new file or change the
|
||||
content of an existing file. This command has two different means
|
||||
of specifying the content of the file.
|
||||
|
||||
External data format::
|
||||
The data content for the file was already supplied by a prior
|
||||
`blob` command. The frontend just needs to connect it.
|
||||
+
|
||||
....
|
||||
'M' SP <mode> SP <dataref> SP <path> LF
|
||||
....
|
||||
+
|
||||
Here `<dataref>` can be either a mark reference (`:<idnum>`)
|
||||
set by a prior `blob` command, or a full 40-byte SHA-1 of an
|
||||
existing Git blob object.
|
||||
|
||||
Inline data format::
|
||||
The data content for the file has not been supplied yet.
|
||||
The frontend wants to supply it as part of this modify
|
||||
command.
|
||||
+
|
||||
....
|
||||
'M' SP <mode> SP 'inline' SP <path> LF
|
||||
data
|
||||
....
|
||||
+
|
||||
See below for a detailed description of the `data` command.
|
||||
|
||||
In both formats `<mode>` is the type of file entry, specified
|
||||
in octal. Git only supports the following modes:
|
||||
|
||||
* `100644` or `644`: A normal (not-executable) file. The majority
|
||||
of files in most projects use this mode. If in doubt, this is
|
||||
what you want.
|
||||
* `100755` or `755`: A normal, but executable, file.
|
||||
* `120000`: A symlink, the content of the file will be the link target.
|
||||
|
||||
In both formats `<path>` is the complete path of the file to be added
|
||||
(if not already existing) or modified (if already existing).
|
||||
|
||||
A `<path>` string must use UNIX-style directory seperators (forward
|
||||
slash `/`), may contain any byte other than `LF`, and must not
|
||||
start with double quote (`"`).
|
||||
|
||||
If an `LF` or double quote must be encoded into `<path>` shell-style
|
||||
quoting should be used, e.g. `"path/with\n and \" in it"`.
|
||||
|
||||
The value of `<path>` must be in canoncial form. That is it must not:
|
||||
|
||||
* contain an empty directory component (e.g. `foo//bar` is invalid),
|
||||
* end with a directory seperator (e.g. `foo/` is invalid),
|
||||
* start with a directory seperator (e.g. `/foo` is invalid),
|
||||
* contain the special component `.` or `..` (e.g. `foo/./bar` and
|
||||
`foo/../bar` are invalid).
|
||||
|
||||
It is recommended that `<path>` always be encoded using UTF-8.
|
||||
|
||||
`filedelete`
|
||||
^^^^^^^^^^^^
|
||||
Included in a `commit` command to remove a file from the branch.
|
||||
If the file removal makes its directory empty, the directory will
|
||||
be automatically removed too. This cascades up the tree until the
|
||||
first non-empty directory or the root is reached.
|
||||
|
||||
....
|
||||
'D' SP <path> LF
|
||||
....
|
||||
|
||||
here `<path>` is the complete path of the file to be removed.
|
||||
See `filemodify` above for a detailed description of `<path>`.
|
||||
|
||||
`filedeleteall`
|
||||
^^^^^^^^^^^^^^^
|
||||
Included in a `commit` command to remove all files (and also all
|
||||
directories) from the branch. This command resets the internal
|
||||
branch structure to have no files in it, allowing the frontend
|
||||
to subsequently add all interesting files from scratch.
|
||||
|
||||
....
|
||||
'deleteall' LF
|
||||
....
|
||||
|
||||
This command is extremely useful if the frontend does not know
|
||||
(or does not care to know) what files are currently on the branch,
|
||||
and therefore cannot generate the proper `filedelete` commands to
|
||||
update the content.
|
||||
|
||||
Issuing a `filedeleteall` followed by the needed `filemodify`
|
||||
commands to set the correct content will produce the same results
|
||||
as sending only the needed `filemodify` and `filedelete` commands.
|
||||
The `filedeleteall` approach may however require fast-import to use slightly
|
||||
more memory per active branch (less than 1 MiB for even most large
|
||||
projects); so frontends that can easily obtain only the affected
|
||||
paths for a commit are encouraged to do so.
|
||||
|
||||
`mark`
|
||||
~~~~~~
|
||||
Arranges for fast-import to save a reference to the current object, allowing
|
||||
the frontend to recall this object at a future point in time, without
|
||||
knowing its SHA-1. Here the current object is the object creation
|
||||
command the `mark` command appears within. This can be `commit`,
|
||||
`tag`, and `blob`, but `commit` is the most common usage.
|
||||
|
||||
....
|
||||
'mark' SP ':' <idnum> LF
|
||||
....
|
||||
|
||||
where `<idnum>` is the number assigned by the frontend to this mark.
|
||||
The value of `<idnum>` is expressed as an ASCII decimal integer.
|
||||
The value 0 is reserved and cannot be used as
|
||||
a mark. Only values greater than or equal to 1 may be used as marks.
|
||||
|
||||
New marks are created automatically. Existing marks can be moved
|
||||
to another object simply by reusing the same `<idnum>` in another
|
||||
`mark` command.
|
||||
|
||||
`tag`
|
||||
~~~~~
|
||||
Creates an annotated tag referring to a specific commit. To create
|
||||
lightweight (non-annotated) tags see the `reset` command below.
|
||||
|
||||
....
|
||||
'tag' SP <name> LF
|
||||
'from' SP <committish> LF
|
||||
'tagger' SP <name> SP LT <email> GT SP <when> LF
|
||||
data
|
||||
LF
|
||||
....
|
||||
|
||||
where `<name>` is the name of the tag to create.
|
||||
|
||||
Tag names are automatically prefixed with `refs/tags/` when stored
|
||||
in Git, so importing the CVS branch symbol `RELENG-1_0-FINAL` would
|
||||
use just `RELENG-1_0-FINAL` for `<name>`, and fast-import will write the
|
||||
corresponding ref as `refs/tags/RELENG-1_0-FINAL`.
|
||||
|
||||
The value of `<name>` must be a valid refname in Git and therefore
|
||||
may contain forward slashes. As `LF` is not valid in a Git refname,
|
||||
no quoting or escaping syntax is supported here.
|
||||
|
||||
The `from` command is the same as in the `commit` command; see
|
||||
above for details.
|
||||
|
||||
The `tagger` command uses the same format as `committer` within
|
||||
`commit`; again see above for details.
|
||||
|
||||
The `data` command following `tagger` must supply the annotated tag
|
||||
message (see below for `data` command syntax). To import an empty
|
||||
tag message use a 0 length data. Tag 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.
|
||||
|
||||
Signing annotated tags during import from within fast-import is not
|
||||
supported. Trying to include your own PGP/GPG signature is not
|
||||
recommended, as the frontend does not (easily) have access to the
|
||||
complete set of bytes which normally goes into such a signature.
|
||||
If signing is required, create lightweight tags from within fast-import with
|
||||
`reset`, then create the annotated versions of those tags offline
|
||||
with the standard gitlink:git-tag[1] process.
|
||||
|
||||
`reset`
|
||||
~~~~~~~
|
||||
Creates (or recreates) the named branch, optionally starting from
|
||||
a specific revision. The reset command allows a frontend to issue
|
||||
a new `from` command for an existing branch, or to create a new
|
||||
branch from an existing commit without creating a new commit.
|
||||
|
||||
....
|
||||
'reset' SP <ref> LF
|
||||
('from' SP <committish> LF)?
|
||||
LF
|
||||
....
|
||||
|
||||
For a detailed description of `<ref>` and `<committish>` see above
|
||||
under `commit` and `from`.
|
||||
|
||||
The `reset` command can also be used to create lightweight
|
||||
(non-annotated) tags. For example:
|
||||
|
||||
====
|
||||
reset refs/tags/938
|
||||
from :938
|
||||
====
|
||||
|
||||
would create the lightweight tag `refs/tags/938` referring to
|
||||
whatever commit mark `:938` references.
|
||||
|
||||
`blob`
|
||||
~~~~~~
|
||||
Requests writing one file revision to the packfile. The revision
|
||||
is not connected to any commit; this connection must be formed in
|
||||
a subsequent `commit` command by referencing the blob through an
|
||||
assigned mark.
|
||||
|
||||
....
|
||||
'blob' LF
|
||||
mark?
|
||||
data
|
||||
....
|
||||
|
||||
The mark command is optional here as some frontends have chosen
|
||||
to generate the Git SHA-1 for the blob on their own, and feed that
|
||||
directly to `commit`. This is typically more work than its worth
|
||||
however, as marks are inexpensive to store and easy to use.
|
||||
|
||||
`data`
|
||||
~~~~~~
|
||||
Supplies raw data (for use as blob/file content, commit messages, or
|
||||
annotated tag messages) to fast-import. Data can be supplied using an exact
|
||||
byte count or delimited with a terminating line. Real frontends
|
||||
intended for production-quality conversions should always use the
|
||||
exact byte count format, as it is more robust and performs better.
|
||||
The delimited format is intended primarily for testing fast-import.
|
||||
|
||||
Exact byte count format::
|
||||
The frontend must specify the number of bytes of data.
|
||||
+
|
||||
....
|
||||
'data' SP <count> LF
|
||||
<raw> LF
|
||||
....
|
||||
+
|
||||
where `<count>` is the exact number of bytes appearing within
|
||||
`<raw>`. The value of `<count>` is expressed as an ASCII decimal
|
||||
integer. The `LF` on either side of `<raw>` is not
|
||||
included in `<count>` and will not be included in the imported data.
|
||||
|
||||
Delimited format::
|
||||
A delimiter string is used to mark the end of the data.
|
||||
fast-import will compute the length by searching for the delimiter.
|
||||
This format is primarly useful for testing and is not
|
||||
recommended for real data.
|
||||
+
|
||||
....
|
||||
'data' SP '<<' <delim> LF
|
||||
<raw> LF
|
||||
<delim> LF
|
||||
....
|
||||
+
|
||||
where `<delim>` is the chosen delimiter string. The string `<delim>`
|
||||
must not appear on a line by itself within `<raw>`, as otherwise
|
||||
fast-import will think the data ends earlier than it really does. The `LF`
|
||||
immediately trailing `<raw>` is part of `<raw>`. This is one of
|
||||
the limitations of the delimited format, it is impossible to supply
|
||||
a data chunk which does not have an LF as its last byte.
|
||||
|
||||
`checkpoint`
|
||||
~~~~~~~~~~~~
|
||||
Forces fast-import to close the current packfile, start a new one, and to
|
||||
save out all current branch refs, tags and marks.
|
||||
|
||||
....
|
||||
'checkpoint' LF
|
||||
LF
|
||||
....
|
||||
|
||||
Note that fast-import automatically switches packfiles when the current
|
||||
packfile reaches \--max-pack-size, or 4 GiB, whichever limit is
|
||||
smaller. During an automatic packfile switch fast-import does not update
|
||||
the branch refs, tags or marks.
|
||||
|
||||
As a `checkpoint` can require a significant amount of CPU time and
|
||||
disk IO (to compute the overall pack SHA-1 checksum, generate the
|
||||
corresponding index file, and update the refs) it can easily take
|
||||
several minutes for a single `checkpoint` command to complete.
|
||||
|
||||
Frontends may choose to issue checkpoints during extremely large
|
||||
and long running imports, or when they need to allow another Git
|
||||
process access to a branch. However given that a 30 GiB Subversion
|
||||
repository can be loaded into Git through fast-import in about 3 hours,
|
||||
explicit checkpointing may not be necessary.
|
||||
|
||||
|
||||
Tips and Tricks
|
||||
---------------
|
||||
The following tips and tricks have been collected from various
|
||||
users of fast-import, and are offered here as suggestions.
|
||||
|
||||
Use One Mark Per Commit
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
When doing a repository conversion, use a unique mark per commit
|
||||
(`mark :<n>`) and supply the \--export-marks option on the command
|
||||
line. fast-import will dump a file which lists every mark and the Git
|
||||
object SHA-1 that corresponds to it. If the frontend can tie
|
||||
the marks back to the source repository, it is easy to verify the
|
||||
accuracy and completeness of the import by comparing each Git
|
||||
commit to the corresponding source revision.
|
||||
|
||||
Coming from a system such as Perforce or Subversion this should be
|
||||
quite simple, as the fast-import mark can also be the Perforce changeset
|
||||
number or the Subversion revision number.
|
||||
|
||||
Freely Skip Around Branches
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Don't bother trying to optimize the frontend to stick to one branch
|
||||
at a time during an import. Although doing so might be slightly
|
||||
faster for fast-import, it tends to increase the complexity of the frontend
|
||||
code considerably.
|
||||
|
||||
The branch LRU builtin to fast-import tends to behave very well, and the
|
||||
cost of activating an inactive branch is so low that bouncing around
|
||||
between branches has virtually no impact on import performance.
|
||||
|
||||
Handling Renames
|
||||
~~~~~~~~~~~~~~~~
|
||||
When importing a renamed file or directory, simply delete the old
|
||||
name(s) and modify the new name(s) during the corresponding commit.
|
||||
Git performs rename detection after-the-fact, rather than explicitly
|
||||
during a commit.
|
||||
|
||||
Use Tag Fixup Branches
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
Some other SCM systems let the user create a tag from multiple
|
||||
files which are not from the same commit/changeset. Or to create
|
||||
tags which are a subset of the files available in the repository.
|
||||
|
||||
Importing these tags as-is in Git is impossible without making at
|
||||
least one commit which ``fixes up'' the files to match the content
|
||||
of the tag. Use fast-import's `reset` command to reset a dummy branch
|
||||
outside of your normal branch space to the base commit for the tag,
|
||||
then commit one or more file fixup commits, and finally tag the
|
||||
dummy branch.
|
||||
|
||||
For example since all normal branches are stored under `refs/heads/`
|
||||
name the tag fixup branch `TAG_FIXUP`. This way it is impossible for
|
||||
the fixup branch used by the importer to have namespace conflicts
|
||||
with real branches imported from the source (the name `TAG_FIXUP`
|
||||
is not `refs/heads/TAG_FIXUP`).
|
||||
|
||||
When committing fixups, consider using `merge` to connect the
|
||||
commit(s) which are supplying file revisions to the fixup branch.
|
||||
Doing so will allow tools such as gitlink:git-blame[1] to track
|
||||
through the real commit history and properly annotate the source
|
||||
files.
|
||||
|
||||
After fast-import terminates the frontend will need to do `rm .git/TAG_FIXUP`
|
||||
to remove the dummy branch.
|
||||
|
||||
Import Now, Repack Later
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
As soon as fast-import completes the Git repository is completely valid
|
||||
and ready for use. Typicallly this takes only a very short time,
|
||||
even for considerably large projects (100,000+ commits).
|
||||
|
||||
However repacking the repository is necessary to improve data
|
||||
locality and access performance. It can also take hours on extremely
|
||||
large projects (especially if -f and a large \--window parameter is
|
||||
used). Since repacking is safe to run alongside readers and writers,
|
||||
run the repack in the background and let it finish when it finishes.
|
||||
There is no reason to wait to explore your new Git project!
|
||||
|
||||
If you choose to wait for the repack, don't try to run benchmarks
|
||||
or performance tests until repacking is completed. fast-import outputs
|
||||
suboptimal packfiles that are simply never seen in real use
|
||||
situations.
|
||||
|
||||
Repacking Historical Data
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
If you are repacking very old imported data (e.g. older than the
|
||||
last year), consider expending some extra CPU time and supplying
|
||||
\--window=50 (or higher) when you run gitlink:git-repack[1].
|
||||
This will take longer, but will also produce a smaller packfile.
|
||||
You only need to expend the effort once, and everyone using your
|
||||
project will benefit from the smaller repository.
|
||||
|
||||
|
||||
Packfile Optimization
|
||||
---------------------
|
||||
When packing a blob fast-import always attempts to deltify against the last
|
||||
blob written. Unless specifically arranged for by the frontend,
|
||||
this will probably not be a prior version of the same file, so the
|
||||
generated delta will not be the smallest possible. The resulting
|
||||
packfile will be compressed, but will not be optimal.
|
||||
|
||||
Frontends which have efficient access to all revisions of a
|
||||
single file (for example reading an RCS/CVS ,v file) can choose
|
||||
to supply all revisions of that file as a sequence of consecutive
|
||||
`blob` commands. This allows fast-import to deltify the different file
|
||||
revisions against each other, saving space in the final packfile.
|
||||
Marks can be used to later identify individual file revisions during
|
||||
a sequence of `commit` commands.
|
||||
|
||||
The packfile(s) created by fast-import do not encourage good disk access
|
||||
patterns. This is caused by fast-import writing the data in the order
|
||||
it is received on standard input, while Git typically organizes
|
||||
data within packfiles to make the most recent (current tip) data
|
||||
appear before historical data. Git also clusters commits together,
|
||||
speeding up revision traversal through better cache locality.
|
||||
|
||||
For this reason it is strongly recommended that users repack the
|
||||
repository with `git repack -a -d` after fast-import completes, allowing
|
||||
Git to reorganize the packfiles for faster data access. If blob
|
||||
deltas are suboptimal (see above) then also adding the `-f` option
|
||||
to force recomputation of all deltas can significantly reduce the
|
||||
final packfile size (30-50% smaller can be quite typical).
|
||||
|
||||
|
||||
Memory Utilization
|
||||
------------------
|
||||
There are a number of factors which affect how much memory fast-import
|
||||
requires to perform an import. Like critical sections of core
|
||||
Git, fast-import uses its own memory allocators to ammortize any overheads
|
||||
associated with malloc. In practice fast-import tends to ammoritize any
|
||||
malloc overheads to 0, due to its use of large block allocations.
|
||||
|
||||
per object
|
||||
~~~~~~~~~~
|
||||
fast-import maintains an in-memory structure for every object written in
|
||||
this execution. On a 32 bit system the structure is 32 bytes,
|
||||
on a 64 bit system the structure is 40 bytes (due to the larger
|
||||
pointer sizes). Objects in the table are not deallocated until
|
||||
fast-import terminates. Importing 2 million objects on a 32 bit system
|
||||
will require approximately 64 MiB of memory.
|
||||
|
||||
The object table is actually a hashtable keyed on the object name
|
||||
(the unique SHA-1). This storage configuration allows fast-import to reuse
|
||||
an existing or already written object and avoid writing duplicates
|
||||
to the output packfile. Duplicate blobs are surprisingly common
|
||||
in an import, typically due to branch merges in the source.
|
||||
|
||||
per mark
|
||||
~~~~~~~~
|
||||
Marks are stored in a sparse array, using 1 pointer (4 bytes or 8
|
||||
bytes, depending on pointer size) per mark. Although the array
|
||||
is sparse, frontends are still strongly encouraged to use marks
|
||||
between 1 and n, where n is the total number of marks required for
|
||||
this import.
|
||||
|
||||
per branch
|
||||
~~~~~~~~~~
|
||||
Branches are classified as active and inactive. The memory usage
|
||||
of the two classes is significantly different.
|
||||
|
||||
Inactive branches are stored in a structure which uses 96 or 120
|
||||
bytes (32 bit or 64 bit systems, respectively), plus the length of
|
||||
the branch name (typically under 200 bytes), per branch. fast-import will
|
||||
easily handle as many as 10,000 inactive branches in under 2 MiB
|
||||
of memory.
|
||||
|
||||
Active branches have the same overhead as inactive branches, but
|
||||
also contain copies of every tree that has been recently modified on
|
||||
that branch. If subtree `include` has not been modified since the
|
||||
branch became active, its contents will not be loaded into memory,
|
||||
but if subtree `src` has been modified by a commit since the branch
|
||||
became active, then its contents will be loaded in memory.
|
||||
|
||||
As active branches store metadata about the files contained on that
|
||||
branch, their in-memory storage size can grow to a considerable size
|
||||
(see below).
|
||||
|
||||
fast-import automatically moves active branches to inactive status based on
|
||||
a simple least-recently-used algorithm. The LRU chain is updated on
|
||||
each `commit` command. The maximum number of active branches can be
|
||||
increased or decreased on the command line with \--active-branches=.
|
||||
|
||||
per active tree
|
||||
~~~~~~~~~~~~~~~
|
||||
Trees (aka directories) use just 12 bytes of memory on top of the
|
||||
memory required for their entries (see ``per active file'' below).
|
||||
The cost of a tree is virtually 0, as its overhead ammortizes out
|
||||
over the individual file entries.
|
||||
|
||||
per active file entry
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
Files (and pointers to subtrees) within active trees require 52 or 64
|
||||
bytes (32/64 bit platforms) per entry. To conserve space, file and
|
||||
tree names are pooled in a common string table, allowing the filename
|
||||
``Makefile'' to use just 16 bytes (after including the string header
|
||||
overhead) no matter how many times it occurs within the project.
|
||||
|
||||
The active branch LRU, when coupled with the filename string pool
|
||||
and lazy loading of subtrees, allows fast-import to efficiently import
|
||||
projects with 2,000+ branches and 45,114+ files in a very limited
|
||||
memory footprint (less than 2.7 MiB per active branch).
|
||||
|
||||
|
||||
Author
|
||||
------
|
||||
Written by Shawn O. Pearce <spearce@spearce.org>.
|
||||
|
||||
Documentation
|
||||
--------------
|
||||
Documentation by Shawn O. Pearce <spearce@spearce.org>.
|
||||
|
||||
GIT
|
||||
---
|
||||
Part of the gitlink:git[7] suite
|
||||
|
||||
@@ -20,6 +20,14 @@ The ref names and their object names of fetched refs are stored
|
||||
in `.git/FETCH_HEAD`. This information is left for a later merge
|
||||
operation done by "git merge".
|
||||
|
||||
When <refspec> stores the fetched result in tracking branches,
|
||||
the tags that point at these branches are automatically
|
||||
followed. This is done by first fetching from the remote using
|
||||
the given <refspec>s, and if the repository has objects that are
|
||||
pointed by remote tags that it does not yet have, then fetch
|
||||
those missing tags. If the other end has tags that point at
|
||||
branches you are not interested in, you will not get them.
|
||||
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
|
||||
@@ -66,7 +66,7 @@ keys.
|
||||
For all objects, the following names can be used:
|
||||
|
||||
refname::
|
||||
The name of the ref (the part after $GIT_DIR/refs/).
|
||||
The name of the ref (the part after $GIT_DIR/).
|
||||
|
||||
objecttype::
|
||||
The type of the object (`blob`, `tree`, `commit`, `tag`).
|
||||
|
||||
@@ -62,6 +62,10 @@ The optional configuration variable 'gc.rerereunresolved' indicates
|
||||
how long records of conflicted merge you have not resolved are
|
||||
kept. This defaults to 15 days.
|
||||
|
||||
The optional configuration variable 'gc.packrefs' determines if
|
||||
`git gc` runs `git-pack-refs`. Without the configuration, `git-pack-refs`
|
||||
is not run in bare repositories by default, to allow older dumb-transport
|
||||
clients fetch from the repository, but this will change in the future.
|
||||
|
||||
See Also
|
||||
--------
|
||||
|
||||
@@ -16,7 +16,7 @@ Shows the commit logs.
|
||||
|
||||
The command takes options applicable to the gitlink:git-rev-list[1]
|
||||
command to control what is shown and how, and options applicable to
|
||||
the gitlink:git-diff-tree[1] commands to control how the change
|
||||
the gitlink:git-diff-tree[1] commands to control how the changes
|
||||
each commit introduces are shown.
|
||||
|
||||
This manual page describes only the most frequently used options.
|
||||
|
||||
@@ -10,7 +10,7 @@ SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git-merge' [-n] [--no-commit] [--squash] [-s <strategy>]...
|
||||
-m=<msg> <remote> <remote>...
|
||||
[-m <msg>] <remote> <remote>...
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
||||
@@ -33,6 +33,60 @@ include::urls.txt[]
|
||||
|
||||
include::merge-strategies.txt[]
|
||||
|
||||
DEFAULT BEHAVIOUR
|
||||
-----------------
|
||||
|
||||
Often people use `git pull` without giving any parameter.
|
||||
Traditionally, this has been equivalent to saying `git pull
|
||||
origin`. However, when configuration `branch.<name>.remote` is
|
||||
present while on branch `<name>`, that value is used instead of
|
||||
`origin`.
|
||||
|
||||
In order to determine what URL to use to fetch from, the value
|
||||
of the configuration `remote.<origin>.url` is consulted
|
||||
and if there is not any such variable, the value on `URL: ` line
|
||||
in `$GIT_DIR/remotes/<origin>` file is used.
|
||||
|
||||
In order to determine what remote branches to fetch (and
|
||||
optionally store in the tracking branches) when the command is
|
||||
run without any refspec parameters on the command line, values
|
||||
of the configuration variable `remote.<origin>.fetch` are
|
||||
consulted, and if there aren't any, `$GIT_DIR/remotes/<origin>`
|
||||
file is consulted and its `Pull: ` lines are used.
|
||||
In addition to the refspec formats described in the OPTIONS
|
||||
section, you can have a globbing refspec that looks like this:
|
||||
|
||||
------------
|
||||
refs/heads/*:refs/remotes/origin/*
|
||||
------------
|
||||
|
||||
A globbing refspec must have a non-empty RHS (i.e. must store
|
||||
what were fetched in tracking branches), and its LHS and RHS
|
||||
must end with `/*`. The above specifies that all remote
|
||||
branches are tracked using tracking branches in
|
||||
`refs/remotes/origin/` hierarchy under the same name.
|
||||
|
||||
The rule to determine which remote branch to merge after
|
||||
fetching is a bit involved, in order not to break backward
|
||||
compatibility.
|
||||
|
||||
If explicit refspecs were given on the command
|
||||
line of `git pull`, they are all merged.
|
||||
|
||||
When no refspec was given on the command line, then `git pull`
|
||||
uses the refspec from the configuration or
|
||||
`$GIT_DIR/remotes/<origin>`. In such cases, the following
|
||||
rules apply:
|
||||
|
||||
. If `branch.<name>.merge` configuration for the current
|
||||
branch `<name>` exists, that is the name of the branch at the
|
||||
remote site that is merged.
|
||||
|
||||
. If the refspec is a globbing one, nothing is merged.
|
||||
|
||||
. Otherwise the remote branch of the first refspec is merged.
|
||||
|
||||
|
||||
EXAMPLES
|
||||
--------
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ git-rebase - Forward-port local commits to the updated upstream head
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-rebase' [-v] [--merge] [--onto <newbase>] <upstream> [<branch>]
|
||||
'git-rebase' [-v] [--merge] [-C<n>] [--onto <newbase>] <upstream> [<branch>]
|
||||
|
||||
'git-rebase' --continue | --skip | --abort
|
||||
|
||||
@@ -114,6 +114,27 @@ would result in:
|
||||
|
||||
This is useful when topicB does not depend on topicA.
|
||||
|
||||
A range of commits could also be removed with rebase. If we have
|
||||
the following situation:
|
||||
|
||||
------------
|
||||
E---F---G---H---I---J topicA
|
||||
------------
|
||||
|
||||
then the command
|
||||
|
||||
git-rebase --onto topicA~5 topicA~2 topicA
|
||||
|
||||
would result in the removal of commits F and G:
|
||||
|
||||
------------
|
||||
E---H'---I'---J' topicA
|
||||
------------
|
||||
|
||||
This is useful if F and G were flawed in some way, or should not be
|
||||
part of topicA. Note that the argument to --onto and the <upstream>
|
||||
parameter can be any valid commit-ish.
|
||||
|
||||
In case of conflict, git-rebase will stop at the first problematic commit
|
||||
and leave conflict markers in the tree. You can use git diff to locate
|
||||
the markers (<<<<<<) and make edits to resolve the conflict. For each
|
||||
@@ -141,10 +162,12 @@ OPTIONS
|
||||
<newbase>::
|
||||
Starting point at which to create the new commits. If the
|
||||
--onto option is not specified, the starting point is
|
||||
<upstream>.
|
||||
<upstream>. May be any valid commit, and not just an
|
||||
existing branch name.
|
||||
|
||||
<upstream>::
|
||||
Upstream branch to compare against.
|
||||
Upstream branch to compare against. May be any valid commit,
|
||||
not just an existing branch name.
|
||||
|
||||
<branch>::
|
||||
Working branch; defaults to HEAD.
|
||||
@@ -173,6 +196,12 @@ OPTIONS
|
||||
-v, \--verbose::
|
||||
Display a diffstat of what changed upstream since the last rebase.
|
||||
|
||||
-C<n>::
|
||||
Ensure at least <n> lines of surrounding context match before
|
||||
and after each change. When fewer lines of surrounding
|
||||
context exist they all must match. By default no context is
|
||||
ever ignored.
|
||||
|
||||
include::merge-strategies.txt[]
|
||||
|
||||
NOTES
|
||||
|
||||
@@ -8,13 +8,18 @@ git-reflog - Manage reflog information
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git-reflog' expire [--dry-run] [--stale-fix]
|
||||
[--expire=<time>] [--expire-unreachable=<time>] [--all] <refs>...
|
||||
|
||||
'git reflog' <subcommand> <options>
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
The command takes various subcommands, and different options
|
||||
depending on the subcommand:
|
||||
|
||||
[verse]
|
||||
git reflog expire [--dry-run] [--stale-fix]
|
||||
[--expire=<time>] [--expire-unreachable=<time>] [--all] <refs>...
|
||||
|
||||
git reflog [show] [log-options]
|
||||
|
||||
Reflog is a mechanism to record when the tip of branches are
|
||||
updated. This command is to manage the information recorded in it.
|
||||
@@ -25,6 +30,10 @@ Entries older than `expire` time, or entries older than
|
||||
tip, are removed from the reflog. This is typically not used
|
||||
directly by the end users -- instead, see gitlink:git-gc[1].
|
||||
|
||||
The subcommand "show" (which is also the default, in the absense of any
|
||||
subcommands) will take all the normal log options, and show the log of
|
||||
the current branch. It is basically an alias for 'git log -g --abbrev-commit
|
||||
--pretty=oneline', see gitlink:git-log[1].
|
||||
|
||||
|
||||
OPTIONS
|
||||
|
||||
@@ -12,19 +12,39 @@ SYNOPSIS
|
||||
'git-remote'
|
||||
'git-remote' add <name> <url>
|
||||
'git-remote' show <name>
|
||||
'git-remote' prune <name>
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
||||
Manage the set of repositories ("remotes") whose branches you track.
|
||||
|
||||
With no arguments, shows a list of existing remotes.
|
||||
|
||||
In the second form, adds a remote named <name> for the repository at
|
||||
COMMANDS
|
||||
--------
|
||||
|
||||
With no arguments, shows a list of existing remotes. Several
|
||||
subcommands are available to perform operations on the remotes.
|
||||
|
||||
'add'::
|
||||
|
||||
Adds a remote named <name> for the repository at
|
||||
<url>. The command `git fetch <name>` can then be used to create and
|
||||
update remote-tracking branches <name>/<branch>.
|
||||
|
||||
In the third form, gives some information about the remote <name>.
|
||||
'show'::
|
||||
|
||||
Gives some information about the remote <name>.
|
||||
|
||||
'prune'::
|
||||
|
||||
Deletes all stale tracking branches under <name>.
|
||||
These stale branches have already been removed from the remote repository
|
||||
referenced by <name>, but are still locally available in "remotes/<name>".
|
||||
|
||||
|
||||
DISCUSSION
|
||||
----------
|
||||
|
||||
The remote configuration is achieved using the `remote.origin.url` and
|
||||
`remote.origin.fetch` configuration variables. (See
|
||||
|
||||
@@ -30,9 +30,9 @@ OPTIONS
|
||||
Instead of incrementally packing the unpacked objects,
|
||||
pack everything available into a single pack.
|
||||
Especially useful when packing a repository that is used
|
||||
for a private development and there no need to worry
|
||||
about people fetching via dumb protocols from it. Use
|
||||
with '-d'.
|
||||
for private development and there is no need to worry
|
||||
about people fetching via dumb file transfer protocols
|
||||
from it. Use with '-d'.
|
||||
|
||||
-d::
|
||||
After packing, if the newly created packs make some
|
||||
|
||||
@@ -12,7 +12,7 @@ SYNOPSIS
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
DEPRECATED. Use `git-merge` instead.
|
||||
DEPRECATED and will be removed in 1.5.1. Use `git-merge` instead.
|
||||
|
||||
Given two commits and a merge message, merge the <merged> commit
|
||||
into <current> commit, with the commit log message <message>.
|
||||
|
||||
@@ -160,6 +160,10 @@ blobs contained in a commit.
|
||||
immediately following a ref name and the ref must have an existing
|
||||
log ($GIT_DIR/logs/<ref>).
|
||||
|
||||
* You can use the '@' construct with an empty ref part to get at a
|
||||
reflog of the current branch. For example, if you are on the
|
||||
branch 'blabla', then '@\{1\}' means the same as 'blabla@\{1\}'.
|
||||
|
||||
* A suffix '{caret}' to a revision parameter means the first parent of
|
||||
that commit object. '{caret}<n>' means the <n>th parent (i.e.
|
||||
'rev{caret}'
|
||||
|
||||
@@ -3,7 +3,7 @@ git-send-pack(1)
|
||||
|
||||
NAME
|
||||
----
|
||||
git-send-pack - Push objects over git protocol to another reposiotory
|
||||
git-send-pack - Push objects over git protocol to another repository
|
||||
|
||||
|
||||
SYNOPSIS
|
||||
|
||||
@@ -11,7 +11,7 @@ SYNOPSIS
|
||||
'git-show-branch' [--all] [--remotes] [--topo-order] [--current]
|
||||
[--more=<n> | --list | --independent | --merge-base]
|
||||
[--no-name | --sha1-name] [--topics] [<rev> | <glob>]...
|
||||
'git-show-branch' (-g|--reflog)[=<n>[,<base>]] [--list] <ref>
|
||||
'git-show-branch' (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@@ -97,11 +97,13 @@ OPTIONS
|
||||
will show the revisions given by "git rev-list {caret}master
|
||||
topic1 topic2"
|
||||
|
||||
--reflog[=<n>[,<base>]] <ref>::
|
||||
--reflog[=<n>[,<base>]] [<ref>]::
|
||||
Shows <n> most recent ref-log entries for the given
|
||||
ref. If <base> is given, <n> entries going back from
|
||||
that entry. <base> can be specified as count or date.
|
||||
`-g` can be used as a short-hand for this option.
|
||||
`-g` can be used as a short-hand for this option. When
|
||||
no explicit <ref> parameter is given, it defaults to the
|
||||
current branch (or `HEAD` if it is detached).
|
||||
|
||||
Note that --more, --list, --independent and --merge-base options
|
||||
are mutually exclusive.
|
||||
|
||||
@@ -25,6 +25,9 @@ with \--name-only).
|
||||
|
||||
For plain blobs, it shows the plain contents.
|
||||
|
||||
The command takes options applicable to the gitlink:git-diff-tree[1] command to
|
||||
control how the changes the commit introduces are shown.
|
||||
|
||||
This manual page describes only the most frequently used options.
|
||||
|
||||
|
||||
|
||||
@@ -133,7 +133,7 @@ manually joining branches on commit.
|
||||
|
||||
'multi-init'::
|
||||
This command supports git-svnimport-like command-line syntax for
|
||||
importing repositories that are layed out as recommended by the
|
||||
importing repositories that are laid out as recommended by the
|
||||
SVN folks. This is a bit more tolerant than the git-svnimport
|
||||
command-line syntax and doesn't require the user to figure out
|
||||
where the repository URL ends and where the repository path
|
||||
|
||||
@@ -80,6 +80,137 @@ it in the repository configuration as follows:
|
||||
[user]
|
||||
signingkey = <gpg-key-id>
|
||||
|
||||
|
||||
DISCUSSION
|
||||
----------
|
||||
|
||||
On Re-tagging
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
What should you do when you tag a wrong commit and you would
|
||||
want to re-tag?
|
||||
|
||||
If you never pushed anything out, just re-tag it. Use "-f" to
|
||||
replace the old one. And you're done.
|
||||
|
||||
But if you have pushed things out (or others could just read
|
||||
your repository directly), then others will have already seen
|
||||
the old tag. In that case you can do one of two things:
|
||||
|
||||
. The sane thing.
|
||||
Just admit you screwed up, and use a different name. Others have
|
||||
already seen one tag-name, and if you keep the same name, you
|
||||
may be in the situation that two people both have "version X",
|
||||
but they actually have 'different' "X"'s. So just call it "X.1"
|
||||
and be done with it.
|
||||
|
||||
. The insane thing.
|
||||
You really want to call the new version "X" too, 'even though'
|
||||
others have already seen the old one. So just use "git tag -f"
|
||||
again, as if you hadn't already published the old one.
|
||||
|
||||
However, Git does *not* (and it should not)change tags behind
|
||||
users back. So if somebody already got the old tag, doing a "git
|
||||
pull" on your tree shouldn't just make them overwrite the old
|
||||
one.
|
||||
|
||||
If somebody got a release tag from you, you cannot just change
|
||||
the tag for them by updating your own one. This is a big
|
||||
security issue, in that people MUST be able to trust their
|
||||
tag-names. If you really want to do the insane thing, you need
|
||||
to just fess up to it, and tell people that you messed up. You
|
||||
can do that by making a very public announcement saying:
|
||||
|
||||
------------
|
||||
Ok, I messed up, and I pushed out an earlier version tagged as X. I
|
||||
then fixed something, and retagged the *fixed* tree as X again.
|
||||
|
||||
If you got the wrong tag, and want the new one, please delete
|
||||
the old one and fetch the new one by doing:
|
||||
|
||||
git tag -d X
|
||||
git fetch origin tag X
|
||||
|
||||
to get my updated tag.
|
||||
|
||||
You can test which tag you have by doing
|
||||
|
||||
git rev-parse X
|
||||
|
||||
which should return 0123456789abcdef.. if you have the new version.
|
||||
|
||||
Sorry for inconvenience.
|
||||
------------
|
||||
|
||||
Does this seem a bit complicated? It *should* be. There is no
|
||||
way that it would be correct to just "fix" it behind peoples
|
||||
backs. People need to know that their tags might have been
|
||||
changed.
|
||||
|
||||
|
||||
On Automatic following
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If you are following somebody else's tree, you are most likely
|
||||
using tracking branches (`refs/heads/origin` in traditional
|
||||
layout, or `refs/remotes/origin/master` in the separate-remote
|
||||
layout). You usually want the tags from the other end.
|
||||
|
||||
On the other hand, if you are fetching because you would want a
|
||||
one-shot merge from somebody else, you typically do not want to
|
||||
get tags from there. This happens more often for people near
|
||||
the toplevel but not limited to them. Mere mortals when pulling
|
||||
from each other do not necessarily want to automatically get
|
||||
private anchor point tags from the other person.
|
||||
|
||||
You would notice "please pull" messages on the mailing list says
|
||||
repo URL and branch name alone. This is designed to be easily
|
||||
cut&pasted to "git fetch" command line:
|
||||
|
||||
------------
|
||||
Linus, please pull from
|
||||
|
||||
git://git..../proj.git master
|
||||
|
||||
to get the following updates...
|
||||
------------
|
||||
|
||||
becomes:
|
||||
|
||||
------------
|
||||
$ git pull git://git..../proj.git master
|
||||
------------
|
||||
|
||||
In such a case, you do not want to automatically follow other's
|
||||
tags.
|
||||
|
||||
One important aspect of git is it is distributed, and being
|
||||
distributed largely means there is no inherent "upstream" or
|
||||
"downstream" in the system. On the face of it, the above
|
||||
example might seem to indicate that the tag namespace is owned
|
||||
by upper echelon of people and tags only flow downwards, but
|
||||
that is not the case. It only shows that the usage pattern
|
||||
determines who are interested in whose tags.
|
||||
|
||||
A one-shot pull is a sign that a commit history is now crossing
|
||||
the boundary between one circle of people (e.g. "people who are
|
||||
primarily interested in networking part of the kernel") who may
|
||||
have their own set of tags (e.g. "this is the third release
|
||||
candidate from the networking group to be proposed for general
|
||||
consumption with 2.6.21 release") to another circle of people
|
||||
(e.g. "people who integrate various subsystem improvements").
|
||||
The latter are usually not interested in the detailed tags used
|
||||
internally in the former group (that is what "internal" means).
|
||||
That is why it is desirable not to follow tags automatically in
|
||||
this case.
|
||||
|
||||
It may well be that among networking people, they may want to
|
||||
exchange the tags internal to their group, but in that workflow
|
||||
they are most likely tracking with each other's progress by
|
||||
having tracking branches. Again, the heuristic to automatically
|
||||
follow such tags is a good thing.
|
||||
|
||||
|
||||
Author
|
||||
------
|
||||
Written by Linus Torvalds <torvalds@osdl.org>,
|
||||
|
||||
@@ -86,6 +86,14 @@ Foreign SCM interface
|
||||
series in git back and forth.
|
||||
|
||||
|
||||
- *hg-to-git* (contrib/)
|
||||
|
||||
hg-to-git converts a Mercurial repository into a git one, and
|
||||
preserves the full branch history in the process. hg-to-git can
|
||||
also be used in an incremental way to keep the git repository
|
||||
in sync with the master Mercurial repository.
|
||||
|
||||
|
||||
Others
|
||||
------
|
||||
|
||||
|
||||
@@ -29,6 +29,24 @@ in a coherent way to git enlightenment ;-).
|
||||
The COMMAND is either a name of a Git command (see below) or an alias
|
||||
as defined in the configuration file (see gitlink:git-config[1]).
|
||||
|
||||
ifdef::stalenotes[]
|
||||
[NOTE]
|
||||
============
|
||||
You are reading the documentation for the latest version of git.
|
||||
Documentation for older releases are available here:
|
||||
|
||||
* link:v1.4.4.4/git.html[documentation for release 1.4.4.4]
|
||||
|
||||
* link:v1.3.3/git.html[documentation for release 1.3.3]
|
||||
|
||||
* link:v1.2.6/git.html[documentation for release 1.2.6]
|
||||
|
||||
* link:v1.0.13/git.html[documentation for release 1.0.13]
|
||||
|
||||
============
|
||||
|
||||
endif::stalenotes[]
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
--version::
|
||||
|
||||
@@ -54,7 +54,7 @@ frequently used options.
|
||||
|
||||
Limit commits to the ones touching files in the given paths. Note, to
|
||||
avoid ambiguity wrt. revision names use "--" to separate the paths
|
||||
from any preceeding options.
|
||||
from any preceding options.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
@@ -90,9 +90,6 @@ parameter, and is invoked after a commit is made.
|
||||
This hook is meant primarily for notification, and cannot affect
|
||||
the outcome of `git-commit`.
|
||||
|
||||
The default 'post-commit' hook, when enabled, demonstrates how to
|
||||
send out a commit notification e-mail.
|
||||
|
||||
update
|
||||
------
|
||||
|
||||
@@ -130,6 +127,8 @@ The standard output of this hook is sent to `stderr`, so if you
|
||||
want to report something to the `git-send-pack` on the other end,
|
||||
you can simply `echo` your messages.
|
||||
|
||||
The default 'update' hook, when enabled, demonstrates how to
|
||||
send out a notification e-mail.
|
||||
|
||||
post-update
|
||||
-----------
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
T="$1"
|
||||
|
||||
for h in *.html *.txt howto/*.txt howto/*.html
|
||||
for h in *.html *.txt howto/*.txt howto/*.html RelNotes-*.txt
|
||||
do
|
||||
if test -f "$T/$h" &&
|
||||
diff -u -I'Last updated [0-9][0-9]-[A-Z][a-z][a-z]-' "$T/$h" "$h"
|
||||
|
||||
@@ -133,14 +133,14 @@ info::
|
||||
in this directory.
|
||||
|
||||
info/refs::
|
||||
This file is to help dumb transports to discover what
|
||||
refs are available in this repository. Whenever you
|
||||
create/delete a new branch or a new tag, `git
|
||||
update-server-info` should be run to keep this file
|
||||
up-to-date if the repository is published for dumb
|
||||
transports. The `git-receive-pack` command, which is
|
||||
run on a remote repository when you `git push` into it,
|
||||
runs `hooks/update` hook to help you achieve this.
|
||||
This file helps dumb transports discover what refs are
|
||||
available in this repository. If the repository is
|
||||
published for dumb transports, this file should be
|
||||
regenerated by `git update-server-info` every time a tag
|
||||
or branch is created or modified. This is normally done
|
||||
from the `hooks/update` hook, which is run by the
|
||||
`git-receive-pack` command when you `git push` into the
|
||||
repository.
|
||||
|
||||
info/grafts::
|
||||
This file records fake commit ancestry information, to
|
||||
|
||||
@@ -352,24 +352,23 @@ situation:
|
||||
|
||||
------------------------------------------------
|
||||
$ git status
|
||||
#
|
||||
# Added but not yet committed:
|
||||
# (will commit)
|
||||
# On branch master
|
||||
# Changes to be committed:
|
||||
# (use "git reset HEAD <file>..." to unstage)
|
||||
#
|
||||
# new file: closing.txt
|
||||
#
|
||||
#
|
||||
# Changed but not added:
|
||||
# (use "git add file1 file2" to include for commit)
|
||||
# Changed but not updated:
|
||||
# (use "git add <file>..." to update what will be committed)
|
||||
#
|
||||
# modified: file.txt
|
||||
#
|
||||
------------------------------------------------
|
||||
|
||||
Since the current state of closing.txt is cached in the index file,
|
||||
it is listed as "added but not yet committed". Since file.txt has
|
||||
it is listed as "Changes to be committed". Since file.txt has
|
||||
changes in the working directory that aren't reflected in the index,
|
||||
it is marked "changed but not added". At this point, running "git
|
||||
it is marked "changed but not updated". At this point, running "git
|
||||
commit" would create a commit that added closing.txt (with its new
|
||||
contents), but that didn't modify file.txt.
|
||||
|
||||
|
||||
@@ -101,27 +101,27 @@ want to commit together. This can be done in a few different ways:
|
||||
|
||||
1) By using 'git add <file_spec>...'
|
||||
|
||||
This can be performed multiple times before a commit. Note that this
|
||||
is not only for adding new files. Even modified files must be
|
||||
added to the set of changes about to be committed. The "git status"
|
||||
command gives you a summary of what is included so far for the
|
||||
next commit. When done you should use the 'git commit' command to
|
||||
make it real.
|
||||
This can be performed multiple times before a commit. Note that this
|
||||
is not only for adding new files. Even modified files must be
|
||||
added to the set of changes about to be committed. The "git status"
|
||||
command gives you a summary of what is included so far for the
|
||||
next commit. When done you should use the 'git commit' command to
|
||||
make it real.
|
||||
|
||||
Note: don't forget to 'add' a file again if you modified it after the
|
||||
first 'add' and before 'commit'. Otherwise only the previous added
|
||||
state of that file will be committed. This is because git tracks
|
||||
content, so what you're really 'add'ing to the commit is the *content*
|
||||
of the file in the state it is in when you 'add' it.
|
||||
Note: don't forget to 'add' a file again if you modified it after the
|
||||
first 'add' and before 'commit'. Otherwise only the previous added
|
||||
state of that file will be committed. This is because git tracks
|
||||
content, so what you're really 'add'ing to the commit is the *content*
|
||||
of the file in the state it is in when you 'add' it.
|
||||
|
||||
2) By using 'git commit -a' directly
|
||||
|
||||
This is a quick way to automatically 'add' the content from all files
|
||||
that were modified since the previous commit, and perform the actual
|
||||
commit without having to separately 'add' them beforehand. This will
|
||||
not add content from new files i.e. files that were never added before.
|
||||
Those files still have to be added explicitly before performing a
|
||||
commit.
|
||||
This is a quick way to automatically 'add' the content from all files
|
||||
that were modified since the previous commit, and perform the actual
|
||||
commit without having to separately 'add' them beforehand. This will
|
||||
not add content from new files i.e. files that were never added before.
|
||||
Those files still have to be added explicitly before performing a
|
||||
commit.
|
||||
|
||||
But here's a twist. If you do 'git commit <file1> <file2> ...' then only
|
||||
the changes belonging to those explicitly specified files will be
|
||||
@@ -458,9 +458,11 @@ $ git reset --hard HEAD^ # reset your current branch and working
|
||||
Be careful with that last command: in addition to losing any changes
|
||||
in the working directory, it will also remove all later commits from
|
||||
this branch. If this branch is the only branch containing those
|
||||
commits, they will be lost. (Also, don't use "git reset" on a
|
||||
publicly-visible branch that other developers pull from, as git will
|
||||
be confused by history that disappears in this way.)
|
||||
commits, they will be lost. Also, don't use "git reset" on a
|
||||
publicly-visible branch that other developers pull from, as it will
|
||||
force needless merges on other developers to clean up the history.
|
||||
If you need to undo changes that you have pushed, use gitlink:git-revert[1]
|
||||
instead.
|
||||
|
||||
The git grep command can search for strings in any version of your
|
||||
project, so
|
||||
|
||||
@@ -398,7 +398,7 @@ branch name, but this longer name can also be useful. Most
|
||||
importantly, it is a globally unique name for this commit: so if you
|
||||
tell somebody else the object name (for example in email), then you are
|
||||
guaranteed that name will refer to the same commit in their repository
|
||||
that you it does in yours (assuming their repository has that commit at
|
||||
that it does in yours (assuming their repository has that commit at
|
||||
all).
|
||||
|
||||
Understanding history: commits, parents, and reachability
|
||||
@@ -425,8 +425,8 @@ if commit X is an ancestor of commit Y. Equivalently, you could say
|
||||
that Y is a descendent of X, or that there is a chain of parents
|
||||
leading from commit Y to commit X.
|
||||
|
||||
Undestanding history: History diagrams
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Understanding history: History diagrams
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
We will sometimes represent git history using diagrams like the one
|
||||
below. Commits are shown as "o", and the links between them with
|
||||
@@ -617,7 +617,7 @@ the relationships between these snapshots.
|
||||
Git provides extremely flexible and fast tools for exploring the
|
||||
history of a project.
|
||||
|
||||
We start with one specialized tool which is useful for finding the
|
||||
We start with one specialized tool that is useful for finding the
|
||||
commit that introduced a bug into a project.
|
||||
|
||||
How to use bisect to find a regression
|
||||
@@ -806,7 +806,7 @@ display options.
|
||||
|
||||
Note that git log starts with the most recent commit and works
|
||||
backwards through the parents; however, since git history can contain
|
||||
multiple independant lines of development, the particular order that
|
||||
multiple independent lines of development, the particular order that
|
||||
commits are listed in may be somewhat arbitrary.
|
||||
|
||||
Generating diffs
|
||||
@@ -1075,7 +1075,7 @@ $ git commit
|
||||
-------------------------------------------------
|
||||
|
||||
and git will prompt you for a commit message and then create the new
|
||||
commmit. Check to make sure it looks like what you expected with
|
||||
commit. Check to make sure it looks like what you expected with
|
||||
|
||||
-------------------------------------------------
|
||||
$ git show
|
||||
@@ -1492,7 +1492,7 @@ dangling commit 13472b7c4b80851a1bc551779171dcb03655e9b5
|
||||
...
|
||||
-------------------------------------------------
|
||||
|
||||
and watch for output that mentions "dangling commits". You can examine
|
||||
You can examine
|
||||
one of those dangling commits with, for example,
|
||||
|
||||
------------------------------------------------
|
||||
@@ -2923,6 +2923,8 @@ Think about how to create a clear chapter dependency graph that will
|
||||
allow people to get to important topics without necessarily reading
|
||||
everything in between.
|
||||
|
||||
Say something about .gitignore.
|
||||
|
||||
Scan Documentation/ for other stuff left out; in particular:
|
||||
howto's
|
||||
some of technical/?
|
||||
@@ -2951,7 +2953,7 @@ Include cross-references to the glossary, where appropriate.
|
||||
Document shallow clones? See draft 1.5.0 release notes for some
|
||||
documentation.
|
||||
|
||||
Add a sectin on working with other version control systems, including
|
||||
Add a section on working with other version control systems, including
|
||||
CVS, Subversion, and just imports of series of release tarballs.
|
||||
|
||||
More details on gitweb?
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
GVF=GIT-VERSION-FILE
|
||||
DEF_VER=v1.5.0-rc3.GIT
|
||||
DEF_VER=v1.5.0.GIT
|
||||
|
||||
LF='
|
||||
'
|
||||
|
||||
19
Makefile
19
Makefile
@@ -195,6 +195,7 @@ SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
|
||||
PROGRAMS = \
|
||||
git-fetch-pack$X git-fsck$X \
|
||||
git-hash-object$X git-index-pack$X git-local-fetch$X \
|
||||
git-fast-import$X \
|
||||
git-merge-index$X git-mktag$X git-mktree$X git-patch-id$X \
|
||||
git-peek-remote$X git-receive-pack$X \
|
||||
git-send-pack$X git-shell$X \
|
||||
@@ -217,8 +218,7 @@ BUILT_INS = \
|
||||
$(patsubst builtin-%.o,git-%$X,$(BUILTIN_OBJS))
|
||||
|
||||
# what 'all' will build and 'install' will install, in gitexecdir
|
||||
ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS) \
|
||||
git-merge-recur$X
|
||||
ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
|
||||
|
||||
# Backward compatibility -- to be removed after 1.0
|
||||
PROGRAMS += git-ssh-pull$X git-ssh-push$X
|
||||
@@ -626,7 +626,7 @@ LIB_OBJS += $(COMPAT_OBJS)
|
||||
ALL_CFLAGS += $(BASIC_CFLAGS)
|
||||
ALL_LDFLAGS += $(BASIC_LDFLAGS)
|
||||
|
||||
export prefix TAR INSTALL DESTDIR SHELL_PATH template_dir
|
||||
export prefix gitexecdir TAR INSTALL DESTDIR SHELL_PATH template_dir
|
||||
|
||||
|
||||
### Build rules
|
||||
@@ -637,6 +637,7 @@ ifneq (,$X)
|
||||
endif
|
||||
|
||||
all::
|
||||
$(MAKE) -C git-gui all
|
||||
$(MAKE) -C perl PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' all
|
||||
$(MAKE) -C templates NOEXECTEMPL='$(NOEXECTEMPL)'
|
||||
|
||||
@@ -650,9 +651,6 @@ git$X: git.c common-cmds.h $(BUILTIN_OBJS) $(GITLIBS) GIT-CFLAGS
|
||||
|
||||
help.o: common-cmds.h
|
||||
|
||||
git-merge-recur$X: git-merge-recursive$X
|
||||
rm -f $@ && ln git-merge-recursive$X $@
|
||||
|
||||
$(BUILT_INS): git$X
|
||||
rm -f $@ && ln git$X $@
|
||||
|
||||
@@ -871,6 +869,7 @@ install: all
|
||||
$(INSTALL) git$X gitk '$(DESTDIR_SQ)$(bindir_SQ)'
|
||||
$(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install
|
||||
$(MAKE) -C perl prefix='$(prefix_SQ)' install
|
||||
$(MAKE) -C git-gui install
|
||||
if test 'z$(bindir_SQ)' != 'z$(gitexecdir_SQ)'; \
|
||||
then \
|
||||
ln -f '$(DESTDIR_SQ)$(bindir_SQ)/git$X' \
|
||||
@@ -904,8 +903,11 @@ dist: git.spec git-archive
|
||||
@mkdir -p $(GIT_TARNAME)
|
||||
@cp git.spec $(GIT_TARNAME)
|
||||
@echo $(GIT_VERSION) > $(GIT_TARNAME)/version
|
||||
@$(MAKE) -C git-gui TARDIR=../$(GIT_TARNAME)/git-gui dist-version
|
||||
$(TAR) rf $(GIT_TARNAME).tar \
|
||||
$(GIT_TARNAME)/git.spec $(GIT_TARNAME)/version
|
||||
$(GIT_TARNAME)/git.spec \
|
||||
$(GIT_TARNAME)/version \
|
||||
$(GIT_TARNAME)/git-gui/version
|
||||
@rm -rf $(GIT_TARNAME)
|
||||
gzip -f -9 $(GIT_TARNAME).tar
|
||||
|
||||
@@ -946,6 +948,7 @@ clean:
|
||||
rm -f gitweb/gitweb.cgi
|
||||
$(MAKE) -C Documentation/ clean
|
||||
$(MAKE) -C perl clean
|
||||
$(MAKE) -C git-gui clean
|
||||
$(MAKE) -C templates/ clean
|
||||
$(MAKE) -C t/ clean
|
||||
rm -f GIT-VERSION-FILE GIT-CFLAGS
|
||||
@@ -960,7 +963,7 @@ check-docs::
|
||||
do \
|
||||
case "$$v" in \
|
||||
git-merge-octopus | git-merge-ours | git-merge-recursive | \
|
||||
git-merge-resolve | git-merge-stupid | git-merge-recur | \
|
||||
git-merge-resolve | git-merge-stupid | \
|
||||
git-ssh-pull | git-ssh-push ) continue ;; \
|
||||
esac ; \
|
||||
test -f "Documentation/$$v.txt" || \
|
||||
|
||||
@@ -12,7 +12,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix)
|
||||
int i;
|
||||
nargv = xmalloc(sizeof(char *) * (argc + 2));
|
||||
|
||||
nargv[0] = "blame";
|
||||
nargv[0] = "annotate";
|
||||
nargv[1] = "-c";
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
|
||||
224
builtin-blame.c
224
builtin-blame.c
@@ -15,9 +15,10 @@
|
||||
#include "revision.h"
|
||||
#include "quote.h"
|
||||
#include "xdiff-interface.h"
|
||||
#include "cache-tree.h"
|
||||
|
||||
static char blame_usage[] =
|
||||
"git-blame [-c] [-l] [-t] [-f] [-n] [-p] [-L n,m] [-S <revs-file>] [-M] [-C] [-C] [commit] [--] file\n"
|
||||
"git-blame [-c] [-l] [-t] [-f] [-n] [-p] [-L n,m] [-S <revs-file>] [-M] [-C] [-C] [--contents <filename>] [--incremental] [commit] [--] file\n"
|
||||
" -c, --compatibility Use the same output mode as git-annotate (Default: off)\n"
|
||||
" -b Show blank SHA-1 for boundary commits (Default: off)\n"
|
||||
" -l, --long Show long commit SHA1 (Default: off)\n"
|
||||
@@ -29,6 +30,7 @@ static char blame_usage[] =
|
||||
" -L n,m Process only line range n,m, counting from 1\n"
|
||||
" -M, -C Find line movements within and across files\n"
|
||||
" --incremental Show blame entries as we find them, incrementally\n"
|
||||
" --contents file Use <file>'s contents as the final image\n"
|
||||
" -S revs-file Use revisions from revs-file instead of calling git-rev-list\n";
|
||||
|
||||
static int longest_file;
|
||||
@@ -39,6 +41,7 @@ static int max_score_digits;
|
||||
static int show_root;
|
||||
static int blank_boundary;
|
||||
static int incremental;
|
||||
static int cmd_is_annotate;
|
||||
|
||||
#ifndef DEBUG
|
||||
#define DEBUG 0
|
||||
@@ -333,9 +336,13 @@ static struct origin *find_origin(struct scoreboard *sb,
|
||||
diff_tree_setup_paths(paths, &diff_opts);
|
||||
if (diff_setup_done(&diff_opts) < 0)
|
||||
die("diff-setup");
|
||||
diff_tree_sha1(parent->tree->object.sha1,
|
||||
origin->commit->tree->object.sha1,
|
||||
"", &diff_opts);
|
||||
|
||||
if (is_null_sha1(origin->commit->object.sha1))
|
||||
do_diff_cache(parent->tree->object.sha1, &diff_opts);
|
||||
else
|
||||
diff_tree_sha1(parent->tree->object.sha1,
|
||||
origin->commit->tree->object.sha1,
|
||||
"", &diff_opts);
|
||||
diffcore_std(&diff_opts);
|
||||
|
||||
/* It is either one entry that says "modified", or "created",
|
||||
@@ -402,9 +409,13 @@ static struct origin *find_rename(struct scoreboard *sb,
|
||||
diff_tree_setup_paths(paths, &diff_opts);
|
||||
if (diff_setup_done(&diff_opts) < 0)
|
||||
die("diff-setup");
|
||||
diff_tree_sha1(parent->tree->object.sha1,
|
||||
origin->commit->tree->object.sha1,
|
||||
"", &diff_opts);
|
||||
|
||||
if (is_null_sha1(origin->commit->object.sha1))
|
||||
do_diff_cache(parent->tree->object.sha1, &diff_opts);
|
||||
else
|
||||
diff_tree_sha1(parent->tree->object.sha1,
|
||||
origin->commit->tree->object.sha1,
|
||||
"", &diff_opts);
|
||||
diffcore_std(&diff_opts);
|
||||
|
||||
for (i = 0; i < diff_queued_diff.nr; i++) {
|
||||
@@ -550,7 +561,7 @@ static void free_patch(struct patch *p)
|
||||
}
|
||||
|
||||
/*
|
||||
* Link in a new blame entry to the scorebord. Entries that cover the
|
||||
* Link in a new blame entry to the scoreboard. Entries that cover the
|
||||
* same line range have been removed from the scoreboard previously.
|
||||
*/
|
||||
static void add_blame_entry(struct scoreboard *sb, struct blame_entry *e)
|
||||
@@ -1047,9 +1058,12 @@ static int find_copy_in_parent(struct scoreboard *sb,
|
||||
(!porigin || strcmp(target->path, porigin->path)))
|
||||
diff_opts.find_copies_harder = 1;
|
||||
|
||||
diff_tree_sha1(parent->tree->object.sha1,
|
||||
target->commit->tree->object.sha1,
|
||||
"", &diff_opts);
|
||||
if (is_null_sha1(target->commit->object.sha1))
|
||||
do_diff_cache(parent->tree->object.sha1, &diff_opts);
|
||||
else
|
||||
diff_tree_sha1(parent->tree->object.sha1,
|
||||
target->commit->tree->object.sha1,
|
||||
"", &diff_opts);
|
||||
|
||||
if (!diff_opts.find_copies_harder)
|
||||
diffcore_std(&diff_opts);
|
||||
@@ -1336,9 +1350,9 @@ static void get_commit_info(struct commit *commit,
|
||||
tmp += 2;
|
||||
endp = strchr(tmp, '\n');
|
||||
if (!endp)
|
||||
goto error_out;
|
||||
endp = tmp + strlen(tmp);
|
||||
len = endp - tmp;
|
||||
if (len >= sizeof(summary_buf))
|
||||
if (len >= sizeof(summary_buf) || len == 0)
|
||||
goto error_out;
|
||||
memcpy(summary_buf, tmp, len);
|
||||
summary_buf[len] = 0;
|
||||
@@ -1392,7 +1406,7 @@ static void found_guilty_entry(struct blame_entry *ent)
|
||||
|
||||
/*
|
||||
* The main loop -- while the scoreboard has lines whose true origin
|
||||
* is still unknown, pick one brame_entry, and allow its current
|
||||
* is still unknown, pick one blame_entry, and allow its current
|
||||
* suspect to pass blames to its parents.
|
||||
*/
|
||||
static void assign_blame(struct scoreboard *sb, struct rev_info *revs, int opt)
|
||||
@@ -1541,12 +1555,12 @@ static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt)
|
||||
int length = (opt & OUTPUT_LONG_OBJECT_NAME) ? 40 : 8;
|
||||
|
||||
if (suspect->commit->object.flags & UNINTERESTING) {
|
||||
if (!blank_boundary) {
|
||||
if (blank_boundary)
|
||||
memset(hex, ' ', length);
|
||||
else if (!cmd_is_annotate) {
|
||||
length--;
|
||||
putchar('^');
|
||||
}
|
||||
else
|
||||
memset(hex, ' ', length);
|
||||
}
|
||||
|
||||
printf("%.*s", length, hex);
|
||||
@@ -1910,6 +1924,137 @@ static int git_blame_config(const char *var, const char *value)
|
||||
return git_default_config(var, value);
|
||||
}
|
||||
|
||||
static struct commit *fake_working_tree_commit(const char *path, const char *contents_from)
|
||||
{
|
||||
struct commit *commit;
|
||||
struct origin *origin;
|
||||
unsigned char head_sha1[20];
|
||||
char *buf;
|
||||
const char *ident;
|
||||
int fd;
|
||||
time_t now;
|
||||
unsigned long fin_size;
|
||||
int size, len;
|
||||
struct cache_entry *ce;
|
||||
unsigned mode;
|
||||
|
||||
if (get_sha1("HEAD", head_sha1))
|
||||
die("No such ref: HEAD");
|
||||
|
||||
time(&now);
|
||||
commit = xcalloc(1, sizeof(*commit));
|
||||
commit->parents = xcalloc(1, sizeof(*commit->parents));
|
||||
commit->parents->item = lookup_commit_reference(head_sha1);
|
||||
commit->object.parsed = 1;
|
||||
commit->date = now;
|
||||
commit->object.type = OBJ_COMMIT;
|
||||
|
||||
origin = make_origin(commit, path);
|
||||
|
||||
if (!contents_from || strcmp("-", contents_from)) {
|
||||
struct stat st;
|
||||
const char *read_from;
|
||||
|
||||
if (contents_from) {
|
||||
if (stat(contents_from, &st) < 0)
|
||||
die("Cannot stat %s", contents_from);
|
||||
read_from = contents_from;
|
||||
}
|
||||
else {
|
||||
if (lstat(path, &st) < 0)
|
||||
die("Cannot lstat %s", path);
|
||||
read_from = path;
|
||||
}
|
||||
fin_size = st.st_size;
|
||||
buf = xmalloc(fin_size+1);
|
||||
mode = canon_mode(st.st_mode);
|
||||
switch (st.st_mode & S_IFMT) {
|
||||
case S_IFREG:
|
||||
fd = open(read_from, O_RDONLY);
|
||||
if (fd < 0)
|
||||
die("cannot open %s", read_from);
|
||||
if (read_in_full(fd, buf, fin_size) != fin_size)
|
||||
die("cannot read %s", read_from);
|
||||
break;
|
||||
case S_IFLNK:
|
||||
if (readlink(read_from, buf, fin_size+1) != fin_size)
|
||||
die("cannot readlink %s", read_from);
|
||||
break;
|
||||
default:
|
||||
die("unsupported file type %s", read_from);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Reading from stdin */
|
||||
contents_from = "standard input";
|
||||
buf = NULL;
|
||||
fin_size = 0;
|
||||
mode = 0;
|
||||
while (1) {
|
||||
ssize_t cnt = 8192;
|
||||
buf = xrealloc(buf, fin_size + cnt);
|
||||
cnt = xread(0, buf + fin_size, cnt);
|
||||
if (cnt < 0)
|
||||
die("read error %s from stdin",
|
||||
strerror(errno));
|
||||
if (!cnt)
|
||||
break;
|
||||
fin_size += cnt;
|
||||
}
|
||||
buf = xrealloc(buf, fin_size + 1);
|
||||
}
|
||||
buf[fin_size] = 0;
|
||||
origin->file.ptr = buf;
|
||||
origin->file.size = fin_size;
|
||||
pretend_sha1_file(buf, fin_size, blob_type, origin->blob_sha1);
|
||||
commit->util = origin;
|
||||
|
||||
/*
|
||||
* Read the current index, replace the path entry with
|
||||
* origin->blob_sha1 without mucking with its mode or type
|
||||
* bits; we are not going to write this index out -- we just
|
||||
* want to run "diff-index --cached".
|
||||
*/
|
||||
discard_cache();
|
||||
read_cache();
|
||||
|
||||
len = strlen(path);
|
||||
if (!mode) {
|
||||
int pos = cache_name_pos(path, len);
|
||||
if (0 <= pos)
|
||||
mode = ntohl(active_cache[pos]->ce_mode);
|
||||
else
|
||||
/* Let's not bother reading from HEAD tree */
|
||||
mode = S_IFREG | 0644;
|
||||
}
|
||||
size = cache_entry_size(len);
|
||||
ce = xcalloc(1, size);
|
||||
hashcpy(ce->sha1, origin->blob_sha1);
|
||||
memcpy(ce->name, path, len);
|
||||
ce->ce_flags = create_ce_flags(len, 0);
|
||||
ce->ce_mode = create_ce_mode(mode);
|
||||
add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
|
||||
|
||||
/*
|
||||
* We are not going to write this out, so this does not matter
|
||||
* right now, but someday we might optimize diff-index --cached
|
||||
* with cache-tree information.
|
||||
*/
|
||||
cache_tree_invalidate_path(active_cache_tree, path);
|
||||
|
||||
commit->buffer = xmalloc(400);
|
||||
ident = fmt_ident("Not Committed Yet", "not.committed.yet", NULL, 0);
|
||||
sprintf(commit->buffer,
|
||||
"tree 0000000000000000000000000000000000000000\n"
|
||||
"parent %s\n"
|
||||
"author %s\n"
|
||||
"committer %s\n\n"
|
||||
"Version of %s from %s\n",
|
||||
sha1_to_hex(head_sha1),
|
||||
ident, ident, path, contents_from ? contents_from : path);
|
||||
return commit;
|
||||
}
|
||||
|
||||
int cmd_blame(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct rev_info revs;
|
||||
@@ -1924,6 +2069,9 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
|
||||
const char *final_commit_name = NULL;
|
||||
char type[10];
|
||||
const char *bottomtop = NULL;
|
||||
const char *contents_from = NULL;
|
||||
|
||||
cmd_is_annotate = !strcmp(argv[0], "annotate");
|
||||
|
||||
git_config(git_blame_config);
|
||||
save_commit_buffer = 0;
|
||||
@@ -1968,6 +2116,11 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
|
||||
die("More than one '-L n,m' option given");
|
||||
bottomtop = arg;
|
||||
}
|
||||
else if (!strcmp("--contents", arg)) {
|
||||
if (++i >= argc)
|
||||
usage(blame_usage);
|
||||
contents_from = argv[i];
|
||||
}
|
||||
else if (!strcmp("--incremental", arg))
|
||||
incremental = 1;
|
||||
else if (!strcmp("--score-debug", arg))
|
||||
@@ -2001,7 +2154,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
|
||||
/*
|
||||
* We have collected options unknown to us in argv[1..unk]
|
||||
* which are to be passed to revision machinery if we are
|
||||
* going to do the "bottom" procesing.
|
||||
* going to do the "bottom" processing.
|
||||
*
|
||||
* The remaining are:
|
||||
*
|
||||
@@ -2087,7 +2240,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
|
||||
argv[unk] = NULL;
|
||||
|
||||
init_revisions(&revs, NULL);
|
||||
setup_revisions(unk, argv, &revs, "HEAD");
|
||||
setup_revisions(unk, argv, &revs, NULL);
|
||||
memset(&sb, 0, sizeof(sb));
|
||||
|
||||
/*
|
||||
@@ -2114,16 +2267,14 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
|
||||
if (!sb.final) {
|
||||
/*
|
||||
* "--not A B -- path" without anything positive;
|
||||
* default to HEAD.
|
||||
* do not default to HEAD, but use the working tree
|
||||
* or "--contents".
|
||||
*/
|
||||
unsigned char head_sha1[20];
|
||||
|
||||
final_commit_name = "HEAD";
|
||||
if (get_sha1(final_commit_name, head_sha1))
|
||||
die("No such ref: HEAD");
|
||||
sb.final = lookup_commit_reference(head_sha1);
|
||||
add_pending_object(&revs, &(sb.final->object), "HEAD");
|
||||
sb.final = fake_working_tree_commit(path, contents_from);
|
||||
add_pending_object(&revs, &(sb.final->object), ":");
|
||||
}
|
||||
else if (contents_from)
|
||||
die("Cannot use --contents with final commit object name");
|
||||
|
||||
/*
|
||||
* If we have bottom, this will mark the ancestors of the
|
||||
@@ -2132,11 +2283,22 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
|
||||
*/
|
||||
prepare_revision_walk(&revs);
|
||||
|
||||
o = get_origin(&sb, sb.final, path);
|
||||
if (fill_blob_sha1(o))
|
||||
die("no such path %s in %s", path, final_commit_name);
|
||||
if (is_null_sha1(sb.final->object.sha1)) {
|
||||
char *buf;
|
||||
o = sb.final->util;
|
||||
buf = xmalloc(o->file.size + 1);
|
||||
memcpy(buf, o->file.ptr, o->file.size + 1);
|
||||
sb.final_buf = buf;
|
||||
sb.final_buf_size = o->file.size;
|
||||
}
|
||||
else {
|
||||
o = get_origin(&sb, sb.final, path);
|
||||
if (fill_blob_sha1(o))
|
||||
die("no such path %s in %s", path, final_commit_name);
|
||||
|
||||
sb.final_buf = read_sha1_file(o->blob_sha1, type, &sb.final_buf_size);
|
||||
sb.final_buf = read_sha1_file(o->blob_sha1, type,
|
||||
&sb.final_buf_size);
|
||||
}
|
||||
num_read_blob++;
|
||||
lno = prepare_lines(&sb);
|
||||
|
||||
|
||||
@@ -316,6 +316,7 @@ static void create_branch(const char *name, const char *start_name,
|
||||
struct commit *commit;
|
||||
unsigned char sha1[20];
|
||||
char ref[PATH_MAX], msg[PATH_MAX + 20];
|
||||
int forcing = 0;
|
||||
|
||||
snprintf(ref, sizeof ref, "refs/heads/%s", name);
|
||||
if (check_ref_format(ref))
|
||||
@@ -326,6 +327,7 @@ static void create_branch(const char *name, const char *start_name,
|
||||
die("A branch named '%s' already exists.", name);
|
||||
else if (!is_bare_repository() && !strcmp(head, name))
|
||||
die("Cannot force update the current branch.");
|
||||
forcing = 1;
|
||||
}
|
||||
|
||||
if (start_sha1)
|
||||
@@ -342,11 +344,15 @@ static void create_branch(const char *name, const char *start_name,
|
||||
if (!lock)
|
||||
die("Failed to lock ref for update: %s.", strerror(errno));
|
||||
|
||||
if (reflog) {
|
||||
if (reflog)
|
||||
log_all_ref_updates = 1;
|
||||
|
||||
if (forcing)
|
||||
snprintf(msg, sizeof msg, "branch: Reset from %s",
|
||||
start_name);
|
||||
else
|
||||
snprintf(msg, sizeof msg, "branch: Created from %s",
|
||||
start_name);
|
||||
}
|
||||
|
||||
if (write_ref_sha1(lock, sha1, msg) < 0)
|
||||
die("Failed to write ref: %s.", strerror(errno));
|
||||
@@ -358,7 +364,7 @@ static void rename_branch(const char *oldname, const char *newname, int force)
|
||||
unsigned char sha1[20];
|
||||
|
||||
if (!oldname)
|
||||
die("cannot rename the curren branch while not on any.");
|
||||
die("cannot rename the current branch while not on any.");
|
||||
|
||||
if (snprintf(oldref, sizeof(oldref), "refs/heads/%s", oldname) > sizeof(oldref))
|
||||
die("Old branchname too long");
|
||||
|
||||
@@ -135,7 +135,7 @@ static const char *find_next(const char *cp)
|
||||
while (*cp) {
|
||||
if (*cp == '%') {
|
||||
/* %( is the start of an atom;
|
||||
* %% is a quoteed per-cent.
|
||||
* %% is a quoted per-cent.
|
||||
*/
|
||||
if (cp[1] == '(')
|
||||
return cp;
|
||||
|
||||
@@ -117,7 +117,7 @@ static void check_unreachable_object(struct object *obj)
|
||||
|
||||
/*
|
||||
* "!used" means that nothing at all points to it, including
|
||||
* other unreacahble objects. In other words, it's the "tip"
|
||||
* other unreachable objects. In other words, it's the "tip"
|
||||
* of some set of unreachable objects, usually a commit that
|
||||
* got dropped.
|
||||
*
|
||||
@@ -477,6 +477,12 @@ static int fsck_handle_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fsck_handle_reflog(const char *logname, const unsigned char *sha1, int flag, void *cb_data)
|
||||
{
|
||||
for_each_reflog_ent(logname, fsck_handle_reflog_ent, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fsck_handle_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
|
||||
{
|
||||
struct object *obj;
|
||||
@@ -495,14 +501,13 @@ static int fsck_handle_ref(const char *refname, const unsigned char *sha1, int f
|
||||
obj->used = 1;
|
||||
mark_reachable(obj, REACHABLE);
|
||||
|
||||
for_each_reflog_ent(refname, fsck_handle_reflog_ent, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void get_default_heads(void)
|
||||
{
|
||||
for_each_ref(fsck_handle_ref, NULL);
|
||||
for_each_reflog(fsck_handle_reflog, NULL);
|
||||
|
||||
/*
|
||||
* Not having any default heads isn't really fatal, but
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "log-tree.h"
|
||||
#include "builtin.h"
|
||||
#include "tag.h"
|
||||
#include "reflog-walk.h"
|
||||
|
||||
static int default_show_root = 1;
|
||||
|
||||
@@ -181,6 +182,37 @@ int cmd_show(int argc, const char **argv, const char *prefix)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is equivalent to "git log -g --abbrev-commit --pretty=oneline"
|
||||
*/
|
||||
int cmd_log_reflog(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct rev_info rev;
|
||||
|
||||
git_config(git_log_config);
|
||||
init_revisions(&rev, prefix);
|
||||
init_reflog_walk(&rev.reflog_info);
|
||||
rev.abbrev_commit = 1;
|
||||
rev.verbose_header = 1;
|
||||
cmd_log_init(argc, argv, prefix, &rev);
|
||||
|
||||
/*
|
||||
* This means that we override whatever commit format the user gave
|
||||
* on the cmd line. Sad, but cmd_log_init() currently doesn't
|
||||
* allow us to set a different default.
|
||||
*/
|
||||
rev.commit_format = CMIT_FMT_ONELINE;
|
||||
rev.always_show_header = 1;
|
||||
|
||||
/*
|
||||
* We get called through "git reflog", so unlike the other log
|
||||
* routines, we need to set up our pager manually..
|
||||
*/
|
||||
setup_pager();
|
||||
|
||||
return cmd_log_walk(&rev);
|
||||
}
|
||||
|
||||
int cmd_log(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct rev_info rev;
|
||||
|
||||
@@ -323,7 +323,7 @@ static const char ls_files_usage[] =
|
||||
int cmd_ls_files(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i;
|
||||
int exc_given = 0;
|
||||
int exc_given = 0, require_work_tree = 0;
|
||||
struct dir_struct dir;
|
||||
|
||||
memset(&dir, 0, sizeof(dir));
|
||||
@@ -363,14 +363,17 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
if (!strcmp(arg, "-m") || !strcmp(arg, "--modified")) {
|
||||
show_modified = 1;
|
||||
require_work_tree = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "-o") || !strcmp(arg, "--others")) {
|
||||
show_others = 1;
|
||||
require_work_tree = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "-i") || !strcmp(arg, "--ignored")) {
|
||||
dir.show_ignored = 1;
|
||||
require_work_tree = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "-s") || !strcmp(arg, "--stage")) {
|
||||
@@ -379,6 +382,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
if (!strcmp(arg, "-k") || !strcmp(arg, "--killed")) {
|
||||
show_killed = 1;
|
||||
require_work_tree = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--directory")) {
|
||||
@@ -447,6 +451,10 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
|
||||
break;
|
||||
}
|
||||
|
||||
if (require_work_tree &&
|
||||
(is_bare_repository() || is_inside_git_dir()))
|
||||
die("This operation must be run in a work tree");
|
||||
|
||||
pathspec = get_pathspec(prefix, argv + i);
|
||||
|
||||
/* Verify that the pathspec matches the prefix */
|
||||
|
||||
114
builtin-push.c
114
builtin-push.c
@@ -54,38 +54,84 @@ static void expand_refspecs(void)
|
||||
for_each_ref(expand_one_ref, NULL);
|
||||
}
|
||||
|
||||
struct wildcard_cb {
|
||||
const char *from_prefix;
|
||||
int from_prefix_len;
|
||||
const char *to_prefix;
|
||||
int to_prefix_len;
|
||||
int force;
|
||||
};
|
||||
|
||||
static int expand_wildcard_ref(const char *ref, const unsigned char *sha1, int flag, void *cb_data)
|
||||
{
|
||||
struct wildcard_cb *cb = cb_data;
|
||||
int len = strlen(ref);
|
||||
char *expanded, *newref;
|
||||
|
||||
if (len < cb->from_prefix_len ||
|
||||
memcmp(cb->from_prefix, ref, cb->from_prefix_len))
|
||||
return 0;
|
||||
expanded = xmalloc(len * 2 + cb->force +
|
||||
(cb->to_prefix_len - cb->from_prefix_len) + 2);
|
||||
newref = expanded + cb->force;
|
||||
if (cb->force)
|
||||
expanded[0] = '+';
|
||||
memcpy(newref, ref, len);
|
||||
newref[len] = ':';
|
||||
memcpy(newref + len + 1, cb->to_prefix, cb->to_prefix_len);
|
||||
strcpy(newref + len + 1 + cb->to_prefix_len,
|
||||
ref + cb->from_prefix_len);
|
||||
add_refspec(expanded);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wildcard_ref(const char *ref)
|
||||
{
|
||||
int len;
|
||||
const char *colon;
|
||||
struct wildcard_cb cb;
|
||||
|
||||
memset(&cb, 0, sizeof(cb));
|
||||
if (ref[0] == '+') {
|
||||
cb.force = 1;
|
||||
ref++;
|
||||
}
|
||||
len = strlen(ref);
|
||||
colon = strchr(ref, ':');
|
||||
if (! (colon && ref < colon &&
|
||||
colon[-2] == '/' && colon[-1] == '*' &&
|
||||
/* "<mine>/<asterisk>:<yours>/<asterisk>" is at least 7 bytes */
|
||||
7 <= len &&
|
||||
ref[len-2] == '/' && ref[len-1] == '*') )
|
||||
return 0 ;
|
||||
cb.from_prefix = ref;
|
||||
cb.from_prefix_len = colon - ref - 1;
|
||||
cb.to_prefix = colon + 1;
|
||||
cb.to_prefix_len = len - (colon - ref) - 2;
|
||||
for_each_ref(expand_wildcard_ref, &cb);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void set_refspecs(const char **refs, int nr)
|
||||
{
|
||||
if (nr) {
|
||||
int pass;
|
||||
for (pass = 0; pass < 2; pass++) {
|
||||
/* pass 0 counts and allocates, pass 1 fills */
|
||||
int i, cnt;
|
||||
for (i = cnt = 0; i < nr; i++) {
|
||||
if (!strcmp("tag", refs[i])) {
|
||||
int len;
|
||||
char *tag;
|
||||
if (nr <= ++i)
|
||||
die("tag <tag> shorthand without <tag>");
|
||||
if (pass) {
|
||||
len = strlen(refs[i]) + 11;
|
||||
tag = xmalloc(len);
|
||||
strcpy(tag, "refs/tags/");
|
||||
strcat(tag, refs[i]);
|
||||
refspec[cnt] = tag;
|
||||
}
|
||||
cnt++;
|
||||
continue;
|
||||
}
|
||||
if (pass)
|
||||
refspec[cnt] = refs[i];
|
||||
cnt++;
|
||||
}
|
||||
if (!pass) {
|
||||
size_t bytes = cnt * sizeof(char *);
|
||||
refspec_nr = cnt;
|
||||
refspec = xrealloc(refspec, bytes);
|
||||
int i;
|
||||
for (i = 0; i < nr; i++) {
|
||||
const char *ref = refs[i];
|
||||
if (!strcmp("tag", ref)) {
|
||||
char *tag;
|
||||
int len;
|
||||
if (nr <= ++i)
|
||||
die("tag shorthand without <tag>");
|
||||
len = strlen(refs[i]) + 11;
|
||||
tag = xmalloc(len);
|
||||
strcpy(tag, "refs/tags/");
|
||||
strcat(tag, refs[i]);
|
||||
ref = tag;
|
||||
}
|
||||
else if (wildcard_ref(ref))
|
||||
continue;
|
||||
add_refspec(ref);
|
||||
}
|
||||
}
|
||||
expand_refspecs();
|
||||
@@ -129,8 +175,10 @@ static int get_remotes_uri(const char *repo, const char *uri[MAX_URI])
|
||||
else
|
||||
error("more than %d URL's specified, ignoring the rest", MAX_URI);
|
||||
}
|
||||
else if (is_refspec && !has_explicit_refspec)
|
||||
add_refspec(xstrdup(s));
|
||||
else if (is_refspec && !has_explicit_refspec) {
|
||||
if (!wildcard_ref(s))
|
||||
add_refspec(xstrdup(s));
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
if (!n)
|
||||
@@ -156,8 +204,10 @@ static int get_remote_config(const char* key, const char* value)
|
||||
error("more than %d URL's specified, ignoring the rest", MAX_URI);
|
||||
}
|
||||
else if (config_get_refspecs &&
|
||||
!strcmp(key + 7 + config_repo_len, ".push"))
|
||||
add_refspec(xstrdup(value));
|
||||
!strcmp(key + 7 + config_repo_len, ".push")) {
|
||||
if (!wildcard_ref(value))
|
||||
add_refspec(xstrdup(value));
|
||||
}
|
||||
else if (config_get_receivepack &&
|
||||
!strcmp(key + 7 + config_repo_len, ".receivepack")) {
|
||||
if (!receivepack) {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
*/
|
||||
|
||||
static const char reflog_expire_usage[] =
|
||||
"git-reflog expire [--verbose] [--dry-run] [--stale-fix] [--expire=<time>] [--expire-unreachable=<time>] [--all] <refs>...";
|
||||
"git-reflog (show|expire) [--verbose] [--dry-run] [--stale-fix] [--expire=<time>] [--expire-unreachable=<time>] [--all] <refs>...";
|
||||
|
||||
static unsigned long default_reflog_expire;
|
||||
static unsigned long default_reflog_expire_unreachable;
|
||||
@@ -245,14 +245,11 @@ static int expire_reflog(const char *ref, const unsigned char *sha1, int unused,
|
||||
char *log_file, *newlog_path = NULL;
|
||||
int status = 0;
|
||||
|
||||
if (strncmp(ref, "refs/", 5))
|
||||
return error("not a ref '%s'", ref);
|
||||
|
||||
memset(&cb, 0, sizeof(cb));
|
||||
/* we take the lock for the ref itself to prevent it from
|
||||
* getting updated.
|
||||
*/
|
||||
lock = lock_ref_sha1(ref + 5, sha1);
|
||||
lock = lock_any_ref_for_update(ref, sha1);
|
||||
if (!lock)
|
||||
return error("cannot lock ref '%s'", ref);
|
||||
log_file = xstrdup(git_path("logs/%s", ref));
|
||||
@@ -359,7 +356,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
|
||||
if (do_all)
|
||||
status |= for_each_ref(expire_reflog, &cb);
|
||||
status |= for_each_reflog(expire_reflog, &cb);
|
||||
while (i < argc) {
|
||||
const char *ref = argv[i++];
|
||||
unsigned char sha1[20];
|
||||
@@ -381,10 +378,16 @@ static const char reflog_usage[] =
|
||||
|
||||
int cmd_reflog(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
if (argc < 2)
|
||||
usage(reflog_usage);
|
||||
else if (!strcmp(argv[1], "expire"))
|
||||
/* With no command, we default to showing it. */
|
||||
if (argc < 2 || *argv[1] == '-')
|
||||
return cmd_log_reflog(argc, argv, prefix);
|
||||
|
||||
if (!strcmp(argv[1], "show"))
|
||||
return cmd_log_reflog(argc - 1, argv + 1, prefix);
|
||||
|
||||
if (!strcmp(argv[1], "expire"))
|
||||
return cmd_reflog_expire(argc - 1, argv + 1, prefix);
|
||||
else
|
||||
usage(reflog_usage);
|
||||
|
||||
/* Not a recognized reflog command..*/
|
||||
usage(reflog_usage);
|
||||
}
|
||||
|
||||
@@ -347,6 +347,11 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
|
||||
printf("%s/.git\n", cwd);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--is-inside-git-dir")) {
|
||||
printf("%s\n", is_inside_git_dir() ? "true"
|
||||
: "false");
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(arg, "--since=", 8)) {
|
||||
show_datestring("--max-age=", arg+8);
|
||||
continue;
|
||||
|
||||
@@ -690,7 +690,10 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
|
||||
|
||||
if (ac == 0) {
|
||||
static const char *fake_av[2];
|
||||
fake_av[0] = "HEAD";
|
||||
const char *refname;
|
||||
|
||||
refname = resolve_ref("HEAD", sha1, 1, NULL);
|
||||
fake_av[0] = xstrdup(refname);
|
||||
fake_av[1] = NULL;
|
||||
av = fake_av;
|
||||
ac = 1;
|
||||
|
||||
@@ -40,6 +40,7 @@ extern int cmd_grep(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_help(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_init_db(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_log(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_log_reflog(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_ls_files(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_ls_tree(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_mailinfo(int argc, const char **argv, const char *prefix);
|
||||
|
||||
3
cache.h
3
cache.h
@@ -258,6 +258,7 @@ extern void * unpack_sha1_file(void *map, unsigned long mapsize, char *type, uns
|
||||
extern void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size);
|
||||
extern int hash_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *sha1);
|
||||
extern int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
|
||||
extern int pretend_sha1_file(void *, unsigned long, const char *, unsigned char *);
|
||||
|
||||
extern int check_sha1_signature(const unsigned char *sha1, void *buf, unsigned long size, const char *type);
|
||||
|
||||
@@ -302,6 +303,7 @@ extern char *sha1_to_hex(const unsigned char *sha1); /* static buffer result! */
|
||||
extern int read_ref(const char *filename, unsigned char *sha1);
|
||||
extern const char *resolve_ref(const char *path, unsigned char *sha1, int, int *);
|
||||
extern int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref);
|
||||
extern int dwim_log(const char *str, int len, unsigned char *sha1, char **ref);
|
||||
|
||||
extern int create_symref(const char *ref, const char *refs_heads_master, const char *logmsg);
|
||||
extern int validate_headref(const char *ref);
|
||||
@@ -322,6 +324,7 @@ unsigned long approxidate(const char *);
|
||||
|
||||
extern const char *git_author_info(int);
|
||||
extern const char *git_committer_info(int);
|
||||
extern const char *fmt_ident(const char *name, const char *email, const char *date_str, int);
|
||||
|
||||
struct checkout {
|
||||
const char *base_dir;
|
||||
|
||||
@@ -482,11 +482,11 @@ static int make_hunks(struct sline *sline, unsigned long cnt,
|
||||
return has_interesting;
|
||||
}
|
||||
|
||||
static void show_parent_lno(struct sline *sline, unsigned long l0, unsigned long l1, int n)
|
||||
static void show_parent_lno(struct sline *sline, unsigned long l0, unsigned long l1, int n, unsigned long null_context)
|
||||
{
|
||||
l0 = sline[l0].p_lno[n];
|
||||
l1 = sline[l1].p_lno[n];
|
||||
printf(" -%lu,%lu", l0, l1-l0);
|
||||
printf(" -%lu,%lu", l0, l1-l0-null_context);
|
||||
}
|
||||
|
||||
static int hunk_comment_line(const char *bol)
|
||||
@@ -519,6 +519,7 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent,
|
||||
unsigned long hunk_end;
|
||||
unsigned long rlines;
|
||||
const char *hunk_comment = NULL;
|
||||
unsigned long null_context = 0;
|
||||
|
||||
while (lno <= cnt && !(sline[lno].flag & mark)) {
|
||||
if (hunk_comment_line(sline[lno].bol))
|
||||
@@ -535,10 +536,28 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent,
|
||||
rlines = hunk_end - lno;
|
||||
if (cnt < hunk_end)
|
||||
rlines--; /* pointing at the last delete hunk */
|
||||
|
||||
if (!context) {
|
||||
/*
|
||||
* Even when running with --unified=0, all
|
||||
* lines in the hunk needs to be processed in
|
||||
* the loop below in order to show the
|
||||
* deletion recorded in lost_head. However,
|
||||
* we do not want to show the resulting line
|
||||
* with all blank context markers in such a
|
||||
* case. Compensate.
|
||||
*/
|
||||
unsigned long j;
|
||||
for (j = lno; j < hunk_end; j++)
|
||||
if (!(sline[j].flag & (mark-1)))
|
||||
null_context++;
|
||||
rlines -= null_context;
|
||||
}
|
||||
|
||||
fputs(c_frag, stdout);
|
||||
for (i = 0; i <= num_parent; i++) putchar(combine_marker);
|
||||
for (i = 0; i < num_parent; i++)
|
||||
show_parent_lno(sline, lno, hunk_end, i);
|
||||
show_parent_lno(sline, lno, hunk_end, i, null_context);
|
||||
printf(" +%lu,%lu ", lno+1, rlines);
|
||||
for (i = 0; i <= num_parent; i++) putchar(combine_marker);
|
||||
|
||||
@@ -578,8 +597,15 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent,
|
||||
if (cnt < lno)
|
||||
break;
|
||||
p_mask = 1;
|
||||
if (!(sl->flag & (mark-1)))
|
||||
if (!(sl->flag & (mark-1))) {
|
||||
/*
|
||||
* This sline was here to hang the
|
||||
* lost lines in front of it.
|
||||
*/
|
||||
if (!context)
|
||||
continue;
|
||||
fputs(c_plain, stdout);
|
||||
}
|
||||
else
|
||||
fputs(c_new, stdout);
|
||||
for (j = 0; j < num_parent; j++) {
|
||||
|
||||
3
commit.c
3
commit.c
@@ -47,7 +47,8 @@ enum cmit_fmt get_commit_format(const char *arg)
|
||||
if (*arg == '=')
|
||||
arg++;
|
||||
for (i = 0; i < ARRAY_SIZE(cmt_fmts); i++) {
|
||||
if (!strncmp(arg, cmt_fmts[i].n, cmt_fmts[i].cmp_len))
|
||||
if (!strncmp(arg, cmt_fmts[i].n, cmt_fmts[i].cmp_len) &&
|
||||
!strncmp(arg, cmt_fmts[i].n, strlen(arg)))
|
||||
return cmt_fmts[i].v;
|
||||
}
|
||||
|
||||
|
||||
2
config.c
2
config.c
@@ -898,7 +898,7 @@ int git_config_rename_section(const char *old_name, const char *new_name)
|
||||
if (buf[i] != old_name[j++])
|
||||
break;
|
||||
}
|
||||
if (buf[i] == ']') {
|
||||
if (buf[i] == ']' && old_name[j] == 0) {
|
||||
/* old_name matches */
|
||||
ret++;
|
||||
store.baselen = strlen(new_name);
|
||||
|
||||
@@ -3,7 +3,17 @@
|
||||
use Gtk2 -init;
|
||||
use Gtk2::SimpleList;
|
||||
|
||||
my $fn = shift or die "require filename to blame";
|
||||
my $hash;
|
||||
my $fn;
|
||||
if ( @ARGV == 1 ) {
|
||||
$hash = "HEAD";
|
||||
$fn = shift;
|
||||
} elsif ( @ARGV == 2 ) {
|
||||
$hash = shift;
|
||||
$fn = shift;
|
||||
} else {
|
||||
die "Usage blameview [<rev>] <filename>";
|
||||
}
|
||||
|
||||
Gtk2::Rc->parse_string(<<'EOS');
|
||||
style "treeview_style"
|
||||
@@ -15,11 +25,12 @@ EOS
|
||||
|
||||
my $window = Gtk2::Window->new('toplevel');
|
||||
$window->signal_connect(destroy => sub { Gtk2->main_quit });
|
||||
my $vpan = Gtk2::VPaned->new();
|
||||
$window->add($vpan);
|
||||
my $scrolled_window = Gtk2::ScrolledWindow->new;
|
||||
$window->add($scrolled_window);
|
||||
$vpan->pack1($scrolled_window, 1, 1);
|
||||
my $fileview = Gtk2::SimpleList->new(
|
||||
'Commit' => 'text',
|
||||
'CommitInfo' => 'text',
|
||||
'FileLine' => 'text',
|
||||
'Data' => 'text'
|
||||
);
|
||||
@@ -27,17 +38,43 @@ $scrolled_window->add($fileview);
|
||||
$fileview->get_column(0)->set_spacing(0);
|
||||
$fileview->set_size_request(1024, 768);
|
||||
$fileview->set_rules_hint(1);
|
||||
$fileview->signal_connect (row_activated => sub {
|
||||
my ($sl, $path, $column) = @_;
|
||||
my $row_ref = $sl->get_row_data_from_path ($path);
|
||||
system("blameview @$row_ref[0] $fn &");
|
||||
});
|
||||
|
||||
my $commitwindow = Gtk2::ScrolledWindow->new();
|
||||
$commitwindow->set_policy ('GTK_POLICY_AUTOMATIC','GTK_POLICY_AUTOMATIC');
|
||||
$vpan->pack2($commitwindow, 1, 1);
|
||||
my $commit_text = Gtk2::TextView->new();
|
||||
my $commit_buffer = Gtk2::TextBuffer->new();
|
||||
$commit_text->set_buffer($commit_buffer);
|
||||
$commitwindow->add($commit_text);
|
||||
|
||||
$fileview->signal_connect (cursor_changed => sub {
|
||||
my ($sl) = @_;
|
||||
my ($path, $focus_column) = $sl->get_cursor();
|
||||
my $row_ref = $sl->get_row_data_from_path ($path);
|
||||
my $c_fh;
|
||||
open($c_fh, '-|', "git cat-file commit @$row_ref[0]")
|
||||
or die "unable to find commit @$row_ref[0]";
|
||||
my @buffer = <$c_fh>;
|
||||
$commit_buffer->set_text("@buffer");
|
||||
close($c_fh);
|
||||
});
|
||||
|
||||
my $fh;
|
||||
open($fh, '-|', "git cat-file blob HEAD:$fn")
|
||||
open($fh, '-|', "git cat-file blob $hash:$fn")
|
||||
or die "unable to open $fn: $!";
|
||||
|
||||
while(<$fh>) {
|
||||
chomp;
|
||||
$fileview->{data}->[$.] = ['HEAD', '?', "$fn:$.", $_];
|
||||
$fileview->{data}->[$.] = ['HEAD', "$fn:$.", $_];
|
||||
}
|
||||
|
||||
my $blame;
|
||||
open($blame, '-|', qw(git blame --incremental --), $fn)
|
||||
open($blame, '-|', qw(git blame --incremental --), $fn, $hash)
|
||||
or die "cannot start git-blame $fn";
|
||||
|
||||
Glib::IO->add_watch(fileno($blame), 'in', \&read_blame_line);
|
||||
@@ -62,8 +99,7 @@ sub flush_blame_line {
|
||||
|
||||
for(my $i = 0; $i < $cnt; $i++) {
|
||||
@{$fileview->{data}->[$lno+$i-1]}[0,1,2] =
|
||||
(substr($commit, 0, 8), $info,
|
||||
$filename . ':' . ($s_lno+$i));
|
||||
(substr($commit, 0, 8), $filename . ':' . ($s_lno+$i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
This is "colordiff" (http://colordiff.sourceforge.net/) by Dave
|
||||
Ewart <davee@sungate.co.uk>, modified specifically for git.
|
||||
@@ -1,196 +0,0 @@
|
||||
#!/usr/bin/perl -w
|
||||
#
|
||||
# $Id: colordiff.pl,v 1.4.2.10 2004/01/04 15:02:59 daveewart Exp $
|
||||
|
||||
########################################################################
|
||||
# #
|
||||
# ColorDiff - a wrapper/replacment for 'diff' producing #
|
||||
# colourful output #
|
||||
# #
|
||||
# Copyright (C)2002-2004 Dave Ewart (davee@sungate.co.uk) #
|
||||
# #
|
||||
########################################################################
|
||||
# #
|
||||
# This program is free software; you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
# the Free Software Foundation; either version 2 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# This program is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License #
|
||||
# along with this program; if not, write to the Free Software #
|
||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #
|
||||
# #
|
||||
########################################################################
|
||||
|
||||
use strict;
|
||||
use Getopt::Long qw(:config pass_through);
|
||||
use IPC::Open2;
|
||||
|
||||
my $app_name = 'colordiff';
|
||||
my $version = '1.0.4';
|
||||
my $author = 'Dave Ewart';
|
||||
my $author_email = 'davee@sungate.co.uk';
|
||||
my $app_www = 'http://colordiff.sourceforge.net/';
|
||||
my $copyright = '(C)2002-2004';
|
||||
my $show_banner = 1;
|
||||
|
||||
# ANSI sequences for colours
|
||||
my %colour;
|
||||
$colour{white} = "\033[1;37m";
|
||||
$colour{yellow} = "\033[1;33m";
|
||||
$colour{green} = "\033[1;32m";
|
||||
$colour{blue} = "\033[1;34m";
|
||||
$colour{cyan} = "\033[1;36m";
|
||||
$colour{red} = "\033[1;31m";
|
||||
$colour{magenta} = "\033[1;35m";
|
||||
$colour{black} = "\033[1;30m";
|
||||
$colour{darkwhite} = "\033[0;37m";
|
||||
$colour{darkyellow} = "\033[0;33m";
|
||||
$colour{darkgreen} = "\033[0;32m";
|
||||
$colour{darkblue} = "\033[0;34m";
|
||||
$colour{darkcyan} = "\033[0;36m";
|
||||
$colour{darkred} = "\033[0;31m";
|
||||
$colour{darkmagenta} = "\033[0;35m";
|
||||
$colour{darkblack} = "\033[0;30m";
|
||||
$colour{OFF} = "\033[0;0m";
|
||||
|
||||
# Default colours if /etc/colordiffrc or ~/.colordiffrc do not exist
|
||||
my $plain_text = $colour{OFF};
|
||||
my $file_old = $colour{red};
|
||||
my $file_new = $colour{blue};
|
||||
my $diff_stuff = $colour{magenta};
|
||||
|
||||
# Locations for personal and system-wide colour configurations
|
||||
my $HOME = $ENV{HOME};
|
||||
my $etcdir = '/etc';
|
||||
|
||||
my ($setting, $value);
|
||||
my @config_files = ("$etcdir/colordiffrc", "$HOME/.colordiffrc");
|
||||
my $config_file;
|
||||
|
||||
foreach $config_file (@config_files) {
|
||||
if (open(COLORDIFFRC, "<$config_file")) {
|
||||
while (<COLORDIFFRC>) {
|
||||
chop;
|
||||
next if (/^#/ || /^$/);
|
||||
s/\s+//g;
|
||||
($setting, $value) = split ('=');
|
||||
if ($setting eq 'banner') {
|
||||
if ($value eq 'no') {
|
||||
$show_banner = 0;
|
||||
}
|
||||
next;
|
||||
}
|
||||
if (!defined $colour{$value}) {
|
||||
print "Invalid colour specification ($value) in $config_file\n";
|
||||
next;
|
||||
}
|
||||
if ($setting eq 'plain') {
|
||||
$plain_text = $colour{$value};
|
||||
}
|
||||
elsif ($setting eq 'oldtext') {
|
||||
$file_old = $colour{$value};
|
||||
}
|
||||
elsif ($setting eq 'newtext') {
|
||||
$file_new = $colour{$value};
|
||||
}
|
||||
elsif ($setting eq 'diffstuff') {
|
||||
$diff_stuff = $colour{$value};
|
||||
}
|
||||
else {
|
||||
print "Unknown option in $etcdir/colordiffrc: $setting\n";
|
||||
}
|
||||
}
|
||||
close COLORDIFFRC;
|
||||
}
|
||||
}
|
||||
|
||||
# colordiff specific options here. Need to pre-declare if using variables
|
||||
GetOptions(
|
||||
"no-banner" => sub { $show_banner = 0 },
|
||||
"plain-text=s" => \&set_color,
|
||||
"file-old=s" => \&set_color,
|
||||
"file-new=s" => \&set_color,
|
||||
"diff-stuff=s" => \&set_color
|
||||
);
|
||||
|
||||
if ($show_banner == 1) {
|
||||
print STDERR "$app_name $version ($app_www)\n";
|
||||
print STDERR "$copyright $author, $author_email\n\n";
|
||||
}
|
||||
|
||||
if (defined $ARGV[0]) {
|
||||
# More reliable way of pulling in arguments
|
||||
open2(\*INPUTSTREAM, undef, "git", "diff", @ARGV);
|
||||
}
|
||||
else {
|
||||
*INPUTSTREAM = \*STDIN;
|
||||
}
|
||||
|
||||
my $record;
|
||||
my $nrecs = 0;
|
||||
my $inside_file_old = 1;
|
||||
my $nparents = undef;
|
||||
|
||||
while (<INPUTSTREAM>) {
|
||||
$nrecs++;
|
||||
if (/^(\@\@+) -[-+0-9, ]+ \1/) {
|
||||
print "$diff_stuff";
|
||||
$nparents = length($1) - 1;
|
||||
}
|
||||
elsif (/^diff -/ || /^index / ||
|
||||
/^old mode / || /^new mode / ||
|
||||
/^deleted file mode / || /^new file mode / ||
|
||||
/^similarity index / || /^dissimilarity index / ||
|
||||
/^copy from / || /^copy to / ||
|
||||
/^rename from / || /^rename to /) {
|
||||
$nparents = undef;
|
||||
print "$diff_stuff";
|
||||
}
|
||||
elsif (defined $nparents) {
|
||||
if ($nparents == 1) {
|
||||
if (/^\+/) {
|
||||
print $file_new;
|
||||
}
|
||||
elsif (/^-/) {
|
||||
print $file_old;
|
||||
}
|
||||
else {
|
||||
print $plain_text;
|
||||
}
|
||||
}
|
||||
elsif (/^ {$nparents}/) {
|
||||
print "$plain_text";
|
||||
}
|
||||
elsif (/^[+ ]{$nparents}/) {
|
||||
print "$file_new";
|
||||
}
|
||||
elsif (/^[- ]{$nparents}/) {
|
||||
print "$file_old";
|
||||
}
|
||||
else {
|
||||
print $plain_text;
|
||||
}
|
||||
}
|
||||
elsif (/^--- / || /^\+\+\+ /) {
|
||||
print $diff_stuff;
|
||||
}
|
||||
else {
|
||||
print "$plain_text";
|
||||
}
|
||||
s/$/$colour{OFF}/;
|
||||
print "$_";
|
||||
}
|
||||
close INPUTSTREAM;
|
||||
|
||||
sub set_color {
|
||||
my ($type, $color) = @_;
|
||||
|
||||
$type =~ s/-/_/;
|
||||
eval "\$$type = \$colour{$color}";
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
# bash completion support for core Git.
|
||||
#
|
||||
# Copyright (C) 2006 Shawn Pearce
|
||||
# Copyright (C) 2006,2007 Shawn Pearce
|
||||
# Conceptually based on gitcompletion (http://gitweb.hawaga.org.uk/).
|
||||
#
|
||||
# The contained completion routines provide support for completing:
|
||||
@@ -61,6 +61,25 @@ __git_ps1 ()
|
||||
fi
|
||||
}
|
||||
|
||||
__gitcomp ()
|
||||
{
|
||||
local all c s=$'\n' IFS=' '$'\t'$'\n'
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
if [ $# -gt 2 ]; then
|
||||
cur="$3"
|
||||
fi
|
||||
for c in $1; do
|
||||
case "$c$4" in
|
||||
--*=*) all="$all$c$4$s" ;;
|
||||
*.) all="$all$c$4$s" ;;
|
||||
*) all="$all$c$4 $s" ;;
|
||||
esac
|
||||
done
|
||||
IFS=$s
|
||||
COMPREPLY=($(compgen -P "$2" -W "$all" -- "$cur"))
|
||||
return
|
||||
}
|
||||
|
||||
__git_heads ()
|
||||
{
|
||||
local cmd i is_hash=y dir="$(__gitdir "$1")"
|
||||
@@ -200,7 +219,7 @@ __git_complete_file ()
|
||||
-- "$cur"))
|
||||
;;
|
||||
*)
|
||||
COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
|
||||
__gitcomp "$(__git_refs)"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
@@ -212,15 +231,18 @@ __git_complete_revlist ()
|
||||
*...*)
|
||||
pfx="${cur%...*}..."
|
||||
cur="${cur#*...}"
|
||||
COMPREPLY=($(compgen -P "$pfx" -W "$(__git_refs)" -- "$cur"))
|
||||
__gitcomp "$(__git_refs)" "$pfx" "$cur"
|
||||
;;
|
||||
*..*)
|
||||
pfx="${cur%..*}.."
|
||||
cur="${cur#*..}"
|
||||
COMPREPLY=($(compgen -P "$pfx" -W "$(__git_refs)" -- "$cur"))
|
||||
__gitcomp "$(__git_refs)" "$pfx" "$cur"
|
||||
;;
|
||||
*.)
|
||||
__gitcomp "$cur."
|
||||
;;
|
||||
*)
|
||||
COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
|
||||
__gitcomp "$(__git_refs)"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
@@ -235,15 +257,27 @@ __git_commands ()
|
||||
for i in $(git help -a|egrep '^ ')
|
||||
do
|
||||
case $i in
|
||||
add--interactive) : plumbing;;
|
||||
applymbox) : ask gittus;;
|
||||
applypatch) : ask gittus;;
|
||||
archimport) : import;;
|
||||
cat-file) : plumbing;;
|
||||
check-ref-format) : plumbing;;
|
||||
commit-tree) : plumbing;;
|
||||
convert-objects) : plumbing;;
|
||||
cvsexportcommit) : export;;
|
||||
cvsimport) : import;;
|
||||
cvsserver) : daemon;;
|
||||
daemon) : daemon;;
|
||||
diff-stages) : nobody uses it;;
|
||||
fast-import) : import;;
|
||||
fsck-objects) : plumbing;;
|
||||
fetch-pack) : plumbing;;
|
||||
fmt-merge-msg) : plumbing;;
|
||||
hash-object) : plumbing;;
|
||||
http-*) : transport;;
|
||||
index-pack) : plumbing;;
|
||||
init-db) : deprecated;;
|
||||
local-fetch) : plumbing;;
|
||||
mailinfo) : plumbing;;
|
||||
mailsplit) : plumbing;;
|
||||
@@ -256,9 +290,15 @@ __git_commands ()
|
||||
parse-remote) : plumbing;;
|
||||
patch-id) : plumbing;;
|
||||
peek-remote) : plumbing;;
|
||||
prune) : plumbing;;
|
||||
prune-packed) : plumbing;;
|
||||
quiltimport) : import;;
|
||||
read-tree) : plumbing;;
|
||||
receive-pack) : plumbing;;
|
||||
reflog) : plumbing;;
|
||||
repo-config) : plumbing;;
|
||||
rerere) : plumbing;;
|
||||
resolve) : dead dont use;;
|
||||
rev-list) : plumbing;;
|
||||
rev-parse) : plumbing;;
|
||||
runstatus) : plumbing;;
|
||||
@@ -268,14 +308,19 @@ __git_commands ()
|
||||
show-index) : plumbing;;
|
||||
ssh-*) : transport;;
|
||||
stripspace) : plumbing;;
|
||||
svn) : import export;;
|
||||
svnimport) : import;;
|
||||
symbolic-ref) : plumbing;;
|
||||
tar-tree) : deprecated;;
|
||||
unpack-file) : plumbing;;
|
||||
unpack-objects) : plumbing;;
|
||||
update-index) : plumbing;;
|
||||
update-ref) : plumbing;;
|
||||
update-server-info) : daemon;;
|
||||
upload-archive) : plumbing;;
|
||||
upload-pack) : plumbing;;
|
||||
write-tree) : plumbing;;
|
||||
verify-tag) : plumbing;;
|
||||
*) echo $i;;
|
||||
esac
|
||||
done
|
||||
@@ -314,22 +359,19 @@ _git_am ()
|
||||
{
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
if [ -d .dotest ]; then
|
||||
COMPREPLY=($(compgen -W "
|
||||
--skip --resolved
|
||||
" -- "$cur"))
|
||||
__gitcomp "--skip --resolved"
|
||||
return
|
||||
fi
|
||||
case "$cur" in
|
||||
--whitespace=*)
|
||||
COMPREPLY=($(compgen -W "$__git_whitespacelist" \
|
||||
-- "${cur##--whitespace=}"))
|
||||
__gitcomp "$__git_whitespacelist" "" "${cur##--whitespace=}"
|
||||
return
|
||||
;;
|
||||
--*)
|
||||
COMPREPLY=($(compgen -W "
|
||||
__gitcomp "
|
||||
--signoff --utf8 --binary --3way --interactive
|
||||
--whitespace=
|
||||
" -- "$cur"))
|
||||
"
|
||||
return
|
||||
esac
|
||||
COMPREPLY=()
|
||||
@@ -340,48 +382,74 @@ _git_apply ()
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
case "$cur" in
|
||||
--whitespace=*)
|
||||
COMPREPLY=($(compgen -W "$__git_whitespacelist" \
|
||||
-- "${cur##--whitespace=}"))
|
||||
__gitcomp "$__git_whitespacelist" "" "${cur##--whitespace=}"
|
||||
return
|
||||
;;
|
||||
--*)
|
||||
COMPREPLY=($(compgen -W "
|
||||
__gitcomp "
|
||||
--stat --numstat --summary --check --index
|
||||
--cached --index-info --reverse --reject --unidiff-zero
|
||||
--apply --no-add --exclude=
|
||||
--whitespace= --inaccurate-eof --verbose
|
||||
" -- "$cur"))
|
||||
"
|
||||
return
|
||||
esac
|
||||
COMPREPLY=()
|
||||
}
|
||||
|
||||
_git_branch ()
|
||||
_git_add ()
|
||||
{
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
COMPREPLY=($(compgen -W "-l -f -d -D $(__git_refs)" -- "$cur"))
|
||||
case "$cur" in
|
||||
--*)
|
||||
__gitcomp "--interactive"
|
||||
return
|
||||
esac
|
||||
COMPREPLY=()
|
||||
}
|
||||
|
||||
_git_cat_file ()
|
||||
_git_bisect ()
|
||||
{
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
case "${COMP_WORDS[0]},$COMP_CWORD" in
|
||||
git-cat-file*,1)
|
||||
COMPREPLY=($(compgen -W "-p -t blob tree commit tag" -- "$cur"))
|
||||
;;
|
||||
git,2)
|
||||
COMPREPLY=($(compgen -W "-p -t blob tree commit tag" -- "$cur"))
|
||||
local i c=1 command
|
||||
while [ $c -lt $COMP_CWORD ]; do
|
||||
i="${COMP_WORDS[c]}"
|
||||
case "$i" in
|
||||
start|bad|good|reset|visualize|replay|log)
|
||||
command="$i"
|
||||
break
|
||||
;;
|
||||
esac
|
||||
c=$((++c))
|
||||
done
|
||||
|
||||
if [ $c -eq $COMP_CWORD -a -z "$command" ]; then
|
||||
__gitcomp "start bad good reset visualize replay log"
|
||||
return
|
||||
fi
|
||||
|
||||
case "$command" in
|
||||
bad|good|reset)
|
||||
__gitcomp "$(__git_refs)"
|
||||
;;
|
||||
*)
|
||||
__git_complete_file
|
||||
COMPREPLY=()
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
_git_branch ()
|
||||
{
|
||||
__gitcomp "$(__git_refs)"
|
||||
}
|
||||
|
||||
_git_checkout ()
|
||||
{
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
COMPREPLY=($(compgen -W "-l -b $(__git_refs)" -- "$cur"))
|
||||
__gitcomp "$(__git_refs)"
|
||||
}
|
||||
|
||||
_git_cherry ()
|
||||
{
|
||||
__gitcomp "$(__git_refs)"
|
||||
}
|
||||
|
||||
_git_cherry_pick ()
|
||||
@@ -389,12 +457,10 @@ _git_cherry_pick ()
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
case "$cur" in
|
||||
--*)
|
||||
COMPREPLY=($(compgen -W "
|
||||
--edit --no-commit
|
||||
" -- "$cur"))
|
||||
__gitcomp "--edit --no-commit"
|
||||
;;
|
||||
*)
|
||||
COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
|
||||
__gitcomp "$(__git_refs)"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
@@ -404,10 +470,10 @@ _git_commit ()
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
case "$cur" in
|
||||
--*)
|
||||
COMPREPLY=($(compgen -W "
|
||||
__gitcomp "
|
||||
--all --author= --signoff --verify --no-verify
|
||||
--edit --amend --include --only
|
||||
" -- "$cur"))
|
||||
"
|
||||
return
|
||||
esac
|
||||
COMPREPLY=()
|
||||
@@ -420,8 +486,7 @@ _git_diff ()
|
||||
|
||||
_git_diff_tree ()
|
||||
{
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
COMPREPLY=($(compgen -W "-r -p -M $(__git_refs)" -- "$cur"))
|
||||
__gitcomp "$(__git_refs)"
|
||||
}
|
||||
|
||||
_git_fetch ()
|
||||
@@ -430,16 +495,15 @@ _git_fetch ()
|
||||
|
||||
case "${COMP_WORDS[0]},$COMP_CWORD" in
|
||||
git-fetch*,1)
|
||||
COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
|
||||
__gitcomp "$(__git_remotes)"
|
||||
;;
|
||||
git,2)
|
||||
COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
|
||||
__gitcomp "$(__git_remotes)"
|
||||
;;
|
||||
*)
|
||||
case "$cur" in
|
||||
*:*)
|
||||
cur="${cur#*:}"
|
||||
COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
|
||||
__gitcomp "$(__git_refs)" "" "${cur#*:}"
|
||||
;;
|
||||
*)
|
||||
local remote
|
||||
@@ -447,7 +511,7 @@ _git_fetch ()
|
||||
git-fetch) remote="${COMP_WORDS[1]}" ;;
|
||||
git) remote="${COMP_WORDS[2]}" ;;
|
||||
esac
|
||||
COMPREPLY=($(compgen -W "$(__git_refs2 "$remote")" -- "$cur"))
|
||||
__gitcomp "$(__git_refs2 "$remote")"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
@@ -459,7 +523,7 @@ _git_format_patch ()
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
case "$cur" in
|
||||
--*)
|
||||
COMPREPLY=($(compgen -W "
|
||||
__gitcomp "
|
||||
--stdout --attach --thread
|
||||
--output-directory
|
||||
--numbered --start-number
|
||||
@@ -467,17 +531,29 @@ _git_format_patch ()
|
||||
--signoff
|
||||
--in-reply-to=
|
||||
--full-index --binary
|
||||
" -- "$cur"))
|
||||
--not --all
|
||||
"
|
||||
return
|
||||
;;
|
||||
esac
|
||||
__git_complete_revlist
|
||||
}
|
||||
|
||||
_git_ls_remote ()
|
||||
_git_gc ()
|
||||
{
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
|
||||
case "$cur" in
|
||||
--*)
|
||||
__gitcomp "--prune"
|
||||
return
|
||||
;;
|
||||
esac
|
||||
COMPREPLY=()
|
||||
}
|
||||
|
||||
_git_ls_remote ()
|
||||
{
|
||||
__gitcomp "$(__git_remotes)"
|
||||
}
|
||||
|
||||
_git_ls_tree ()
|
||||
@@ -490,13 +566,13 @@ _git_log ()
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
case "$cur" in
|
||||
--pretty=*)
|
||||
COMPREPLY=($(compgen -W "
|
||||
__gitcomp "
|
||||
oneline short medium full fuller email raw
|
||||
" -- "${cur##--pretty=}"))
|
||||
" "" "${cur##--pretty=}"
|
||||
return
|
||||
;;
|
||||
--*)
|
||||
COMPREPLY=($(compgen -W "
|
||||
__gitcomp "
|
||||
--max-count= --max-age= --since= --after=
|
||||
--min-age= --before= --until=
|
||||
--root --not --topo-order --date-order
|
||||
@@ -506,7 +582,8 @@ _git_log ()
|
||||
--author= --committer= --grep=
|
||||
--all-match
|
||||
--pretty= --name-status --name-only
|
||||
" -- "$cur"))
|
||||
--not --all
|
||||
"
|
||||
return
|
||||
;;
|
||||
esac
|
||||
@@ -518,34 +595,31 @@ _git_merge ()
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
case "${COMP_WORDS[COMP_CWORD-1]}" in
|
||||
-s|--strategy)
|
||||
COMPREPLY=($(compgen -W "$(__git_merge_strategies)" -- "$cur"))
|
||||
__gitcomp "$(__git_merge_strategies)"
|
||||
return
|
||||
esac
|
||||
case "$cur" in
|
||||
--strategy=*)
|
||||
COMPREPLY=($(compgen -W "$(__git_merge_strategies)" \
|
||||
-- "${cur##--strategy=}"))
|
||||
__gitcomp "$(__git_merge_strategies)" "" "${cur##--strategy=}"
|
||||
return
|
||||
;;
|
||||
--*)
|
||||
COMPREPLY=($(compgen -W "
|
||||
__gitcomp "
|
||||
--no-commit --no-summary --squash --strategy
|
||||
" -- "$cur"))
|
||||
"
|
||||
return
|
||||
esac
|
||||
COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
|
||||
__gitcomp "$(__git_refs)"
|
||||
}
|
||||
|
||||
_git_merge_base ()
|
||||
{
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
|
||||
__gitcomp "$(__git_refs)"
|
||||
}
|
||||
|
||||
_git_name_rev ()
|
||||
{
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
COMPREPLY=($(compgen -W "--tags --all --stdin" -- "$cur"))
|
||||
__gitcomp "--tags --all --stdin"
|
||||
}
|
||||
|
||||
_git_pull ()
|
||||
@@ -554,10 +628,10 @@ _git_pull ()
|
||||
|
||||
case "${COMP_WORDS[0]},$COMP_CWORD" in
|
||||
git-pull*,1)
|
||||
COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
|
||||
__gitcomp "$(__git_remotes)"
|
||||
;;
|
||||
git,2)
|
||||
COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
|
||||
__gitcomp "$(__git_remotes)"
|
||||
;;
|
||||
*)
|
||||
local remote
|
||||
@@ -565,7 +639,7 @@ _git_pull ()
|
||||
git-pull) remote="${COMP_WORDS[1]}" ;;
|
||||
git) remote="${COMP_WORDS[2]}" ;;
|
||||
esac
|
||||
COMPREPLY=($(compgen -W "$(__git_refs "$remote")" -- "$cur"))
|
||||
__gitcomp "$(__git_refs "$remote")"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
@@ -576,10 +650,10 @@ _git_push ()
|
||||
|
||||
case "${COMP_WORDS[0]},$COMP_CWORD" in
|
||||
git-push*,1)
|
||||
COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
|
||||
__gitcomp "$(__git_remotes)"
|
||||
;;
|
||||
git,2)
|
||||
COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
|
||||
__gitcomp "$(__git_remotes)"
|
||||
;;
|
||||
*)
|
||||
case "$cur" in
|
||||
@@ -589,11 +663,10 @@ _git_push ()
|
||||
git-push) remote="${COMP_WORDS[1]}" ;;
|
||||
git) remote="${COMP_WORDS[2]}" ;;
|
||||
esac
|
||||
cur="${cur#*:}"
|
||||
COMPREPLY=($(compgen -W "$(__git_refs "$remote")" -- "$cur"))
|
||||
__gitcomp "$(__git_refs "$remote")" "" "${cur#*:}"
|
||||
;;
|
||||
*)
|
||||
COMPREPLY=($(compgen -W "$(__git_refs2)" -- "$cur"))
|
||||
__gitcomp "$(__git_refs2)"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
@@ -603,30 +676,25 @@ _git_push ()
|
||||
_git_rebase ()
|
||||
{
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
if [ -d .dotest ]; then
|
||||
COMPREPLY=($(compgen -W "
|
||||
--continue --skip --abort
|
||||
" -- "$cur"))
|
||||
if [ -d .dotest ] || [ -d .git/.dotest-merge ]; then
|
||||
__gitcomp "--continue --skip --abort"
|
||||
return
|
||||
fi
|
||||
case "${COMP_WORDS[COMP_CWORD-1]}" in
|
||||
-s|--strategy)
|
||||
COMPREPLY=($(compgen -W "$(__git_merge_strategies)" -- "$cur"))
|
||||
__gitcomp "$(__git_merge_strategies)"
|
||||
return
|
||||
esac
|
||||
case "$cur" in
|
||||
--strategy=*)
|
||||
COMPREPLY=($(compgen -W "$(__git_merge_strategies)" \
|
||||
-- "${cur##--strategy=}"))
|
||||
__gitcomp "$(__git_merge_strategies)" "" "${cur##--strategy=}"
|
||||
return
|
||||
;;
|
||||
--*)
|
||||
COMPREPLY=($(compgen -W "
|
||||
--onto --merge --strategy
|
||||
" -- "$cur"))
|
||||
__gitcomp "--onto --merge --strategy"
|
||||
return
|
||||
esac
|
||||
COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
|
||||
__gitcomp "$(__git_refs)"
|
||||
}
|
||||
|
||||
_git_config ()
|
||||
@@ -635,26 +703,40 @@ _git_config ()
|
||||
local prv="${COMP_WORDS[COMP_CWORD-1]}"
|
||||
case "$prv" in
|
||||
branch.*.remote)
|
||||
COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
|
||||
__gitcomp "$(__git_remotes)"
|
||||
return
|
||||
;;
|
||||
branch.*.merge)
|
||||
COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
|
||||
__gitcomp "$(__git_refs)"
|
||||
return
|
||||
;;
|
||||
remote.*.fetch)
|
||||
local remote="${prv#remote.}"
|
||||
remote="${remote%.fetch}"
|
||||
COMPREPLY=($(compgen -W "$(__git_refs_remotes "$remote")" \
|
||||
-- "$cur"))
|
||||
__gitcomp "$(__git_refs_remotes "$remote")"
|
||||
return
|
||||
;;
|
||||
remote.*.push)
|
||||
local remote="${prv#remote.}"
|
||||
remote="${remote%.push}"
|
||||
COMPREPLY=($(compgen -W "$(git --git-dir="$(__gitdir)" \
|
||||
__gitcomp "$(git --git-dir="$(__gitdir)" \
|
||||
for-each-ref --format='%(refname):%(refname)' \
|
||||
refs/heads)" -- "$cur"))
|
||||
refs/heads)"
|
||||
return
|
||||
;;
|
||||
pull.twohead|pull.octopus)
|
||||
__gitcomp "$(__git_merge_strategies)"
|
||||
return
|
||||
;;
|
||||
color.branch|color.diff|color.status)
|
||||
__gitcomp "always never auto"
|
||||
return
|
||||
;;
|
||||
color.*.*)
|
||||
__gitcomp "
|
||||
black red green yellow blue magenta cyan white
|
||||
bold dim ul blink reverse
|
||||
"
|
||||
return
|
||||
;;
|
||||
*.*)
|
||||
@@ -664,41 +746,39 @@ _git_config ()
|
||||
esac
|
||||
case "$cur" in
|
||||
--*)
|
||||
COMPREPLY=($(compgen -W "
|
||||
__gitcomp "
|
||||
--global --list --replace-all
|
||||
--get --get-all --get-regexp
|
||||
--unset --unset-all
|
||||
" -- "$cur"))
|
||||
--add --unset --unset-all
|
||||
"
|
||||
return
|
||||
;;
|
||||
branch.*.*)
|
||||
local pfx="${cur%.*}."
|
||||
cur="${cur##*.}"
|
||||
COMPREPLY=($(compgen -P "$pfx" -W "remote merge" -- "$cur"))
|
||||
__gitcomp "remote merge" "$pfx" "$cur"
|
||||
return
|
||||
;;
|
||||
branch.*)
|
||||
local pfx="${cur%.*}."
|
||||
cur="${cur#*.}"
|
||||
COMPREPLY=($(compgen -P "$pfx" -S . \
|
||||
-W "$(__git_heads)" -- "$cur"))
|
||||
__gitcomp "$(__git_heads)" "$pfx" "$cur" "."
|
||||
return
|
||||
;;
|
||||
remote.*.*)
|
||||
local pfx="${cur%.*}."
|
||||
cur="${cur##*.}"
|
||||
COMPREPLY=($(compgen -P "$pfx" -W "url fetch push" -- "$cur"))
|
||||
__gitcomp "url fetch push" "$pfx" "$cur"
|
||||
return
|
||||
;;
|
||||
remote.*)
|
||||
local pfx="${cur%.*}."
|
||||
cur="${cur#*.}"
|
||||
COMPREPLY=($(compgen -P "$pfx" -S . \
|
||||
-W "$(__git_remotes)" -- "$cur"))
|
||||
__gitcomp "$(__git_remotes)" "$pfx" "$cur" "."
|
||||
return
|
||||
;;
|
||||
esac
|
||||
COMPREPLY=($(compgen -W "
|
||||
__gitcomp "
|
||||
apply.whitespace
|
||||
core.fileMode
|
||||
core.gitProxy
|
||||
@@ -710,47 +790,105 @@ _git_config ()
|
||||
core.warnAmbiguousRefs
|
||||
core.compression
|
||||
core.legacyHeaders
|
||||
i18n.commitEncoding
|
||||
i18n.logOutputEncoding
|
||||
diff.color
|
||||
core.packedGitWindowSize
|
||||
core.packedGitLimit
|
||||
color.branch
|
||||
color.branch.current
|
||||
color.branch.local
|
||||
color.branch.remote
|
||||
color.branch.plain
|
||||
color.diff
|
||||
color.diff.plain
|
||||
color.diff.meta
|
||||
color.diff.frag
|
||||
color.diff.old
|
||||
color.diff.new
|
||||
color.diff.commit
|
||||
color.diff.whitespace
|
||||
color.pager
|
||||
color.status
|
||||
color.status.header
|
||||
color.status.added
|
||||
color.status.changed
|
||||
color.status.untracked
|
||||
diff.renameLimit
|
||||
diff.renames
|
||||
pager.color
|
||||
color.pager
|
||||
status.color
|
||||
color.status
|
||||
log.showroot
|
||||
show.difftree
|
||||
showbranch.default
|
||||
whatchanged.difftree
|
||||
fetch.unpackLimit
|
||||
format.headers
|
||||
gitcvs.enabled
|
||||
gitcvs.logfile
|
||||
gc.reflogexpire
|
||||
gc.reflogexpireunreachable
|
||||
gc.rerereresolved
|
||||
gc.rerereunresolved
|
||||
http.sslVerify
|
||||
http.sslCert
|
||||
http.sslKey
|
||||
http.sslCAInfo
|
||||
http.sslCAPath
|
||||
http.maxRequests
|
||||
http.lowSpeedLimit http.lowSpeedTime
|
||||
http.lowSpeedLimit
|
||||
http.lowSpeedTime
|
||||
http.noEPSV
|
||||
pack.window
|
||||
repack.useDeltaBaseOffset
|
||||
pull.octopus pull.twohead
|
||||
i18n.commitEncoding
|
||||
i18n.logOutputEncoding
|
||||
log.showroot
|
||||
merge.summary
|
||||
merge.verbosity
|
||||
pack.window
|
||||
pull.octopus
|
||||
pull.twohead
|
||||
repack.useDeltaBaseOffset
|
||||
show.difftree
|
||||
showbranch.default
|
||||
tar.umask
|
||||
transfer.unpackLimit
|
||||
receive.unpackLimit
|
||||
receive.denyNonFastForwards
|
||||
user.name user.email
|
||||
tar.umask
|
||||
gitcvs.enabled
|
||||
gitcvs.logfile
|
||||
user.name
|
||||
user.email
|
||||
user.signingkey
|
||||
whatchanged.difftree
|
||||
branch. remote.
|
||||
" -- "$cur"))
|
||||
"
|
||||
}
|
||||
|
||||
_git_remote ()
|
||||
{
|
||||
local i c=1 command
|
||||
while [ $c -lt $COMP_CWORD ]; do
|
||||
i="${COMP_WORDS[c]}"
|
||||
case "$i" in
|
||||
add|show|prune) command="$i"; break ;;
|
||||
esac
|
||||
c=$((++c))
|
||||
done
|
||||
|
||||
if [ $c -eq $COMP_CWORD -a -z "$command" ]; then
|
||||
__gitcomp "add show prune"
|
||||
return
|
||||
fi
|
||||
|
||||
case "$command" in
|
||||
show|prune)
|
||||
__gitcomp "$(__git_remotes)"
|
||||
;;
|
||||
*)
|
||||
COMPREPLY=()
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
_git_reset ()
|
||||
{
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
local opt="--mixed --hard --soft"
|
||||
COMPREPLY=($(compgen -W "$opt $(__git_refs)" -- "$cur"))
|
||||
case "$cur" in
|
||||
--*)
|
||||
__gitcomp "--mixed --hard --soft"
|
||||
return
|
||||
;;
|
||||
esac
|
||||
__gitcomp "$(__git_refs)"
|
||||
}
|
||||
|
||||
_git_show ()
|
||||
@@ -758,13 +896,13 @@ _git_show ()
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
case "$cur" in
|
||||
--pretty=*)
|
||||
COMPREPLY=($(compgen -W "
|
||||
__gitcomp "
|
||||
oneline short medium full fuller email raw
|
||||
" -- "${cur##--pretty=}"))
|
||||
" "" "${cur##--pretty=}"
|
||||
return
|
||||
;;
|
||||
--*)
|
||||
COMPREPLY=($(compgen -W "--pretty=" -- "$cur"))
|
||||
__gitcomp "--pretty="
|
||||
return
|
||||
;;
|
||||
esac
|
||||
@@ -787,12 +925,12 @@ _git ()
|
||||
done
|
||||
|
||||
if [ $c -eq $COMP_CWORD -a -z "$command" ]; then
|
||||
COMPREPLY=($(compgen -W "
|
||||
--git-dir= --version --exec-path
|
||||
$(__git_commands)
|
||||
$(__git_aliases)
|
||||
" -- "${COMP_WORDS[COMP_CWORD]}"))
|
||||
return;
|
||||
case "${COMP_WORDS[COMP_CWORD]}" in
|
||||
--*=*) COMPREPLY=() ;;
|
||||
--*) __gitcomp "--git-dir= --bare --version --exec-path" ;;
|
||||
*) __gitcomp "$(__git_commands) $(__git_aliases)" ;;
|
||||
esac
|
||||
return
|
||||
fi
|
||||
|
||||
local expansion=$(__git_aliased_command "$command")
|
||||
@@ -800,10 +938,12 @@ _git ()
|
||||
|
||||
case "$command" in
|
||||
am) _git_am ;;
|
||||
add) _git_add ;;
|
||||
apply) _git_apply ;;
|
||||
bisect) _git_bisect ;;
|
||||
branch) _git_branch ;;
|
||||
cat-file) _git_cat_file ;;
|
||||
checkout) _git_checkout ;;
|
||||
cherry) _git_cherry ;;
|
||||
cherry-pick) _git_cherry_pick ;;
|
||||
commit) _git_commit ;;
|
||||
config) _git_config ;;
|
||||
@@ -811,6 +951,7 @@ _git ()
|
||||
diff-tree) _git_diff_tree ;;
|
||||
fetch) _git_fetch ;;
|
||||
format-patch) _git_format_patch ;;
|
||||
gc) _git_gc ;;
|
||||
log) _git_log ;;
|
||||
ls-remote) _git_ls_remote ;;
|
||||
ls-tree) _git_ls_tree ;;
|
||||
@@ -820,7 +961,7 @@ _git ()
|
||||
pull) _git_pull ;;
|
||||
push) _git_push ;;
|
||||
rebase) _git_rebase ;;
|
||||
repo-config) _git_config ;;
|
||||
remote) _git_remote ;;
|
||||
reset) _git_reset ;;
|
||||
show) _git_show ;;
|
||||
show-branch) _git_log ;;
|
||||
@@ -832,33 +973,42 @@ _git ()
|
||||
_gitk ()
|
||||
{
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
COMPREPLY=($(compgen -W "--all $(__git_refs)" -- "$cur"))
|
||||
case "$cur" in
|
||||
--*)
|
||||
__gitcomp "--not --all"
|
||||
return
|
||||
;;
|
||||
esac
|
||||
__git_complete_revlist
|
||||
}
|
||||
|
||||
complete -o default -o nospace -F _git git
|
||||
complete -o default -F _gitk gitk
|
||||
complete -o default -F _git_am git-am
|
||||
complete -o default -F _git_apply git-apply
|
||||
complete -o default -F _git_branch git-branch
|
||||
complete -o default -o nospace -F _git_cat_file git-cat-file
|
||||
complete -o default -F _git_checkout git-checkout
|
||||
complete -o default -F _git_cherry_pick git-cherry-pick
|
||||
complete -o default -F _git_commit git-commit
|
||||
complete -o default -o nospace -F _gitk gitk
|
||||
complete -o default -o nospace -F _git_am git-am
|
||||
complete -o default -o nospace -F _git_apply git-apply
|
||||
complete -o default -o nospace -F _git_bisect git-bisect
|
||||
complete -o default -o nospace -F _git_branch git-branch
|
||||
complete -o default -o nospace -F _git_checkout git-checkout
|
||||
complete -o default -o nospace -F _git_cherry git-cherry
|
||||
complete -o default -o nospace -F _git_cherry_pick git-cherry-pick
|
||||
complete -o default -o nospace -F _git_commit git-commit
|
||||
complete -o default -o nospace -F _git_diff git-diff
|
||||
complete -o default -F _git_diff_tree git-diff-tree
|
||||
complete -o default -o nospace -F _git_diff_tree git-diff-tree
|
||||
complete -o default -o nospace -F _git_fetch git-fetch
|
||||
complete -o default -o nospace -F _git_format_patch git-format-patch
|
||||
complete -o default -o nospace -F _git_gc git-gc
|
||||
complete -o default -o nospace -F _git_log git-log
|
||||
complete -o default -F _git_ls_remote git-ls-remote
|
||||
complete -o default -o nospace -F _git_ls_remote git-ls-remote
|
||||
complete -o default -o nospace -F _git_ls_tree git-ls-tree
|
||||
complete -o default -F _git_merge git-merge
|
||||
complete -o default -F _git_merge_base git-merge-base
|
||||
complete -o default -F _git_name_rev git-name-rev
|
||||
complete -o default -o nospace -F _git_merge git-merge
|
||||
complete -o default -o nospace -F _git_merge_base git-merge-base
|
||||
complete -o default -o nospace -F _git_name_rev git-name-rev
|
||||
complete -o default -o nospace -F _git_pull git-pull
|
||||
complete -o default -o nospace -F _git_push git-push
|
||||
complete -o default -F _git_rebase git-rebase
|
||||
complete -o default -F _git_config git-config
|
||||
complete -o default -F _git_reset git-reset
|
||||
complete -o default -o nospace -F _git_rebase git-rebase
|
||||
complete -o default -o nospace -F _git_config git-config
|
||||
complete -o default -o nospace -F _git_remote git-remote
|
||||
complete -o default -o nospace -F _git_reset git-reset
|
||||
complete -o default -o nospace -F _git_show git-show
|
||||
complete -o default -o nospace -F _git_log git-show-branch
|
||||
complete -o default -o nospace -F _git_log git-whatchanged
|
||||
@@ -868,19 +1018,20 @@ complete -o default -o nospace -F _git_log git-whatchanged
|
||||
# included the '.exe' suffix.
|
||||
#
|
||||
if [ Cygwin = "$(uname -o 2>/dev/null)" ]; then
|
||||
complete -o default -F _git_apply git-apply.exe
|
||||
complete -o default -o nospace -F _git_add git-add.exe
|
||||
complete -o default -o nospace -F _git_apply git-apply.exe
|
||||
complete -o default -o nospace -F _git git.exe
|
||||
complete -o default -F _git_branch git-branch.exe
|
||||
complete -o default -o nospace -F _git_cat_file git-cat-file.exe
|
||||
complete -o default -o nospace -F _git_branch git-branch.exe
|
||||
complete -o default -o nospace -F _git_cherry git-cherry.exe
|
||||
complete -o default -o nospace -F _git_diff git-diff.exe
|
||||
complete -o default -o nospace -F _git_diff_tree git-diff-tree.exe
|
||||
complete -o default -o nospace -F _git_format_patch git-format-patch.exe
|
||||
complete -o default -o nospace -F _git_log git-log.exe
|
||||
complete -o default -o nospace -F _git_ls_tree git-ls-tree.exe
|
||||
complete -o default -F _git_merge_base git-merge-base.exe
|
||||
complete -o default -F _git_name_rev git-name-rev.exe
|
||||
complete -o default -o nospace -F _git_merge_base git-merge-base.exe
|
||||
complete -o default -o nospace -F _git_name_rev git-name-rev.exe
|
||||
complete -o default -o nospace -F _git_push git-push.exe
|
||||
complete -o default -F _git_config git-config
|
||||
complete -o default -o nospace -F _git_config git-config
|
||||
complete -o default -o nospace -F _git_show git-show.exe
|
||||
complete -o default -o nospace -F _git_log git-show-branch.exe
|
||||
complete -o default -o nospace -F _git_log git-whatchanged.exe
|
||||
|
||||
380
contrib/emacs/git-blame.el
Normal file
380
contrib/emacs/git-blame.el
Normal file
@@ -0,0 +1,380 @@
|
||||
;;; git-blame.el --- Minor mode for incremental blame for Git -*- coding: utf-8 -*-
|
||||
;;
|
||||
;; Copyright (C) 2007 David Kågedal
|
||||
;;
|
||||
;; Authors: David Kågedal <davidk@lysator.liu.se>
|
||||
;; Created: 31 Jan 2007
|
||||
;; Message-ID: <87iren2vqx.fsf@morpheus.local>
|
||||
;; License: GPL
|
||||
;; Keywords: git, version control, release management
|
||||
;;
|
||||
;; Compatibility: Emacs21
|
||||
|
||||
|
||||
;; This file is *NOT* part of GNU Emacs.
|
||||
;; This file is distributed under the same terms as GNU Emacs.
|
||||
|
||||
;; This program is free software; you can redistribute it and/or
|
||||
;; modify it under the terms of the GNU General Public License as
|
||||
;; published by the Free Software Foundation; either version 2 of
|
||||
;; the License, or (at your option) any later version.
|
||||
|
||||
;; This program is distributed in the hope that it will be
|
||||
;; useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
;; warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
;; PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public
|
||||
;; License along with this program; if not, write to the Free
|
||||
;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
;; MA 02111-1307 USA
|
||||
|
||||
;; http://www.fsf.org/copyleft/gpl.html
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; Here is an Emacs implementation of incremental git-blame. When you
|
||||
;; turn it on while viewing a file, the editor buffer will be updated by
|
||||
;; setting the background of individual lines to a color that reflects
|
||||
;; which commit it comes from. And when you move around the buffer, a
|
||||
;; one-line summary will be shown in the echo area.
|
||||
|
||||
;;; Installation:
|
||||
;;
|
||||
;; To use this package, put it somewhere in `load-path' (or add
|
||||
;; directory with git-blame.el to `load-path'), and add the following
|
||||
;; line to your .emacs:
|
||||
;;
|
||||
;; (require 'git-blame)
|
||||
;;
|
||||
;; If you do not want to load this package before it is necessary, you
|
||||
;; can make use of the `autoload' feature, e.g. by adding to your .emacs
|
||||
;; the following lines
|
||||
;;
|
||||
;; (autoload 'git-blame-mode "git-blame"
|
||||
;; "Minor mode for incremental blame for Git." t)
|
||||
;;
|
||||
;; Then first use of `M-x git-blame-mode' would load the package.
|
||||
|
||||
;;; Compatibility:
|
||||
;;
|
||||
;; It requires GNU Emacs 21. If you'are using Emacs 20, try
|
||||
;; changing this:
|
||||
;;
|
||||
;; (overlay-put ovl 'face (list :background
|
||||
;; (cdr (assq 'color (cddddr info)))))
|
||||
;;
|
||||
;; to
|
||||
;;
|
||||
;; (overlay-put ovl 'face (cons 'background-color
|
||||
;; (cdr (assq 'color (cddddr info)))))
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;
|
||||
;;; Code:
|
||||
|
||||
(require 'cl) ; to use `push', `pop'
|
||||
|
||||
(defun color-scale (l)
|
||||
(let* ((colors ())
|
||||
r g b)
|
||||
(setq r l)
|
||||
(while r
|
||||
(setq g l)
|
||||
(while g
|
||||
(setq b l)
|
||||
(while b
|
||||
(push (concat "#" (car r) (car g) (car b)) colors)
|
||||
(pop b))
|
||||
(pop g))
|
||||
(pop r))
|
||||
colors))
|
||||
|
||||
(defvar git-blame-dark-colors
|
||||
(color-scale '("0c" "04" "24" "1c" "2c" "34" "14" "3c")))
|
||||
|
||||
(defvar git-blame-light-colors
|
||||
(color-scale '("c4" "d4" "cc" "dc" "f4" "e4" "fc" "ec")))
|
||||
|
||||
(defvar git-blame-ancient-color "dark green")
|
||||
|
||||
(defvar git-blame-autoupdate t
|
||||
"*Automatically update the blame display while editing")
|
||||
|
||||
(defvar git-blame-proc nil
|
||||
"The running git-blame process")
|
||||
(make-variable-buffer-local 'git-blame-proc)
|
||||
|
||||
(defvar git-blame-overlays nil
|
||||
"The git-blame overlays used in the current buffer.")
|
||||
(make-variable-buffer-local 'git-blame-overlays)
|
||||
|
||||
(defvar git-blame-cache nil
|
||||
"A cache of git-blame information for the current buffer")
|
||||
(make-variable-buffer-local 'git-blame-cache)
|
||||
|
||||
(defvar git-blame-idle-timer nil
|
||||
"An idle timer that updates the blame")
|
||||
(make-variable-buffer-local 'git-blame-cache)
|
||||
|
||||
(defvar git-blame-update-queue nil
|
||||
"A queue of update requests")
|
||||
(make-variable-buffer-local 'git-blame-update-queue)
|
||||
|
||||
(defvar git-blame-mode nil)
|
||||
(make-variable-buffer-local 'git-blame-mode)
|
||||
(unless (assq 'git-blame-mode minor-mode-alist)
|
||||
(setq minor-mode-alist
|
||||
(cons (list 'git-blame-mode " blame")
|
||||
minor-mode-alist)))
|
||||
|
||||
;;;###autoload
|
||||
(defun git-blame-mode (&optional arg)
|
||||
"Minor mode for displaying Git blame"
|
||||
(interactive "P")
|
||||
(if arg
|
||||
(setq git-blame-mode (eq arg 1))
|
||||
(setq git-blame-mode (not git-blame-mode)))
|
||||
(make-local-variable 'git-blame-colors)
|
||||
(if git-blame-autoupdate
|
||||
(add-hook 'after-change-functions 'git-blame-after-change nil t)
|
||||
(remove-hook 'after-change-functions 'git-blame-after-change t))
|
||||
(git-blame-cleanup)
|
||||
(if git-blame-mode
|
||||
(progn
|
||||
(let ((bgmode (cdr (assoc 'background-mode (frame-parameters)))))
|
||||
(if (eq bgmode 'dark)
|
||||
(setq git-blame-colors git-blame-dark-colors)
|
||||
(setq git-blame-colors git-blame-light-colors)))
|
||||
(setq git-blame-cache (make-hash-table :test 'equal))
|
||||
(git-blame-run))
|
||||
(cancel-timer git-blame-idle-timer)))
|
||||
|
||||
;;;###autoload
|
||||
(defun git-reblame ()
|
||||
"Recalculate all blame information in the current buffer"
|
||||
(unless git-blame-mode
|
||||
(error "git-blame is not active"))
|
||||
(interactive)
|
||||
(git-blame-cleanup)
|
||||
(git-blame-run))
|
||||
|
||||
(defun git-blame-run (&optional startline endline)
|
||||
(if git-blame-proc
|
||||
;; Should maybe queue up a new run here
|
||||
(message "Already running git blame")
|
||||
(let ((display-buf (current-buffer))
|
||||
(blame-buf (get-buffer-create
|
||||
(concat " git blame for " (buffer-name))))
|
||||
(args '("--incremental" "--contents" "-")))
|
||||
(if startline
|
||||
(setq args (append args
|
||||
(list "-L" (format "%d,%d" startline endline)))))
|
||||
(setq args (append args
|
||||
(list (file-name-nondirectory buffer-file-name))))
|
||||
(setq git-blame-proc
|
||||
(apply 'start-process
|
||||
"git-blame" blame-buf
|
||||
"git" "blame"
|
||||
args))
|
||||
(with-current-buffer blame-buf
|
||||
(erase-buffer)
|
||||
(make-local-variable 'git-blame-file)
|
||||
(make-local-variable 'git-blame-current)
|
||||
(setq git-blame-file display-buf)
|
||||
(setq git-blame-current nil))
|
||||
(set-process-filter git-blame-proc 'git-blame-filter)
|
||||
(set-process-sentinel git-blame-proc 'git-blame-sentinel)
|
||||
(process-send-region git-blame-proc (point-min) (point-max))
|
||||
(process-send-eof git-blame-proc))))
|
||||
|
||||
(defun remove-git-blame-text-properties (start end)
|
||||
(let ((modified (buffer-modified-p))
|
||||
(inhibit-read-only t))
|
||||
(remove-text-properties start end '(point-entered nil))
|
||||
(set-buffer-modified-p modified)))
|
||||
|
||||
(defun git-blame-cleanup ()
|
||||
"Remove all blame properties"
|
||||
(mapcar 'delete-overlay git-blame-overlays)
|
||||
(setq git-blame-overlays nil)
|
||||
(remove-git-blame-text-properties (point-min) (point-max)))
|
||||
|
||||
(defun git-blame-update-region (start end)
|
||||
"Rerun blame to get updates between START and END"
|
||||
(let ((overlays (overlays-in start end)))
|
||||
(while overlays
|
||||
(let ((overlay (pop overlays)))
|
||||
(if (< (overlay-start overlay) start)
|
||||
(setq start (overlay-start overlay)))
|
||||
(if (> (overlay-end overlay) end)
|
||||
(setq end (overlay-end overlay)))
|
||||
(setq git-blame-overlays (delete overlay git-blame-overlays))
|
||||
(delete-overlay overlay))))
|
||||
(remove-git-blame-text-properties start end)
|
||||
;; We can be sure that start and end are at line breaks
|
||||
(git-blame-run (1+ (count-lines (point-min) start))
|
||||
(count-lines (point-min) end)))
|
||||
|
||||
(defun git-blame-sentinel (proc status)
|
||||
(with-current-buffer (process-buffer proc)
|
||||
(with-current-buffer git-blame-file
|
||||
(setq git-blame-proc nil)
|
||||
(if git-blame-update-queue
|
||||
(git-blame-delayed-update))))
|
||||
;;(kill-buffer (process-buffer proc))
|
||||
;;(message "git blame finished")
|
||||
)
|
||||
|
||||
(defvar in-blame-filter nil)
|
||||
|
||||
(defun git-blame-filter (proc str)
|
||||
(save-excursion
|
||||
(set-buffer (process-buffer proc))
|
||||
(goto-char (process-mark proc))
|
||||
(insert-before-markers str)
|
||||
(goto-char 0)
|
||||
(unless in-blame-filter
|
||||
(let ((more t)
|
||||
(in-blame-filter t))
|
||||
(while more
|
||||
(setq more (git-blame-parse)))))))
|
||||
|
||||
(defun git-blame-parse ()
|
||||
(cond ((looking-at "\\([0-9a-f]\\{40\\}\\) \\([0-9]+\\) \\([0-9]+\\) \\([0-9]+\\)\n")
|
||||
(let ((hash (match-string 1))
|
||||
(src-line (string-to-number (match-string 2)))
|
||||
(res-line (string-to-number (match-string 3)))
|
||||
(num-lines (string-to-number (match-string 4))))
|
||||
(setq git-blame-current
|
||||
(if (string= hash "0000000000000000000000000000000000000000")
|
||||
nil
|
||||
(git-blame-new-commit
|
||||
hash src-line res-line num-lines))))
|
||||
(delete-region (point) (match-end 0))
|
||||
t)
|
||||
((looking-at "filename \\(.+\\)\n")
|
||||
(let ((filename (match-string 1)))
|
||||
(git-blame-add-info "filename" filename))
|
||||
(delete-region (point) (match-end 0))
|
||||
t)
|
||||
((looking-at "\\([a-z-]+\\) \\(.+\\)\n")
|
||||
(let ((key (match-string 1))
|
||||
(value (match-string 2)))
|
||||
(git-blame-add-info key value))
|
||||
(delete-region (point) (match-end 0))
|
||||
t)
|
||||
((looking-at "boundary\n")
|
||||
(setq git-blame-current nil)
|
||||
(delete-region (point) (match-end 0))
|
||||
t)
|
||||
(t
|
||||
nil)))
|
||||
|
||||
|
||||
(defun git-blame-new-commit (hash src-line res-line num-lines)
|
||||
(save-excursion
|
||||
(set-buffer git-blame-file)
|
||||
(let ((info (gethash hash git-blame-cache))
|
||||
(inhibit-point-motion-hooks t)
|
||||
(inhibit-modification-hooks t))
|
||||
(when (not info)
|
||||
(let ((color (pop git-blame-colors)))
|
||||
(unless color
|
||||
(setq color git-blame-ancient-color))
|
||||
(setq info (list hash src-line res-line num-lines
|
||||
(git-describe-commit hash)
|
||||
(cons 'color color))))
|
||||
(puthash hash info git-blame-cache))
|
||||
(goto-line res-line)
|
||||
(while (> num-lines 0)
|
||||
(if (get-text-property (point) 'git-blame)
|
||||
(forward-line)
|
||||
(let* ((start (point))
|
||||
(end (progn (forward-line 1) (point)))
|
||||
(ovl (make-overlay start end)))
|
||||
(push ovl git-blame-overlays)
|
||||
(overlay-put ovl 'git-blame info)
|
||||
(overlay-put ovl 'help-echo hash)
|
||||
(overlay-put ovl 'face (list :background
|
||||
(cdr (assq 'color (nthcdr 5 info)))))
|
||||
;; the point-entered property doesn't seem to work in overlays
|
||||
;;(overlay-put ovl 'point-entered
|
||||
;; `(lambda (x y) (git-blame-identify ,hash)))
|
||||
(let ((modified (buffer-modified-p)))
|
||||
(put-text-property (if (= start 1) start (1- start)) (1- end)
|
||||
'point-entered
|
||||
`(lambda (x y) (git-blame-identify ,hash)))
|
||||
(set-buffer-modified-p modified))))
|
||||
(setq num-lines (1- num-lines))))))
|
||||
|
||||
(defun git-blame-add-info (key value)
|
||||
(if git-blame-current
|
||||
(nconc git-blame-current (list (cons (intern key) value)))))
|
||||
|
||||
(defun git-blame-current-commit ()
|
||||
(let ((info (get-char-property (point) 'git-blame)))
|
||||
(if info
|
||||
(car info)
|
||||
(error "No commit info"))))
|
||||
|
||||
(defun git-describe-commit (hash)
|
||||
(with-temp-buffer
|
||||
(call-process "git" nil t nil
|
||||
"log" "-1" "--pretty=oneline"
|
||||
hash)
|
||||
(buffer-substring (point-min) (1- (point-max)))))
|
||||
|
||||
(defvar git-blame-last-identification nil)
|
||||
(make-variable-buffer-local 'git-blame-last-identification)
|
||||
(defun git-blame-identify (&optional hash)
|
||||
(interactive)
|
||||
(let ((info (gethash (or hash (git-blame-current-commit)) git-blame-cache)))
|
||||
(when (and info (not (eq info git-blame-last-identification)))
|
||||
(message "%s" (nth 4 info))
|
||||
(setq git-blame-last-identification info))))
|
||||
|
||||
;; (defun git-blame-after-save ()
|
||||
;; (when git-blame-mode
|
||||
;; (git-blame-cleanup)
|
||||
;; (git-blame-run)))
|
||||
;; (add-hook 'after-save-hook 'git-blame-after-save)
|
||||
|
||||
(defun git-blame-after-change (start end length)
|
||||
(when git-blame-mode
|
||||
(git-blame-enq-update start end)))
|
||||
|
||||
(defvar git-blame-last-update nil)
|
||||
(make-variable-buffer-local 'git-blame-last-update)
|
||||
(defun git-blame-enq-update (start end)
|
||||
"Mark the region between START and END as needing blame update"
|
||||
;; Try to be smart and avoid multiple callouts for sequential
|
||||
;; editing
|
||||
(cond ((and git-blame-last-update
|
||||
(= start (cdr git-blame-last-update)))
|
||||
(setcdr git-blame-last-update end))
|
||||
((and git-blame-last-update
|
||||
(= end (car git-blame-last-update)))
|
||||
(setcar git-blame-last-update start))
|
||||
(t
|
||||
(setq git-blame-last-update (cons start end))
|
||||
(setq git-blame-update-queue (nconc git-blame-update-queue
|
||||
(list git-blame-last-update)))))
|
||||
(unless (or git-blame-proc git-blame-idle-timer)
|
||||
(setq git-blame-idle-timer
|
||||
(run-with-idle-timer 0.5 nil 'git-blame-delayed-update))))
|
||||
|
||||
(defun git-blame-delayed-update ()
|
||||
(setq git-blame-idle-timer nil)
|
||||
(if git-blame-update-queue
|
||||
(let ((first (pop git-blame-update-queue))
|
||||
(inhibit-point-motion-hooks t))
|
||||
(git-blame-update-region (car first) (cdr first)))))
|
||||
|
||||
(provide 'git-blame)
|
||||
|
||||
;;; git-blame.el ends here
|
||||
103
contrib/fast-import/import-tars.perl
Executable file
103
contrib/fast-import/import-tars.perl
Executable file
@@ -0,0 +1,103 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
## tar archive frontend for git-fast-import
|
||||
##
|
||||
## For example:
|
||||
##
|
||||
## mkdir project; cd project; git init
|
||||
## perl import-tars.perl *.tar.bz2
|
||||
## git whatchanged import-tars
|
||||
##
|
||||
|
||||
use strict;
|
||||
die "usage: import-tars *.tar.{gz,bz2,Z}\n" unless @ARGV;
|
||||
|
||||
my $branch_name = 'import-tars';
|
||||
my $branch_ref = "refs/heads/$branch_name";
|
||||
my $committer_name = 'T Ar Creator';
|
||||
my $committer_email = 'tar@example.com';
|
||||
|
||||
open(FI, '|-', 'git', 'fast-import', '--quiet')
|
||||
or die "Unable to start git fast-import: $!\n";
|
||||
foreach my $tar_file (@ARGV)
|
||||
{
|
||||
$tar_file =~ m,([^/]+)$,;
|
||||
my $tar_name = $1;
|
||||
|
||||
if ($tar_name =~ s/\.(tar\.gz|tgz)$//) {
|
||||
open(I, '-|', 'gzcat', $tar_file) or die "Unable to gzcat $tar_file: $!\n";
|
||||
} elsif ($tar_name =~ s/\.(tar\.bz2|tbz2)$//) {
|
||||
open(I, '-|', 'bzcat', $tar_file) or die "Unable to bzcat $tar_file: $!\n";
|
||||
} elsif ($tar_name =~ s/\.tar\.Z$//) {
|
||||
open(I, '-|', 'zcat', $tar_file) or die "Unable to zcat $tar_file: $!\n";
|
||||
} elsif ($tar_name =~ s/\.tar$//) {
|
||||
open(I, $tar_file) or die "Unable to open $tar_file: $!\n";
|
||||
} else {
|
||||
die "Unrecognized compression format: $tar_file\n";
|
||||
}
|
||||
|
||||
my $commit_time = 0;
|
||||
my $next_mark = 1;
|
||||
my $have_top_dir = 1;
|
||||
my ($top_dir, %files);
|
||||
|
||||
while (read(I, $_, 512) == 512) {
|
||||
my ($name, $mode, $uid, $gid, $size, $mtime,
|
||||
$chksum, $typeflag, $linkname, $magic,
|
||||
$version, $uname, $gname, $devmajor, $devminor,
|
||||
$prefix) = unpack 'Z100 Z8 Z8 Z8 Z12 Z12
|
||||
Z8 Z1 Z100 Z6
|
||||
Z2 Z32 Z32 Z8 Z8 Z*', $_;
|
||||
last unless $name;
|
||||
$mode = oct $mode;
|
||||
$size = oct $size;
|
||||
$mtime = oct $mtime;
|
||||
next if $mode & 0040000;
|
||||
|
||||
print FI "blob\n", "mark :$next_mark\n", "data $size\n";
|
||||
while ($size > 0 && read(I, $_, 512) == 512) {
|
||||
print FI substr($_, 0, $size);
|
||||
$size -= 512;
|
||||
}
|
||||
print FI "\n";
|
||||
|
||||
my $path = "$prefix$name";
|
||||
$files{$path} = [$next_mark++, $mode];
|
||||
|
||||
$commit_time = $mtime if $mtime > $commit_time;
|
||||
$path =~ m,^([^/]+)/,;
|
||||
$top_dir = $1 unless $top_dir;
|
||||
$have_top_dir = 0 if $top_dir ne $1;
|
||||
}
|
||||
|
||||
print FI <<EOF;
|
||||
commit $branch_ref
|
||||
committer $committer_name <$committer_email> $commit_time +0000
|
||||
data <<END_OF_COMMIT_MESSAGE
|
||||
Imported from $tar_file.
|
||||
END_OF_COMMIT_MESSAGE
|
||||
|
||||
deleteall
|
||||
EOF
|
||||
|
||||
foreach my $path (keys %files)
|
||||
{
|
||||
my ($mark, $mode) = @{$files{$path}};
|
||||
$path =~ s,^([^/]+)/,, if $have_top_dir;
|
||||
printf FI "M %o :%i %s\n", $mode & 0111 ? 0755 : 0644, $mark, $path;
|
||||
}
|
||||
print FI "\n";
|
||||
|
||||
print FI <<EOF;
|
||||
tag $tar_name
|
||||
from $branch_ref
|
||||
tagger $committer_name <$committer_email> $commit_time +0000
|
||||
data <<END_OF_TAG_MESSAGE
|
||||
Package $tar_name
|
||||
END_OF_TAG_MESSAGE
|
||||
|
||||
EOF
|
||||
|
||||
close I;
|
||||
}
|
||||
close FI;
|
||||
233
contrib/hg-to-git/hg-to-git.py
Executable file
233
contrib/hg-to-git/hg-to-git.py
Executable file
@@ -0,0 +1,233 @@
|
||||
#! /usr/bin/python
|
||||
|
||||
""" hg-to-svn.py - A Mercurial to GIT converter
|
||||
|
||||
Copyright (C)2007 Stelian Pop <stelian@popies.net>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
"""
|
||||
|
||||
import os, os.path, sys
|
||||
import tempfile, popen2, pickle, getopt
|
||||
import re
|
||||
|
||||
# Maps hg version -> git version
|
||||
hgvers = {}
|
||||
# List of children for each hg revision
|
||||
hgchildren = {}
|
||||
# Current branch for each hg revision
|
||||
hgbranch = {}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
def usage():
|
||||
|
||||
print """\
|
||||
%s: [OPTIONS] <hgprj>
|
||||
|
||||
options:
|
||||
-s, --gitstate=FILE: name of the state to be saved/read
|
||||
for incrementals
|
||||
|
||||
required:
|
||||
hgprj: name of the HG project to import (directory)
|
||||
""" % sys.argv[0]
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
def getgitenv(user, date):
|
||||
env = ''
|
||||
elems = re.compile('(.*?)\s+<(.*)>').match(user)
|
||||
if elems:
|
||||
env += 'export GIT_AUTHOR_NAME="%s" ;' % elems.group(1)
|
||||
env += 'export GIT_COMMITER_NAME="%s" ;' % elems.group(1)
|
||||
env += 'export GIT_AUTHOR_EMAIL="%s" ;' % elems.group(2)
|
||||
env += 'export GIT_COMMITER_EMAIL="%s" ;' % elems.group(2)
|
||||
else:
|
||||
env += 'export GIT_AUTHOR_NAME="%s" ;' % user
|
||||
env += 'export GIT_COMMITER_NAME="%s" ;' % user
|
||||
env += 'export GIT_AUTHOR_EMAIL= ;'
|
||||
env += 'export GIT_COMMITER_EMAIL= ;'
|
||||
|
||||
env += 'export GIT_AUTHOR_DATE="%s" ;' % date
|
||||
env += 'export GIT_COMMITTER_DATE="%s" ;' % date
|
||||
return env
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
state = ''
|
||||
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], 's:t:', ['gitstate=', 'tempdir='])
|
||||
for o, a in opts:
|
||||
if o in ('-s', '--gitstate'):
|
||||
state = a
|
||||
state = os.path.abspath(state)
|
||||
|
||||
if len(args) != 1:
|
||||
raise('params')
|
||||
except:
|
||||
usage()
|
||||
sys.exit(1)
|
||||
|
||||
hgprj = args[0]
|
||||
os.chdir(hgprj)
|
||||
|
||||
if state:
|
||||
if os.path.exists(state):
|
||||
print 'State does exist, reading'
|
||||
f = open(state, 'r')
|
||||
hgvers = pickle.load(f)
|
||||
else:
|
||||
print 'State does not exist, first run'
|
||||
|
||||
tip = os.popen('hg tip | head -1 | cut -f 2 -d :').read().strip()
|
||||
print 'tip is', tip
|
||||
|
||||
# Calculate the branches
|
||||
print 'analysing the branches...'
|
||||
hgchildren["0"] = ()
|
||||
hgbranch["0"] = "master"
|
||||
for cset in range(1, int(tip) + 1):
|
||||
hgchildren[str(cset)] = ()
|
||||
prnts = os.popen('hg log -r %d | grep ^parent: | cut -f 2 -d :' % cset).readlines()
|
||||
if len(prnts) > 0:
|
||||
parent = prnts[0].strip()
|
||||
else:
|
||||
parent = str(cset - 1)
|
||||
hgchildren[parent] += ( str(cset), )
|
||||
if len(prnts) > 1:
|
||||
mparent = prnts[1].strip()
|
||||
hgchildren[mparent] += ( str(cset), )
|
||||
else:
|
||||
mparent = None
|
||||
|
||||
if mparent:
|
||||
# For merge changesets, take either one, preferably the 'master' branch
|
||||
if hgbranch[mparent] == 'master':
|
||||
hgbranch[str(cset)] = 'master'
|
||||
else:
|
||||
hgbranch[str(cset)] = hgbranch[parent]
|
||||
else:
|
||||
# Normal changesets
|
||||
# For first children, take the parent branch, for the others create a new branch
|
||||
if hgchildren[parent][0] == str(cset):
|
||||
hgbranch[str(cset)] = hgbranch[parent]
|
||||
else:
|
||||
hgbranch[str(cset)] = "branch-" + str(cset)
|
||||
|
||||
if not hgvers.has_key("0"):
|
||||
print 'creating repository'
|
||||
os.system('git-init-db')
|
||||
|
||||
# loop through every hg changeset
|
||||
for cset in range(int(tip) + 1):
|
||||
|
||||
# incremental, already seen
|
||||
if hgvers.has_key(str(cset)):
|
||||
continue
|
||||
|
||||
# get info
|
||||
prnts = os.popen('hg log -r %d | grep ^parent: | cut -f 2 -d :' % cset).readlines()
|
||||
if len(prnts) > 0:
|
||||
parent = prnts[0].strip()
|
||||
else:
|
||||
parent = str(cset - 1)
|
||||
if len(prnts) > 1:
|
||||
mparent = prnts[1].strip()
|
||||
else:
|
||||
mparent = None
|
||||
|
||||
(fdcomment, filecomment) = tempfile.mkstemp()
|
||||
csetcomment = os.popen('hg log -r %d -v | grep -v ^changeset: | grep -v ^parent: | grep -v ^user: | grep -v ^date | grep -v ^files: | grep -v ^description: | grep -v ^tag:' % cset).read().strip()
|
||||
os.write(fdcomment, csetcomment)
|
||||
os.close(fdcomment)
|
||||
|
||||
date = os.popen('hg log -r %d | grep ^date: | cut -f 2- -d :' % cset).read().strip()
|
||||
|
||||
tag = os.popen('hg log -r %d | grep ^tag: | cut -f 2- -d :' % cset).read().strip()
|
||||
|
||||
user = os.popen('hg log -r %d | grep ^user: | cut -f 2- -d :' % cset).read().strip()
|
||||
|
||||
print '-----------------------------------------'
|
||||
print 'cset:', cset
|
||||
print 'branch:', hgbranch[str(cset)]
|
||||
print 'user:', user
|
||||
print 'date:', date
|
||||
print 'comment:', csetcomment
|
||||
print 'parent:', parent
|
||||
if mparent:
|
||||
print 'mparent:', mparent
|
||||
if tag:
|
||||
print 'tag:', tag
|
||||
print '-----------------------------------------'
|
||||
|
||||
# checkout the parent if necessary
|
||||
if cset != 0:
|
||||
if hgbranch[str(cset)] == "branch-" + str(cset):
|
||||
print 'creating new branch', hgbranch[str(cset)]
|
||||
os.system('git-checkout -b %s %s' % (hgbranch[str(cset)], hgvers[parent]))
|
||||
else:
|
||||
print 'checking out branch', hgbranch[str(cset)]
|
||||
os.system('git-checkout %s' % hgbranch[str(cset)])
|
||||
|
||||
# merge
|
||||
if mparent:
|
||||
if hgbranch[parent] == hgbranch[str(cset)]:
|
||||
otherbranch = hgbranch[mparent]
|
||||
else:
|
||||
otherbranch = hgbranch[parent]
|
||||
print 'merging', otherbranch, 'into', hgbranch[str(cset)]
|
||||
os.system(getgitenv(user, date) + 'git-merge --no-commit -s ours "" %s %s' % (hgbranch[str(cset)], otherbranch))
|
||||
|
||||
# remove everything except .git and .hg directories
|
||||
os.system('find . \( -path "./.hg" -o -path "./.git" \) -prune -o ! -name "." -print | xargs rm -rf')
|
||||
|
||||
# repopulate with checkouted files
|
||||
os.system('hg update -C %d' % cset)
|
||||
|
||||
# add new files
|
||||
os.system('git-ls-files -x .hg --others | git-update-index --add --stdin')
|
||||
# delete removed files
|
||||
os.system('git-ls-files -x .hg --deleted | git-update-index --remove --stdin')
|
||||
|
||||
# commit
|
||||
os.system(getgitenv(user, date) + 'git-commit -a -F %s' % filecomment)
|
||||
os.unlink(filecomment)
|
||||
|
||||
# tag
|
||||
if tag and tag != 'tip':
|
||||
os.system(getgitenv(user, date) + 'git-tag %s' % tag)
|
||||
|
||||
# delete branch if not used anymore...
|
||||
if mparent and len(hgchildren[str(cset)]):
|
||||
print "Deleting unused branch:", otherbranch
|
||||
os.system('git-branch -d %s' % otherbranch)
|
||||
|
||||
# retrieve and record the version
|
||||
vvv = os.popen('git-show | head -1').read()
|
||||
vvv = vvv[vvv.index(' ') + 1 : ].strip()
|
||||
print 'record', cset, '->', vvv
|
||||
hgvers[str(cset)] = vvv
|
||||
|
||||
os.system('git-repack -a -d')
|
||||
|
||||
# write the state for incrementals
|
||||
if state:
|
||||
print 'Writing state'
|
||||
f = open(state, 'w')
|
||||
pickle.dump(hgvers, f)
|
||||
|
||||
# vim: et ts=8 sw=4 sts=4
|
||||
21
contrib/hg-to-git/hg-to-git.txt
Normal file
21
contrib/hg-to-git/hg-to-git.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
hg-to-git.py is able to convert a Mercurial repository into a git one,
|
||||
and preserves the branches in the process (unlike tailor)
|
||||
|
||||
hg-to-git.py can probably be greatly improved (it's a rather crude
|
||||
combination of shell and python) but it does already work quite well for
|
||||
me. Features:
|
||||
- supports incremental conversion
|
||||
(for keeping a git repo in sync with a hg one)
|
||||
- supports hg branches
|
||||
- converts hg tags
|
||||
|
||||
Note that the git repository will be created 'in place' (at the same
|
||||
location as the source hg repo). You will have to manually remove the
|
||||
'.hg' directory after the conversion.
|
||||
|
||||
Also note that the incremental conversion uses 'simple' hg changesets
|
||||
identifiers (ordinals, as opposed to SHA-1 ids), and since these ids
|
||||
are not stable across different repositories the hg-to-git.py state file
|
||||
is forever tied to one hg repository.
|
||||
|
||||
Stelian Pop <stelian@popies.net>
|
||||
@@ -1,42 +0,0 @@
|
||||
#
|
||||
# Even with git, we don't always have name translations.
|
||||
# So have an email->real name table to translate the
|
||||
# (hopefully few) missing names
|
||||
#
|
||||
# repo-abbrev: /pub/scm/linux/kernel/git/
|
||||
#
|
||||
Adrian Bunk <bunk@stusta.de>
|
||||
Andreas Herrmann <aherrman@de.ibm.com>
|
||||
Andrew Morton <akpm@osdl.org>
|
||||
Andrew Vasquez <andrew.vasquez@qlogic.com>
|
||||
Christoph Hellwig <hch@lst.de>
|
||||
Corey Minyard <minyard@acm.org>
|
||||
David Woodhouse <dwmw2@shinybook.infradead.org>
|
||||
Domen Puncer <domen@coderock.org>
|
||||
Douglas Gilbert <dougg@torque.net>
|
||||
Ed L Cashin <ecashin@coraid.com>
|
||||
Evgeniy Polyakov <johnpol@2ka.mipt.ru>
|
||||
Felix Moeller <felix@derklecks.de>
|
||||
Frank Zago <fzago@systemfabricworks.com>
|
||||
Greg Kroah-Hartman <gregkh@suse.de>
|
||||
James Bottomley <jejb@mulgrave.(none)>
|
||||
James Bottomley <jejb@titanic.il.steeleye.com>
|
||||
Jeff Garzik <jgarzik@pretzel.yyz.us>
|
||||
Jens Axboe <axboe@suse.de>
|
||||
Kay Sievers <kay.sievers@vrfy.org>
|
||||
Mitesh shah <mshah@teja.com>
|
||||
Morten Welinder <terra@gnome.org>
|
||||
Morten Welinder <welinder@anemone.rentec.com>
|
||||
Morten Welinder <welinder@darter.rentec.com>
|
||||
Morten Welinder <welinder@troll.com>
|
||||
Nguyen Anh Quynh <aquynh@gmail.com>
|
||||
Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
|
||||
Peter A Jonsson <pj@ludd.ltu.se>
|
||||
Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
|
||||
Rudolf Marek <R.Marek@sh.cvut.cz>
|
||||
Rui Saraiva <rmps@joel.ist.utl.pt>
|
||||
Sachin P Sant <ssant@in.ibm.com>
|
||||
Santtu Hyrkk,Av(B <santtu.hyrkko@gmail.com>
|
||||
Simon Kelley <simon@thekelleys.org.uk>
|
||||
Tejun Heo <htejun@gmail.com>
|
||||
Tony Luck <tony.luck@intel.com>
|
||||
2
daemon.c
2
daemon.c
@@ -408,7 +408,7 @@ static void make_service_overridable(const char *name, int ena) {
|
||||
|
||||
/*
|
||||
* Separate the "extra args" information as supplied by the client connection.
|
||||
* Any resulting data is squirrelled away in the given interpolation table.
|
||||
* Any resulting data is squirreled away in the given interpolation table.
|
||||
*/
|
||||
static void parse_extra_args(struct interp *table, char *extra_args, int buflen)
|
||||
{
|
||||
|
||||
44
diff-lib.c
44
diff-lib.c
@@ -7,6 +7,7 @@
|
||||
#include "diff.h"
|
||||
#include "diffcore.h"
|
||||
#include "revision.h"
|
||||
#include "cache-tree.h"
|
||||
|
||||
/*
|
||||
* diff-files
|
||||
@@ -271,7 +272,7 @@ static int diff_cache(struct rev_info *revs,
|
||||
break;
|
||||
}
|
||||
/* Show difference between old and new */
|
||||
show_modified(revs,ac[1], ce, 1,
|
||||
show_modified(revs, ac[1], ce, 1,
|
||||
cached, match_missing);
|
||||
break;
|
||||
case 1:
|
||||
@@ -372,3 +373,44 @@ int run_diff_index(struct rev_info *revs, int cached)
|
||||
diff_flush(&revs->diffopt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt)
|
||||
{
|
||||
struct tree *tree;
|
||||
struct rev_info revs;
|
||||
int i;
|
||||
struct cache_entry **dst;
|
||||
struct cache_entry *last = NULL;
|
||||
|
||||
/*
|
||||
* This is used by git-blame to run diff-cache internally;
|
||||
* it potentially needs to repeatedly run this, so we will
|
||||
* start by removing the higher order entries the last round
|
||||
* left behind.
|
||||
*/
|
||||
dst = active_cache;
|
||||
for (i = 0; i < active_nr; i++) {
|
||||
struct cache_entry *ce = active_cache[i];
|
||||
if (ce_stage(ce)) {
|
||||
if (last && !strcmp(ce->name, last->name))
|
||||
continue;
|
||||
cache_tree_invalidate_path(active_cache_tree,
|
||||
ce->name);
|
||||
last = ce;
|
||||
ce->ce_mode = 0;
|
||||
ce->ce_flags &= ~htons(CE_STAGEMASK);
|
||||
}
|
||||
*dst++ = ce;
|
||||
}
|
||||
active_nr = dst - active_cache;
|
||||
|
||||
init_revisions(&revs, NULL);
|
||||
revs.prune_data = opt->paths;
|
||||
tree = parse_tree_indirect(tree_sha1);
|
||||
if (!tree)
|
||||
die("bad tree object %s", sha1_to_hex(tree_sha1));
|
||||
if (read_tree(tree, 1, opt->paths))
|
||||
return error("unable to read tree %s", sha1_to_hex(tree_sha1));
|
||||
return diff_cache(&revs, active_cache, active_nr, revs.prune_data,
|
||||
1, 0);
|
||||
}
|
||||
|
||||
91
diff.c
91
diff.c
@@ -560,6 +560,24 @@ static char *pprint_rename(const char *a, const char *b)
|
||||
int pfx_length, sfx_length;
|
||||
int len_a = strlen(a);
|
||||
int len_b = strlen(b);
|
||||
int qlen_a = quote_c_style(a, NULL, NULL, 0);
|
||||
int qlen_b = quote_c_style(b, NULL, NULL, 0);
|
||||
|
||||
if (qlen_a || qlen_b) {
|
||||
if (qlen_a) len_a = qlen_a;
|
||||
if (qlen_b) len_b = qlen_b;
|
||||
name = xmalloc( len_a + len_b + 5 );
|
||||
if (qlen_a)
|
||||
quote_c_style(a, name, NULL, 0);
|
||||
else
|
||||
memcpy(name, a, len_a);
|
||||
memcpy(name + len_a, " => ", 4);
|
||||
if (qlen_b)
|
||||
quote_c_style(b, name + len_a + 4, NULL, 0);
|
||||
else
|
||||
memcpy(name + len_a + 4, b, len_b + 1);
|
||||
return name;
|
||||
}
|
||||
|
||||
/* Find common prefix */
|
||||
pfx_length = 0;
|
||||
@@ -716,12 +734,14 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options)
|
||||
struct diffstat_file *file = data->files[i];
|
||||
int change = file->added + file->deleted;
|
||||
|
||||
len = quote_c_style(file->name, NULL, NULL, 0);
|
||||
if (len) {
|
||||
char *qname = xmalloc(len + 1);
|
||||
quote_c_style(file->name, qname, NULL, 0);
|
||||
free(file->name);
|
||||
file->name = qname;
|
||||
if (!file->is_renamed) { /* renames are already quoted by pprint_rename */
|
||||
len = quote_c_style(file->name, NULL, NULL, 0);
|
||||
if (len) {
|
||||
char *qname = xmalloc(len + 1);
|
||||
quote_c_style(file->name, qname, NULL, 0);
|
||||
free(file->name);
|
||||
file->name = qname;
|
||||
}
|
||||
}
|
||||
|
||||
len = strlen(file->name);
|
||||
@@ -853,7 +873,7 @@ static void show_numstat(struct diffstat_t* data, struct diff_options *options)
|
||||
printf("-\t-\t");
|
||||
else
|
||||
printf("%d\t%d\t", file->added, file->deleted);
|
||||
if (options->line_termination &&
|
||||
if (options->line_termination && !file->is_renamed &&
|
||||
quote_c_style(file->name, NULL, NULL, 0))
|
||||
quote_c_style(file->name, NULL, stdout, 0);
|
||||
else
|
||||
@@ -1359,6 +1379,7 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
|
||||
s->data = xmmap(NULL, s->size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
close(fd);
|
||||
s->should_munmap = 1;
|
||||
/* FIXME! CRLF -> LF conversion goes here, based on "s->path" */
|
||||
}
|
||||
else {
|
||||
char type[20];
|
||||
@@ -2200,13 +2221,13 @@ static void diff_flush_raw(struct diff_filepair *p,
|
||||
free((void*)path_two);
|
||||
}
|
||||
|
||||
static void diff_flush_name(struct diff_filepair *p, int line_termination)
|
||||
static void diff_flush_name(struct diff_filepair *p, struct diff_options *opt)
|
||||
{
|
||||
char *path = p->two->path;
|
||||
|
||||
if (line_termination)
|
||||
if (opt->line_termination)
|
||||
path = quote_one(p->two->path);
|
||||
printf("%s%c", path, line_termination);
|
||||
printf("%s%c", path, opt->line_termination);
|
||||
if (p->two->path != path)
|
||||
free(path);
|
||||
}
|
||||
@@ -2413,24 +2434,29 @@ static void flush_one_pair(struct diff_filepair *p, struct diff_options *opt)
|
||||
else if (fmt & (DIFF_FORMAT_RAW | DIFF_FORMAT_NAME_STATUS))
|
||||
diff_flush_raw(p, opt);
|
||||
else if (fmt & DIFF_FORMAT_NAME)
|
||||
diff_flush_name(p, opt->line_termination);
|
||||
diff_flush_name(p, opt);
|
||||
}
|
||||
|
||||
static void show_file_mode_name(const char *newdelete, struct diff_filespec *fs)
|
||||
{
|
||||
char *name = quote_one(fs->path);
|
||||
if (fs->mode)
|
||||
printf(" %s mode %06o %s\n", newdelete, fs->mode, fs->path);
|
||||
printf(" %s mode %06o %s\n", newdelete, fs->mode, name);
|
||||
else
|
||||
printf(" %s %s\n", newdelete, fs->path);
|
||||
printf(" %s %s\n", newdelete, name);
|
||||
free(name);
|
||||
}
|
||||
|
||||
|
||||
static void show_mode_change(struct diff_filepair *p, int show_name)
|
||||
{
|
||||
if (p->one->mode && p->two->mode && p->one->mode != p->two->mode) {
|
||||
if (show_name)
|
||||
if (show_name) {
|
||||
char *name = quote_one(p->two->path);
|
||||
printf(" mode change %06o => %06o %s\n",
|
||||
p->one->mode, p->two->mode, p->two->path);
|
||||
p->one->mode, p->two->mode, name);
|
||||
free(name);
|
||||
}
|
||||
else
|
||||
printf(" mode change %06o => %06o\n",
|
||||
p->one->mode, p->two->mode);
|
||||
@@ -2439,34 +2465,11 @@ static void show_mode_change(struct diff_filepair *p, int show_name)
|
||||
|
||||
static void show_rename_copy(const char *renamecopy, struct diff_filepair *p)
|
||||
{
|
||||
const char *old, *new;
|
||||
char *names = pprint_rename(p->one->path, p->two->path);
|
||||
|
||||
/* Find common prefix */
|
||||
old = p->one->path;
|
||||
new = p->two->path;
|
||||
while (1) {
|
||||
const char *slash_old, *slash_new;
|
||||
slash_old = strchr(old, '/');
|
||||
slash_new = strchr(new, '/');
|
||||
if (!slash_old ||
|
||||
!slash_new ||
|
||||
slash_old - old != slash_new - new ||
|
||||
memcmp(old, new, slash_new - new))
|
||||
break;
|
||||
old = slash_old + 1;
|
||||
new = slash_new + 1;
|
||||
}
|
||||
/* p->one->path thru old is the common prefix, and old and new
|
||||
* through the end of names are renames
|
||||
*/
|
||||
if (old != p->one->path)
|
||||
printf(" %s %.*s{%s => %s} (%d%%)\n", renamecopy,
|
||||
(int)(old - p->one->path), p->one->path,
|
||||
old, new, (int)(0.5 + p->score * 100.0/MAX_SCORE));
|
||||
else
|
||||
printf(" %s %s => %s (%d%%)\n", renamecopy,
|
||||
p->one->path, p->two->path,
|
||||
(int)(0.5 + p->score * 100.0/MAX_SCORE));
|
||||
printf(" %s %s (%d%%)\n", renamecopy, names,
|
||||
(int)(0.5 + p->score * 100.0/MAX_SCORE));
|
||||
free(names);
|
||||
show_mode_change(p, 0);
|
||||
}
|
||||
|
||||
@@ -2487,8 +2490,10 @@ static void diff_summary(struct diff_filepair *p)
|
||||
break;
|
||||
default:
|
||||
if (p->score) {
|
||||
printf(" rewrite %s (%d%%)\n", p->two->path,
|
||||
char *name = quote_one(p->two->path);
|
||||
printf(" rewrite %s (%d%%)\n", name,
|
||||
(int)(0.5 + p->score * 100.0/MAX_SCORE));
|
||||
free(name);
|
||||
show_mode_change(p, 0);
|
||||
} else show_mode_change(p, 1);
|
||||
break;
|
||||
|
||||
1
diff.h
1
diff.h
@@ -222,6 +222,7 @@ extern int run_diff_files(struct rev_info *revs, int silent_on_removed);
|
||||
|
||||
extern int run_diff_index(struct rev_info *revs, int cached);
|
||||
|
||||
extern int do_diff_cache(const unsigned char *, struct diff_options *);
|
||||
extern int diff_flush_patch_id(struct diff_options *, unsigned char *);
|
||||
|
||||
#endif /* DIFF_H */
|
||||
|
||||
1
entry.c
1
entry.c
@@ -89,6 +89,7 @@ static int write_entry(struct cache_entry *ce, char *path, struct checkout *stat
|
||||
return error("git-checkout-index: unable to create file %s (%s)",
|
||||
path, strerror(errno));
|
||||
}
|
||||
/* FIXME: LF -> CRLF conversion goes here, based on "ce->name" */
|
||||
wrote = write_in_full(fd, new, size);
|
||||
close(fd);
|
||||
free(new);
|
||||
|
||||
2081
fast-import.c
Normal file
2081
fast-import.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,5 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
|
||||
use strict;
|
||||
|
||||
sub run_cmd_pipe {
|
||||
@@ -282,7 +281,7 @@ sub update_cmd {
|
||||
HEADER => $status_head, },
|
||||
@mods);
|
||||
if (@update) {
|
||||
system(qw(git update-index --add --),
|
||||
system(qw(git update-index --add --remove --),
|
||||
map { $_->{VALUE} } @update);
|
||||
say_n_paths('updated', @update);
|
||||
}
|
||||
|
||||
11
git-am.sh
11
git-am.sh
@@ -3,7 +3,7 @@
|
||||
# Copyright (c) 2005, 2006 Junio C Hamano
|
||||
|
||||
USAGE='[--signoff] [--dotest=<dir>] [--utf8 | --no-utf8] [--binary] [--3way]
|
||||
[--interactive] [--whitespace=<option>] <mbox>...
|
||||
[--interactive] [--whitespace=<option>] [-C<n>] [-p<n>] <mbox>...
|
||||
or, when resuming [--skip | --resolved]'
|
||||
. git-sh-setup
|
||||
set_reflog_action am
|
||||
@@ -106,7 +106,8 @@ It does not apply to blobs recorded in its index."
|
||||
}
|
||||
|
||||
prec=4
|
||||
dotest=.dotest sign= utf8=t keep= skip= interactive= resolved= binary= ws= resolvemsg=
|
||||
dotest=.dotest sign= utf8=t keep= skip= interactive= resolved= binary= resolvemsg=
|
||||
git_apply_opt=
|
||||
|
||||
while case "$#" in 0) break;; esac
|
||||
do
|
||||
@@ -141,8 +142,8 @@ do
|
||||
--sk|--ski|--skip)
|
||||
skip=t; shift ;;
|
||||
|
||||
--whitespace=*)
|
||||
ws=$1; shift ;;
|
||||
--whitespace=*|-C*|-p*)
|
||||
git_apply_opt="$git_apply_opt $1"; shift ;;
|
||||
|
||||
--resolvemsg=*)
|
||||
resolvemsg=$(echo "$1" | sed -e "s/^--resolvemsg=//"); shift ;;
|
||||
@@ -394,7 +395,7 @@ do
|
||||
|
||||
case "$resolved" in
|
||||
'')
|
||||
git-apply $binary --index $ws "$dotest/patch"
|
||||
git-apply $git_apply_opt $binary --index "$dotest/patch"
|
||||
apply_status=$?
|
||||
;;
|
||||
t)
|
||||
|
||||
@@ -95,6 +95,15 @@ $ENV{'TMPDIR'} = $opt_t if $opt_t; # $ENV{TMPDIR} will affect tempdir() calls:
|
||||
my $tmp = tempdir('git-archimport-XXXXXX', TMPDIR => 1, CLEANUP => 1);
|
||||
$opt_v && print "+ Using $tmp as temporary directory\n";
|
||||
|
||||
unless (-d $git_dir) { # initial import needs empty directory
|
||||
opendir DIR, '.' or die "Unable to open current directory: $!\n";
|
||||
while (my $entry = readdir DIR) {
|
||||
$entry =~ /^\.\.?$/ or
|
||||
die "Initial import needs an empty current working directory.\n"
|
||||
}
|
||||
closedir DIR
|
||||
}
|
||||
|
||||
my %reachable = (); # Arch repositories we can access
|
||||
my %unreachable = (); # Arch repositories we can't access :<
|
||||
my @psets = (); # the collection
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
USAGE='[start|bad|good|next|reset|visualize]'
|
||||
USAGE='[start|bad|good|next|reset|visualize|replay|log]'
|
||||
LONG_USAGE='git bisect start [<pathspec>] reset bisect state and start bisection.
|
||||
git bisect bad [<rev>] mark <rev> a known-bad revision.
|
||||
git bisect good [<rev>...] mark <rev>... known-good revisions.
|
||||
@@ -11,6 +11,7 @@ git bisect replay <logfile> replay bisection log
|
||||
git bisect log show bisect log.'
|
||||
|
||||
. git-sh-setup
|
||||
require_work_tree
|
||||
|
||||
sq() {
|
||||
@@PERL@@ -e '
|
||||
@@ -152,7 +153,7 @@ bisect_next() {
|
||||
nr=$(eval "git-rev-list $rev $good -- $(cat $GIT_DIR/BISECT_NAMES)" | wc -l) || exit
|
||||
echo "Bisecting: $nr revisions left to test after this"
|
||||
echo "$rev" > "$GIT_DIR/refs/heads/new-bisect"
|
||||
git checkout new-bisect || exit
|
||||
git checkout -q new-bisect || exit
|
||||
mv "$GIT_DIR/refs/heads/new-bisect" "$GIT_DIR/refs/heads/bisect" &&
|
||||
GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD refs/heads/bisect
|
||||
git-show-branch "$rev"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
USAGE='[-f] [-b <new_branch>] [-m] [<branch>] [<paths>...]'
|
||||
USAGE='[-q] [-f] [-b <new_branch>] [-m] [<branch>] [<paths>...]'
|
||||
SUBDIRECTORY_OK=Sometimes
|
||||
. git-sh-setup
|
||||
require_work_tree
|
||||
@@ -15,6 +15,7 @@ branch=
|
||||
newbranch=
|
||||
newbranch_log=
|
||||
merge=
|
||||
quiet=
|
||||
LF='
|
||||
'
|
||||
while [ "$#" != "0" ]; do
|
||||
@@ -40,6 +41,9 @@ while [ "$#" != "0" ]; do
|
||||
-m)
|
||||
merge=1
|
||||
;;
|
||||
"-q")
|
||||
quiet=1
|
||||
;;
|
||||
--)
|
||||
break
|
||||
;;
|
||||
@@ -153,35 +157,25 @@ detach_warn=
|
||||
if test -z "$branch$newbranch" && test "$new" != "$old"
|
||||
then
|
||||
detached="$new"
|
||||
if test -n "$oldbranch"
|
||||
if test -n "$oldbranch" && test -z "$quiet"
|
||||
then
|
||||
detach_warn="Note: you are not on any branch and are at commit \"$new_name\"
|
||||
detach_warn="Note: moving to \"$new_name\" which isn't a local branch
|
||||
If you want to create a new branch from this checkout, you may do so
|
||||
(now or later) by using -b with the checkout command again. Example:
|
||||
git checkout -b <new_branch_name>"
|
||||
fi
|
||||
elif test -z "$oldbranch" && test -n "$branch"
|
||||
elif test -z "$oldbranch" && test -z "$quiet"
|
||||
then
|
||||
# Coming back...
|
||||
if test -z "$force"
|
||||
then
|
||||
git show-ref -d -s | grep "$old" >/dev/null || {
|
||||
echo >&2 \
|
||||
"You are not on any branch and switching to branch '$new_name'
|
||||
may lose your changes. At this point, you can do one of two things:
|
||||
(1) Decide it is Ok and say 'git checkout -f $new_name';
|
||||
(2) Start a new branch from the current commit, by saying
|
||||
'git checkout -b <branch-name>'.
|
||||
Leaving your HEAD detached; not switching to branch '$new_name'."
|
||||
exit 1;
|
||||
}
|
||||
fi
|
||||
echo >&2 "Previous HEAD position was $old"
|
||||
fi
|
||||
|
||||
if [ "X$old" = X ]
|
||||
then
|
||||
echo >&2 "warning: You appear to be on a branch yet to be born."
|
||||
echo >&2 "warning: Forcing checkout of $new_name."
|
||||
if test -z "$quiet"
|
||||
then
|
||||
echo >&2 "warning: You appear to be on a branch yet to be born."
|
||||
echo >&2 "warning: Forcing checkout of $new_name."
|
||||
fi
|
||||
force=1
|
||||
fi
|
||||
|
||||
@@ -233,7 +227,7 @@ else
|
||||
exit 0
|
||||
)
|
||||
saved_err=$?
|
||||
if test "$saved_err" = 0
|
||||
if test "$saved_err" = 0 && test -z "$quiet"
|
||||
then
|
||||
git diff-index --name-status "$new"
|
||||
fi
|
||||
@@ -258,11 +252,9 @@ if [ "$?" -eq 0 ]; then
|
||||
if test -n "$branch"
|
||||
then
|
||||
GIT_DIR="$GIT_DIR" git-symbolic-ref -m "checkout: moving to $branch" HEAD "refs/heads/$branch"
|
||||
if test -n "$newbranch"
|
||||
if test -z "$quiet"
|
||||
then
|
||||
echo >&2 "Switched to a new branch \"$branch\""
|
||||
else
|
||||
echo >&2 "Switched to branch \"$branch\""
|
||||
echo >&2 "Switched to${newbranch:+ a new} branch \"$branch\""
|
||||
fi
|
||||
elif test -n "$detached"
|
||||
then
|
||||
|
||||
29
git-clone.sh
29
git-clone.sh
@@ -178,19 +178,32 @@ esac && export GIT_DIR && git-init ${template+"$template"} || usage
|
||||
|
||||
if test -n "$reference"
|
||||
then
|
||||
ref_git=
|
||||
if test -d "$reference"
|
||||
then
|
||||
if test -d "$reference/.git/objects"
|
||||
then
|
||||
reference="$reference/.git"
|
||||
ref_git="$reference/.git"
|
||||
elif test -d "$reference/objects"
|
||||
then
|
||||
ref_git="$reference"
|
||||
fi
|
||||
reference=$(cd "$reference" && pwd)
|
||||
echo "$reference/objects" >"$GIT_DIR/objects/info/alternates"
|
||||
(cd "$reference" && tar cf - refs) |
|
||||
(cd "$GIT_DIR/refs" &&
|
||||
mkdir reference-tmp &&
|
||||
cd reference-tmp &&
|
||||
tar xf -)
|
||||
fi
|
||||
if test -n "$ref_git"
|
||||
then
|
||||
ref_git=$(cd "$ref_git" && pwd)
|
||||
echo "$ref_git/objects" >"$GIT_DIR/objects/info/alternates"
|
||||
(
|
||||
GIT_DIR="$ref_git" git for-each-ref \
|
||||
--format='%(objectname) %(*objectname)'
|
||||
) |
|
||||
while read a b
|
||||
do
|
||||
test -z "$a" ||
|
||||
git update-ref "refs/reference-tmp/$a" "$a"
|
||||
test -z "$b" ||
|
||||
git update-ref "refs/reference-tmp/$b" "$b"
|
||||
done
|
||||
else
|
||||
die "reference repository '$reference' is not a local directory."
|
||||
fi
|
||||
|
||||
@@ -528,6 +528,7 @@ else
|
||||
rloga='commit (initial)'
|
||||
current=''
|
||||
fi
|
||||
set_reflog_action "$rloga"
|
||||
|
||||
if test -z "$no_edit"
|
||||
then
|
||||
@@ -602,7 +603,7 @@ then
|
||||
fi &&
|
||||
commit=$(cat "$GIT_DIR"/COMMIT_MSG | git-commit-tree $tree $PARENTS) &&
|
||||
rlogm=$(sed -e 1q "$GIT_DIR"/COMMIT_MSG) &&
|
||||
git-update-ref -m "$rloga: $rlogm" HEAD $commit "$current" &&
|
||||
git-update-ref -m "$GIT_REFLOG_ACTION: $rlogm" HEAD $commit "$current" &&
|
||||
rm -f -- "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/MERGE_MSG" &&
|
||||
if test -f "$NEXT_INDEX"
|
||||
then
|
||||
|
||||
@@ -15,9 +15,9 @@ unless ($ENV{GIT_DIR} && -r $ENV{GIT_DIR}){
|
||||
die "GIT_DIR is not defined or is unreadable";
|
||||
}
|
||||
|
||||
our ($opt_h, $opt_p, $opt_v, $opt_c, $opt_f, $opt_a, $opt_m );
|
||||
our ($opt_h, $opt_P, $opt_p, $opt_v, $opt_c, $opt_f, $opt_a, $opt_m );
|
||||
|
||||
getopts('hpvcfam:');
|
||||
getopts('hPpvcfam:');
|
||||
|
||||
$opt_h && usage();
|
||||
|
||||
@@ -89,7 +89,7 @@ if ($parent) {
|
||||
last;
|
||||
}; # found it
|
||||
}
|
||||
die "Did not find $parent in the parents for this commit!" if !$found;
|
||||
die "Did not find $parent in the parents for this commit!" if !$found and !$opt_P;
|
||||
} else { # we don't have a parent from the cmdline...
|
||||
if (@parents == 1) { # it's safe to get it from the commit
|
||||
$parent = $parents[0];
|
||||
|
||||
@@ -85,7 +85,35 @@ sub write_author_info($) {
|
||||
close ($f);
|
||||
}
|
||||
|
||||
getopts("haivmkuo:d:p:C:z:s:M:P:A:S:L:") or usage();
|
||||
# convert getopts specs for use by git-repo-config
|
||||
sub read_repo_config {
|
||||
# Split the string between characters, unless there is a ':'
|
||||
# So "abc:de" becomes ["a", "b", "c:", "d", "e"]
|
||||
my @opts = split(/ *(?!:)/, shift);
|
||||
foreach my $o (@opts) {
|
||||
my $key = $o;
|
||||
$key =~ s/://g;
|
||||
my $arg = 'git-repo-config';
|
||||
$arg .= ' --bool' if ($o !~ /:$/);
|
||||
|
||||
chomp(my $tmp = `$arg --get cvsimport.$key`);
|
||||
if ($tmp && !($arg =~ /--bool/ && $tmp eq 'false')) {
|
||||
no strict 'refs';
|
||||
my $opt_name = "opt_" . $key;
|
||||
if (!$$opt_name) {
|
||||
$$opt_name = $tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (@ARGV == 0) {
|
||||
chomp(my $module = `git-repo-config --get cvsimport.module`);
|
||||
push(@ARGV, $module);
|
||||
}
|
||||
}
|
||||
|
||||
my $opts = "haivmkuo:d:p:C:z:s:M:P:A:S:L:";
|
||||
read_repo_config($opts);
|
||||
getopts($opts) or usage();
|
||||
usage if $opt_h;
|
||||
|
||||
@ARGV <= 1 or usage();
|
||||
|
||||
17
git-fetch.sh
17
git-fetch.sh
@@ -253,23 +253,10 @@ if test "$tags"
|
||||
then
|
||||
taglist=`IFS=' ' &&
|
||||
echo "$ls_remote_result" |
|
||||
git-show-ref --exclude-existing=refs/tags/ |
|
||||
while read sha1 name
|
||||
do
|
||||
case "$sha1" in
|
||||
fail)
|
||||
exit 1
|
||||
esac
|
||||
case "$name" in
|
||||
*^*) continue ;;
|
||||
refs/tags/*) ;;
|
||||
*) continue ;;
|
||||
esac
|
||||
if git-check-ref-format "$name"
|
||||
then
|
||||
echo ".${name}:${name}"
|
||||
else
|
||||
echo >&2 "warning: tag ${name} ignored"
|
||||
fi
|
||||
echo ".${name}:${name}"
|
||||
done` || exit
|
||||
if test "$#" -gt 1
|
||||
then
|
||||
|
||||
@@ -22,6 +22,14 @@ do
|
||||
shift
|
||||
done
|
||||
|
||||
case "$(git config --get gc.packrefs)" in
|
||||
notbare|"")
|
||||
test $(is_bare_repository) = true || pack_refs=true;;
|
||||
*)
|
||||
pack_refs=$(git config --bool --get gc.packrefs)
|
||||
esac
|
||||
|
||||
test "true" != "$pack_refs" ||
|
||||
git-pack-refs --prune &&
|
||||
git-reflog expire --all &&
|
||||
git-repack -a -d -l &&
|
||||
|
||||
3
git-gui/.gitignore
vendored
Normal file
3
git-gui/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
GIT-VERSION-FILE
|
||||
git-citool
|
||||
git-gui
|
||||
77
git-gui/GIT-VERSION-GEN
Executable file
77
git-gui/GIT-VERSION-GEN
Executable file
@@ -0,0 +1,77 @@
|
||||
#!/bin/sh
|
||||
|
||||
GVF=GIT-VERSION-FILE
|
||||
DEF_VER=0.6.GITGUI
|
||||
|
||||
LF='
|
||||
'
|
||||
|
||||
tree_search ()
|
||||
{
|
||||
head=$1
|
||||
tree=$2
|
||||
for p in $(git rev-list --parents --max-count=1 $head 2>/dev/null)
|
||||
do
|
||||
test $tree = $(git rev-parse $p^{tree} 2>/dev/null) &&
|
||||
vn=$(git describe --abbrev=4 $p 2>/dev/null) &&
|
||||
case "$vn" in
|
||||
gitgui-[0-9]*) echo $vn; break;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# We may be a subproject, so try looking for the merge
|
||||
# commit that supplied this directory content if we are
|
||||
# not at the toplevel. We probably will always be the
|
||||
# second parent in the commit, but we shouldn't rely on
|
||||
# that fact.
|
||||
#
|
||||
# If we are at the toplevel or the merge assumption fails
|
||||
# try looking for a gitgui-* tag, or fallback onto the
|
||||
# distributed version file.
|
||||
|
||||
if prefix="$(git rev-parse --show-prefix 2>/dev/null)"
|
||||
test -n "$prefix" &&
|
||||
head=$(git rev-list --max-count=1 HEAD -- . 2>/dev/null) &&
|
||||
tree=$(git rev-parse --verify "HEAD:$prefix" 2>/dev/null) &&
|
||||
VN=$(tree_search $head $tree)
|
||||
case "$VN" in
|
||||
gitgui-[0-9]*) : happy ;;
|
||||
*) (exit 1) ;;
|
||||
esac
|
||||
then
|
||||
VN=$(echo "$VN" | sed -e 's/^gitgui-//;s/-/./g');
|
||||
elif VN=$(git describe --abbrev=4 HEAD 2>/dev/null) &&
|
||||
case "$VN" in
|
||||
gitgui-[0-9]*) : happy ;;
|
||||
*) (exit 1) ;;
|
||||
esac
|
||||
then
|
||||
VN=$(echo "$VN" | sed -e 's/^gitgui-//;s/-/./g');
|
||||
elif test -f version
|
||||
then
|
||||
VN=$(cat version) || VN="$DEF_VER"
|
||||
else
|
||||
VN="$DEF_VER"
|
||||
fi
|
||||
|
||||
dirty=$(sh -c 'git diff-index --name-only HEAD' 2>/dev/null) || dirty=
|
||||
case "$dirty" in
|
||||
'')
|
||||
;;
|
||||
*)
|
||||
VN="$VN-dirty" ;;
|
||||
esac
|
||||
|
||||
if test -r $GVF
|
||||
then
|
||||
VC=$(sed -e 's/^GITGUI_VERSION = //' <$GVF)
|
||||
else
|
||||
VC=unset
|
||||
fi
|
||||
test "$VN" = "$VC" || {
|
||||
echo >&2 "GITGUI_VERSION = $VN"
|
||||
echo "GITGUI_VERSION = $VN" >$GVF
|
||||
}
|
||||
|
||||
|
||||
56
git-gui/Makefile
Normal file
56
git-gui/Makefile
Normal file
@@ -0,0 +1,56 @@
|
||||
all::
|
||||
|
||||
GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
|
||||
@$(SHELL_PATH) ./GIT-VERSION-GEN
|
||||
-include GIT-VERSION-FILE
|
||||
|
||||
SCRIPT_SH = git-gui.sh
|
||||
GITGUI_BUILT_INS = git-citool
|
||||
ALL_PROGRAMS = $(GITGUI_BUILT_INS) $(patsubst %.sh,%,$(SCRIPT_SH))
|
||||
|
||||
ifndef SHELL_PATH
|
||||
SHELL_PATH = /bin/sh
|
||||
endif
|
||||
|
||||
ifndef gitexecdir
|
||||
gitexecdir := $(shell git --exec-path)
|
||||
endif
|
||||
|
||||
ifndef INSTALL
|
||||
INSTALL = install
|
||||
endif
|
||||
|
||||
DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
|
||||
gitexecdir_SQ = $(subst ','\'',$(gitexecdir))
|
||||
SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
|
||||
|
||||
$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
|
||||
rm -f $@ $@+
|
||||
sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
|
||||
-e 's/@@GITGUI_VERSION@@/$(GITGUI_VERSION)/g' \
|
||||
$@.sh >$@+
|
||||
chmod +x $@+
|
||||
mv $@+ $@
|
||||
|
||||
$(GITGUI_BUILT_INS): git-gui
|
||||
rm -f $@ && ln git-gui $@
|
||||
|
||||
# These can record GITGUI_VERSION
|
||||
$(patsubst %.sh,%,$(SCRIPT_SH)): GIT-VERSION-FILE
|
||||
|
||||
all:: $(ALL_PROGRAMS)
|
||||
|
||||
install: all
|
||||
$(INSTALL) -d -m755 '$(DESTDIR_SQ)$(gitexecdir_SQ)'
|
||||
$(INSTALL) git-gui '$(DESTDIR_SQ)$(gitexecdir_SQ)'
|
||||
$(foreach p,$(GITGUI_BUILT_INS), rm -f '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' && ln '$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' ;)
|
||||
|
||||
dist-version:
|
||||
@mkdir -p $(TARDIR)
|
||||
@echo $(GITGUI_VERSION) > $(TARDIR)/version
|
||||
|
||||
clean::
|
||||
rm -f $(ALL_PROGRAMS) GIT-VERSION-FILE
|
||||
|
||||
.PHONY: all install dist-version clean
|
||||
.PHONY: .FORCE-GIT-VERSION-FILE
|
||||
44
git-gui/TODO
Normal file
44
git-gui/TODO
Normal file
@@ -0,0 +1,44 @@
|
||||
Items outstanding:
|
||||
|
||||
* Add file to .gitignore or info/excludes.
|
||||
|
||||
* Populate the pull menu with local branches.
|
||||
|
||||
* Make use of the new default merge data stored in repo-config.
|
||||
|
||||
* Checkout a different local branch.
|
||||
|
||||
* Push any local branch to a remote branch.
|
||||
|
||||
* Merge any local branches through a real merge UI.
|
||||
|
||||
* Allow user to define keyboard shortcuts for frequently used fetch
|
||||
or merge operations. Or maybe just define a keyboard shortcut
|
||||
for default fetch/default merge of current branch is enough;
|
||||
but I do know a few users who merge a couple of common branches
|
||||
also into the same branch so one default isn't quite enough.
|
||||
|
||||
* Better organize fetch/push/pull console windows.
|
||||
|
||||
* Clone UI (to download a new repository).
|
||||
|
||||
* Remotes editor (for .git/config format only).
|
||||
|
||||
* Show a shortlog of the last couple of commits in the main window,
|
||||
to give the user warm fuzzy feelings that we have their data
|
||||
saved. Actually this may be the set of commits not yet in
|
||||
the upstream (aka default merge branch remote repository).
|
||||
|
||||
* GUI configuration editor for options listed in
|
||||
git.git/Documentation/config.txt. Ideally this would
|
||||
parse that file and generate the options dialog from
|
||||
the documentation itself, and include the help text
|
||||
from the documentation as part of the UI somehow.
|
||||
|
||||
Known bugs:
|
||||
|
||||
* git-gui sometimes just closes on Windows with no error message.
|
||||
I'm not sure what the problem is here. I suspect the wish
|
||||
process is just terminating due to a segfault or something,
|
||||
as the do_quit proc in git-gui doesn't run. It often seems to
|
||||
occur while writing a commit message in the buffer. Odd.
|
||||
5924
git-gui/git-gui.sh
Executable file
5924
git-gui/git-gui.sh
Executable file
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@
|
||||
# Copyright (c) 2005 Linus Torvalds
|
||||
# Copyright (c) 2005 Junio C Hamano
|
||||
#
|
||||
# Resolve two trees, using enhancd multi-base read-tree.
|
||||
# Resolve two trees, using enhanced multi-base read-tree.
|
||||
|
||||
# The first parameters up to -- are merge bases; the rest are heads.
|
||||
bases= head= remotes= sep_seen=
|
||||
|
||||
@@ -174,12 +174,8 @@ canon_refs_list_for_fetch () {
|
||||
else
|
||||
for merge_branch in $merge_branches
|
||||
do
|
||||
if test "$remote" = "$merge_branch" ||
|
||||
test "$local" = "$merge_branch"
|
||||
then
|
||||
dot_prefix=
|
||||
break
|
||||
fi
|
||||
[ "$remote" = "$merge_branch" ] &&
|
||||
dot_prefix= && break
|
||||
done
|
||||
fi
|
||||
case "$remote" in
|
||||
|
||||
@@ -59,7 +59,7 @@ if ! [ -d "$QUILT_PATCHES" ] ; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Temporay directories
|
||||
# Temporary directories
|
||||
tmp_dir=.dotest
|
||||
tmp_msg="$tmp_dir/msg"
|
||||
tmp_patch="$tmp_dir/patch"
|
||||
|
||||
@@ -45,6 +45,7 @@ do_merge=
|
||||
dotest=$GIT_DIR/.dotest-merge
|
||||
prec=4
|
||||
verbose=
|
||||
git_am_opt=
|
||||
|
||||
continue_merge () {
|
||||
test -n "$prev_head" || die "prev_head must be defined"
|
||||
@@ -213,6 +214,10 @@ do
|
||||
-v|--verbose)
|
||||
verbose=t
|
||||
;;
|
||||
-C*)
|
||||
git_am_opt=$1
|
||||
shift
|
||||
;;
|
||||
-*)
|
||||
usage
|
||||
;;
|
||||
@@ -322,7 +327,7 @@ fi
|
||||
if test -z "$do_merge"
|
||||
then
|
||||
git-format-patch -k --stdout --full-index --ignore-if-in-upstream "$upstream"..ORIG_HEAD |
|
||||
git am --binary -3 -k --resolvemsg="$RESOLVEMSG"
|
||||
git am $git_am_opt --binary -3 -k --resolvemsg="$RESOLVEMSG"
|
||||
exit $?
|
||||
fi
|
||||
|
||||
|
||||
138
git-remote.perl
138
git-remote.perl
@@ -130,7 +130,7 @@ sub update_ls_remote {
|
||||
$info->{'LS_REMOTE'} = \@ref;
|
||||
}
|
||||
|
||||
sub show_wildcard_mapping {
|
||||
sub list_wildcard_mapping {
|
||||
my ($forced, $ours, $ls) = @_;
|
||||
my %refs;
|
||||
for (@$ls) {
|
||||
@@ -156,25 +156,14 @@ sub show_wildcard_mapping {
|
||||
push @tracked, $_;
|
||||
}
|
||||
}
|
||||
if (@new) {
|
||||
print " New remote branches (next fetch will store in remotes/$ours)\n";
|
||||
print " @new\n";
|
||||
}
|
||||
if (@stale) {
|
||||
print " Stale tracking branches in remotes/$ours (you'd better remove them)\n";
|
||||
print " @stale\n";
|
||||
}
|
||||
if (@tracked) {
|
||||
print " Tracked remote branches\n";
|
||||
print " @tracked\n";
|
||||
}
|
||||
return \@new, \@stale, \@tracked;
|
||||
}
|
||||
|
||||
sub show_mapping {
|
||||
sub list_mapping {
|
||||
my ($name, $info) = @_;
|
||||
my $fetch = $info->{'FETCH'};
|
||||
my $ls = $info->{'LS_REMOTE'};
|
||||
my (@stale, @tracked);
|
||||
my (@new, @stale, @tracked);
|
||||
|
||||
for (@$fetch) {
|
||||
next unless (/(\+)?([^:]+):(.*)/);
|
||||
@@ -182,7 +171,11 @@ sub show_mapping {
|
||||
if ($theirs eq 'refs/heads/*' &&
|
||||
$ours =~ /^refs\/remotes\/(.*)\/\*$/) {
|
||||
# wildcard mapping
|
||||
show_wildcard_mapping($forced, $1, $ls);
|
||||
my ($w_new, $w_stale, $w_tracked)
|
||||
= list_wildcard_mapping($forced, $1, $ls);
|
||||
push @new, @$w_new;
|
||||
push @stale, @$w_stale;
|
||||
push @tracked, @$w_tracked;
|
||||
}
|
||||
elsif ($theirs =~ /\*/ || $ours =~ /\*/) {
|
||||
print STDERR "Warning: unrecognized mapping in remotes.$name.fetch: $_\n";
|
||||
@@ -196,13 +189,40 @@ sub show_mapping {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (@stale) {
|
||||
print " Stale tracking branches in remotes/$name (you'd better remove them)\n";
|
||||
print " @stale\n";
|
||||
return \@new, \@stale, \@tracked;
|
||||
}
|
||||
|
||||
sub show_mapping {
|
||||
my ($name, $info) = @_;
|
||||
my ($new, $stale, $tracked) = list_mapping($name, $info);
|
||||
if (@$new) {
|
||||
print " New remote branches (next fetch will store in remotes/$name)\n";
|
||||
print " @$new\n";
|
||||
}
|
||||
if (@tracked) {
|
||||
if (@$stale) {
|
||||
print " Stale tracking branches in remotes/$name (use 'git remote prune')\n";
|
||||
print " @$stale\n";
|
||||
}
|
||||
if (@$tracked) {
|
||||
print " Tracked remote branches\n";
|
||||
print " @tracked\n";
|
||||
print " @$tracked\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub prune_remote {
|
||||
my ($name, $ls_remote) = @_;
|
||||
if (!exists $remote->{$name}) {
|
||||
print STDERR "No such remote $name\n";
|
||||
return;
|
||||
}
|
||||
my $info = $remote->{$name};
|
||||
update_ls_remote($ls_remote, $info);
|
||||
|
||||
my ($new, $stale, $tracked) = list_mapping($name, $info);
|
||||
my $prefix = "refs/remotes/$name";
|
||||
foreach my $to_prune (@$stale) {
|
||||
my @v = $git->command(qw(rev-parse --verify), "$prefix/$to_prune");
|
||||
$git->command(qw(update-ref -d), "$prefix/$to_prune", $v[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,14 +253,30 @@ sub show_remote {
|
||||
}
|
||||
|
||||
sub add_remote {
|
||||
my ($name, $url) = @_;
|
||||
my ($name, $url, $opts) = @_;
|
||||
if (exists $remote->{$name}) {
|
||||
print STDERR "remote $name already exists.\n";
|
||||
exit(1);
|
||||
}
|
||||
$git->command('config', "remote.$name.url", $url);
|
||||
$git->command('config', "remote.$name.fetch",
|
||||
"+refs/heads/*:refs/remotes/$name/*");
|
||||
my $track = $opts->{'track'} || ["*"];
|
||||
|
||||
for (@$track) {
|
||||
$git->command('config', '--add', "remote.$name.fetch",
|
||||
"+refs/heads/$_:refs/remotes/$name/$_");
|
||||
}
|
||||
if ($opts->{'fetch'}) {
|
||||
$git->command('fetch', $name);
|
||||
}
|
||||
if (exists $opts->{'master'}) {
|
||||
$git->command('symbolic-ref', "refs/remotes/$name/HEAD",
|
||||
"refs/remotes/$name/$opts->{'master'}");
|
||||
}
|
||||
}
|
||||
|
||||
sub add_usage {
|
||||
print STDERR "Usage: git remote add [-f] [-t track]* [-m master] <name> <url>\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!@ARGV) {
|
||||
@@ -267,16 +303,62 @@ elsif ($ARGV[0] eq 'show') {
|
||||
show_remote($ARGV[$i], $ls_remote);
|
||||
}
|
||||
}
|
||||
elsif ($ARGV[0] eq 'add') {
|
||||
if (@ARGV != 3) {
|
||||
print STDERR "Usage: git remote add <name> <url>\n";
|
||||
elsif ($ARGV[0] eq 'prune') {
|
||||
my $ls_remote = 1;
|
||||
my $i;
|
||||
for ($i = 1; $i < @ARGV; $i++) {
|
||||
if ($ARGV[$i] eq '-n') {
|
||||
$ls_remote = 0;
|
||||
}
|
||||
else {
|
||||
last;
|
||||
}
|
||||
}
|
||||
if ($i >= @ARGV) {
|
||||
print STDERR "Usage: git remote prune <remote>\n";
|
||||
exit(1);
|
||||
}
|
||||
add_remote($ARGV[1], $ARGV[2]);
|
||||
for (; $i < @ARGV; $i++) {
|
||||
prune_remote($ARGV[$i], $ls_remote);
|
||||
}
|
||||
}
|
||||
elsif ($ARGV[0] eq 'add') {
|
||||
my %opts = ();
|
||||
while (1 < @ARGV && $ARGV[1] =~ /^-/) {
|
||||
my $opt = $ARGV[1];
|
||||
shift @ARGV;
|
||||
if ($opt eq '-f' || $opt eq '--fetch') {
|
||||
$opts{'fetch'} = 1;
|
||||
next;
|
||||
}
|
||||
if ($opt eq '-t' || $opt eq '--track') {
|
||||
if (@ARGV < 1) {
|
||||
add_usage();
|
||||
}
|
||||
$opts{'track'} ||= [];
|
||||
push @{$opts{'track'}}, $ARGV[1];
|
||||
shift @ARGV;
|
||||
next;
|
||||
}
|
||||
if ($opt eq '-m' || $opt eq '--master') {
|
||||
if ((@ARGV < 1) || exists $opts{'master'}) {
|
||||
add_usage();
|
||||
}
|
||||
$opts{'master'} = $ARGV[1];
|
||||
shift @ARGV;
|
||||
next;
|
||||
}
|
||||
add_usage();
|
||||
}
|
||||
if (@ARGV != 3) {
|
||||
add_usage();
|
||||
}
|
||||
add_remote($ARGV[1], $ARGV[2], \%opts);
|
||||
}
|
||||
else {
|
||||
print STDERR "Usage: git remote\n";
|
||||
print STDERR " git remote add <name> <url>\n";
|
||||
print STDERR " git remote show <name>\n";
|
||||
print STDERR " git remote prune <name>\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -54,6 +54,8 @@ do
|
||||
shift
|
||||
done
|
||||
|
||||
set_reflog_action "$me"
|
||||
|
||||
test "$me,$replay" = "revert,t" && usage
|
||||
|
||||
case "$no_commit" in
|
||||
|
||||
@@ -48,7 +48,8 @@ cd_to_toplevel () {
|
||||
}
|
||||
|
||||
require_work_tree () {
|
||||
test $(is_bare_repository) = false ||
|
||||
test $(is_bare_repository) = false &&
|
||||
test $(git-rev-parse --is-inside-git-dir) = false ||
|
||||
die "fatal: $0 cannot be used without a working tree."
|
||||
}
|
||||
|
||||
|
||||
12
git-svn.perl
12
git-svn.perl
@@ -681,7 +681,7 @@ sub show_log {
|
||||
process_commit($_, $r_min, $r_max) foreach reverse @k;
|
||||
}
|
||||
out:
|
||||
eval { command_close_pipe($log) };
|
||||
close $log;
|
||||
print '-' x72,"\n" unless $_incremental || $_oneline;
|
||||
}
|
||||
|
||||
@@ -1475,7 +1475,7 @@ sub map_tree_joins {
|
||||
$seen{$commit} = 1;
|
||||
}
|
||||
}
|
||||
eval { command_close_pipe($pipe) };
|
||||
close $pipe;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1610,7 +1610,7 @@ sub read_repo_config {
|
||||
@$v = @tmp if @tmp;
|
||||
} else {
|
||||
chomp(my $tmp = `$arg --get svn.$key`);
|
||||
if ($tmp && !($arg =~ / --bool / && $tmp eq 'false')) {
|
||||
if ($tmp && !($arg =~ / --bool/ && $tmp eq 'false')) {
|
||||
$$v = $tmp;
|
||||
}
|
||||
}
|
||||
@@ -1669,7 +1669,7 @@ sub write_grafts {
|
||||
last unless /^\S/;
|
||||
}
|
||||
}
|
||||
eval { command_close_pipe($ch) }; # breaking the pipe
|
||||
close $ch; # breaking the pipe
|
||||
|
||||
# if real parents are the only ones in the grafts, drop it
|
||||
next if join(' ',sort keys %$p) eq join(' ',sort keys %x);
|
||||
@@ -1766,7 +1766,7 @@ sub get_commit_time {
|
||||
} elsif ($tz =~ s/^\-//) {
|
||||
$s -= tz_to_s_offset($tz);
|
||||
}
|
||||
eval { command_close_pipe($fh) };
|
||||
close $fh;
|
||||
return $s;
|
||||
}
|
||||
die "Can't get commit time for commit: $cmt\n";
|
||||
@@ -2846,7 +2846,7 @@ sub rmdirs {
|
||||
delete $rm->{join '/', @dn};
|
||||
}
|
||||
unless (%$rm) {
|
||||
eval { command_close_pipe($fh) };
|
||||
close $fh;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
24
git.c
24
git.c
@@ -163,6 +163,16 @@ static int handle_alias(int *argcp, const char ***argv)
|
||||
alias_command = (*argv)[0];
|
||||
git_config(git_alias_config);
|
||||
if (alias_string) {
|
||||
if (alias_string[0] == '!') {
|
||||
trace_printf("trace: alias to shell cmd: %s => %s\n",
|
||||
alias_command, alias_string + 1);
|
||||
ret = system(alias_string + 1);
|
||||
if (ret >= 0 && WIFEXITED(ret) &&
|
||||
WEXITSTATUS(ret) != 127)
|
||||
exit(WEXITSTATUS(ret));
|
||||
die("Failed to run '%s' when expanding alias '%s'\n",
|
||||
alias_string + 1, alias_command);
|
||||
}
|
||||
count = split_cmdline(alias_string, &new_argv);
|
||||
option_count = handle_options(&new_argv, &count);
|
||||
memmove(new_argv - option_count, new_argv,
|
||||
@@ -313,8 +323,9 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
|
||||
prefix = setup_git_directory();
|
||||
if (p->option & USE_PAGER)
|
||||
setup_pager();
|
||||
if ((p->option & NOT_BARE) && is_bare_repository())
|
||||
die("%s cannot be used in a bare git directory", cmd);
|
||||
if ((p->option & NOT_BARE) &&
|
||||
(is_bare_repository() || is_inside_git_dir()))
|
||||
die("%s must be run in a work tree", cmd);
|
||||
trace_argv_printf(argv, argc, "trace: built-in: git");
|
||||
|
||||
exit(p->fn(argc, argv, prefix));
|
||||
@@ -410,8 +421,15 @@ int main(int argc, const char **argv, char **envp)
|
||||
done_alias = 1;
|
||||
}
|
||||
|
||||
if (errno == ENOENT)
|
||||
if (errno == ENOENT) {
|
||||
if (done_alias) {
|
||||
fprintf(stderr, "Expansion of alias '%s' failed; "
|
||||
"'%s' is not a git-command\n",
|
||||
cmd, argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
help_unknown_cmd(cmd);
|
||||
}
|
||||
|
||||
fprintf(stderr, "Failed to run command '%s': %s\n",
|
||||
cmd, strerror(errno));
|
||||
|
||||
50
git.spec.in
50
git.spec.in
@@ -9,15 +9,12 @@ URL: http://kernel.org/pub/software/scm/git/
|
||||
Source: http://kernel.org/pub/software/scm/git/%{name}-%{version}.tar.gz
|
||||
BuildRequires: zlib-devel >= 1.2, openssl-devel, curl-devel, expat-devel %{!?_without_docs:, xmlto, asciidoc > 6.0.3}
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
|
||||
Requires: git-core, git-svn, git-cvs, git-arch, git-email, gitk, perl-Git
|
||||
Requires: git-core, git-svn, git-cvs, git-arch, git-email, gitk, git-gui, perl-Git
|
||||
|
||||
%description
|
||||
This is a stupid (but extremely fast) directory content manager. It
|
||||
doesn't do a whole lot, but what it _does_ do is track directory
|
||||
contents efficiently. It is intended to be the base of an efficient,
|
||||
distributed source code management system. This package includes
|
||||
rudimentary tools that can be used as a SCM, but you should look
|
||||
elsewhere for tools for ordinary humans layered on top of this.
|
||||
Git is a fast, scalable, distributed revision control system with an
|
||||
unusually rich command set that provides both high-level operations
|
||||
and full access to internals.
|
||||
|
||||
This is a dummy package which brings in all subpackages.
|
||||
|
||||
@@ -26,12 +23,9 @@ Summary: Core git tools
|
||||
Group: Development/Tools
|
||||
Requires: zlib >= 1.2, rsync, curl, less, openssh-clients, expat
|
||||
%description core
|
||||
This is a stupid (but extremely fast) directory content manager. It
|
||||
doesn't do a whole lot, but what it _does_ do is track directory
|
||||
contents efficiently. It is intended to be the base of an efficient,
|
||||
distributed source code management system. This package includes
|
||||
rudimentary tools that can be used as a SCM, but you should look
|
||||
elsewhere for tools for ordinary humans layered on top of this.
|
||||
Git is a fast, scalable, distributed revision control system with an
|
||||
unusually rich command set that provides both high-level operations
|
||||
and full access to internals.
|
||||
|
||||
These are the core tools with minimal dependencies.
|
||||
|
||||
@@ -63,6 +57,13 @@ Requires: git-core = %{version}-%{release}
|
||||
%description email
|
||||
Git tools for sending email.
|
||||
|
||||
%package gui
|
||||
Summary: Git GUI tool
|
||||
Group: Development/Tools
|
||||
Requires: git-core = %{version}-%{release}, tk >= 8.4
|
||||
%description gui
|
||||
Git GUI tool
|
||||
|
||||
%package -n gitk
|
||||
Summary: Git revision tree visualiser ('gitk')
|
||||
Group: Development/Tools
|
||||
@@ -89,17 +90,18 @@ make %{_smp_mflags} CFLAGS="$RPM_OPT_FLAGS" WITH_OWN_SUBPROCESS_PY=YesPlease \
|
||||
|
||||
%install
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
make %{_smp_mflags} DESTDIR=$RPM_BUILD_ROOT WITH_OWN_SUBPROCESS_PY=YesPlease \
|
||||
make %{_smp_mflags} CFLAGS="$RPM_OPT_FLAGS" DESTDIR=$RPM_BUILD_ROOT \
|
||||
WITH_OWN_SUBPROCESS_PY=YesPlease \
|
||||
prefix=%{_prefix} mandir=%{_mandir} INSTALLDIRS=vendor \
|
||||
install %{!?_without_docs: install-doc}
|
||||
find $RPM_BUILD_ROOT -type f -name .packlist -exec rm -f {} ';'
|
||||
find $RPM_BUILD_ROOT -type f -name '*.bs' -empty -exec rm -f {} ';'
|
||||
find $RPM_BUILD_ROOT -type f -name perllocal.pod -exec rm -f {} ';'
|
||||
|
||||
(find $RPM_BUILD_ROOT%{_bindir} -type f | grep -vE "archimport|svn|cvs|email|gitk" | sed -e s@^$RPM_BUILD_ROOT@@) > bin-man-doc-files
|
||||
(find $RPM_BUILD_ROOT%{_bindir} -type f | grep -vE "archimport|svn|cvs|email|gitk|git-gui|git-citool" | sed -e s@^$RPM_BUILD_ROOT@@) > bin-man-doc-files
|
||||
(find $RPM_BUILD_ROOT%{perl_vendorlib} -type f | sed -e s@^$RPM_BUILD_ROOT@@) >> perl-files
|
||||
%if %{!?_without_docs:1}0
|
||||
(find $RPM_BUILD_ROOT%{_mandir} $RPM_BUILD_ROOT/Documentation -type f | grep -vE "archimport|svn|git-cvs|email|gitk" | sed -e s@^$RPM_BUILD_ROOT@@ -e 's/$/*/' ) >> bin-man-doc-files
|
||||
(find $RPM_BUILD_ROOT%{_mandir} $RPM_BUILD_ROOT/Documentation -type f | grep -vE "archimport|svn|git-cvs|email|gitk|git-gui|git-citool" | sed -e s@^$RPM_BUILD_ROOT@@ -e 's/$/*/' ) >> bin-man-doc-files
|
||||
%else
|
||||
rm -rf $RPM_BUILD_ROOT%{_mandir}
|
||||
%endif
|
||||
@@ -138,6 +140,16 @@ rm -rf $RPM_BUILD_ROOT
|
||||
%{!?_without_docs: %{_mandir}/man1/*email*.1*}
|
||||
%{!?_without_docs: %doc Documentation/*email*.html }
|
||||
|
||||
%files gui
|
||||
%defattr(-,root,root)
|
||||
%{_bindir}/git-gui
|
||||
%{_bindir}/git-citool
|
||||
# Not Yet...
|
||||
# %{!?_without_docs: %{_mandir}/man1/git-gui.1}
|
||||
# %{!?_without_docs: %doc Documentation/git-gui.html}
|
||||
# %{!?_without_docs: %{_mandir}/man1/git-citool.1}
|
||||
# %{!?_without_docs: %doc Documentation/git-citool.html}
|
||||
|
||||
%files -n gitk
|
||||
%defattr(-,root,root)
|
||||
%doc Documentation/*gitk*.txt
|
||||
@@ -155,6 +167,12 @@ rm -rf $RPM_BUILD_ROOT
|
||||
%{!?_without_docs: %doc Documentation/*.html }
|
||||
|
||||
%changelog
|
||||
* Mon Feb 13 2007 Nicolas Pitre <nico@cam.org>
|
||||
- Update core package description (Git isn't as stupid as it used to be)
|
||||
|
||||
* Mon Feb 12 2007 Junio C Hamano <junkio@cox.net>
|
||||
- Add git-gui and git-citool.
|
||||
|
||||
* Mon Nov 14 2005 H. Peter Anvin <hpa@zytor.com> 0.99.9j-1
|
||||
- Change subpackage names to git-<name> instead of git-core-<name>
|
||||
- Create empty root package which brings in all subpackages
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user