Merge branch 'master' into js/shallow
This is to adjust to: count-objects -v: show number of packs as well. which will break a test in this series. Signed-off-by: Junio C Hamano <junkio@cox.net>
This commit is contained in:
commit
37818d7db0
6
.gitignore
vendored
6
.gitignore
vendored
@ -2,6 +2,7 @@ GIT-CFLAGS
|
||||
GIT-VERSION-FILE
|
||||
git
|
||||
git-add
|
||||
git-add--interactive
|
||||
git-am
|
||||
git-annotate
|
||||
git-apply
|
||||
@ -10,6 +11,7 @@ git-applypatch
|
||||
git-archimport
|
||||
git-archive
|
||||
git-bisect
|
||||
git-blame
|
||||
git-branch
|
||||
git-cat-file
|
||||
git-check-ref-format
|
||||
@ -60,13 +62,13 @@ git-mailsplit
|
||||
git-merge
|
||||
git-merge-base
|
||||
git-merge-index
|
||||
git-merge-file
|
||||
git-merge-tree
|
||||
git-merge-octopus
|
||||
git-merge-one-file
|
||||
git-merge-ours
|
||||
git-merge-recur
|
||||
git-merge-recursive
|
||||
git-merge-recursive-old
|
||||
git-merge-resolve
|
||||
git-merge-stupid
|
||||
git-mktag
|
||||
@ -87,6 +89,7 @@ git-quiltimport
|
||||
git-read-tree
|
||||
git-rebase
|
||||
git-receive-pack
|
||||
git-reflog
|
||||
git-relink
|
||||
git-repack
|
||||
git-repo-config
|
||||
@ -152,4 +155,3 @@ config.status
|
||||
config.mak.autogen
|
||||
config.mak.append
|
||||
configure
|
||||
git-blame
|
||||
|
37
.mailmap
Normal file
37
.mailmap
Normal file
@ -0,0 +1,37 @@
|
||||
#
|
||||
# This list is used by git-shortlog to fix a few botched name translations
|
||||
# in the git archive, either because the author's full name was messed up
|
||||
# and/or not always written the same way, making contributions from the
|
||||
# same person appearing not to be so.
|
||||
#
|
||||
|
||||
Aneesh Kumar K.V <aneesh.kumar@gmail.com>
|
||||
Chris Shoemaker <c.shoemaker@cox.net>
|
||||
Daniel Barkalow <barkalow@iabervon.org>
|
||||
David Kågedal <davidk@lysator.liu.se>
|
||||
Fredrik Kuivinen <freku045@student.liu.se>
|
||||
H. Peter Anvin <hpa@bonde.sc.orionmulti.com>
|
||||
H. Peter Anvin <hpa@tazenda.sc.orionmulti.com>
|
||||
H. Peter Anvin <hpa@trantor.hos.anvin.org>
|
||||
Horst H. von Brand <vonbrand@inf.utfsm.cl>
|
||||
Joachim Berdal Haga <cjhaga@fys.uio.no>
|
||||
Jon Loeliger <jdl@freescale.com>
|
||||
Jon Seymour <jon@blackcubes.dyndns.org>
|
||||
Karl Hasselström <kha@treskal.com>
|
||||
Kent Engstrom <kent@lysator.liu.se>
|
||||
Lars Doelle <lars.doelle@on-line.de>
|
||||
Lars Doelle <lars.doelle@on-line ! de>
|
||||
Lukas Sandström <lukass@etek.chalmers.se>
|
||||
Martin Langhoff <martin@catalyst.net.nz>
|
||||
Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
|
||||
Ramsay Allan Jones <ramsay@ramsay1.demon.co.uk>
|
||||
René Scharfe <rene.scharfe@lsrfire.ath.cx>
|
||||
Robert Fitzsimons <robfitz@273k.net>
|
||||
Santi Béjar <sbejar@gmail.com>
|
||||
Sean Estabrooks <seanlkml@sympatico.ca>
|
||||
Shawn O. Pearce <spearce@spearce.org>
|
||||
Tony Luck <tony.luck@intel.com>
|
||||
Ville Skyttä <scop@xemacs.org>
|
||||
YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
|
||||
anonymous <linux@horizon.com>
|
||||
anonymous <linux@horizon.net>
|
@ -32,6 +32,7 @@ man7dir=$(mandir)/man7
|
||||
# DESTDIR=
|
||||
|
||||
INSTALL?=install
|
||||
DOC_REF = origin/man
|
||||
|
||||
-include ../config.mak.autogen
|
||||
|
||||
@ -56,8 +57,8 @@ man7: $(DOC_MAN7)
|
||||
|
||||
install: man
|
||||
$(INSTALL) -d -m755 $(DESTDIR)$(man1dir) $(DESTDIR)$(man7dir)
|
||||
$(INSTALL) $(DOC_MAN1) $(DESTDIR)$(man1dir)
|
||||
$(INSTALL) $(DOC_MAN7) $(DESTDIR)$(man7dir)
|
||||
$(INSTALL) -m644 $(DOC_MAN1) $(DESTDIR)$(man1dir)
|
||||
$(INSTALL) -m644 $(DOC_MAN7) $(DESTDIR)$(man7dir)
|
||||
|
||||
|
||||
#
|
||||
@ -112,3 +113,6 @@ $(patsubst %.txt,%.html,$(wildcard howto/*.txt)): %.html : %.txt
|
||||
|
||||
install-webdoc : html
|
||||
sh ./install-webdoc.sh $(WEBDOC_DEST)
|
||||
|
||||
quick-install:
|
||||
sh ./install-doc-quick.sh $(DOC_REF) $(mandir)
|
||||
|
@ -13,4 +13,18 @@
|
||||
<xsl:apply-templates/>
|
||||
<xsl:text>.br </xsl:text>
|
||||
</xsl:template>
|
||||
|
||||
<!-- sorry, this is not about callouts, but attempts to work around
|
||||
spurious .sp at the tail of the line docbook stylesheets seem to add -->
|
||||
<xsl:template match="simpara">
|
||||
<xsl:variable name="content">
|
||||
<xsl:apply-templates/>
|
||||
</xsl:variable>
|
||||
<xsl:value-of select="normalize-space($content)"/>
|
||||
<xsl:if test="not(ancestor::authorblurb) and
|
||||
not(ancestor::personblurb)">
|
||||
<xsl:text> </xsl:text>
|
||||
</xsl:if>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
||||
|
@ -31,6 +31,11 @@ Example
|
||||
external = "/usr/local/bin/gnu-diff -u"
|
||||
renames = true
|
||||
|
||||
[branch "devel"]
|
||||
remote = origin
|
||||
merge = refs/heads/devel
|
||||
|
||||
|
||||
Variables
|
||||
~~~~~~~~~
|
||||
|
||||
@ -79,8 +84,11 @@ core.logAllRefUpdates::
|
||||
file is automatically created for branch heads.
|
||||
|
||||
This information can be used to determine what commit
|
||||
was the tip of a branch "2 days ago". This value is
|
||||
false by default (no automated creation of log files).
|
||||
was the tip of a branch "2 days ago".
|
||||
|
||||
This value is true by default in a repository that has
|
||||
a working directory associated with it, and false by
|
||||
default in a bare repository.
|
||||
|
||||
core.repositoryFormatVersion::
|
||||
Internal variable identifying the repository format and layout
|
||||
@ -125,21 +133,24 @@ apply.whitespace::
|
||||
|
||||
branch.<name>.remote::
|
||||
When in branch <name>, it tells `git fetch` which remote to fetch.
|
||||
If this option is not given, `git fetch` defaults to remote "origin".
|
||||
|
||||
branch.<name>.merge::
|
||||
When in branch <name>, it tells `git fetch` the default remote branch
|
||||
to be merged.
|
||||
When in branch <name>, it tells `git fetch` the default refspec to
|
||||
be marked for merging in FETCH_HEAD. The value has exactly to match
|
||||
a remote part of one of the refspecs which are fetched from the remote
|
||||
given by "branch.<name>.remote".
|
||||
The merge information is used by `git pull` (which at first calls
|
||||
`git fetch`) to lookup the default branch for merging. Without
|
||||
this option, `git pull` defaults to merge the first refspec fetched.
|
||||
Specify multiple values to get an octopus merge.
|
||||
|
||||
pager.color::
|
||||
A boolean to enable/disable colored output when the pager is in
|
||||
use (default is true).
|
||||
|
||||
diff.color::
|
||||
color.diff::
|
||||
When true (or `always`), always use colors in patch.
|
||||
When false (or `never`), never. When set to `auto`, use
|
||||
colors only when the output is to the terminal.
|
||||
|
||||
diff.color.<slot>::
|
||||
color.diff.<slot>::
|
||||
Use customized color for diff colorization. `<slot>`
|
||||
specifies which part of the patch to use the specified
|
||||
color, and is one of `plain` (context text), `meta`
|
||||
@ -150,6 +161,24 @@ diff.color.<slot>::
|
||||
`red`, `green`, `yellow`, `blue`, `magenta`, `cyan`, or
|
||||
`white`.
|
||||
|
||||
color.pager::
|
||||
A boolean to enable/disable colored output when the pager is in
|
||||
use (default is true).
|
||||
|
||||
color.status::
|
||||
A boolean to enable/disable color in the output of
|
||||
gitlink:git-status[1]. May be set to `true` (or `always`),
|
||||
`false` (or `never`) or `auto`, in which case colors are used
|
||||
only when the output is to a terminal. Defaults to false.
|
||||
|
||||
color.status.<slot>::
|
||||
Use customized color for status colorization. `<slot>` is
|
||||
one of `header` (the header text of the status message),
|
||||
`added` or `updated` (files which are added but not committed),
|
||||
`changed` (files which are changed but not added in the index),
|
||||
or `untracked` (files which are not tracked by git). The values of
|
||||
these variables may be specified as in color.diff.<slot>.
|
||||
|
||||
diff.renameLimit::
|
||||
The number of files to consider when performing the copy/rename
|
||||
detection; equivalent to the git diff option '-l'.
|
||||
@ -264,20 +293,6 @@ showbranch.default::
|
||||
The default set of branches for gitlink:git-show-branch[1].
|
||||
See gitlink:git-show-branch[1].
|
||||
|
||||
status.color::
|
||||
A boolean to enable/disable color in the output of
|
||||
gitlink:git-status[1]. May be set to `true` (or `always`),
|
||||
`false` (or `never`) or `auto`, in which case colors are used
|
||||
only when the output is to a terminal. Defaults to false.
|
||||
|
||||
status.color.<slot>::
|
||||
Use customized color for status colorization. `<slot>` is
|
||||
one of `header` (the header text of the status message),
|
||||
`updated` (files which are updated but not committed),
|
||||
`changed` (files which are changed but not updated in the index),
|
||||
or `untracked` (files which are not tracked by git). The values of
|
||||
these variables may be specified as in diff.color.<slot>.
|
||||
|
||||
tar.umask::
|
||||
By default, gitlink:git-tar-tree[1] sets file and directories modes
|
||||
to 0666 or 0777. While this is both useful and acceptable for projects
|
||||
|
@ -57,7 +57,7 @@ $ git-init-db
|
||||
to which git will reply
|
||||
|
||||
----------------
|
||||
defaulting to local storage area
|
||||
Initialized empty Git repository in .git/
|
||||
----------------
|
||||
|
||||
which is just git's way of saying that you haven't been doing anything
|
||||
@ -336,17 +336,9 @@ $ commit=$(echo 'Initial commit' | git-commit-tree $tree)
|
||||
$ git-update-ref HEAD $commit
|
||||
------------------------------------------------
|
||||
|
||||
which will say:
|
||||
|
||||
----------------
|
||||
Committing initial tree 8988da15d077d4829fc51d8544c097def6644dbb
|
||||
----------------
|
||||
|
||||
just to warn you about the fact that it created a totally new commit
|
||||
that is not related to anything else. Normally you do this only *once*
|
||||
for a project ever, and all later commits will be parented on top of an
|
||||
earlier commit, and you'll never see this "Committing initial tree"
|
||||
message ever again.
|
||||
In this case this creates a totally new commit that is not related to
|
||||
anything else. Normally you do this only *once* for a project ever, and
|
||||
all later commits will be parented on top of an earlier commit.
|
||||
|
||||
Again, normally you'd never actually do this by hand. There is a
|
||||
helpful script called `git commit` that will do all of this for you. So
|
||||
|
@ -1,43 +1,122 @@
|
||||
git for CVS users
|
||||
=================
|
||||
|
||||
So you're a CVS user. That's OK, it's a treatable condition. The job of
|
||||
this document is to put you on the road to recovery, by helping you
|
||||
convert an existing cvs repository to git, and by showing you how to use a
|
||||
git repository in a cvs-like fashion.
|
||||
Git differs from CVS in that every working tree contains a repository with
|
||||
a full copy of the project history, and no repository is inherently more
|
||||
important than any other. However, you can emulate the CVS model by
|
||||
designating a single shared repository which people can synchronize with;
|
||||
this document explains how to do that.
|
||||
|
||||
Some basic familiarity with git is required. This
|
||||
link:tutorial.html[tutorial introduction to git] should be sufficient.
|
||||
|
||||
First, note some ways that git differs from CVS:
|
||||
Developing against a shared repository
|
||||
--------------------------------------
|
||||
|
||||
* Commits are atomic and project-wide, not per-file as in CVS.
|
||||
Suppose a shared repository is set up in /pub/repo.git on the host
|
||||
foo.com. Then as an individual committer you can clone the shared
|
||||
repository over ssh with:
|
||||
|
||||
* Offline work is supported: you can make multiple commits locally,
|
||||
then submit them when you're ready.
|
||||
------------------------------------------------
|
||||
$ git clone foo.com:/pub/repo.git/ my-project
|
||||
$ cd my-project
|
||||
------------------------------------------------
|
||||
|
||||
* Branching is fast and easy.
|
||||
and hack away. The equivalent of `cvs update` is
|
||||
|
||||
* Every working tree contains a repository with a full copy of the
|
||||
project history, and no repository is inherently more important than
|
||||
any other. However, you can emulate the CVS model by designating a
|
||||
single shared repository which people can synchronize with; see below
|
||||
for details.
|
||||
------------------------------------------------
|
||||
$ git pull origin
|
||||
------------------------------------------------
|
||||
|
||||
which merges in any work that others might have done since the clone
|
||||
operation. If there are uncommitted changes in your working tree, commit
|
||||
them first before running git pull.
|
||||
|
||||
[NOTE]
|
||||
================================
|
||||
The first `git clone` places the following in the
|
||||
`my-project/.git/remotes/origin` file, and that's why the previous step
|
||||
and the next step both work.
|
||||
------------
|
||||
URL: foo.com:/pub/project.git/
|
||||
Pull: refs/heads/master:refs/remotes/origin/master
|
||||
------------
|
||||
================================
|
||||
|
||||
You can update the shared repository with your changes by first committing
|
||||
your changes, and then using the gitlink:git-push[1] command:
|
||||
|
||||
------------------------------------------------
|
||||
$ git push origin master
|
||||
------------------------------------------------
|
||||
|
||||
to "push" those commits to the shared repository. If someone else has
|
||||
updated the repository more recently, `git push`, like `cvs commit`, will
|
||||
complain, in which case you must pull any changes before attempting the
|
||||
push again.
|
||||
|
||||
In the `git push` command above we specify the name of the remote branch
|
||||
to update (`master`). If we leave that out, `git push` tries to update
|
||||
any branches in the remote repository that have the same name as a branch
|
||||
in the local repository. So the last `push` can be done with either of:
|
||||
|
||||
------------
|
||||
$ git push origin
|
||||
$ git push foo.com:/pub/project.git/
|
||||
------------
|
||||
|
||||
as long as the shared repository does not have any branches
|
||||
other than `master`.
|
||||
|
||||
Setting Up a Shared Repository
|
||||
------------------------------
|
||||
|
||||
We assume you have already created a git repository for your project,
|
||||
possibly created from scratch or from a tarball (see the
|
||||
link:tutorial.html[tutorial]), or imported from an already existing CVS
|
||||
repository (see the next section).
|
||||
|
||||
Assume your existing repo is at /home/alice/myproject. Create a new "bare"
|
||||
repository (a repository without a working tree) and fetch your project into
|
||||
it:
|
||||
|
||||
------------------------------------------------
|
||||
$ mkdir /pub/my-repo.git
|
||||
$ cd /pub/my-repo.git
|
||||
$ git --bare init-db --shared
|
||||
$ git --bare fetch /home/alice/myproject master:master
|
||||
------------------------------------------------
|
||||
|
||||
Next, give every team member read/write access to this repository. One
|
||||
easy way to do this is to give all the team members ssh access to the
|
||||
machine where the repository is hosted. If you don't want to give them a
|
||||
full shell on the machine, there is a restricted shell which only allows
|
||||
users to do git pushes and pulls; see gitlink:git-shell[1].
|
||||
|
||||
Put all the committers in the same group, and make the repository
|
||||
writable by that group:
|
||||
|
||||
------------------------------------------------
|
||||
$ chgrp -R $group /pub/my-repo.git
|
||||
------------------------------------------------
|
||||
|
||||
Make sure committers have a umask of at most 027, so that the directories
|
||||
they create are writable and searchable by other group members.
|
||||
|
||||
Importing a CVS archive
|
||||
-----------------------
|
||||
|
||||
First, install version 2.1 or higher of cvsps from
|
||||
link:http://www.cobite.com/cvsps/[http://www.cobite.com/cvsps/] and make
|
||||
sure it is in your path. The magic command line is then
|
||||
sure it is in your path. Then cd to a checked out CVS working directory
|
||||
of the project you are interested in and run gitlink:git-cvsimport[1]:
|
||||
|
||||
-------------------------------------------
|
||||
$ git cvsimport -v -d <cvsroot> -C <destination> <module>
|
||||
$ git cvsimport -C <destination>
|
||||
-------------------------------------------
|
||||
|
||||
This puts a git archive of the named CVS module in the directory
|
||||
<destination>, which will be created if necessary. The -v option makes
|
||||
the conversion script very chatty.
|
||||
<destination>, which will be created if necessary.
|
||||
|
||||
The import checks out from CVS every revision of every file. Reportedly
|
||||
cvsimport can average some twenty revisions per second, so for a
|
||||
@ -55,14 +134,32 @@ work, you must not modify the imported branches; instead, create new
|
||||
branches for your own changes, and merge in the imported branches as
|
||||
necessary.
|
||||
|
||||
Development Models
|
||||
------------------
|
||||
Advanced Shared Repository Management
|
||||
-------------------------------------
|
||||
|
||||
Git allows you to specify scripts called "hooks" to be run at certain
|
||||
points. You can use these, for example, to send all commits to the shared
|
||||
repository to a mailing list. See link:hooks.html[Hooks used by git].
|
||||
|
||||
You can enforce finer grained permissions using update hooks. See
|
||||
link:howto/update-hook-example.txt[Controlling access to branches using
|
||||
update hooks].
|
||||
|
||||
Providing CVS Access to a git Repository
|
||||
----------------------------------------
|
||||
|
||||
It is also possible to provide true CVS access to a git repository, so
|
||||
that developers can still use CVS; see gitlink:git-cvsserver[1] for
|
||||
details.
|
||||
|
||||
Alternative Development Models
|
||||
------------------------------
|
||||
|
||||
CVS users are accustomed to giving a group of developers commit access to
|
||||
a common repository. In the next section we'll explain how to do this
|
||||
with git. However, the distributed nature of git allows other development
|
||||
models, and you may want to first consider whether one of them might be a
|
||||
better fit for your project.
|
||||
a common repository. As we've seen, this is also possible with git.
|
||||
However, the distributed nature of git allows other development models,
|
||||
and you may want to first consider whether one of them might be a better
|
||||
fit for your project.
|
||||
|
||||
For example, you can choose a single person to maintain the project's
|
||||
primary public repository. Other developers then clone this repository
|
||||
@ -75,230 +172,3 @@ variants of this model.
|
||||
|
||||
With a small group, developers may just pull changes from each other's
|
||||
repositories without the need for a central maintainer.
|
||||
|
||||
Emulating the CVS Development Model
|
||||
-----------------------------------
|
||||
|
||||
Start with an ordinary git working directory containing the project, and
|
||||
remove the checked-out files, keeping just the bare .git directory:
|
||||
|
||||
------------------------------------------------
|
||||
$ mv project/.git /pub/repo.git
|
||||
$ rm -r project/
|
||||
------------------------------------------------
|
||||
|
||||
Next, give every team member read/write access to this repository. One
|
||||
easy way to do this is to give all the team members ssh access to the
|
||||
machine where the repository is hosted. If you don't want to give them a
|
||||
full shell on the machine, there is a restricted shell which only allows
|
||||
users to do git pushes and pulls; see gitlink:git-shell[1].
|
||||
|
||||
Put all the committers in the same group, and make the repository
|
||||
writable by that group:
|
||||
|
||||
------------------------------------------------
|
||||
$ chgrp -R $group repo.git
|
||||
$ find repo.git -mindepth 1 -type d |xargs chmod ug+rwx,g+s
|
||||
$ GIT_DIR=repo.git git repo-config core.sharedrepository true
|
||||
------------------------------------------------
|
||||
|
||||
Make sure committers have a umask of at most 027, so that the directories
|
||||
they create are writable and searchable by other group members.
|
||||
|
||||
Suppose this repository is now set up in /pub/repo.git on the host
|
||||
foo.com. Then as an individual committer you can clone the shared
|
||||
repository:
|
||||
|
||||
------------------------------------------------
|
||||
$ git clone foo.com:/pub/repo.git/ my-project
|
||||
$ cd my-project
|
||||
------------------------------------------------
|
||||
|
||||
and hack away. The equivalent of `cvs update` is
|
||||
|
||||
------------------------------------------------
|
||||
$ git pull origin
|
||||
------------------------------------------------
|
||||
|
||||
which merges in any work that others might have done since the clone
|
||||
operation.
|
||||
|
||||
[NOTE]
|
||||
================================
|
||||
The first `git clone` places the following in the
|
||||
`my-project/.git/remotes/origin` file, and that's why the previous step
|
||||
and the next step both work.
|
||||
------------
|
||||
URL: foo.com:/pub/project.git/ my-project
|
||||
Pull: master:origin
|
||||
------------
|
||||
================================
|
||||
|
||||
You can update the shared repository with your changes using:
|
||||
|
||||
------------------------------------------------
|
||||
$ git push origin master
|
||||
------------------------------------------------
|
||||
|
||||
If someone else has updated the repository more recently, `git push`, like
|
||||
`cvs commit`, will complain, in which case you must pull any changes
|
||||
before attempting the push again.
|
||||
|
||||
In the `git push` command above we specify the name of the remote branch
|
||||
to update (`master`). If we leave that out, `git push` tries to update
|
||||
any branches in the remote repository that have the same name as a branch
|
||||
in the local repository. So the last `push` can be done with either of:
|
||||
|
||||
------------
|
||||
$ git push origin
|
||||
$ git push repo.shared.xz:/pub/scm/project.git/
|
||||
------------
|
||||
|
||||
as long as the shared repository does not have any branches
|
||||
other than `master`.
|
||||
|
||||
[NOTE]
|
||||
============
|
||||
Because of this behavior, if the shared repository and the developer's
|
||||
repository both have branches named `origin`, then a push like the above
|
||||
attempts to update the `origin` branch in the shared repository from the
|
||||
developer's `origin` branch. The results may be unexpected, so it's
|
||||
usually best to remove any branch named `origin` from the shared
|
||||
repository.
|
||||
============
|
||||
|
||||
Advanced Shared Repository Management
|
||||
-------------------------------------
|
||||
|
||||
Git allows you to specify scripts called "hooks" to be run at certain
|
||||
points. You can use these, for example, to send all commits to the shared
|
||||
repository to a mailing list. See link:hooks.html[Hooks used by git].
|
||||
|
||||
You can enforce finer grained permissions using update hooks. See
|
||||
link:howto/update-hook-example.txt[Controlling access to branches using
|
||||
update hooks].
|
||||
|
||||
CVS annotate
|
||||
------------
|
||||
|
||||
So, something has gone wrong, and you don't know whom to blame, and
|
||||
you're an ex-CVS user and used to do "cvs annotate" to see who caused
|
||||
the breakage. You're looking for the "git annotate", and it's just
|
||||
claiming not to find such a script. You're annoyed.
|
||||
|
||||
Yes, that's right. Core git doesn't do "annotate", although it's
|
||||
technically possible, and there are at least two specialized scripts out
|
||||
there that can be used to get equivalent information (see the git
|
||||
mailing list archives for details).
|
||||
|
||||
git has a couple of alternatives, though, that you may find sufficient
|
||||
or even superior depending on your use. One is called "git-whatchanged"
|
||||
(for obvious reasons) and the other one is called "pickaxe" ("a tool for
|
||||
the software archaeologist").
|
||||
|
||||
The "git-whatchanged" script is a truly trivial script that can give you
|
||||
a good overview of what has changed in a file or a directory (or an
|
||||
arbitrary list of files or directories). The "pickaxe" support is an
|
||||
additional layer that can be used to further specify exactly what you're
|
||||
looking for, if you already know the specific area that changed.
|
||||
|
||||
Let's step back a bit and think about the reason why you would
|
||||
want to do "cvs annotate a-file.c" to begin with.
|
||||
|
||||
You would use "cvs annotate" on a file when you have trouble
|
||||
with a function (or even a single "if" statement in a function)
|
||||
that happens to be defined in the file, which does not do what
|
||||
you want it to do. And you would want to find out why it was
|
||||
written that way, because you are about to modify it to suit
|
||||
your needs, and at the same time you do not want to break its
|
||||
current callers. For that, you are trying to find out why the
|
||||
original author did things that way in the original context.
|
||||
|
||||
Many times, it may be enough to see the commit log messages of
|
||||
commits that touch the file in question, possibly along with the
|
||||
patches themselves, like this:
|
||||
|
||||
$ git-whatchanged -p a-file.c
|
||||
|
||||
This will show log messages and patches for each commit that
|
||||
touches a-file.
|
||||
|
||||
This, however, may not be very useful when this file has many
|
||||
modifications that are not related to the piece of code you are
|
||||
interested in. You would see many log messages and patches that
|
||||
do not have anything to do with the piece of code you are
|
||||
interested in. As an example, assuming that you have this piece
|
||||
of code that you are interested in in the HEAD version:
|
||||
|
||||
if (frotz) {
|
||||
nitfol();
|
||||
}
|
||||
|
||||
you would use git-rev-list and git-diff-tree like this:
|
||||
|
||||
$ git-rev-list HEAD |
|
||||
git-diff-tree --stdin -v -p -S'if (frotz) {
|
||||
nitfol();
|
||||
}'
|
||||
|
||||
We have already talked about the "\--stdin" form of git-diff-tree
|
||||
command that reads the list of commits and compares each commit
|
||||
with its parents (otherwise you should go back and read the tutorial).
|
||||
The git-whatchanged command internally runs
|
||||
the equivalent of the above command, and can be used like this:
|
||||
|
||||
$ git-whatchanged -p -S'if (frotz) {
|
||||
nitfol();
|
||||
}'
|
||||
|
||||
When the -S option is used, git-diff-tree command outputs
|
||||
differences between two commits only if one tree has the
|
||||
specified string in a file and the corresponding file in the
|
||||
other tree does not. The above example looks for a commit that
|
||||
has the "if" statement in it in a file, but its parent commit
|
||||
does not have it in the same shape in the corresponding file (or
|
||||
the other way around, where the parent has it and the commit
|
||||
does not), and the differences between them are shown, along
|
||||
with the commit message (thanks to the -v flag). It does not
|
||||
show anything for commits that do not touch this "if" statement.
|
||||
|
||||
Also, in the original context, the same statement might have
|
||||
appeared at first in a different file and later the file was
|
||||
renamed to "a-file.c". CVS annotate would not help you to go
|
||||
back across such a rename, but git would still help you in such
|
||||
a situation. For that, you can give the -C flag to
|
||||
git-diff-tree, like this:
|
||||
|
||||
$ git-whatchanged -p -C -S'if (frotz) {
|
||||
nitfol();
|
||||
}'
|
||||
|
||||
When the -C flag is used, file renames and copies are followed.
|
||||
So if the "if" statement in question happens to be in "a-file.c"
|
||||
in the current HEAD commit, even if the file was originally
|
||||
called "o-file.c" and then renamed in an earlier commit, or if
|
||||
the file was created by copying an existing "o-file.c" in an
|
||||
earlier commit, you will not lose track. If the "if" statement
|
||||
did not change across such a rename or copy, then the commit that
|
||||
does rename or copy would not show in the output, and if the
|
||||
"if" statement was modified while the file was still called
|
||||
"o-file.c", it would find the commit that changed the statement
|
||||
when it was in "o-file.c".
|
||||
|
||||
NOTE: The current version of "git-diff-tree -C" is not eager
|
||||
enough to find copies, and it will miss the fact that a-file.c
|
||||
was created by copying o-file.c unless o-file.c was somehow
|
||||
changed in the same commit.
|
||||
|
||||
You can use the --pickaxe-all flag in addition to the -S flag.
|
||||
This causes the differences from all the files contained in
|
||||
those two commits, not just the differences between the files
|
||||
that contain this changed "if" statement:
|
||||
|
||||
$ git-whatchanged -p -C -S'if (frotz) {
|
||||
nitfol();
|
||||
}' --pickaxe-all
|
||||
|
||||
NOTE: This option is called "--pickaxe-all" because -S
|
||||
option is internally called "pickaxe", a tool for software
|
||||
archaeologists.
|
||||
|
@ -65,62 +65,17 @@ Generating patches with -p
|
||||
|
||||
When "git-diff-index", "git-diff-tree", or "git-diff-files" are run
|
||||
with a '-p' option, they do not produce the output described above;
|
||||
instead they produce a patch file.
|
||||
instead they produce a patch file. You can customize the creation
|
||||
of such patches via the GIT_EXTERNAL_DIFF and the GIT_DIFF_OPTS
|
||||
environment variables.
|
||||
|
||||
The patch generation can be customized at two levels.
|
||||
|
||||
1. When the environment variable 'GIT_EXTERNAL_DIFF' is not set,
|
||||
these commands internally invoke "diff" like this:
|
||||
|
||||
diff -L a/<path> -L b/<path> -pu <old> <new>
|
||||
+
|
||||
For added files, `/dev/null` is used for <old>. For removed
|
||||
files, `/dev/null` is used for <new>
|
||||
+
|
||||
The "diff" formatting options can be customized via the
|
||||
environment variable 'GIT_DIFF_OPTS'. For example, if you
|
||||
prefer context diff:
|
||||
|
||||
GIT_DIFF_OPTS=-c git-diff-index -p HEAD
|
||||
|
||||
|
||||
2. When the environment variable 'GIT_EXTERNAL_DIFF' is set, the
|
||||
program named by it is called, instead of the diff invocation
|
||||
described above.
|
||||
+
|
||||
For a path that is added, removed, or modified,
|
||||
'GIT_EXTERNAL_DIFF' is called with 7 parameters:
|
||||
|
||||
path old-file old-hex old-mode new-file new-hex new-mode
|
||||
+
|
||||
where:
|
||||
|
||||
<old|new>-file:: are files GIT_EXTERNAL_DIFF can use to read the
|
||||
contents of <old|new>,
|
||||
<old|new>-hex:: are the 40-hexdigit SHA1 hashes,
|
||||
<old|new>-mode:: are the octal representation of the file modes.
|
||||
|
||||
+
|
||||
The file parameters can point at the user's working file
|
||||
(e.g. `new-file` in "git-diff-files"), `/dev/null` (e.g. `old-file`
|
||||
when a new file is added), or a temporary file (e.g. `old-file` in the
|
||||
index). 'GIT_EXTERNAL_DIFF' should not worry about unlinking the
|
||||
temporary file --- it is removed when 'GIT_EXTERNAL_DIFF' exits.
|
||||
|
||||
For a path that is unmerged, 'GIT_EXTERNAL_DIFF' is called with 1
|
||||
parameter, <path>.
|
||||
|
||||
|
||||
git specific extension to diff format
|
||||
-------------------------------------
|
||||
|
||||
What -p option produces is slightly different from the
|
||||
traditional diff format.
|
||||
What the -p option produces is slightly different from the traditional
|
||||
diff format.
|
||||
|
||||
1. It is preceded with a "git diff" header, that looks like
|
||||
this:
|
||||
|
||||
diff --git a/file1 b/file2
|
||||
diff --git a/file1 b/file2
|
||||
+
|
||||
The `a/` and `b/` filenames are the same unless rename/copy is
|
||||
involved. Especially, even for a creation or a deletion,
|
||||
|
@ -19,7 +19,14 @@
|
||||
--numstat::
|
||||
Similar to \--stat, but shows number of added and
|
||||
deleted lines in decimal notation and pathname without
|
||||
abbreviation, to make it more machine friendly.
|
||||
abbreviation, to make it more machine friendly. For
|
||||
binary files, outputs two `-` instead of saying
|
||||
`0 0`.
|
||||
|
||||
--shortstat::
|
||||
Output only the last line of the --stat format containing total
|
||||
number of modified files, as well as number of added and deleted
|
||||
lines.
|
||||
|
||||
--summary::
|
||||
Output a condensed summary of extended header information
|
||||
@ -129,5 +136,21 @@
|
||||
-a::
|
||||
Shorthand for "--text".
|
||||
|
||||
--ignore-space-change::
|
||||
Ignore changes in amount of white space. This ignores white
|
||||
space at line end, and consider all other sequences of one or
|
||||
more white space characters to be equivalent.
|
||||
|
||||
-b::
|
||||
Shorthand for "--ignore-space-change".
|
||||
|
||||
--ignore-all-space::
|
||||
Ignore white space when comparing lines. This ignores
|
||||
difference even if one line has white space where the other
|
||||
line has none.
|
||||
|
||||
-w::
|
||||
Shorthand for "--ignore-all-space".
|
||||
|
||||
For more detailed explanation on these common options, see also
|
||||
link:diffcore.html[diffcore documentation].
|
||||
|
@ -47,11 +47,11 @@ $ git repack <3>
|
||||
$ git prune <4>
|
||||
------------
|
||||
+
|
||||
<1> running without "--full" is usually cheap and assures the
|
||||
<1> running without `\--full` is usually cheap and assures the
|
||||
repository health reasonably well.
|
||||
<2> check how many loose objects there are and how much
|
||||
disk space is wasted by not repacking.
|
||||
<3> without "-a" repacks incrementally. repacking every 4-5MB
|
||||
<3> without `-a` repacks incrementally. repacking every 4-5MB
|
||||
of loose objects accumulation may be a good rule of thumb.
|
||||
<4> after repack, prune removes the duplicate loose objects.
|
||||
|
||||
@ -80,8 +80,7 @@ following commands.
|
||||
* gitlink:git-checkout[1] and gitlink:git-branch[1] to switch
|
||||
branches.
|
||||
|
||||
* gitlink:git-add[1] and gitlink:git-update-index[1] to manage
|
||||
the index file.
|
||||
* gitlink:git-add[1] to manage the index file.
|
||||
|
||||
* gitlink:git-diff[1] and gitlink:git-status[1] to see what
|
||||
you are in the middle of doing.
|
||||
@ -91,8 +90,7 @@ following commands.
|
||||
* gitlink:git-reset[1] and gitlink:git-checkout[1] (with
|
||||
pathname parameters) to undo changes.
|
||||
|
||||
* gitlink:git-pull[1] with "." as the remote to merge between
|
||||
local branches.
|
||||
* gitlink:git-merge[1] to merge between local branches.
|
||||
|
||||
* gitlink:git-rebase[1] to maintain topic branches.
|
||||
|
||||
@ -101,7 +99,7 @@ following commands.
|
||||
Examples
|
||||
~~~~~~~~
|
||||
|
||||
Use a tarball as a starting point for a new repository:
|
||||
Use a tarball as a starting point for a new repository.::
|
||||
+
|
||||
------------
|
||||
$ tar zxf frotz.tar.gz
|
||||
@ -123,7 +121,7 @@ $ edit/compile/test
|
||||
$ git checkout -- curses/ux_audio_oss.c <2>
|
||||
$ git add curses/ux_audio_alsa.c <3>
|
||||
$ edit/compile/test
|
||||
$ git diff <4>
|
||||
$ git diff HEAD <4>
|
||||
$ git commit -a -s <5>
|
||||
$ edit/compile/test
|
||||
$ git reset --soft HEAD^ <6>
|
||||
@ -131,15 +129,15 @@ $ edit/compile/test
|
||||
$ git diff ORIG_HEAD <7>
|
||||
$ git commit -a -c ORIG_HEAD <8>
|
||||
$ git checkout master <9>
|
||||
$ git pull . alsa-audio <10>
|
||||
$ git merge alsa-audio <10>
|
||||
$ git log --since='3 days ago' <11>
|
||||
$ git log v2.43.. curses/ <12>
|
||||
------------
|
||||
+
|
||||
<1> create a new topic branch.
|
||||
<2> revert your botched changes in "curses/ux_audio_oss.c".
|
||||
<2> revert your botched changes in `curses/ux_audio_oss.c`.
|
||||
<3> you need to tell git if you added a new file; removal and
|
||||
modification will be caught if you do "commit -a" later.
|
||||
modification will be caught if you do `git commit -a` later.
|
||||
<4> to see what changes you are committing.
|
||||
<5> commit everything as you have tested, with your sign-off.
|
||||
<6> take the last commit back, keeping what is in the working tree.
|
||||
@ -147,11 +145,13 @@ modification will be caught if you do "commit -a" later.
|
||||
<8> redo the commit undone in the previous step, using the message
|
||||
you originally wrote.
|
||||
<9> switch to the master branch.
|
||||
<10> merge a topic branch into your master branch
|
||||
<10> merge a topic branch into your master branch. You can also use
|
||||
`git pull . alsa-audio`, i.e. pull from the local repository.
|
||||
<11> review commit logs; other forms to limit output can be
|
||||
combined and include --max-count=10 (show 10 commits), --until='2005-12-10'.
|
||||
<12> view only the changes that touch what's in curses/
|
||||
directory, since v2.43 tag.
|
||||
combined and include `\--max-count=10` (show 10 commits),
|
||||
`\--until=2005-12-10`, etc.
|
||||
<12> view only the changes that touch what's in `curses/`
|
||||
directory, since `v2.43` tag.
|
||||
|
||||
|
||||
Individual Developer (Participant)[[Individual Developer (Participant)]]
|
||||
@ -193,7 +193,7 @@ $ git fetch --tags <8>
|
||||
+
|
||||
<1> repeat as needed.
|
||||
<2> extract patches from your branch for e-mail submission.
|
||||
<3> "pull" fetches from "origin" by default and merges into the
|
||||
<3> `git pull` fetches from `origin` by default and merges into the
|
||||
current branch.
|
||||
<4> immediately after pulling, look at the changes done upstream
|
||||
since last time we checked, only in the
|
||||
@ -201,37 +201,41 @@ area we are interested in.
|
||||
<5> fetch from a specific branch from a specific repository and merge.
|
||||
<6> revert the pull.
|
||||
<7> garbage collect leftover objects from reverted pull.
|
||||
<8> from time to time, obtain official tags from the "origin"
|
||||
and store them under .git/refs/tags/.
|
||||
<8> from time to time, obtain official tags from the `origin`
|
||||
and store them under `.git/refs/tags/`.
|
||||
|
||||
|
||||
Push into another repository.::
|
||||
+
|
||||
------------
|
||||
satellite$ git clone mothership:frotz/.git frotz <1>
|
||||
satellite$ git clone mothership:frotz frotz <1>
|
||||
satellite$ cd frotz
|
||||
satellite$ cat .git/remotes/origin <2>
|
||||
URL: mothership:frotz/.git
|
||||
Pull: master:origin
|
||||
satellite$ echo 'Push: master:satellite' >>.git/remotes/origin <3>
|
||||
satellite$ git repo-config --get-regexp '^(remote|branch)\.' <2>
|
||||
remote.origin.url mothership:frotz
|
||||
remote.origin.fetch refs/heads/*:refs/remotes/origin/*
|
||||
branch.master.remote origin
|
||||
branch.master.merge refs/heads/master
|
||||
satellite$ git repo-config remote.origin.push \
|
||||
master:refs/remotes/satellite/master <3>
|
||||
satellite$ edit/compile/test/commit
|
||||
satellite$ git push origin <4>
|
||||
|
||||
mothership$ cd frotz
|
||||
mothership$ git checkout master
|
||||
mothership$ git pull . satellite <5>
|
||||
mothership$ git merge satellite/master <5>
|
||||
------------
|
||||
+
|
||||
<1> mothership machine has a frotz repository under your home
|
||||
directory; clone from it to start a repository on the satellite
|
||||
machine.
|
||||
<2> clone creates this file by default. It arranges "git pull"
|
||||
to fetch and store the master branch head of mothership machine
|
||||
to local "origin" branch.
|
||||
<3> arrange "git push" to push local "master" branch to
|
||||
"satellite" branch of the mothership machine.
|
||||
<4> push will stash our work away on "satellite" branch on the
|
||||
mothership machine. You could use this as a back-up method.
|
||||
<2> clone sets these configuration variables by default.
|
||||
It arranges `git pull` to fetch and store the branches of mothership
|
||||
machine to local `remotes/origin/*` tracking branches.
|
||||
<3> arrange `git push` to push local `master` branch to
|
||||
`remotes/satellite/master` branch of the mothership machine.
|
||||
<4> push will stash our work away on `remotes/satellite/master`
|
||||
tracking branch on the mothership machine. You could use this as
|
||||
a back-up method.
|
||||
<5> on mothership machine, merge the work done on the satellite
|
||||
machine into the master branch.
|
||||
|
||||
@ -247,7 +251,7 @@ $ git format-patch -k -m --stdout v2.6.14..private2.6.14 |
|
||||
+
|
||||
<1> create a private branch based on a well known (but somewhat behind)
|
||||
tag.
|
||||
<2> forward port all changes in private2.6.14 branch to master branch
|
||||
<2> forward port all changes in `private2.6.14` branch to `master` branch
|
||||
without a formal "merging".
|
||||
|
||||
|
||||
@ -284,13 +288,13 @@ $ mailx <3>
|
||||
& s 2 3 4 5 ./+to-apply
|
||||
& s 7 8 ./+hold-linus
|
||||
& q
|
||||
$ git checkout master
|
||||
$ git checkout -b topic/one master
|
||||
$ git am -3 -i -s -u ./+to-apply <4>
|
||||
$ compile/test
|
||||
$ git checkout -b hold/linus && git am -3 -i -s -u ./+hold-linus <5>
|
||||
$ git checkout topic/one && git rebase master <6>
|
||||
$ git checkout pu && git reset --hard master <7>
|
||||
$ git pull . topic/one topic/two && git pull . hold/linus <8>
|
||||
$ git checkout pu && git reset --hard next <7>
|
||||
$ git merge topic/one topic/two && git merge hold/linus <8>
|
||||
$ git checkout maint
|
||||
$ git cherry-pick master~4 <9>
|
||||
$ compile/test
|
||||
@ -307,29 +311,32 @@ they are.
|
||||
that are not quite ready.
|
||||
<4> apply them, interactively, with my sign-offs.
|
||||
<5> create topic branch as needed and apply, again with my
|
||||
sign-offs.
|
||||
sign-offs.
|
||||
<6> rebase internal topic branch that has not been merged to the
|
||||
master, nor exposed as a part of a stable branch.
|
||||
<7> restart "pu" every time from the master.
|
||||
<7> restart `pu` every time from the next.
|
||||
<8> and bundle topic branches still cooking.
|
||||
<9> backport a critical fix.
|
||||
<10> create a signed tag.
|
||||
<11> make sure I did not accidentally rewind master beyond what I
|
||||
already pushed out. "ko" shorthand points at the repository I have
|
||||
already pushed out. `ko` shorthand points at the repository I have
|
||||
at kernel.org, and looks like this:
|
||||
+
|
||||
------------
|
||||
$ cat .git/remotes/ko
|
||||
URL: kernel.org:/pub/scm/git/git.git
|
||||
Pull: master:refs/tags/ko-master
|
||||
Pull: next:refs/tags/ko-next
|
||||
Pull: maint:refs/tags/ko-maint
|
||||
Push: master
|
||||
Push: next
|
||||
Push: +pu
|
||||
Push: maint
|
||||
------------
|
||||
+
|
||||
In the output from "git show-branch", "master" should have
|
||||
everything "ko-master" has.
|
||||
In the output from `git show-branch`, `master` should have
|
||||
everything `ko-master` has, and `next` should have
|
||||
everything `ko-next` has.
|
||||
|
||||
<12> push out the bleeding edge.
|
||||
<13> push the tag out, too.
|
||||
@ -406,7 +413,7 @@ $ grep git /etc/shells <2>
|
||||
------------
|
||||
+
|
||||
<1> log-in shell is set to /usr/bin/git-shell, which does not
|
||||
allow anything but "git push" and "git pull". The users should
|
||||
allow anything but `git push` and `git pull`. The users should
|
||||
get an ssh access to the machine.
|
||||
<2> in many distributions /etc/shells needs to list what is used
|
||||
as the login shell.
|
||||
|
@ -3,24 +3,45 @@ git-add(1)
|
||||
|
||||
NAME
|
||||
----
|
||||
git-add - Add files to the index file
|
||||
git-add - Add file contents to the changeset to be committed next
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-add' [-n] [-v] [--] <file>...
|
||||
'git-add' [-n] [-v] [-f] [--interactive] [--] <file>...
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
A simple wrapper for git-update-index to add files to the index,
|
||||
for people used to do "cvs add".
|
||||
All the changed file contents to be committed together in a single set
|
||||
of changes must be "added" with the 'add' command before using the
|
||||
'commit' command. This is not only for adding new files. Even modified
|
||||
files must be added to the set of changes about to be committed.
|
||||
|
||||
This command can be performed multiple times before a commit. The added
|
||||
content corresponds to the state of specified file(s) at the time the
|
||||
'add' command is used. This means the 'commit' command will not consider
|
||||
subsequent changes to already added content if it is not added again before
|
||||
the commit.
|
||||
|
||||
The 'git status' command can be used to obtain a summary of what is included
|
||||
for the next commit.
|
||||
|
||||
This command can be used to add ignored files with `-f` (force)
|
||||
option, but they have to be
|
||||
explicitly and exactly specified from the command line. File globbing
|
||||
and recursive behaviour do not add ignored files.
|
||||
|
||||
Please see gitlink:git-commit[1] for alternative ways to add content to a
|
||||
commit.
|
||||
|
||||
It only adds non-ignored files, to add ignored files use
|
||||
"git update-index --add".
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
<file>...::
|
||||
Files to add to the index (see gitlink:git-ls-files[1]).
|
||||
Files to add content from. Fileglobs (e.g. `*.c`) can
|
||||
be given to add all matching files. Also a
|
||||
leading directory name (e.g. `dir` to add `dir/file1`
|
||||
and `dir/file2`) can be given to add all files in the
|
||||
directory, recursively.
|
||||
|
||||
-n::
|
||||
Don't actually add the file(s), just show if they exist.
|
||||
@ -28,33 +49,25 @@ OPTIONS
|
||||
-v::
|
||||
Be verbose.
|
||||
|
||||
-f::
|
||||
Allow adding otherwise ignored files.
|
||||
|
||||
\--interactive::
|
||||
Add modified contents in the working tree interactively to
|
||||
the index.
|
||||
|
||||
\--::
|
||||
This option can be used to separate command-line options from
|
||||
the list of files, (useful when filenames might be mistaken
|
||||
for command-line options).
|
||||
|
||||
|
||||
DISCUSSION
|
||||
----------
|
||||
|
||||
The list of <file> given to the command is fed to `git-ls-files`
|
||||
command to list files that are not registered in the index and
|
||||
are not ignored/excluded by `$GIT_DIR/info/exclude` file or
|
||||
`.gitignore` file in each directory. This means two things:
|
||||
|
||||
. You can put the name of a directory on the command line, and
|
||||
the command will add all files in it and its subdirectories;
|
||||
|
||||
. Giving the name of a file that is already in index does not
|
||||
run `git-update-index` on that path.
|
||||
|
||||
|
||||
EXAMPLES
|
||||
--------
|
||||
git-add Documentation/\\*.txt::
|
||||
|
||||
Adds all `\*.txt` files that are not in the index under
|
||||
`Documentation` directory and its subdirectories.
|
||||
Adds content from all `\*.txt` files under `Documentation`
|
||||
directory and its subdirectories.
|
||||
+
|
||||
Note that the asterisk `\*` is quoted from the shell in this
|
||||
example; this lets the command to include the files from
|
||||
@ -62,15 +75,131 @@ subdirectories of `Documentation/` directory.
|
||||
|
||||
git-add git-*.sh::
|
||||
|
||||
Adds all git-*.sh scripts that are not in the index.
|
||||
Considers adding content from all git-*.sh scripts.
|
||||
Because this example lets shell expand the asterisk
|
||||
(i.e. you are listing the files explicitly), it does not
|
||||
add `subdir/git-foo.sh` to the index.
|
||||
consider `subdir/git-foo.sh`.
|
||||
|
||||
Interactive mode
|
||||
----------------
|
||||
When the command enters the interactive mode, it shows the
|
||||
output of the 'status' subcommand, and then goes into ints
|
||||
interactive command loop.
|
||||
|
||||
The command loop shows the list of subcommands available, and
|
||||
gives a prompt "What now> ". In general, when the prompt ends
|
||||
with a single '>', you can pick only one of the choices given
|
||||
and type return, like this:
|
||||
|
||||
------------
|
||||
*** Commands ***
|
||||
1: status 2: update 3: revert 4: add untracked
|
||||
5: patch 6: diff 7: quit 8: help
|
||||
What now> 1
|
||||
------------
|
||||
|
||||
You also could say "s" or "sta" or "status" above as long as the
|
||||
choice is unique.
|
||||
|
||||
The main command loop has 6 subcommands (plus help and quit).
|
||||
|
||||
status::
|
||||
|
||||
This shows the change between HEAD and index (i.e. what will be
|
||||
committed if you say "git commit"), and between index and
|
||||
working tree files (i.e. what you could stage further before
|
||||
"git commit" using "git-add") for each path. A sample output
|
||||
looks like this:
|
||||
+
|
||||
------------
|
||||
staged unstaged path
|
||||
1: binary nothing foo.png
|
||||
2: +403/-35 +1/-1 git-add--interactive.perl
|
||||
------------
|
||||
+
|
||||
It shows that foo.png has differences from HEAD (but that is
|
||||
binary so line count cannot be shown) and there is no
|
||||
difference between indexed copy and the working tree
|
||||
version (if the working tree version were also different,
|
||||
'binary' would have been shown in place of 'nothing'). The
|
||||
other file, git-add--interactive.perl, has 403 lines added
|
||||
and 35 lines deleted if you commit what is in the index, but
|
||||
working tree file has further modifications (one addition and
|
||||
one deletion).
|
||||
|
||||
update::
|
||||
|
||||
This shows the status information and gives prompt
|
||||
"Update>>". When the prompt ends with double '>>', you can
|
||||
make more than one selection, concatenated with whitespace or
|
||||
comma. Also you can say ranges. E.g. "2-5 7,9" to choose
|
||||
2,3,4,5,7,9 from the list. You can say '*' to choose
|
||||
everything.
|
||||
+
|
||||
What you chose are then highlighted with '*',
|
||||
like this:
|
||||
+
|
||||
------------
|
||||
staged unstaged path
|
||||
1: binary nothing foo.png
|
||||
* 2: +403/-35 +1/-1 git-add--interactive.perl
|
||||
------------
|
||||
+
|
||||
To remove selection, prefix the input with `-`
|
||||
like this:
|
||||
+
|
||||
------------
|
||||
Update>> -2
|
||||
------------
|
||||
+
|
||||
After making the selection, answer with an empty line to stage the
|
||||
contents of working tree files for selected paths in the index.
|
||||
|
||||
revert::
|
||||
|
||||
This has a very similar UI to 'update', and the staged
|
||||
information for selected paths are reverted to that of the
|
||||
HEAD version. Reverting new paths makes them untracked.
|
||||
|
||||
add untracked::
|
||||
|
||||
This has a very similar UI to 'update' and
|
||||
'revert', and lets you add untracked paths to the index.
|
||||
|
||||
patch::
|
||||
|
||||
This lets you choose one path out of 'status' like selection.
|
||||
After choosing the path, it presents diff between the index
|
||||
and the working tree file and asks you if you want to stage
|
||||
the change of each hunk. You can say:
|
||||
|
||||
y - add the change from that hunk to index
|
||||
n - do not add the change from that hunk to index
|
||||
a - add the change from that hunk and all the rest to index
|
||||
d - do not the change from that hunk nor any of the rest to index
|
||||
j - do not decide on this hunk now, and view the next
|
||||
undecided hunk
|
||||
J - do not decide on this hunk now, and view the next hunk
|
||||
k - do not decide on this hunk now, and view the previous
|
||||
undecided hunk
|
||||
K - do not decide on this hunk now, and view the previous hunk
|
||||
+
|
||||
After deciding the fate for all hunks, if there is any hunk
|
||||
that was chosen, the index is updated with the selected hunks.
|
||||
|
||||
diff::
|
||||
|
||||
This lets you review what will be committed (i.e. between
|
||||
HEAD and index).
|
||||
|
||||
|
||||
See Also
|
||||
--------
|
||||
gitlink:git-status[1]
|
||||
gitlink:git-rm[1]
|
||||
gitlink:git-ls-files[1]
|
||||
gitlink:git-mv[1]
|
||||
gitlink:git-commit[1]
|
||||
gitlink:git-update-index[1]
|
||||
|
||||
Author
|
||||
------
|
||||
|
@ -33,8 +33,9 @@ OPTIONS
|
||||
--numstat::
|
||||
Similar to \--stat, but shows number of added and
|
||||
deleted lines in decimal notation and pathname without
|
||||
abbreviation, to make it more machine friendly. Turns
|
||||
off "apply".
|
||||
abbreviation, to make it more machine friendly. For
|
||||
binary files, outputs two `-` instead of saying
|
||||
`0 0`. Turns off "apply".
|
||||
|
||||
--summary::
|
||||
Instead of applying the patch, output a condensed
|
||||
|
@ -8,9 +8,10 @@ git-branch - List, create, or delete branches.
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git-branch' [-r] [-a]
|
||||
'git-branch' [-r | -a] [-v [--abbrev=<length>]]
|
||||
'git-branch' [-l] [-f] <branchname> [<start-point>]
|
||||
'git-branch' (-d | -D) <branchname>...
|
||||
'git-branch' (-m | -M) [<oldbranch>] <newbranch>
|
||||
'git-branch' (-d | -D) [-r] <branchname>...
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@ -24,9 +25,16 @@ It will start out with a head equal to the one given as <start-point>.
|
||||
If no <start-point> is given, the branch will be created with a head
|
||||
equal to that of the currently checked out branch.
|
||||
|
||||
With a '-m' or '-M' option, <oldbranch> will be renamed to <newbranch>.
|
||||
If <oldbranch> had a corresponding reflog, it is renamed to match
|
||||
<newbranch>, and a reflog entry is created to remember the branch
|
||||
renaming. If <newbranch> exists, -M must be used to force the rename
|
||||
to happen.
|
||||
|
||||
With a `-d` or `-D` option, `<branchname>` will be deleted. You may
|
||||
specify more than one branch for deletion. If the branch currently
|
||||
has a ref log then the ref log will also be deleted.
|
||||
has a ref log then the ref log will also be deleted. Use -r together with -d
|
||||
to delete remote-tracking branches.
|
||||
|
||||
|
||||
OPTIONS
|
||||
@ -46,12 +54,25 @@ OPTIONS
|
||||
Force the creation of a new branch even if it means deleting
|
||||
a branch that already exists with the same name.
|
||||
|
||||
-m::
|
||||
Move/rename a branch and the corresponding reflog.
|
||||
|
||||
-M::
|
||||
Move/rename a branch even if the new branchname already exists.
|
||||
|
||||
-r::
|
||||
List the remote-tracking branches.
|
||||
List or delete (if used with -d) the remote-tracking branches.
|
||||
|
||||
-a::
|
||||
List both remote-tracking branches and local branches.
|
||||
|
||||
-v::
|
||||
Show sha1 and commit subjectline for each head.
|
||||
|
||||
--abbrev=<length>::
|
||||
Alter minimum display length for sha1 in output listing,
|
||||
default value is 7.
|
||||
|
||||
<branchname>::
|
||||
The name of the branch to create or delete.
|
||||
The new branch name must pass all checks defined by
|
||||
@ -63,6 +84,12 @@ OPTIONS
|
||||
be given as a branch name, a commit-id, or a tag. If this option
|
||||
is omitted, the current branch is assumed.
|
||||
|
||||
<oldbranch>::
|
||||
The name of an existing branch to rename.
|
||||
|
||||
<newbranch>::
|
||||
The new name for an existing branch. The same restrictions as for
|
||||
<branchname> applies.
|
||||
|
||||
|
||||
Examples
|
||||
@ -85,10 +112,12 @@ Delete unneeded branch::
|
||||
------------
|
||||
$ git clone git://git.kernel.org/.../git.git my.git
|
||||
$ cd my.git
|
||||
$ git branch -D todo <1>
|
||||
$ git branch -d -r todo html man <1>
|
||||
$ git branch -D test <2>
|
||||
------------
|
||||
+
|
||||
<1> delete todo branch even if the "master" branch does not have all
|
||||
<1> delete remote-tracking branches "todo", "html", "man"
|
||||
<2> delete "test" branch even if the "master" branch does not have all
|
||||
commits from todo branch.
|
||||
|
||||
|
||||
|
@ -11,27 +11,25 @@ SYNOPSIS
|
||||
[verse]
|
||||
'git-clone' [--template=<template_directory>] [-l [-s]] [-q] [-n] [--bare]
|
||||
[-o <name>] [-u <upload-pack>] [--reference <repository>]
|
||||
[--use-separate-remote | --use-immingled-remote] <repository>
|
||||
[<directory>]
|
||||
<repository> [<directory>]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
Clones a repository into a newly created directory. All remote
|
||||
branch heads are copied under `$GIT_DIR/refs/heads/`, except
|
||||
that the remote `master` is also copied to `origin` branch.
|
||||
|
||||
In addition, `$GIT_DIR/remotes/origin` file is set up to have
|
||||
this line:
|
||||
Clones a repository into a newly created directory, creates
|
||||
remote-tracking branches for each branch in the cloned repository
|
||||
(visible using `git branch -r`), and creates and checks out a master
|
||||
branch equal to the cloned repository's master branch.
|
||||
|
||||
Pull: master:origin
|
||||
|
||||
This is to help the typical workflow of working off of the
|
||||
remote `master` branch. Every time `git pull` without argument
|
||||
is run, the progress on the remote `master` branch is tracked by
|
||||
copying it into the local `origin` branch, and merged into the
|
||||
branch you are currently working on. Remote branches other than
|
||||
`master` are also added there to be tracked.
|
||||
After the clone, a plain `git fetch` without arguments will update
|
||||
all the remote-tracking branches, and a `git pull` without
|
||||
arguments will in addition merge the remote master branch into the
|
||||
current branch.
|
||||
|
||||
This default configuration is achieved by creating references to
|
||||
the remote branch heads under `$GIT_DIR/refs/remotes/origin` and
|
||||
by initializing `remote.origin.url` and `remote.origin.fetch`
|
||||
configuration variables.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
@ -100,18 +98,6 @@ OPTIONS
|
||||
if unset the templates are taken from the installation
|
||||
defined default, typically `/usr/share/git-core/templates`.
|
||||
|
||||
--use-separate-remote::
|
||||
Save remotes heads under `$GIT_DIR/remotes/origin/` instead
|
||||
of `$GIT_DIR/refs/heads/`. Only the local master branch is
|
||||
saved in the latter. This is the default.
|
||||
|
||||
--use-immingled-remote::
|
||||
Save remotes heads in the same namespace as the local
|
||||
heads, `$GIT_DIR/refs/heads/'. In regular repositories,
|
||||
this is a legacy setup git-clone created by default in
|
||||
older Git versions, and will be removed before the next
|
||||
major release.
|
||||
|
||||
<repository>::
|
||||
The (possibly remote) repository to clone from. It can
|
||||
be any URL git-fetch supports.
|
||||
|
@ -14,25 +14,41 @@ SYNOPSIS
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
Updates the index file for given paths, or all modified files if
|
||||
'-a' is specified, and makes a commit object. The command specified
|
||||
by either the VISUAL or EDITOR environment variables are used to edit
|
||||
the commit log message.
|
||||
Use 'git commit' when you want to record your changes into the repository
|
||||
along with a log message describing what the commit is about. All changes
|
||||
to be committed must be explicitly identified using one of the following
|
||||
methods:
|
||||
|
||||
Several environment variable are used during commits. They are
|
||||
documented in gitlink:git-commit-tree[1].
|
||||
1. by using gitlink:git-add[1] to incrementally "add" changes to the
|
||||
next commit before using the 'commit' command (Note: even modified
|
||||
files must be "added");
|
||||
|
||||
2. by using gitlink:git-rm[1] to identify content removal for the next
|
||||
commit, again before using the 'commit' command;
|
||||
|
||||
3. by directly listing files containing changes to be committed as arguments
|
||||
to the 'commit' command, in which cases only those files alone will be
|
||||
considered for the commit;
|
||||
|
||||
4. by using the -a switch with the 'commit' command to automatically "add"
|
||||
changes from all known files i.e. files that have already been committed
|
||||
before, and perform the actual commit.
|
||||
|
||||
The gitlink:git-status[1] command can be used to obtain a
|
||||
summary of what is included by any of the above for the next
|
||||
commit by giving the same set of parameters you would give to
|
||||
this command.
|
||||
|
||||
If you make a commit and then found a mistake immediately after
|
||||
that, you can recover from it with gitlink:git-reset[1].
|
||||
|
||||
This command can run `commit-msg`, `pre-commit`, and
|
||||
`post-commit` hooks. See link:hooks.html[hooks] for more
|
||||
information.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
-a|--all::
|
||||
Update all paths in the index file. This flag notices
|
||||
files that have been modified and deleted, but new files
|
||||
you have not told git about are not affected.
|
||||
Tell the command to automatically stage files that have
|
||||
been modified and deleted, but new files you have not
|
||||
told git about are not affected.
|
||||
|
||||
-c or -C <commit>::
|
||||
Take existing commit object, and reuse the log message
|
||||
@ -55,16 +71,13 @@ OPTIONS
|
||||
-s|--signoff::
|
||||
Add Signed-off-by line at the end of the commit message.
|
||||
|
||||
-v|--verify::
|
||||
Look for suspicious lines the commit introduces, and
|
||||
abort committing if there is one. The definition of
|
||||
'suspicious lines' is currently the lines that has
|
||||
trailing whitespaces, and the lines whose indentation
|
||||
has a SP character immediately followed by a TAB
|
||||
character. This is the default.
|
||||
|
||||
-n|--no-verify::
|
||||
The opposite of `--verify`.
|
||||
--no-verify::
|
||||
By default, the command looks for suspicious lines the
|
||||
commit introduces, and aborts committing if there is one.
|
||||
The definition of 'suspicious lines' is currently the
|
||||
lines that has trailing whitespaces, and the lines whose
|
||||
indentation has a SP character immediately followed by a
|
||||
TAB character. This option turns off the check.
|
||||
|
||||
-e|--edit::
|
||||
The message taken from file with `-F`, command line with
|
||||
@ -95,69 +108,140 @@ but can be used to amend a merge commit.
|
||||
--
|
||||
|
||||
-i|--include::
|
||||
Instead of committing only the files specified on the
|
||||
command line, update them in the index file and then
|
||||
commit the whole index. This is the traditional
|
||||
behavior.
|
||||
Before making a commit out of staged contents so far,
|
||||
stage the contents of paths given on the command line
|
||||
as well. This is usually not what you want unless you
|
||||
are concluding a conflicted merge.
|
||||
|
||||
-o|--only::
|
||||
Commit only the files specified on the command line.
|
||||
This format cannot be used during a merge, nor when the
|
||||
index and the latest commit does not match on the
|
||||
specified paths to avoid confusion.
|
||||
-q|--quiet::
|
||||
Supress commit summary message.
|
||||
|
||||
\--::
|
||||
Do not interpret any more arguments as options.
|
||||
|
||||
<file>...::
|
||||
Files to be committed. The meaning of these is
|
||||
different between `--include` and `--only`. Without
|
||||
either, it defaults `--only` semantics.
|
||||
|
||||
If you make a commit and then found a mistake immediately after
|
||||
that, you can recover from it with gitlink:git-reset[1].
|
||||
When files are given on the command line, the command
|
||||
commits the contents of the named files, without
|
||||
recording the changes already staged. The contents of
|
||||
these files are also staged for the next commit on top
|
||||
of what have been staged before.
|
||||
|
||||
|
||||
Discussion
|
||||
----------
|
||||
EXAMPLES
|
||||
--------
|
||||
When recording your own work, the contents of modified files in
|
||||
your working tree are temporarily stored to a staging area
|
||||
called the "index" with gitlink:git-add[1]. Removal
|
||||
of a file is staged with gitlink:git-rm[1]. After building the
|
||||
state to be committed incrementally with these commands, `git
|
||||
commit` (without any pathname parameter) is used to record what
|
||||
has been staged so far. This is the most basic form of the
|
||||
command. An example:
|
||||
|
||||
`git commit` without _any_ parameter commits the tree structure
|
||||
recorded by the current index file. This is a whole-tree commit
|
||||
even the command is invoked from a subdirectory.
|
||||
------------
|
||||
$ edit hello.c
|
||||
$ git rm goodbye.c
|
||||
$ git add hello.c
|
||||
$ git commit
|
||||
------------
|
||||
|
||||
`git commit --include paths...` is equivalent to
|
||||
////////////
|
||||
We should fix 'git rm' to remove goodbye.c from both index and
|
||||
working tree for the above example.
|
||||
////////////
|
||||
|
||||
git update-index --remove paths...
|
||||
git commit
|
||||
Instead of staging files after each individual change, you can
|
||||
tell `git commit` to notice the changes to the files whose
|
||||
contents are tracked in
|
||||
your working tree and do corresponding `git add` and `git rm`
|
||||
for you. That is, this example does the same as the earlier
|
||||
example if there is no other change in your working tree:
|
||||
|
||||
That is, update the specified paths to the index and then commit
|
||||
the whole tree.
|
||||
------------
|
||||
$ edit hello.c
|
||||
$ rm goodbye.c
|
||||
$ git commit -a
|
||||
------------
|
||||
|
||||
`git commit paths...` largely bypasses the index file and
|
||||
commits only the changes made to the specified paths. It has
|
||||
however several safety valves to prevent confusion.
|
||||
The command `git commit -a` first looks at your working tree,
|
||||
notices that you have modified hello.c and removed goodbye.c,
|
||||
and performs necessary `git add` and `git rm` for you.
|
||||
|
||||
. It refuses to run during a merge (i.e. when
|
||||
`$GIT_DIR/MERGE_HEAD` exists), and reminds trained git users
|
||||
that the traditional semantics now needs -i flag.
|
||||
After staging changes to many files, you can alter the order the
|
||||
changes are recorded in, by giving pathnames to `git commit`.
|
||||
When pathnames are given, the command makes a commit that
|
||||
only records the changes made to the named paths:
|
||||
|
||||
. It refuses to run if named `paths...` are different in HEAD
|
||||
and the index (ditto about reminding). Added paths are OK.
|
||||
This is because an earlier `git diff` (not `git diff HEAD`)
|
||||
would have shown the differences since the last `git
|
||||
update-index paths...` to the user, and an inexperienced user
|
||||
may mistakenly think that the changes between the index and
|
||||
the HEAD (i.e. earlier changes made before the last `git
|
||||
update-index paths...` was done) are not being committed.
|
||||
------------
|
||||
$ edit hello.c hello.h
|
||||
$ git add hello.c hello.h
|
||||
$ edit Makefile
|
||||
$ git commit Makefile
|
||||
------------
|
||||
|
||||
. It reads HEAD commit into a temporary index file, updates the
|
||||
specified `paths...` and makes a commit. At the same time,
|
||||
the real index file is also updated with the same `paths...`.
|
||||
This makes a commit that records the modification to `Makefile`.
|
||||
The changes staged for `hello.c` and `hello.h` are not included
|
||||
in the resulting commit. However, their changes are not lost --
|
||||
they are still staged and merely held back. After the above
|
||||
sequence, if you do:
|
||||
|
||||
`git commit --all` updates the index file with _all_ changes to
|
||||
the working tree, and makes a whole-tree commit, regardless of
|
||||
which subdirectory the command is invoked in.
|
||||
------------
|
||||
$ git commit
|
||||
------------
|
||||
|
||||
this second commit would record the changes to `hello.c` and
|
||||
`hello.h` as expected.
|
||||
|
||||
After a merge (initiated by either gitlink:git-merge[1] or
|
||||
gitlink:git-pull[1]) stops because of conflicts, cleanly merged
|
||||
paths are already staged to be committed for you, and paths that
|
||||
conflicted are left in unmerged state. You would have to first
|
||||
check which paths are conflicting with gitlink:git-status[1]
|
||||
and after fixing them manually in your working tree, you would
|
||||
stage the result as usual with gitlink:git-add[1]:
|
||||
|
||||
------------
|
||||
$ git status | grep unmerged
|
||||
unmerged: hello.c
|
||||
$ edit hello.c
|
||||
$ git add hello.c
|
||||
------------
|
||||
|
||||
After resolving conflicts and staging the result, `git ls-files -u`
|
||||
would stop mentioning the conflicted path. When you are done,
|
||||
run `git commit` to finally record the merge:
|
||||
|
||||
------------
|
||||
$ git commit
|
||||
------------
|
||||
|
||||
As with the case to record your own changes, you can use `-a`
|
||||
option to save typing. One difference is that during a merge
|
||||
resolution, you cannot use `git commit` with pathnames to
|
||||
alter the order the changes are committed, because the merge
|
||||
should be recorded as a single commit. In fact, the command
|
||||
refuses to run when given pathnames (but see `-i` option).
|
||||
|
||||
|
||||
ENVIRONMENT VARIABLES
|
||||
---------------------
|
||||
The command specified by either the VISUAL or EDITOR environment
|
||||
variables is used to edit the commit log message.
|
||||
|
||||
HOOKS
|
||||
-----
|
||||
This command can run `commit-msg`, `pre-commit`, and
|
||||
`post-commit` hooks. See link:hooks.html[hooks] for more
|
||||
information.
|
||||
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
gitlink:git-add[1],
|
||||
gitlink:git-rm[1],
|
||||
gitlink:git-mv[1],
|
||||
gitlink:git-merge[1],
|
||||
gitlink:git-commit-tree[1]
|
||||
|
||||
Author
|
||||
------
|
||||
|
@ -20,8 +20,8 @@ OPTIONS
|
||||
-v::
|
||||
In addition to the number of loose objects and disk
|
||||
space consumed, it reports the number of in-pack
|
||||
objects, and number of objects that can be removed by
|
||||
running `git-prune-packed`.
|
||||
objects, number of packs, and number of objects that can be
|
||||
removed by running `git-prune-packed`.
|
||||
|
||||
|
||||
Author
|
||||
|
@ -8,36 +8,54 @@ git-diff - Show changes between commits, commit and working tree, etc
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-diff' [ --diff-options ] <tree-ish>{0,2} [<path>...]
|
||||
'git-diff' [ --diff-options ] <commit>{0,2} [--] [<path>...]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
Show changes between two trees, a tree and the working tree, a
|
||||
tree and the index file, or the index file and the working tree.
|
||||
The combination of what is compared with what is determined by
|
||||
the number of trees given to the command.
|
||||
|
||||
* When no <tree-ish> is given, the working tree and the index
|
||||
file are compared, using `git-diff-files`.
|
||||
'git-diff' [--options] [--] [<path>...]::
|
||||
|
||||
* When one <tree-ish> is given, the working tree and the named
|
||||
tree are compared, using `git-diff-index`. The option
|
||||
`--cached` can be given to compare the index file and
|
||||
the named tree.
|
||||
This form is to view the changes you made relative to
|
||||
the index (staging area for the next commit). In other
|
||||
words, the differences are what you _could_ tell git to
|
||||
further add to the index but you still haven't. You can
|
||||
stage these changes by using gitlink:git-add[1].
|
||||
|
||||
'git-diff' [--options] --cached [<commit>] [--] [<path>...]::
|
||||
|
||||
This form is to view the changes you staged for the next
|
||||
commit relative to the named <commit>. Typically you
|
||||
would want comparison with the latest commit, so if you
|
||||
do not give <commit>, it defaults to HEAD.
|
||||
|
||||
'git-diff' [--options] <commit> [--] [<path>...]::
|
||||
|
||||
This form is to view the changes you have in your
|
||||
working tree relative to the named <commit>. You can
|
||||
use HEAD to compare it with the latest commit, or a
|
||||
branch name to compare with the tip of a different
|
||||
branch.
|
||||
|
||||
'git-diff' [--options] <commit> <commit> [--] [<path>...]::
|
||||
|
||||
This form is to view the changes between two <commit>,
|
||||
for example, tips of two branches.
|
||||
|
||||
Just in case if you are doing something exotic, it should be
|
||||
noted that all of the <commit> in the above description can be
|
||||
any <tree-ish>.
|
||||
|
||||
* When two <tree-ish>s are given, these two trees are compared
|
||||
using `git-diff-tree`.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
--diff-options::
|
||||
'--diff-options' are passed to the `git-diff-files`,
|
||||
`git-diff-index`, and `git-diff-tree` commands. See the
|
||||
documentation for these commands for description.
|
||||
include::diff-options.txt[]
|
||||
|
||||
<path>...::
|
||||
The <path> arguments are also passed to `git-diff-\*`
|
||||
commands.
|
||||
The <paths> parameters, when given, are used to limit
|
||||
the diff to the named paths (you can give directory
|
||||
names and get diff for all files under them).
|
||||
|
||||
|
||||
EXAMPLES
|
||||
@ -51,7 +69,7 @@ $ git diff --cached <2>
|
||||
$ git diff HEAD <3>
|
||||
------------
|
||||
+
|
||||
<1> changes in the working tree since your last git-update-index.
|
||||
<1> changes in the working tree not yet staged for the next commit.
|
||||
<2> changes between the index and your last commit; what you
|
||||
would be committing if you run "git commit" without "-a" option.
|
||||
<3> changes in the working tree since your last commit; what you
|
||||
|
92
Documentation/git-merge-file.txt
Normal file
92
Documentation/git-merge-file.txt
Normal file
@ -0,0 +1,92 @@
|
||||
git-merge-file(1)
|
||||
=================
|
||||
|
||||
NAME
|
||||
----
|
||||
git-merge-file - three-way file merge
|
||||
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git-merge-file' [-L <current-name> [-L <base-name> [-L <other-name>]]]
|
||||
[-p|--stdout] [-q|--quiet] <current-file> <base-file> <other-file>
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
git-file-merge incorporates all changes that lead from the `<base-file>`
|
||||
to `<other-file>` into `<current-file>`. The result ordinarily goes into
|
||||
`<current-file>`. git-merge-file is useful for combining separate changes
|
||||
to an original. Suppose `<base-file>` is the original, and both
|
||||
`<current-file>` and `<other-file>` are modifications of `<base-file>`.
|
||||
Then git-merge-file combines both changes.
|
||||
|
||||
A conflict occurs if both `<current-file>` and `<other-file>` have changes
|
||||
in a common segment of lines. If a conflict is found, git-merge-file
|
||||
normally outputs a warning and brackets the conflict with <<<<<<< and
|
||||
>>>>>>> lines. A typical conflict will look like this:
|
||||
|
||||
<<<<<<< A
|
||||
lines in file A
|
||||
=======
|
||||
lines in file B
|
||||
>>>>>>> B
|
||||
|
||||
If there are conflicts, the user should edit the result and delete one of
|
||||
the alternatives.
|
||||
|
||||
The exit value of this program is negative on error, and the number of
|
||||
conflicts otherwise. If the merge was clean, the exit value is 0.
|
||||
|
||||
git-merge-file is designed to be a minimal clone of RCS merge, that is, it
|
||||
implements all of RCS merge's functionality which is needed by
|
||||
gitlink:git[1].
|
||||
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
|
||||
-L <label>::
|
||||
This option may be given up to three times, and
|
||||
specifies labels to be used in place of the
|
||||
corresponding file names in conflict reports. That is,
|
||||
`git-merge-file -L x -L y -L z a b c` generates output that
|
||||
looks like it came from files x, y and z instead of
|
||||
from files a, b and c.
|
||||
|
||||
-p::
|
||||
Send results to standard output instead of overwriting
|
||||
`<current-file>`.
|
||||
|
||||
-q::
|
||||
Quiet; do not warn about conflicts.
|
||||
|
||||
|
||||
EXAMPLES
|
||||
--------
|
||||
|
||||
git merge-file README.my README README.upstream::
|
||||
|
||||
combines the changes of README.my and README.upstream since README,
|
||||
tries to merge them and writes the result into README.my.
|
||||
|
||||
git merge-file -L a -L b -L c tmp/a123 tmp/b234 tmp/c345::
|
||||
|
||||
merges tmp/a123 and tmp/c345 with the base tmp/b234, but uses labels
|
||||
`a` and `c` instead of `tmp/a123` and `tmp/c345`.
|
||||
|
||||
|
||||
Author
|
||||
------
|
||||
Written by Johannes Schindelin <johannes.schindelin@gmx.de>
|
||||
|
||||
|
||||
Documentation
|
||||
--------------
|
||||
Documentation by Johannes Schindelin and the git-list <git@vger.kernel.org>,
|
||||
with parts copied from the original documentation of RCS merge.
|
||||
|
||||
GIT
|
||||
---
|
||||
Part of the gitlink:git[7] suite
|
@ -40,8 +40,8 @@ If "git-merge-index" is called with multiple <file>s (or -a) then it
|
||||
processes them in turn only stopping if merge returns a non-zero exit
|
||||
code.
|
||||
|
||||
Typically this is run with the a script calling the merge command from
|
||||
the RCS package.
|
||||
Typically this is run with the a script calling git's imitation of
|
||||
the merge command from the RCS package.
|
||||
|
||||
A sample script called "git-merge-one-file" is included in the
|
||||
distribution.
|
||||
|
@ -8,12 +8,14 @@ git-merge - Grand Unified Merge Driver
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-merge' [-n] [--no-commit] [-s <strategy>]... <msg> <head> <remote> <remote>...
|
||||
|
||||
[verse]
|
||||
'git-merge' [-n] [--no-commit] [--squash] [-s <strategy>]...
|
||||
[--reflog-action=<action>]
|
||||
-m=<msg> <remote> <remote>...
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
This is the top-level user interface to the merge machinery
|
||||
This is the top-level interface to the merge machinery
|
||||
which drives multiple merge strategy scripts.
|
||||
|
||||
|
||||
@ -27,13 +29,19 @@ include::merge-options.txt[]
|
||||
to give a good default for automated `git-merge` invocations.
|
||||
|
||||
<head>::
|
||||
our branch head commit.
|
||||
Our branch head commit. This has to be `HEAD`, so new
|
||||
syntax does not require it
|
||||
|
||||
<remote>::
|
||||
other branch head merged into our branch. You need at
|
||||
Other branch head merged into our branch. You need at
|
||||
least one <remote>. Specifying more than one <remote>
|
||||
obviously means you are trying an Octopus.
|
||||
|
||||
--reflog-action=<action>::
|
||||
This is used internally when `git-pull` calls this command
|
||||
to record that the merge was created by `pull` command
|
||||
in the `ref-log` entry that results from the merge.
|
||||
|
||||
include::merge-strategies.txt[]
|
||||
|
||||
|
||||
|
@ -49,12 +49,14 @@ corresponding remotes file---see below), then all the
|
||||
refs that exist both on the local side and on the remote
|
||||
side are updated.
|
||||
+
|
||||
Some short-cut notations are also supported.
|
||||
`tag <tag>` means the same as `refs/tags/<tag>:refs/tags/<tag>`.
|
||||
+
|
||||
* `tag <tag>` means the same as `refs/tags/<tag>:refs/tags/<tag>`.
|
||||
* A parameter <ref> without a colon is equivalent to
|
||||
<ref>`:`<ref>, hence updates <ref> in the destination from <ref>
|
||||
in the source.
|
||||
A parameter <ref> without a colon is equivalent to
|
||||
<ref>`:`<ref>, hence updates <ref> in the destination from <ref>
|
||||
in the source.
|
||||
+
|
||||
Pushing an empty <src> allows you to delete the <dst> ref from
|
||||
the remote repository.
|
||||
|
||||
\--all::
|
||||
Instead of naming each ref to push, specifies that all
|
||||
@ -75,7 +77,8 @@ include::urls.txt[]
|
||||
|
||||
Author
|
||||
------
|
||||
Written by Junio C Hamano <junkio@cox.net>
|
||||
Written by Junio C Hamano <junkio@cox.net>, later rewritten in C
|
||||
by Linus Torvalds <torvalds@osdl.org>
|
||||
|
||||
Documentation
|
||||
--------------
|
||||
|
@ -8,7 +8,7 @@ git-read-tree - Reads tree information into the index
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-read-tree' (<tree-ish> | [[-m [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] <tree-ish1> [<tree-ish2> [<tree-ish3>]])
|
||||
'git-read-tree' (<tree-ish> | [[-m [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] [--exclude-per-directory=<gitignore>] <tree-ish1> [<tree-ish2> [<tree-ish3>]])
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
@ -71,6 +71,20 @@ OPTIONS
|
||||
directory. Note that the `<prefix>/` value must end
|
||||
with a slash.
|
||||
|
||||
--exclude-per-directory=<gitignore>::
|
||||
When running the command with `-u` and `-m` options, the
|
||||
merge result may need to overwrite paths that are not
|
||||
tracked in the current branch. The command usually
|
||||
refuses to proceed with the merge to avoid losing such a
|
||||
path. However this safety valve sometimes gets in the
|
||||
way. For example, it often happens that the other
|
||||
branch added a file that used to be a generated file in
|
||||
your branch, and the safety valve triggers when you try
|
||||
to switch to that branch after you ran `make` but before
|
||||
running `make clean` to remove the generated file. This
|
||||
option tells the command to read per-directory exclude
|
||||
file (usually '.gitignore') and allows such an untracked
|
||||
but explicitly ignored file to be overwritten.
|
||||
|
||||
<tree-ish#>::
|
||||
The id of the tree object(s) to be read/merged.
|
||||
|
@ -10,6 +10,7 @@ SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git-repo-config' [--global] [type] name [value [value_regex]]
|
||||
'git-repo-config' [--global] [type] --add name value
|
||||
'git-repo-config' [--global] [type] --replace-all name [value [value_regex]]
|
||||
'git-repo-config' [--global] [type] --get name [value_regex]
|
||||
'git-repo-config' [--global] [type] --get-all name [value_regex]
|
||||
@ -23,7 +24,8 @@ You can query/set/replace/unset options with this command. The name is
|
||||
actually the section and the key separated by a dot, and the value will be
|
||||
escaped.
|
||||
|
||||
If you want to set/unset an option which can occur on multiple
|
||||
Multiple lines can be added to an option by using the '--add' option.
|
||||
If you want to update or unset an option which can occur on multiple
|
||||
lines, a POSIX regexp `value_regex` needs to be given. Only the
|
||||
existing values that match the regexp are updated or unset. If
|
||||
you want to handle the lines that do *not* match the regex, just
|
||||
@ -53,6 +55,10 @@ OPTIONS
|
||||
Default behavior is to replace at most one line. This replaces
|
||||
all lines matching the key (and optionally the value_regex).
|
||||
|
||||
--add::
|
||||
Adds a new line to the option without altering any existing
|
||||
values. This is the same as providing '^$' as the value_regex.
|
||||
|
||||
--get::
|
||||
Get the value for a given key (optionally filtered by a regex
|
||||
matching the value). Returns error code 1 if the key was not
|
||||
@ -77,6 +83,12 @@ OPTIONS
|
||||
-l, --list::
|
||||
List all variables set in config file.
|
||||
|
||||
--bool::
|
||||
git-repo-config will ensure that the output is "true" or "false"
|
||||
|
||||
--int::
|
||||
git-repo-config will ensure that the output is a simple decimal number
|
||||
|
||||
|
||||
ENVIRONMENT
|
||||
-----------
|
||||
@ -188,6 +200,12 @@ To actually match only values with an exclamation mark, you have to
|
||||
% git repo-config section.key value '[!]'
|
||||
------------
|
||||
|
||||
To add a new proxy, without altering any of the existing ones, use
|
||||
|
||||
------------
|
||||
% git repo-config core.gitproxy '"proxy" for example.com'
|
||||
------------
|
||||
|
||||
|
||||
include::config.txt[]
|
||||
|
||||
|
@ -7,8 +7,7 @@ git-rerere - Reuse recorded resolve
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-rerere'
|
||||
|
||||
'git-rerere' [clear|diff|status]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@ -27,6 +26,38 @@ results and applying the previously recorded hand resolution.
|
||||
You need to create `$GIT_DIR/rr-cache` directory to enable this
|
||||
command.
|
||||
|
||||
|
||||
COMMANDS
|
||||
--------
|
||||
|
||||
Normally, git-rerere is run without arguments or user-intervention.
|
||||
However, it has several commands that allow it to interact with
|
||||
its working state.
|
||||
|
||||
'clear'::
|
||||
|
||||
This resets the metadata used by rerere if a merge resolution is to be
|
||||
is aborted. Calling gitlink:git-am[1] --skip or gitlink:git-rebase[1]
|
||||
[--skip|--abort] will automatcally invoke this command.
|
||||
|
||||
'diff'::
|
||||
|
||||
This displays diffs for the current state of the resolution. It is
|
||||
useful for tracking what has changed while the user is resolving
|
||||
conflicts. Additional arguments are passed directly to the system
|
||||
diff(1) command installed in PATH.
|
||||
|
||||
'status'::
|
||||
|
||||
Like diff, but this only prints the filenames that will be tracked
|
||||
for resolutions.
|
||||
|
||||
'gc'::
|
||||
|
||||
This command is used to prune records of conflicted merge that
|
||||
occurred long time ago.
|
||||
|
||||
|
||||
DISCUSSION
|
||||
----------
|
||||
|
||||
|
@ -7,7 +7,9 @@ git-reset - Reset current HEAD to the specified state
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-reset' [--mixed | --soft | --hard] [<commit-ish>]
|
||||
[verse]
|
||||
'git-reset' [--mixed | --soft | --hard] [<commit>]
|
||||
'git-reset' [--mixed] <commit> [--] <paths>...
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@ -21,6 +23,10 @@ the undo in the history.
|
||||
If you want to undo a commit other than the latest on a branch,
|
||||
gitlink:git-revert[1] is your friend.
|
||||
|
||||
The second form with 'paths' is used to revert selected paths in
|
||||
the index from a given commit, without moving HEAD.
|
||||
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
--mixed::
|
||||
@ -31,15 +37,15 @@ OPTIONS
|
||||
--soft::
|
||||
Does not touch the index file nor the working tree at all, but
|
||||
requires them to be in a good order. This leaves all your changed
|
||||
files "Updated but not checked in", as gitlink:git-status[1] would
|
||||
files "Added but not yet committed", as gitlink:git-status[1] would
|
||||
put it.
|
||||
|
||||
--hard::
|
||||
Matches the working tree and index to that of the tree being
|
||||
switched to. Any changes to tracked files in the working tree
|
||||
since <commit-ish> are lost.
|
||||
since <commit> are lost.
|
||||
|
||||
<commit-ish>::
|
||||
<commit>::
|
||||
Commit to make the current HEAD.
|
||||
|
||||
Examples
|
||||
|
@ -10,6 +10,7 @@ SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git-rev-list' [ \--max-count=number ]
|
||||
[ \--skip=number ]
|
||||
[ \--max-age=timestamp ]
|
||||
[ \--min-age=timestamp ]
|
||||
[ \--sparse ]
|
||||
@ -139,6 +140,10 @@ limiting may be applied.
|
||||
|
||||
Limit the number of commits output.
|
||||
|
||||
--skip='number'::
|
||||
|
||||
Skip 'number' commits before starting to show the commit output.
|
||||
|
||||
--since='date', --after='date'::
|
||||
|
||||
Show commits more recent than a specific date.
|
||||
|
@ -7,51 +7,54 @@ git-rm - Remove files from the working tree and from the index
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-rm' [-f] [-n] [-v] [--] <file>...
|
||||
'git-rm' [-f] [-n] [-r] [--cached] [--] <file>...
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
A convenience wrapper for git-update-index --remove. For those coming
|
||||
from cvs, git-rm provides an operation similar to "cvs rm" or "cvs
|
||||
remove".
|
||||
Remove files from the working tree and from the index. The
|
||||
files have to be identical to the tip of the branch, and no
|
||||
updates to its contents must have been placed in the staging
|
||||
area (aka index).
|
||||
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
<file>...::
|
||||
Files to remove from the index and optionally, from the
|
||||
working tree as well.
|
||||
Files to remove. Fileglobs (e.g. `*.c`) can be given to
|
||||
remove all matching files. Also a leading directory name
|
||||
(e.g. `dir` to add `dir/file1` and `dir/file2`) can be
|
||||
given to remove all files in the directory, recursively,
|
||||
but this requires `-r` option to be given for safety.
|
||||
|
||||
-f::
|
||||
Remove files from the working tree as well as from the index.
|
||||
Override the up-to-date check.
|
||||
|
||||
-n::
|
||||
Don't actually remove the file(s), just show if they exist in
|
||||
the index.
|
||||
|
||||
-v::
|
||||
Be verbose.
|
||||
-r::
|
||||
Allow recursive removal when a leading directory name is
|
||||
given.
|
||||
|
||||
\--::
|
||||
This option can be used to separate command-line options from
|
||||
the list of files, (useful when filenames might be mistaken
|
||||
for command-line options).
|
||||
|
||||
\--cached::
|
||||
This option can be used to tell the command to remove
|
||||
the paths only from the index, leaving working tree
|
||||
files.
|
||||
|
||||
|
||||
DISCUSSION
|
||||
----------
|
||||
|
||||
The list of <file> given to the command is fed to `git-ls-files`
|
||||
command to list files that are registered in the index and
|
||||
are not ignored/excluded by `$GIT_DIR/info/exclude` file or
|
||||
`.gitignore` file in each directory. This means two things:
|
||||
|
||||
. You can put the name of a directory on the command line, and the
|
||||
command will remove all files in it and its subdirectories (the
|
||||
directories themselves are never removed from the working tree);
|
||||
|
||||
. Giving the name of a file that is not in the index does not
|
||||
remove that file.
|
||||
The list of <file> given to the command can be exact pathnames,
|
||||
file glob patterns, or leading directory name. The command
|
||||
removes only the paths that is known to git. Giving the name of
|
||||
a file that you have not told git about does not remove that file.
|
||||
|
||||
|
||||
EXAMPLES
|
||||
@ -69,10 +72,10 @@ subdirectories of `Documentation/` directory.
|
||||
git-rm -f git-*.sh::
|
||||
|
||||
Remove all git-*.sh scripts that are in the index. The files
|
||||
are removed from the index, and (because of the -f option),
|
||||
from the working tree as well. Because this example lets the
|
||||
shell expand the asterisk (i.e. you are listing the files
|
||||
explicitly), it does not remove `subdir/git-foo.sh`.
|
||||
are removed from the index, and from the working
|
||||
tree. Because this example lets the shell expand the
|
||||
asterisk (i.e. you are listing the files explicitly), it
|
||||
does not remove `subdir/git-foo.sh`.
|
||||
|
||||
See Also
|
||||
--------
|
||||
|
@ -8,6 +8,7 @@ git-shortlog - Summarize 'git log' output
|
||||
SYNOPSIS
|
||||
--------
|
||||
git-log --pretty=short | 'git-shortlog' [-h] [-n] [-s]
|
||||
git-shortlog [-n|--number] [-s|--summary] [<committish>...]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
@ -8,9 +8,10 @@ git-show-branch - Show branches and their commits
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git-show-branch' [--all] [--heads] [--tags] [--topo-order] [--current]
|
||||
'git-show-branch' [--all] [--remotes] [--topo-order] [--current]
|
||||
[--more=<n> | --list | --independent | --merge-base]
|
||||
[--no-name | --sha1-name] [<rev> | <glob>]...
|
||||
[--no-name | --sha1-name] [--topics] [<rev> | <glob>]...
|
||||
'git-show-branch' --reflog[=<n>] <ref>
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@ -37,9 +38,11 @@ OPTIONS
|
||||
branches under $GIT_DIR/refs/heads/topic, giving
|
||||
`topic/*` would show all of them.
|
||||
|
||||
--all --heads --tags::
|
||||
Show all refs under $GIT_DIR/refs, $GIT_DIR/refs/heads,
|
||||
and $GIT_DIR/refs/tags, respectively.
|
||||
-r|--remotes::
|
||||
Show the remote-tracking branches.
|
||||
|
||||
-a|--all::
|
||||
Show both remote-tracking branches and local branches.
|
||||
|
||||
--current::
|
||||
With this option, the command includes the current
|
||||
@ -86,6 +89,18 @@ OPTIONS
|
||||
of "master"), name them with the unique prefix of their
|
||||
object names.
|
||||
|
||||
--topics::
|
||||
Shows only commits that are NOT on the first branch given.
|
||||
This helps track topic branches by hiding any commit that
|
||||
is already in the main line of development. When given
|
||||
"git show-branch --topics master topic1 topic2", this
|
||||
will show the revisions given by "git rev-list {caret}master
|
||||
topic1 topic2"
|
||||
|
||||
--reflog[=<n>] <ref>::
|
||||
Shows <n> most recent ref-log entries for the given ref.
|
||||
|
||||
|
||||
Note that --more, --list, --independent and --merge-base options
|
||||
are mutually exclusive.
|
||||
|
||||
|
@ -3,20 +3,27 @@ git-show(1)
|
||||
|
||||
NAME
|
||||
----
|
||||
git-show - Show one commit with difference it introduces
|
||||
git-show - Show various types of objects
|
||||
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-show' <option>...
|
||||
'git-show' [options] <object>...
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
Shows commit log and textual diff for a single commit. The
|
||||
command internally invokes 'git-rev-list' piped to
|
||||
'git-diff-tree', and takes command line options for both of
|
||||
these commands. It also presents the merge commit in a special
|
||||
format as produced by 'git-diff-tree --cc'.
|
||||
Shows one or more objects (blobs, trees, tags and commits).
|
||||
|
||||
For commits it shows the log message and textual diff. It also
|
||||
presents the merge commit in a special format as produced by
|
||||
'git-diff-tree --cc'.
|
||||
|
||||
For tags, it shows the tag message and the referenced objects.
|
||||
|
||||
For trees, it shows the names (equivalent to gitlink:git-ls-tree[1]
|
||||
with \--name-only).
|
||||
|
||||
For plain blobs, it shows the plain contents.
|
||||
|
||||
This manual page describes only the most frequently used options.
|
||||
|
||||
@ -28,6 +35,25 @@ OPTIONS
|
||||
|
||||
include::pretty-formats.txt[]
|
||||
|
||||
|
||||
EXAMPLES
|
||||
--------
|
||||
|
||||
git show v1.0.0::
|
||||
Shows the tag `v1.0.0`.
|
||||
|
||||
git show v1.0.0^{tree}::
|
||||
Shows the tree pointed to by the tag `v1.0.0`.
|
||||
|
||||
git show next~10:Documentation/README
|
||||
Shows the contents of the file `Documentation/README` as
|
||||
they were current in the 10th last commit of the branch
|
||||
`next`.
|
||||
|
||||
git show master:Makefile master:t/Makefile
|
||||
Concatenates the contents of said Makefiles in the head
|
||||
of the branch `master`.
|
||||
|
||||
Author
|
||||
------
|
||||
Written by Linus Torvalds <torvalds@osdl.org> and
|
||||
|
@ -49,7 +49,7 @@ latest revision.
|
||||
|
||||
Note: You should never attempt to modify the remotes/git-svn
|
||||
branch outside of git-svn. Instead, create a branch from
|
||||
remotes/git-svn and work on that branch. Use the 'commit'
|
||||
remotes/git-svn and work on that branch. Use the 'dcommit'
|
||||
command (see below) to write git commits back to
|
||||
remotes/git-svn.
|
||||
|
||||
@ -57,12 +57,14 @@ See '<<fetch-args,Additional Fetch Arguments>>' if you are interested in
|
||||
manually joining branches on commit.
|
||||
|
||||
'dcommit'::
|
||||
Commit all diffs from the current HEAD directly to the SVN
|
||||
Commit all diffs from a specified head directly to the SVN
|
||||
repository, and then rebase or reset (depending on whether or
|
||||
not there is a diff between SVN and HEAD). It is recommended
|
||||
not there is a diff between SVN and head). It is recommended
|
||||
that you run git-svn fetch and rebase (not pull) your commits
|
||||
against the latest changes in the SVN repository.
|
||||
This is advantageous over 'commit' (below) because it produces
|
||||
An optional command-line argument may be specified as an
|
||||
alternative to HEAD.
|
||||
This is advantageous over 'set-tree' (below) because it produces
|
||||
cleaner, more linear history.
|
||||
|
||||
'log'::
|
||||
@ -87,7 +89,7 @@ manually joining branches on commit.
|
||||
|
||||
Any other arguments are passed directly to `git log'
|
||||
|
||||
'commit'::
|
||||
'set-tree'::
|
||||
You should consider using 'dcommit' instead of this command.
|
||||
Commit specified commit or tree objects to SVN. This relies on
|
||||
your imported fetch data being up-to-date. This makes
|
||||
@ -170,7 +172,7 @@ This can allow you to make partial mirrors when running fetch.
|
||||
-::
|
||||
--stdin::
|
||||
|
||||
Only used with the 'commit' command.
|
||||
Only used with the 'set-tree' command.
|
||||
|
||||
Read a list of commits from stdin and commit them in reverse
|
||||
order. Only the leading sha1 is read from each line, so
|
||||
@ -178,7 +180,7 @@ git-rev-list --pretty=oneline output can be used.
|
||||
|
||||
--rmdir::
|
||||
|
||||
Only used with the 'dcommit', 'commit' and 'commit-diff' commands.
|
||||
Only used with the 'dcommit', 'set-tree' and 'commit-diff' commands.
|
||||
|
||||
Remove directories from the SVN tree if there are no files left
|
||||
behind. SVN can version empty directories, and they are not
|
||||
@ -191,7 +193,7 @@ repo-config key: svn.rmdir
|
||||
-e::
|
||||
--edit::
|
||||
|
||||
Only used with the 'dcommit', 'commit' and 'commit-diff' commands.
|
||||
Only used with the 'dcommit', 'set-tree' and 'commit-diff' commands.
|
||||
|
||||
Edit the commit message before committing to SVN. This is off by
|
||||
default for objects that are commits, and forced on when committing
|
||||
@ -202,7 +204,7 @@ repo-config key: svn.edit
|
||||
-l<num>::
|
||||
--find-copies-harder::
|
||||
|
||||
Only used with the 'dcommit', 'commit' and 'commit-diff' commands.
|
||||
Only used with the 'dcommit', 'set-tree' and 'commit-diff' commands.
|
||||
|
||||
They are both passed directly to git-diff-tree see
|
||||
gitlink:git-diff-tree[1] for more information.
|
||||
@ -274,7 +276,7 @@ ADVANCED OPTIONS
|
||||
|
||||
-b<refname>::
|
||||
--branch <refname>::
|
||||
Used with 'fetch' or 'commit'.
|
||||
Used with 'fetch', 'dcommit' or 'set-tree'.
|
||||
|
||||
This can be used to join arbitrary git branches to remotes/git-svn
|
||||
on new commits where the tree object is equivalent.
|
||||
@ -368,7 +370,7 @@ SVN was very wrong.
|
||||
Basic Examples
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
Tracking and contributing to an Subversion managed-project:
|
||||
Tracking and contributing to a Subversion-managed project:
|
||||
|
||||
------------------------------------------------------------------------
|
||||
# Initialize a repo (like git init-db):
|
||||
@ -377,10 +379,9 @@ Tracking and contributing to an Subversion managed-project:
|
||||
git-svn fetch
|
||||
# Create your own branch to hack on:
|
||||
git checkout -b my-branch remotes/git-svn
|
||||
# Commit only the git commits you want to SVN:
|
||||
git-svn commit <tree-ish> [<tree-ish_2> ...]
|
||||
# Commit all the git commits from my-branch that don't exist in SVN:
|
||||
git-svn commit remotes/git-svn..my-branch
|
||||
# Do some work, and then commit your new changes to SVN, as well as
|
||||
# automatically updating your working HEAD:
|
||||
git-svn dcommit
|
||||
# Something is committed to SVN, rebase the latest into your branch:
|
||||
git-svn fetch && git rebase remotes/git-svn
|
||||
# Append svn:ignore settings to the default git exclude file:
|
||||
@ -391,11 +392,11 @@ REBASE VS. PULL
|
||||
---------------
|
||||
|
||||
Originally, git-svn recommended that the remotes/git-svn branch be
|
||||
pulled from. This is because the author favored 'git-svn commit B'
|
||||
to commit a single head rather than the 'git-svn commit A..B' notation
|
||||
pulled from. This is because the author favored 'git-svn set-tree B'
|
||||
to commit a single head rather than the 'git-svn set-tree A..B' notation
|
||||
to commit multiple commits.
|
||||
|
||||
If you use 'git-svn commit A..B' to commit several diffs and you do not
|
||||
If you use 'git-svn set-tree A..B' to commit several diffs and you do not
|
||||
have the latest remotes/git-svn merged into my-branch, you should use
|
||||
'git rebase' to update your work branch instead of 'git pull'. 'pull'
|
||||
can cause non-linear history to be flattened when committing into SVN,
|
||||
@ -404,26 +405,24 @@ which can lead to merge commits reversing previous commits in SVN.
|
||||
DESIGN PHILOSOPHY
|
||||
-----------------
|
||||
Merge tracking in Subversion is lacking and doing branched development
|
||||
with Subversion is cumbersome as a result. git-svn completely forgoes
|
||||
any automated merge/branch tracking on the Subversion side and leaves it
|
||||
entirely up to the user on the git side. It's simply not worth it to do
|
||||
a useful translation when the original signal is weak.
|
||||
with Subversion is cumbersome as a result. git-svn does not do
|
||||
automated merge/branch tracking by default and leaves it entirely up to
|
||||
the user on the git side.
|
||||
|
||||
[[tracking-multiple-repos]]
|
||||
TRACKING MULTIPLE REPOSITORIES OR BRANCHES
|
||||
------------------------------------------
|
||||
This is for advanced users, most users should ignore this section.
|
||||
|
||||
Because git-svn does not care about relationships between different
|
||||
branches or directories in a Subversion repository, git-svn has a simple
|
||||
hack to allow it to track an arbitrary number of related _or_ unrelated
|
||||
SVN repositories via one git repository. Simply set the GIT_SVN_ID
|
||||
environment variable to a name other other than "git-svn" (the default)
|
||||
and git-svn will ignore the contents of the $GIT_DIR/svn/git-svn directory
|
||||
and instead do all of its work in $GIT_DIR/svn/$GIT_SVN_ID for that
|
||||
invocation. The interface branch will be remotes/$GIT_SVN_ID, instead of
|
||||
remotes/git-svn. Any remotes/$GIT_SVN_ID branch should never be modified
|
||||
by the user outside of git-svn commands.
|
||||
SVN repositories via one git repository. Simply use the --id/-i flag or
|
||||
set the GIT_SVN_ID environment variable to a name other other than
|
||||
"git-svn" (the default) and git-svn will ignore the contents of the
|
||||
$GIT_DIR/svn/git-svn directory and instead do all of its work in
|
||||
$GIT_DIR/svn/$GIT_SVN_ID for that invocation. The interface branch will
|
||||
be remotes/$GIT_SVN_ID, instead of remotes/git-svn. Any
|
||||
remotes/$GIT_SVN_ID branch should never be modified by the user outside
|
||||
of git-svn commands.
|
||||
|
||||
[[fetch-args]]
|
||||
ADDITIONAL FETCH ARGUMENTS
|
||||
@ -486,7 +485,8 @@ If you are not using the SVN::* Perl libraries and somebody commits a
|
||||
conflicting changeset to SVN at a bad moment (right before you commit)
|
||||
causing a conflict and your commit to fail, your svn working tree
|
||||
($GIT_DIR/git-svn/tree) may be dirtied. The easiest thing to do is
|
||||
probably just to rm -rf $GIT_DIR/git-svn/tree and run 'rebuild'.
|
||||
probably just to rm -rf $GIT_DIR/git-svn/tree and run 'rebuild'. You
|
||||
can avoid this problem entirely by using 'dcommit'.
|
||||
|
||||
We ignore all SVN properties except svn:executable. Too difficult to
|
||||
map them since we rely heavily on git write-tree being _exactly_ the
|
||||
|
@ -15,6 +15,7 @@ SYNOPSIS
|
||||
[ -b branch_subdir ] [ -T trunk_subdir ] [ -t tag_subdir ]
|
||||
[ -s start_chg ] [ -m ] [ -r ] [ -M regex ]
|
||||
[ -I <ignorefile_name> ] [ -A <author_file> ]
|
||||
[ -P <path_from_trunk> ]
|
||||
<SVN_repository_URL> [ <path> ]
|
||||
|
||||
|
||||
@ -103,9 +104,17 @@ repository without -A.
|
||||
|
||||
-l <max_rev>::
|
||||
Specify a maximum revision number to pull.
|
||||
+
|
||||
Formerly, this option controlled how many revisions to pull,
|
||||
due to SVN memory leaks. (These have been worked around.)
|
||||
|
||||
Formerly, this option controlled how many revisions to pull,
|
||||
due to SVN memory leaks. (These have been worked around.)
|
||||
-P <path_from_trunk>::
|
||||
Partial import of the SVN tree.
|
||||
+
|
||||
By default, the whole tree on the SVN trunk (/trunk) is imported.
|
||||
'-P my/proj' will import starting only from '/trunk/my/proj'.
|
||||
This option is useful when you want to import one project from a
|
||||
svn repo which hosts multiple projects under the same trunk.
|
||||
|
||||
-v::
|
||||
Verbosity: let 'svnimport' report what it is doing.
|
||||
|
@ -19,29 +19,22 @@ argument to see on which branch your working tree is on.
|
||||
Give two arguments, create or update a symbolic ref <name> to
|
||||
point at the given branch <ref>.
|
||||
|
||||
Traditionally, `.git/HEAD` is a symlink pointing at
|
||||
`refs/heads/master`. When we want to switch to another branch,
|
||||
we did `ln -sf refs/heads/newbranch .git/HEAD`, and when we want
|
||||
A symbolic ref is a regular file that stores a string that
|
||||
begins with `ref: refs/`. For example, your `.git/HEAD` is
|
||||
a regular file whose contents is `ref: refs/heads/master`.
|
||||
|
||||
NOTES
|
||||
-----
|
||||
In the past, `.git/HEAD` was a symbolic link pointing at
|
||||
`refs/heads/master`. When we wanted to switch to another branch,
|
||||
we did `ln -sf refs/heads/newbranch .git/HEAD`, and when we wanted
|
||||
to find out which branch we are on, we did `readlink .git/HEAD`.
|
||||
This was fine, and internally that is what still happens by
|
||||
default, but on platforms that do not have working symlinks,
|
||||
or that do not have the `readlink(1)` command, this was a bit
|
||||
cumbersome. On some platforms, `ln -sf` does not even work as
|
||||
advertised (horrors).
|
||||
|
||||
A symbolic ref can be a regular file that stores a string that
|
||||
begins with `ref: refs/`. For example, your `.git/HEAD` *can*
|
||||
be a regular file whose contents is `ref: refs/heads/master`.
|
||||
This can be used on a filesystem that does not support symbolic
|
||||
links. Instead of doing `readlink .git/HEAD`, `git-symbolic-ref
|
||||
HEAD` can be used to find out which branch we are on. To point
|
||||
the HEAD to `newbranch`, instead of `ln -sf refs/heads/newbranch
|
||||
.git/HEAD`, `git-symbolic-ref HEAD refs/heads/newbranch` can be
|
||||
used.
|
||||
|
||||
Currently, .git/HEAD uses a regular file symbolic ref on Cygwin,
|
||||
and everywhere else it is implemented as a symlink. This can be
|
||||
changed at compilation time.
|
||||
advertised (horrors). Therefore symbolic links are now deprecated
|
||||
and symbolic refs are used by default.
|
||||
|
||||
Author
|
||||
------
|
||||
|
@ -9,7 +9,8 @@ git-tag - Create a tag object signed with GPG
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git-tag' [-a | -s | -u <key-id>] [-f | -d] [-m <msg>] <name> [<head>]
|
||||
'git-tag' [-a | -s | -u <key-id>] [-f | -d] [-m <msg> | -F <file>]
|
||||
<name> [<head>]
|
||||
'git-tag' -l [<pattern>]
|
||||
|
||||
DESCRIPTION
|
||||
@ -60,6 +61,9 @@ OPTIONS
|
||||
-m <msg>::
|
||||
Use the given tag message (instead of prompting)
|
||||
|
||||
-F <file>::
|
||||
Take the tag message from the given file. Use '-' to
|
||||
read the message from the standard input.
|
||||
|
||||
Author
|
||||
------
|
||||
|
@ -351,6 +351,9 @@ gitlink:git-init-db[1]::
|
||||
Creates an empty git object database, or reinitialize an
|
||||
existing one.
|
||||
|
||||
gitlink:git-merge-file[1]::
|
||||
Runs a threeway merge.
|
||||
|
||||
gitlink:git-merge-index[1]::
|
||||
Runs a merge for files needing merging.
|
||||
|
||||
@ -639,11 +642,35 @@ git Commits
|
||||
git Diffs
|
||||
~~~~~~~~~
|
||||
'GIT_DIFF_OPTS'::
|
||||
Only valid setting is "--unified=??" or "-u??" to set the
|
||||
number of context lines shown when a unified diff is created.
|
||||
This takes precedence over any "-U" or "--unified" option
|
||||
value passed on the git diff command line.
|
||||
|
||||
'GIT_EXTERNAL_DIFF'::
|
||||
see the "generating patches" section in :
|
||||
gitlink:git-diff-index[1];
|
||||
gitlink:git-diff-files[1];
|
||||
gitlink:git-diff-tree[1]
|
||||
When the environment variable 'GIT_EXTERNAL_DIFF' is set, the
|
||||
program named by it is called, instead of the diff invocation
|
||||
described above. For a path that is added, removed, or modified,
|
||||
'GIT_EXTERNAL_DIFF' is called with 7 parameters:
|
||||
|
||||
path old-file old-hex old-mode new-file new-hex new-mode
|
||||
+
|
||||
where:
|
||||
|
||||
<old|new>-file:: are files GIT_EXTERNAL_DIFF can use to read the
|
||||
contents of <old|new>,
|
||||
<old|new>-hex:: are the 40-hexdigit SHA1 hashes,
|
||||
<old|new>-mode:: are the octal representation of the file modes.
|
||||
|
||||
+
|
||||
The file parameters can point at the user's working file
|
||||
(e.g. `new-file` in "git-diff-files"), `/dev/null` (e.g. `old-file`
|
||||
when a new file is added), or a temporary file (e.g. `old-file` in the
|
||||
index). 'GIT_EXTERNAL_DIFF' should not worry about unlinking the
|
||||
temporary file --- it is removed when 'GIT_EXTERNAL_DIFF' exits.
|
||||
+
|
||||
For a path that is unmerged, 'GIT_EXTERNAL_DIFF' is called with 1
|
||||
parameter, <path>.
|
||||
|
||||
other
|
||||
~~~~~
|
||||
|
31
Documentation/install-doc-quick.sh
Executable file
31
Documentation/install-doc-quick.sh
Executable file
@ -0,0 +1,31 @@
|
||||
#!/bin/sh
|
||||
# This requires a branch named in $head
|
||||
# (usually 'man' or 'html', provided by the git.git repository)
|
||||
set -e
|
||||
head="$1"
|
||||
mandir="$2"
|
||||
SUBDIRECTORY_OK=t
|
||||
USAGE='<refname> <target directory>'
|
||||
. git-sh-setup
|
||||
export GIT_DIR
|
||||
|
||||
test -z "$mandir" && usage
|
||||
if ! git-rev-parse --verify "$head^0" >/dev/null; then
|
||||
echo >&2 "head: $head does not exist in the current repository"
|
||||
usage
|
||||
fi
|
||||
|
||||
GIT_INDEX_FILE=`pwd`/.quick-doc.index
|
||||
export GIT_INDEX_FILE
|
||||
rm -f "$GIT_INDEX_FILE"
|
||||
git-read-tree $head
|
||||
git-checkout-index -a -f --prefix="$mandir"/
|
||||
|
||||
if test -n "$GZ"; then
|
||||
cd "$mandir"
|
||||
for i in `git-ls-tree -r --name-only $head`
|
||||
do
|
||||
gzip < $i > $i.gz && rm $i
|
||||
done
|
||||
fi
|
||||
rm -f "$GIT_INDEX_FILE"
|
@ -4,7 +4,7 @@ Use of index and Racy git problem
|
||||
Background
|
||||
----------
|
||||
|
||||
The index is one of the most important data structure in git.
|
||||
The index is one of the most important data structures in git.
|
||||
It represents a virtual working tree state by recording list of
|
||||
paths and their object names and serves as a staging area to
|
||||
write out the next tree object to be committed. The state is
|
||||
@ -16,7 +16,7 @@ virtual working tree state in the index and the files in the
|
||||
working tree. The most obvious case is when the user asks `git
|
||||
diff` (or its low level implementation, `git diff-files`) or
|
||||
`git-ls-files --modified`. In addition, git internally checks
|
||||
if the files in the working tree is different from what are
|
||||
if the files in the working tree are different from what are
|
||||
recorded in the index to avoid stomping on local changes in them
|
||||
during patch application, switching branches, and merging.
|
||||
|
||||
@ -24,9 +24,9 @@ In order to speed up this comparison between the files in the
|
||||
working tree and the index entries, the index entries record the
|
||||
information obtained from the filesystem via `lstat(2)` system
|
||||
call when they were last updated. When checking if they differ,
|
||||
git first runs `lstat(2)` on the files and compare the result
|
||||
git first runs `lstat(2)` on the files and compares the result
|
||||
with this information (this is what was originally done by the
|
||||
`ce_match_stat()` function, which the current code does in
|
||||
`ce_match_stat()` function, but the current code does it in
|
||||
`ce_match_stat_basic()` function). If some of these "cached
|
||||
stat information" fields do not match, git can tell that the
|
||||
files are modified without even looking at their contents.
|
||||
@ -53,8 +53,9 @@ Racy git
|
||||
There is one slight problem with the optimization based on the
|
||||
cached stat information. Consider this sequence:
|
||||
|
||||
: modify 'foo'
|
||||
$ git update-index 'foo'
|
||||
: modify 'foo' in-place without changing its size
|
||||
: modify 'foo' again, in-place, without changing its size
|
||||
|
||||
The first `update-index` computes the object name of the
|
||||
contents of file `foo` and updates the index entry for `foo`
|
||||
@ -62,7 +63,8 @@ along with the `struct stat` information. If the modification
|
||||
that follows it happens very fast so that the file's `st_mtime`
|
||||
timestamp does not change, after this sequence, the cached stat
|
||||
information the index entry records still exactly match what you
|
||||
can obtain from the filesystem, but the file `foo` is modified.
|
||||
would see in the filesystem, even though the file `foo` is now
|
||||
different.
|
||||
This way, git can incorrectly think files in the working tree
|
||||
are unmodified even though they actually are. This is called
|
||||
the "racy git" problem (discovered by Pasky), and the entries
|
||||
@ -87,7 +89,7 @@ the stat information from updated paths, `st_mtime` timestamp of
|
||||
it is usually the same as or newer than any of the paths the
|
||||
index contains. And no matter how quick the modification that
|
||||
follows `git update-index foo` finishes, the resulting
|
||||
`st_mtime` timestamp on `foo` cannot get the timestamp earlier
|
||||
`st_mtime` timestamp on `foo` cannot get a value earlier
|
||||
than the index file. Therefore, index entries that can be
|
||||
racily clean are limited to the ones that have the same
|
||||
timestamp as the index file itself.
|
||||
@ -111,7 +113,7 @@ value, and falsely clean entry `foo` would not be caught by the
|
||||
timestamp comparison check done with the former logic anymore.
|
||||
The latter makes sure that the cached stat information for `foo`
|
||||
would never match with the file in the working tree, so later
|
||||
checks by `ce_match_stat_basic()` would report the index entry
|
||||
checks by `ce_match_stat_basic()` would report that the index entry
|
||||
does not match the file and git does not have to fall back on more
|
||||
expensive `ce_modified_check_fs()`.
|
||||
|
||||
@ -155,17 +157,16 @@ of the cached stat information.
|
||||
Avoiding runtime penalty
|
||||
------------------------
|
||||
|
||||
In order to avoid the above runtime penalty, the recent "master"
|
||||
branch (post 1.4.2) has a code that makes sure the index file
|
||||
gets timestamp newer than the youngest files in the index when
|
||||
In order to avoid the above runtime penalty, post 1.4.2 git used
|
||||
to have a code that made sure the index file
|
||||
got timestamp newer than the youngest files in the index when
|
||||
there are many young files with the same timestamp as the
|
||||
resulting index file would otherwise would have by waiting
|
||||
before finishing writing the index file out.
|
||||
|
||||
I suspect that in practice the situation where many paths in the
|
||||
index are all racily clean is quite rare. The only code paths
|
||||
that can record recent timestamp for large number of paths I
|
||||
know of are:
|
||||
I suspected that in practice the situation where many paths in the
|
||||
index are all racily clean was quite rare. The only code paths
|
||||
that can record recent timestamp for large number of paths are:
|
||||
|
||||
. Initial `git add .` of a large project.
|
||||
|
||||
@ -188,6 +189,7 @@ youngest file in the working tree. This means that in these
|
||||
cases there actually will not be any racily clean entry in
|
||||
the resulting index.
|
||||
|
||||
So in summary I think we should not worry about avoiding the
|
||||
runtime penalty and get rid of the "wait before finishing
|
||||
writing" code out.
|
||||
Based on this discussion, the current code does not use the
|
||||
"workaround" to avoid the runtime penalty that does not exist in
|
||||
practice anymore. This was done with commit 0fc82cff on Aug 15,
|
||||
2006.
|
||||
|
@ -18,17 +18,18 @@ Let's start a new project and create a small amount of history:
|
||||
$ mkdir test-project
|
||||
$ cd test-project
|
||||
$ git init-db
|
||||
defaulting to local storage area
|
||||
Initialized empty Git repository in .git/
|
||||
$ echo 'hello world' > file.txt
|
||||
$ git add .
|
||||
$ git commit -a -m "initial commit"
|
||||
Committing initial tree 92b8b694ffb1675e5975148e1121810081dbdffe
|
||||
Created initial commit 54196cc2703dc165cbd373a65a4dcf22d50ae7f7
|
||||
create mode 100644 file.txt
|
||||
$ echo 'hello world!' >file.txt
|
||||
$ git commit -a -m "add emphasis"
|
||||
Created commit c4d59f390b9cfd4318117afde11d601c1085f241
|
||||
------------------------------------------------
|
||||
|
||||
What are the 40 digits of hex that git responded to the first commit
|
||||
with?
|
||||
What are the 40 digits of hex that git responded to the commit with?
|
||||
|
||||
We saw in part one of the tutorial that commits have names like this.
|
||||
It turns out that every object in the git history is stored under
|
||||
@ -38,13 +39,25 @@ the same data twice (since identical data is given an identical SHA1
|
||||
name), and that the contents of a git object will never change (since
|
||||
that would change the object's name as well).
|
||||
|
||||
It is expected that the content of the commit object you created while
|
||||
following the example above generates a different SHA1 hash than
|
||||
the one shown above because the commit object records the time when
|
||||
it was created and the name of the person performing the commit.
|
||||
|
||||
We can ask git about this particular object with the cat-file
|
||||
command--just cut-and-paste from the reply to the initial commit, to
|
||||
save yourself typing all 40 hex digits:
|
||||
command. Don't copy the 40 hex digits from this example but use those
|
||||
from your own version. Note that you can shorten it to only a few
|
||||
characters to save yourself typing all 40 hex digits:
|
||||
|
||||
------------------------------------------------
|
||||
$ git cat-file -t 92b8b694ffb1675e5975148e1121810081dbdffe
|
||||
tree
|
||||
$ git-cat-file -t 54196cc2
|
||||
commit
|
||||
$ git-cat-file commit 54196cc2
|
||||
tree 92b8b694ffb1675e5975148e1121810081dbdffe
|
||||
author J. Bruce Fields <bfields@puzzle.fieldses.org> 1143414668 -0500
|
||||
committer J. Bruce Fields <bfields@puzzle.fieldses.org> 1143414668 -0500
|
||||
|
||||
initial commit
|
||||
------------------------------------------------
|
||||
|
||||
A tree can refer to one or more "blob" objects, each corresponding to
|
||||
@ -101,8 +114,7 @@ $ find .git/objects/
|
||||
|
||||
and the contents of these files is just the compressed data plus a
|
||||
header identifying their length and their type. The type is either a
|
||||
blob, a tree, a commit, or a tag. We've seen a blob and a tree now,
|
||||
so next we should look at a commit.
|
||||
blob, a tree, a commit, or a tag.
|
||||
|
||||
The simplest commit to find is the HEAD commit, which we can find
|
||||
from .git/HEAD:
|
||||
@ -341,23 +353,23 @@ situation:
|
||||
------------------------------------------------
|
||||
$ git status
|
||||
#
|
||||
# Updated but not checked in:
|
||||
# Added but not yet committed:
|
||||
# (will commit)
|
||||
#
|
||||
# new file: closing.txt
|
||||
#
|
||||
#
|
||||
# Changed but not updated:
|
||||
# (use git-update-index to mark for commit)
|
||||
# Changed but not added:
|
||||
# (use "git add file1 file2" to include for commit)
|
||||
#
|
||||
# modified: file.txt
|
||||
#
|
||||
------------------------------------------------
|
||||
|
||||
Since the current state of closing.txt is cached in the index file,
|
||||
it is listed as "updated but not checked in". Since file.txt has
|
||||
it is listed as "added but not yet committed". Since file.txt has
|
||||
changes in the working directory that aren't reflected in the index,
|
||||
it is marked "changed but not updated". At this point, running "git
|
||||
it is marked "changed but not added". 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.
|
||||
|
||||
|
@ -11,6 +11,18 @@ diff" with:
|
||||
$ man git-diff
|
||||
------------------------------------------------
|
||||
|
||||
It is a good idea to introduce yourself to git before doing any
|
||||
operation. The easiest way to do so is:
|
||||
|
||||
------------------------------------------------
|
||||
$ cat >~/.gitconfig <<\EOF
|
||||
[user]
|
||||
name = Your Name Comes Here
|
||||
email = you@yourdomain.example.com
|
||||
EOF
|
||||
------------------------------------------------
|
||||
|
||||
|
||||
Importing a new project
|
||||
-----------------------
|
||||
|
||||
@ -26,12 +38,13 @@ $ git init-db
|
||||
Git will reply
|
||||
|
||||
------------------------------------------------
|
||||
defaulting to local storage area
|
||||
Initialized empty Git repository in .git/
|
||||
------------------------------------------------
|
||||
|
||||
You've now initialized the working directory--you may notice a new
|
||||
directory created, named ".git". Tell git that you want it to track
|
||||
every file under the current directory with
|
||||
every file under the current directory with (notice the dot '.'
|
||||
that means the current directory):
|
||||
|
||||
------------------------------------------------
|
||||
$ git add .
|
||||
@ -40,7 +53,7 @@ $ git add .
|
||||
Finally,
|
||||
|
||||
------------------------------------------------
|
||||
$ git commit -a
|
||||
$ git commit
|
||||
------------------------------------------------
|
||||
|
||||
will prompt you for a commit message, then record the current state
|
||||
@ -55,11 +68,17 @@ $ git diff
|
||||
to review your changes. When you're done,
|
||||
|
||||
------------------------------------------------
|
||||
$ git commit -a
|
||||
$ git commit file1 file2...
|
||||
------------------------------------------------
|
||||
|
||||
will again prompt your for a message describing the change, and then
|
||||
record the new versions of the modified files.
|
||||
record the new versions of the files you listed. It is cumbersome
|
||||
to list all files and you can say `-a` (which stands for 'all')
|
||||
instead.
|
||||
|
||||
------------------------------------------------
|
||||
$ git commit -a
|
||||
------------------------------------------------
|
||||
|
||||
A note on commit messages: Though not required, it's a good idea to
|
||||
begin the commit message with a single short (less than 50 character)
|
||||
@ -68,14 +87,48 @@ thorough description. Tools that turn commits into email, for
|
||||
example, use the first line on the Subject line and the rest of the
|
||||
commit in the body.
|
||||
|
||||
To add a new file, first create the file, then
|
||||
|
||||
------------------------------------------------
|
||||
$ git add path/to/new/file
|
||||
------------------------------------------------
|
||||
Git tracks content not files
|
||||
----------------------------
|
||||
|
||||
then commit as usual. No special command is required when removing a
|
||||
file; just remove it, then commit.
|
||||
With git you have to explicitly "add" all the changed _content_ you
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
But here's a twist. If you do 'git commit <file1> <file2> ...' then only
|
||||
the changes belonging to those explicitly specified files will be
|
||||
committed, entirely bypassing the current "added" changes. Those "added"
|
||||
changes will still remain available for a subsequent commit though.
|
||||
|
||||
However, for normal usage you only have to remember 'git add' + 'git commit'
|
||||
and/or 'git commit -a'.
|
||||
|
||||
|
||||
Viewing the changelog
|
||||
---------------------
|
||||
|
||||
At any point you can view the history of your changes using
|
||||
|
||||
@ -209,29 +262,28 @@ at /home/bob/myrepo. She does this with:
|
||||
|
||||
------------------------------------------------
|
||||
$ cd /home/alice/project
|
||||
$ git pull /home/bob/myrepo
|
||||
$ git pull /home/bob/myrepo master
|
||||
------------------------------------------------
|
||||
|
||||
This actually pulls changes from the branch in Bob's repository named
|
||||
"master". Alice could request a different branch by adding the name
|
||||
of the branch to the end of the git pull command line.
|
||||
This merges the changes from Bob's "master" branch into Alice's
|
||||
current branch. If Alice has made her own changes in the meantime,
|
||||
then she may need to manually fix any conflicts. (Note that the
|
||||
"master" argument in the above command is actually unnecessary, as it
|
||||
is the default.)
|
||||
|
||||
This merges Bob's changes into her repository; "git log" will
|
||||
now show the new commits. If Alice has made her own changes in the
|
||||
meantime, then Bob's changes will be merged in, and she will need to
|
||||
manually fix any conflicts.
|
||||
The "pull" command thus performs two operations: it fetches changes
|
||||
from a remote branch, then merges them into the current branch.
|
||||
|
||||
A more cautious Alice might wish to examine Bob's changes before
|
||||
pulling them. She can do this by creating a temporary branch just
|
||||
for the purpose of studying Bob's changes:
|
||||
You can perform the first operation alone using the "git fetch"
|
||||
command. For example, Alice could create a temporary branch just to
|
||||
track Bob's changes, without merging them with her own, using:
|
||||
|
||||
-------------------------------------
|
||||
$ git fetch /home/bob/myrepo master:bob-incoming
|
||||
-------------------------------------
|
||||
|
||||
which fetches the changes from Bob's master branch into a new branch
|
||||
named bob-incoming. (Unlike git pull, git fetch just fetches a copy
|
||||
of Bob's line of development without doing any merging). Then
|
||||
named bob-incoming. Then
|
||||
|
||||
-------------------------------------
|
||||
$ git log -p master..bob-incoming
|
||||
@ -240,8 +292,8 @@ $ git log -p master..bob-incoming
|
||||
shows a list of all the changes that Bob made since he branched from
|
||||
Alice's master branch.
|
||||
|
||||
After examining those changes, and possibly fixing things, Alice can
|
||||
pull the changes into her master branch:
|
||||
After examining those changes, and possibly fixing things, Alice
|
||||
could pull the changes into her master branch:
|
||||
|
||||
-------------------------------------
|
||||
$ git checkout master
|
||||
@ -251,6 +303,18 @@ $ git pull . bob-incoming
|
||||
The last command is a pull from the "bob-incoming" branch in Alice's
|
||||
own repository.
|
||||
|
||||
Alice could also perform both steps at once with:
|
||||
|
||||
-------------------------------------
|
||||
$ git pull /home/bob/myrepo master:bob-incoming
|
||||
-------------------------------------
|
||||
|
||||
This is just like the "git pull /home/bob/myrepo master" that we saw
|
||||
before, except that it also stores the unmerged changes from bob's
|
||||
master branch in bob-incoming before merging them into Alice's
|
||||
current branch. Note that git pull always merges into the current
|
||||
branch, regardless of what else is given on the commandline.
|
||||
|
||||
Later, Bob can update his repo with Alice's latest changes using
|
||||
|
||||
-------------------------------------
|
||||
|
@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
GVF=GIT-VERSION-FILE
|
||||
DEF_VER=v1.4.4.1.GIT
|
||||
DEF_VER=v1.4.5-rc0.GIT
|
||||
|
||||
LF='
|
||||
'
|
||||
|
22
INSTALL
22
INSTALL
@ -72,25 +72,6 @@ Issues of note:
|
||||
- expat library; git-http-push uses it for remote lock
|
||||
management over DAV. Similar to "curl" above, this is optional.
|
||||
|
||||
- "GNU diff" to generate patches. Of course, you don't _have_ to
|
||||
generate patches if you don't want to, but let's face it, you'll
|
||||
be wanting to. Or why did you get git in the first place?
|
||||
|
||||
Non-GNU versions of the diff/patch programs don't generally support
|
||||
the unified patch format (which is the one git uses), so you
|
||||
really do want to get the GNU one. Trust me, you will want to
|
||||
do that even if it wasn't for git. There's no point in living
|
||||
in the dark ages any more.
|
||||
|
||||
- "merge", the standard UNIX three-way merge program. It usually
|
||||
comes with the "rcs" package on most Linux distributions, so if
|
||||
you have a developer install you probably have it already, but a
|
||||
"graphical user desktop" install might have left it out.
|
||||
|
||||
You'll only need the merge program if you do development using
|
||||
git, and if you only use git to track other peoples work you'll
|
||||
never notice the lack of it.
|
||||
|
||||
- "wish", the Tcl/Tk windowing shell is used in gitk to show the
|
||||
history graphically
|
||||
|
||||
@ -99,9 +80,6 @@ Issues of note:
|
||||
- "perl" and POSIX-compliant shells are needed to use most of
|
||||
the barebone Porcelainish scripts.
|
||||
|
||||
- "python" 2.3 or more recent; if you have 2.3, you may need
|
||||
to build with "make WITH_OWN_SUBPROCESS_PY=YesPlease".
|
||||
|
||||
- Some platform specific issues are dealt with Makefile rules,
|
||||
but depending on your specific installation, you may not
|
||||
have all the libraries/tools needed, or you may have
|
||||
|
119
Makefile
119
Makefile
@ -69,7 +69,8 @@ all:
|
||||
#
|
||||
# Define NO_MMAP if you want to avoid mmap.
|
||||
#
|
||||
# Define WITH_OWN_SUBPROCESS_PY if you want to use with python 2.3.
|
||||
# Define NO_FAST_WORKING_DIRECTORY if accessing objects in pack files is
|
||||
# generally faster on your platform than accessing the working directory.
|
||||
#
|
||||
# Define NO_IPV6 if you lack IPv6 support and getaddrinfo().
|
||||
#
|
||||
@ -78,13 +79,6 @@ all:
|
||||
#
|
||||
# Define NO_ICONV if your libc does not properly support iconv.
|
||||
#
|
||||
# Define NO_ACCURATE_DIFF if your diff program at least sometimes misses
|
||||
# a missing newline at the end of the file.
|
||||
#
|
||||
# Define COLLISION_CHECK below if you believe that SHA1's
|
||||
# 1461501637330902918203684832716283019655932542976 hashes do not give you
|
||||
# sufficient guarantee that no collisions between objects will ever happen.
|
||||
#
|
||||
# Define USE_NSEC below if you want git to care about sub-second file mtimes
|
||||
# and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and
|
||||
# it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely
|
||||
@ -93,6 +87,10 @@ all:
|
||||
#
|
||||
# Define USE_STDEV below if you want git to care about the underlying device
|
||||
# change being considered an inode change from the update-cache perspective.
|
||||
#
|
||||
# Define NO_PERL_MAKEMAKER if you cannot use Makefiles generated by perl's
|
||||
# MakeMaker (e.g. using ActiveState under Cygwin).
|
||||
#
|
||||
|
||||
GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
|
||||
@$(SHELL_PATH) ./GIT-VERSION-GEN
|
||||
@ -116,7 +114,6 @@ prefix = $(HOME)
|
||||
bindir = $(prefix)/bin
|
||||
gitexecdir = $(bindir)
|
||||
template_dir = $(prefix)/share/git-core/templates/
|
||||
GIT_PYTHON_DIR = $(prefix)/share/git-core/python
|
||||
# DESTDIR=
|
||||
|
||||
# default configuration for gitweb
|
||||
@ -135,7 +132,7 @@ GITWEB_FAVICON = git-favicon.png
|
||||
GITWEB_SITE_HEADER =
|
||||
GITWEB_SITE_FOOTER =
|
||||
|
||||
export prefix bindir gitexecdir template_dir GIT_PYTHON_DIR
|
||||
export prefix bindir gitexecdir template_dir
|
||||
|
||||
CC = gcc
|
||||
AR = ar
|
||||
@ -173,18 +170,14 @@ SCRIPT_SH = \
|
||||
git-lost-found.sh git-quiltimport.sh
|
||||
|
||||
SCRIPT_PERL = \
|
||||
git-add--interactive.perl \
|
||||
git-archimport.perl git-cvsimport.perl git-relink.perl \
|
||||
git-shortlog.perl git-rerere.perl \
|
||||
git-cvsserver.perl \
|
||||
git-svnimport.perl git-cvsexportcommit.perl \
|
||||
git-send-email.perl git-svn.perl
|
||||
|
||||
SCRIPT_PYTHON = \
|
||||
git-merge-recursive-old.py
|
||||
|
||||
SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
|
||||
$(patsubst %.perl,%,$(SCRIPT_PERL)) \
|
||||
$(patsubst %.py,%,$(SCRIPT_PYTHON)) \
|
||||
git-cherry-pick git-status git-instaweb
|
||||
|
||||
# ... and all the rest that could be moved out of bindir to gitexecdir
|
||||
@ -227,12 +220,8 @@ endif
|
||||
ifndef PERL_PATH
|
||||
PERL_PATH = /usr/bin/perl
|
||||
endif
|
||||
ifndef PYTHON_PATH
|
||||
PYTHON_PATH = /usr/bin/python
|
||||
endif
|
||||
|
||||
PYMODULES = \
|
||||
gitMergeCommon.py
|
||||
export PERL_PATH
|
||||
|
||||
LIB_FILE=libgit.a
|
||||
XDIFF_LIB=xdiff/lib.a
|
||||
@ -241,7 +230,8 @@ LIB_H = \
|
||||
archive.h blob.h cache.h commit.h csum-file.h delta.h grep.h \
|
||||
diff.h object.h pack.h pkt-line.h quote.h refs.h list-objects.h sideband.h \
|
||||
run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \
|
||||
tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h
|
||||
tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h \
|
||||
utf8.h
|
||||
|
||||
DIFF_OBJS = \
|
||||
diff.o diff-lib.o diffcore-break.o diffcore-order.o \
|
||||
@ -260,7 +250,7 @@ LIB_OBJS = \
|
||||
revision.o pager.o tree-walk.o xdiff-interface.o \
|
||||
write_or_die.o trace.o list-objects.o grep.o \
|
||||
alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \
|
||||
color.o wt-status.o archive-zip.o archive-tar.o shallow.o
|
||||
color.o wt-status.o archive-zip.o archive-tar.o shallow.o utf8.o
|
||||
|
||||
BUILTIN_OBJS = \
|
||||
builtin-add.o \
|
||||
@ -288,6 +278,7 @@ BUILTIN_OBJS = \
|
||||
builtin-ls-tree.o \
|
||||
builtin-mailinfo.o \
|
||||
builtin-mailsplit.o \
|
||||
builtin-merge-file.o \
|
||||
builtin-mv.o \
|
||||
builtin-name-rev.o \
|
||||
builtin-pack-objects.o \
|
||||
@ -295,11 +286,14 @@ BUILTIN_OBJS = \
|
||||
builtin-prune-packed.o \
|
||||
builtin-push.o \
|
||||
builtin-read-tree.o \
|
||||
builtin-reflog.o \
|
||||
builtin-repo-config.o \
|
||||
builtin-rerere.o \
|
||||
builtin-rev-list.o \
|
||||
builtin-rev-parse.o \
|
||||
builtin-rm.o \
|
||||
builtin-runstatus.o \
|
||||
builtin-shortlog.o \
|
||||
builtin-show-branch.o \
|
||||
builtin-stripspace.o \
|
||||
builtin-symbolic-ref.o \
|
||||
@ -334,18 +328,6 @@ ifeq ($(uname_S),Darwin)
|
||||
NEEDS_SSL_WITH_CRYPTO = YesPlease
|
||||
NEEDS_LIBICONV = YesPlease
|
||||
NO_STRLCPY = YesPlease
|
||||
ifndef NO_FINK
|
||||
ifeq ($(shell test -d /sw/lib && echo y),y)
|
||||
BASIC_CFLAGS += -I/sw/include
|
||||
BASIC_LDFLAGS += -L/sw/lib
|
||||
endif
|
||||
endif
|
||||
ifndef NO_DARWIN_PORTS
|
||||
ifeq ($(shell test -d /opt/local/lib && echo y),y)
|
||||
BASIC_CFLAGS += -I/opt/local/include
|
||||
BASIC_LDFLAGS += -L/opt/local/lib
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
ifeq ($(uname_S),SunOS)
|
||||
NEEDS_SOCKET = YesPlease
|
||||
@ -374,6 +356,7 @@ ifeq ($(uname_O),Cygwin)
|
||||
NO_SYMLINK_HEAD = YesPlease
|
||||
NEEDS_LIBICONV = YesPlease
|
||||
NO_C99_FORMAT = YesPlease
|
||||
NO_FAST_WORKING_DIRECTORY = UnfortunatelyYes
|
||||
# There are conflicting reports about this.
|
||||
# On some boxes NO_MMAP is needed, and not so elsewhere.
|
||||
# Try uncommenting this if you see things break -- YMMV.
|
||||
@ -423,12 +406,17 @@ endif
|
||||
-include config.mak.autogen
|
||||
-include config.mak
|
||||
|
||||
ifdef WITH_OWN_SUBPROCESS_PY
|
||||
PYMODULES += compat/subprocess.py
|
||||
else
|
||||
ifeq ($(NO_PYTHON),)
|
||||
ifneq ($(shell $(PYTHON_PATH) -c 'import subprocess;print"OK"' 2>/dev/null),OK)
|
||||
PYMODULES += compat/subprocess.py
|
||||
ifeq ($(uname_S),Darwin)
|
||||
ifndef NO_FINK
|
||||
ifeq ($(shell test -d /sw/lib && echo y),y)
|
||||
BASIC_CFLAGS += -I/sw/include
|
||||
BASIC_LDFLAGS += -L/sw/lib
|
||||
endif
|
||||
endif
|
||||
ifndef NO_DARWIN_PORTS
|
||||
ifeq ($(shell test -d /opt/local/lib && echo y),y)
|
||||
BASIC_CFLAGS += -I/opt/local/include
|
||||
BASIC_LDFLAGS += -L/opt/local/lib
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
@ -520,6 +508,9 @@ ifdef NO_MMAP
|
||||
COMPAT_CFLAGS += -DNO_MMAP
|
||||
COMPAT_OBJS += compat/mmap.o
|
||||
endif
|
||||
ifdef NO_FAST_WORKING_DIRECTORY
|
||||
BASIC_CFLAGS += -DNO_FAST_WORKING_DIRECTORY
|
||||
endif
|
||||
ifdef NO_IPV6
|
||||
BASIC_CFLAGS += -DNO_IPV6
|
||||
endif
|
||||
@ -558,8 +549,8 @@ else
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
ifdef NO_ACCURATE_DIFF
|
||||
BASIC_CFLAGS += -DNO_ACCURATE_DIFF
|
||||
ifdef NO_PERL_MAKEMAKER
|
||||
export NO_PERL_MAKEMAKER
|
||||
endif
|
||||
|
||||
# Shell quote (do not use $(call) to accommodate ancient setups);
|
||||
@ -574,8 +565,6 @@ prefix_SQ = $(subst ','\'',$(prefix))
|
||||
|
||||
SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
|
||||
PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))
|
||||
PYTHON_PATH_SQ = $(subst ','\'',$(PYTHON_PATH))
|
||||
GIT_PYTHON_DIR_SQ = $(subst ','\'',$(GIT_PYTHON_DIR))
|
||||
|
||||
LIBS = $(GITLIBS) $(EXTLIBS)
|
||||
|
||||
@ -592,8 +581,8 @@ export prefix TAR INSTALL DESTDIR SHELL_PATH template_dir
|
||||
|
||||
all: $(ALL_PROGRAMS) $(BUILT_INS) git$X gitk gitweb/gitweb.cgi
|
||||
|
||||
all: perl/Makefile
|
||||
$(MAKE) -C perl
|
||||
all:
|
||||
$(MAKE) -C perl PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' all
|
||||
$(MAKE) -C templates
|
||||
|
||||
strip: $(PROGRAMS) git$X
|
||||
@ -622,12 +611,15 @@ $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
|
||||
-e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
|
||||
-e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
|
||||
-e 's/@@NO_CURL@@/$(NO_CURL)/g' \
|
||||
-e 's/@@NO_PYTHON@@/$(NO_PYTHON)/g' \
|
||||
$@.sh >$@+
|
||||
chmod +x $@+
|
||||
mv $@+ $@
|
||||
|
||||
$(patsubst %.perl,%,$(SCRIPT_PERL)): perl/Makefile
|
||||
$(patsubst %.perl,%,$(SCRIPT_PERL)): perl/perl.mak
|
||||
|
||||
perl/perl.mak: GIT-CFLAGS
|
||||
$(MAKE) -C perl PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' $(@F)
|
||||
|
||||
$(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl
|
||||
rm -f $@ $@+
|
||||
INSTLIBDIR=`$(MAKE) -C perl -s --no-print-directory instlibdir` && \
|
||||
@ -644,15 +636,6 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl
|
||||
chmod +x $@+
|
||||
mv $@+ $@
|
||||
|
||||
$(patsubst %.py,%,$(SCRIPT_PYTHON)) : % : %.py GIT-CFLAGS
|
||||
rm -f $@ $@+
|
||||
sed -e '1s|#!.*python|#!$(PYTHON_PATH_SQ)|' \
|
||||
-e 's|@@GIT_PYTHON_PATH@@|$(GIT_PYTHON_DIR_SQ)|g' \
|
||||
-e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
|
||||
$@.py >$@+
|
||||
chmod +x $@+
|
||||
mv $@+ $@
|
||||
|
||||
git-cherry-pick: git-revert
|
||||
cp $< $@+
|
||||
mv $@+ $@
|
||||
@ -689,7 +672,6 @@ git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css
|
||||
sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
|
||||
-e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
|
||||
-e 's/@@NO_CURL@@/$(NO_CURL)/g' \
|
||||
-e 's/@@NO_PYTHON@@/$(NO_PYTHON)/g' \
|
||||
-e '/@@GITWEB_CGI@@/r gitweb/gitweb.cgi' \
|
||||
-e '/@@GITWEB_CGI@@/d' \
|
||||
-e '/@@GITWEB_CSS@@/r gitweb/gitweb.css' \
|
||||
@ -709,7 +691,6 @@ configure: configure.ac
|
||||
git$X git.spec \
|
||||
$(patsubst %.sh,%,$(SCRIPT_SH)) \
|
||||
$(patsubst %.perl,%,$(SCRIPT_PERL)) \
|
||||
$(patsubst %.py,%,$(SCRIPT_PYTHON)) \
|
||||
: GIT-VERSION-FILE
|
||||
|
||||
%.o: %.c GIT-CFLAGS
|
||||
@ -759,7 +740,8 @@ $(DIFF_OBJS): diffcore.h
|
||||
$(LIB_FILE): $(LIB_OBJS)
|
||||
rm -f $@ && $(AR) rcs $@ $(LIB_OBJS)
|
||||
|
||||
XDIFF_OBJS=xdiff/xdiffi.o xdiff/xprepare.o xdiff/xutils.o xdiff/xemit.o
|
||||
XDIFF_OBJS=xdiff/xdiffi.o xdiff/xprepare.o xdiff/xutils.o xdiff/xemit.o \
|
||||
xdiff/xmerge.o
|
||||
$(XDIFF_OBJS): xdiff/xinclude.h xdiff/xmacros.h xdiff/xdiff.h xdiff/xtypes.h \
|
||||
xdiff/xutils.h xdiff/xprepare.h xdiff/xdiffi.h xdiff/xemit.h
|
||||
|
||||
@ -783,7 +765,7 @@ tags:
|
||||
find . -name '*.[hcS]' -print | xargs ctags -a
|
||||
|
||||
### Detect prefix changes
|
||||
TRACK_CFLAGS = $(subst ','\'',$(ALL_CFLAGS)):$(GIT_PYTHON_DIR_SQ):\
|
||||
TRACK_CFLAGS = $(subst ','\'',$(ALL_CFLAGS)):\
|
||||
$(bindir_SQ):$(gitexecdir_SQ):$(template_dir_SQ):$(prefix_SQ)
|
||||
|
||||
GIT-CFLAGS: .FORCE-GIT-CFLAGS
|
||||
@ -799,7 +781,6 @@ GIT-CFLAGS: .FORCE-GIT-CFLAGS
|
||||
# However, the environment gets quite big, and some programs have problems
|
||||
# with that.
|
||||
|
||||
export NO_PYTHON
|
||||
export NO_SVN_TESTS
|
||||
|
||||
test: all
|
||||
@ -808,8 +789,8 @@ test: all
|
||||
test-date$X: test-date.c date.o ctype.o
|
||||
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) test-date.c date.o ctype.o
|
||||
|
||||
test-delta$X: test-delta.c diff-delta.o patch-delta.o
|
||||
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $^
|
||||
test-delta$X: test-delta.o diff-delta.o patch-delta.o $(GITLIBS)
|
||||
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
|
||||
|
||||
test-dump-cache-tree$X: dump-cache-tree.o $(GITLIBS)
|
||||
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
|
||||
@ -833,9 +814,7 @@ install: all
|
||||
$(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
|
||||
$(INSTALL) git$X gitk '$(DESTDIR_SQ)$(bindir_SQ)'
|
||||
$(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install
|
||||
$(MAKE) -C perl install
|
||||
$(INSTALL) -d -m755 '$(DESTDIR_SQ)$(GIT_PYTHON_DIR_SQ)'
|
||||
$(INSTALL) $(PYMODULES) '$(DESTDIR_SQ)$(GIT_PYTHON_DIR_SQ)'
|
||||
$(MAKE) -C perl prefix='$(prefix_SQ)' install
|
||||
if test 'z$(bindir_SQ)' != 'z$(gitexecdir_SQ)'; \
|
||||
then \
|
||||
ln -f '$(DESTDIR_SQ)$(bindir_SQ)/git$X' \
|
||||
@ -848,6 +827,8 @@ install: all
|
||||
install-doc:
|
||||
$(MAKE) -C Documentation install
|
||||
|
||||
quick-install-doc:
|
||||
$(MAKE) -C Documentation quick-install
|
||||
|
||||
|
||||
|
||||
@ -905,8 +886,7 @@ clean:
|
||||
rm -f $(htmldocs).tar.gz $(manpages).tar.gz
|
||||
rm -f gitweb/gitweb.cgi
|
||||
$(MAKE) -C Documentation/ clean
|
||||
[ ! -f perl/Makefile ] || $(MAKE) -C perl/ clean || $(MAKE) -C perl/ clean
|
||||
rm -f perl/ppport.h perl/Makefile.old
|
||||
$(MAKE) -C perl clean
|
||||
$(MAKE) -C templates/ clean
|
||||
$(MAKE) -C t/ clean
|
||||
rm -f GIT-VERSION-FILE GIT-CFLAGS
|
||||
@ -922,7 +902,6 @@ check-docs::
|
||||
case "$$v" in \
|
||||
git-merge-octopus | git-merge-ours | git-merge-recursive | \
|
||||
git-merge-resolve | git-merge-stupid | git-merge-recur | \
|
||||
git-merge-recursive-old | \
|
||||
git-ssh-pull | git-ssh-push ) continue ;; \
|
||||
esac ; \
|
||||
test -f "Documentation/$$v.txt" || \
|
||||
|
@ -1,7 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2006 Rene Scharfe
|
||||
*/
|
||||
#include <time.h>
|
||||
#include "cache.h"
|
||||
#include "commit.h"
|
||||
#include "strbuf.h"
|
||||
|
@ -1,7 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2006 Rene Scharfe
|
||||
*/
|
||||
#include <time.h>
|
||||
#include "cache.h"
|
||||
#include "commit.h"
|
||||
#include "blob.h"
|
||||
|
1
blob.c
1
blob.c
@ -1,6 +1,5 @@
|
||||
#include "cache.h"
|
||||
#include "blob.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
const char *blob_type = "blob";
|
||||
|
||||
|
@ -3,15 +3,14 @@
|
||||
*
|
||||
* Copyright (C) 2006 Linus Torvalds
|
||||
*/
|
||||
#include <fnmatch.h>
|
||||
|
||||
#include "cache.h"
|
||||
#include "builtin.h"
|
||||
#include "dir.h"
|
||||
#include "exec_cmd.h"
|
||||
#include "cache-tree.h"
|
||||
|
||||
static const char builtin_add_usage[] =
|
||||
"git-add [-n] [-v] <filepattern>...";
|
||||
"git-add [-n] [-v] [-f] [--interactive] [--] <filepattern>...";
|
||||
|
||||
static void prune_directory(struct dir_struct *dir, const char **pathspec, int prefix)
|
||||
{
|
||||
@ -27,7 +26,14 @@ static void prune_directory(struct dir_struct *dir, const char **pathspec, int p
|
||||
i = dir->nr;
|
||||
while (--i >= 0) {
|
||||
struct dir_entry *entry = *src++;
|
||||
if (!match_pathspec(pathspec, entry->name, entry->len, prefix, seen)) {
|
||||
int how = match_pathspec(pathspec, entry->name, entry->len,
|
||||
prefix, seen);
|
||||
/*
|
||||
* ignored entries can be added with exact match,
|
||||
* but not with glob nor recursive.
|
||||
*/
|
||||
if (!how ||
|
||||
(entry->ignored_entry && how != MATCHED_EXACTLY)) {
|
||||
free(entry);
|
||||
continue;
|
||||
}
|
||||
@ -56,6 +62,8 @@ static void fill_directory(struct dir_struct *dir, const char **pathspec)
|
||||
|
||||
/* Set up the default git porcelain excludes */
|
||||
memset(dir, 0, sizeof(*dir));
|
||||
if (pathspec)
|
||||
dir->show_both = 1;
|
||||
dir->exclude_per_dir = ".gitignore";
|
||||
path = git_path("info/exclude");
|
||||
if (!access(path, R_OK))
|
||||
@ -83,20 +91,34 @@ static void fill_directory(struct dir_struct *dir, const char **pathspec)
|
||||
|
||||
static struct lock_file lock_file;
|
||||
|
||||
static const char ignore_warning[] =
|
||||
"The following paths are ignored by one of your .gitignore files:\n";
|
||||
|
||||
int cmd_add(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i, newfd;
|
||||
int verbose = 0, show_only = 0;
|
||||
int verbose = 0, show_only = 0, ignored_too = 0;
|
||||
const char **pathspec;
|
||||
struct dir_struct dir;
|
||||
int add_interactive = 0;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (!strcmp("--interactive", argv[i]))
|
||||
add_interactive++;
|
||||
}
|
||||
if (add_interactive) {
|
||||
const char *args[] = { "add--interactive", NULL };
|
||||
|
||||
if (add_interactive != 1 || argc != 2)
|
||||
die("add --interactive does not take any parameters");
|
||||
execv_git_cmd(args);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
git_config(git_default_config);
|
||||
|
||||
newfd = hold_lock_file_for_update(&lock_file, get_index_file(), 1);
|
||||
|
||||
if (read_cache() < 0)
|
||||
die("index file corrupt");
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
|
||||
@ -110,12 +132,21 @@ int cmd_add(int argc, const char **argv, const char *prefix)
|
||||
show_only = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "-f")) {
|
||||
ignored_too = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "-v")) {
|
||||
verbose = 1;
|
||||
continue;
|
||||
}
|
||||
usage(builtin_add_usage);
|
||||
}
|
||||
if (argc <= i) {
|
||||
fprintf(stderr, "Nothing specified, nothing added.\n");
|
||||
fprintf(stderr, "Maybe you wanted to say 'git add .'?\n");
|
||||
return 0;
|
||||
}
|
||||
pathspec = get_pathspec(prefix, argv + i);
|
||||
|
||||
fill_directory(&dir, pathspec);
|
||||
@ -123,6 +154,8 @@ int cmd_add(int argc, const char **argv, const char *prefix)
|
||||
if (show_only) {
|
||||
const char *sep = "", *eof = "";
|
||||
for (i = 0; i < dir.nr; i++) {
|
||||
if (!ignored_too && dir.entries[i]->ignored_entry)
|
||||
continue;
|
||||
printf("%s%s", sep, dir.entries[i]->name);
|
||||
sep = " ";
|
||||
eof = "\n";
|
||||
@ -131,6 +164,27 @@ int cmd_add(int argc, const char **argv, const char *prefix)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (read_cache() < 0)
|
||||
die("index file corrupt");
|
||||
|
||||
if (!ignored_too) {
|
||||
int has_ignored = -1;
|
||||
for (i = 0; has_ignored < 0 && i < dir.nr; i++)
|
||||
if (dir.entries[i]->ignored_entry)
|
||||
has_ignored = i;
|
||||
if (0 <= has_ignored) {
|
||||
fprintf(stderr, ignore_warning);
|
||||
for (i = has_ignored; i < dir.nr; i++) {
|
||||
if (!dir.entries[i]->ignored_entry)
|
||||
continue;
|
||||
fprintf(stderr, "%s\n", dir.entries[i]->name);
|
||||
}
|
||||
fprintf(stderr,
|
||||
"Use -f if you really want to add them.\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < dir.nr; i++)
|
||||
add_file_to_index(dir.entries[i]->name, verbose);
|
||||
|
||||
|
@ -6,7 +6,6 @@
|
||||
* This applies patches on top of some (arbitrary) version of the SCM.
|
||||
*
|
||||
*/
|
||||
#include <fnmatch.h>
|
||||
#include "cache.h"
|
||||
#include "cache-tree.h"
|
||||
#include "quote.h"
|
||||
|
@ -2,7 +2,6 @@
|
||||
* Copyright (c) 2006 Franck Bui-Huu
|
||||
* Copyright (c) 2006 Rene Scharfe
|
||||
*/
|
||||
#include <time.h>
|
||||
#include "cache.h"
|
||||
#include "builtin.h"
|
||||
#include "archive.h"
|
||||
|
@ -15,14 +15,12 @@
|
||||
#include "revision.h"
|
||||
#include "xdiff-interface.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <regex.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"
|
||||
" -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"
|
||||
" --root Do not treat root commits as boundaries (Default: off)\n"
|
||||
" -t, --time Show raw timestamp (Default: off)\n"
|
||||
" -f, --show-name Show original filename (Default: auto)\n"
|
||||
" -n, --show-number Show original linenumber (Default: off)\n"
|
||||
@ -36,6 +34,8 @@ static int longest_author;
|
||||
static int max_orig_digits;
|
||||
static int max_digits;
|
||||
static int max_score_digits;
|
||||
static int show_root;
|
||||
static int blank_boundary;
|
||||
|
||||
#ifndef DEBUG
|
||||
#define DEBUG 0
|
||||
@ -1090,6 +1090,14 @@ static void assign_blame(struct scoreboard *sb, struct rev_info *revs, int opt)
|
||||
if (!(commit->object.flags & UNINTERESTING) &&
|
||||
!(revs->max_age != -1 && commit->date < revs->max_age))
|
||||
pass_blame(sb, suspect, opt);
|
||||
else {
|
||||
commit->object.flags |= UNINTERESTING;
|
||||
if (commit->object.parsed)
|
||||
mark_parents_uninteresting(commit);
|
||||
}
|
||||
/* treat root commit as boundary */
|
||||
if (!commit->parents && !show_root)
|
||||
commit->object.flags |= UNINTERESTING;
|
||||
|
||||
/* Take responsibility for the remaining entries */
|
||||
for (ent = sb->ent; ent; ent = ent->next)
|
||||
@ -1273,6 +1281,8 @@ static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent)
|
||||
printf("committer-tz %s\n", ci.committer_tz);
|
||||
printf("filename %s\n", suspect->path);
|
||||
printf("summary %s\n", ci.summary);
|
||||
if (suspect->commit->object.flags & UNINTERESTING)
|
||||
printf("boundary\n");
|
||||
}
|
||||
else if (suspect->commit->object.flags & MORE_THAN_ONE_PATH)
|
||||
printf("filename %s\n", suspect->path);
|
||||
@ -1308,8 +1318,18 @@ static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt)
|
||||
cp = nth_line(sb, ent->lno);
|
||||
for (cnt = 0; cnt < ent->num_lines; cnt++) {
|
||||
char ch;
|
||||
int length = (opt & OUTPUT_LONG_OBJECT_NAME) ? 40 : 8;
|
||||
|
||||
printf("%.*s", (opt & OUTPUT_LONG_OBJECT_NAME) ? 40 : 8, hex);
|
||||
if (suspect->commit->object.flags & UNINTERESTING) {
|
||||
if (!blank_boundary) {
|
||||
length--;
|
||||
putchar('^');
|
||||
}
|
||||
else
|
||||
memset(hex, ' ', length);
|
||||
}
|
||||
|
||||
printf("%.*s", length, hex);
|
||||
if (opt & OUTPUT_ANNOTATE_COMPAT)
|
||||
printf("\t(%10s\t%10s\t%d)", ci.author,
|
||||
format_time(ci.author_time, ci.author_tz,
|
||||
@ -1435,14 +1455,14 @@ static void find_alignment(struct scoreboard *sb, int *option)
|
||||
struct commit_info ci;
|
||||
int num;
|
||||
|
||||
if (strcmp(suspect->path, sb->path))
|
||||
*option |= OUTPUT_SHOW_NAME;
|
||||
num = strlen(suspect->path);
|
||||
if (longest_file < num)
|
||||
longest_file = num;
|
||||
if (!(suspect->commit->object.flags & METAINFO_SHOWN)) {
|
||||
suspect->commit->object.flags |= METAINFO_SHOWN;
|
||||
get_commit_info(suspect->commit, &ci, 1);
|
||||
if (strcmp(suspect->path, sb->path))
|
||||
*option |= OUTPUT_SHOW_NAME;
|
||||
num = strlen(suspect->path);
|
||||
if (longest_file < num)
|
||||
longest_file = num;
|
||||
num = strlen(ci.author);
|
||||
if (longest_author < num)
|
||||
longest_author = num;
|
||||
@ -1626,6 +1646,19 @@ static void prepare_blame_range(struct scoreboard *sb,
|
||||
usage(blame_usage);
|
||||
}
|
||||
|
||||
static int git_blame_config(const char *var, const char *value)
|
||||
{
|
||||
if (!strcmp(var, "blame.showroot")) {
|
||||
show_root = git_config_bool(var, value);
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(var, "blame.blankboundary")) {
|
||||
blank_boundary = git_config_bool(var, value);
|
||||
return 0;
|
||||
}
|
||||
return git_default_config(var, value);
|
||||
}
|
||||
|
||||
int cmd_blame(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct rev_info revs;
|
||||
@ -1641,6 +1674,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
|
||||
char type[10];
|
||||
const char *bottomtop = NULL;
|
||||
|
||||
git_config(git_blame_config);
|
||||
save_commit_buffer = 0;
|
||||
|
||||
opt = 0;
|
||||
@ -1649,6 +1683,10 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
|
||||
const char *arg = argv[i];
|
||||
if (*arg != '-')
|
||||
break;
|
||||
else if (!strcmp("-b", arg))
|
||||
blank_boundary = 1;
|
||||
else if (!strcmp("--root", arg))
|
||||
show_root = 1;
|
||||
else if (!strcmp("-c", arg))
|
||||
output_option |= OUTPUT_ANNOTATE_COMPAT;
|
||||
else if (!strcmp("-t", arg))
|
||||
@ -1787,6 +1825,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
|
||||
/* Now we got rev and path. We do not want the path pruning
|
||||
* but we may want "bottom" processing.
|
||||
*/
|
||||
argv[unk++] = "--"; /* terminate the rev name */
|
||||
argv[unk] = NULL;
|
||||
|
||||
init_revisions(&revs, NULL);
|
||||
|
292
builtin-branch.c
292
builtin-branch.c
@ -6,55 +6,127 @@
|
||||
*/
|
||||
|
||||
#include "cache.h"
|
||||
#include "color.h"
|
||||
#include "refs.h"
|
||||
#include "commit.h"
|
||||
#include "builtin.h"
|
||||
|
||||
static const char builtin_branch_usage[] =
|
||||
"git-branch (-d | -D) <branchname> | [-l] [-f] <branchname> [<start-point>] | [-r] | [-a]";
|
||||
"git-branch [-r] (-d | -D) <branchname> | [-l] [-f] <branchname> [<start-point>] | (-m | -M) [<oldbranch>] <newbranch> | [-r | -a] [-v [--abbrev=<length>]]";
|
||||
|
||||
#define REF_UNKNOWN_TYPE 0x00
|
||||
#define REF_LOCAL_BRANCH 0x01
|
||||
#define REF_REMOTE_BRANCH 0x02
|
||||
#define REF_TAG 0x04
|
||||
|
||||
static const char *head;
|
||||
static unsigned char head_sha1[20];
|
||||
|
||||
static int in_merge_bases(const unsigned char *sha1,
|
||||
struct commit *rev1,
|
||||
struct commit *rev2)
|
||||
static int branch_use_color;
|
||||
static char branch_colors[][COLOR_MAXLEN] = {
|
||||
"\033[m", /* reset */
|
||||
"", /* PLAIN (normal) */
|
||||
"\033[31m", /* REMOTE (red) */
|
||||
"", /* LOCAL (normal) */
|
||||
"\033[32m", /* CURRENT (green) */
|
||||
};
|
||||
enum color_branch {
|
||||
COLOR_BRANCH_RESET = 0,
|
||||
COLOR_BRANCH_PLAIN = 1,
|
||||
COLOR_BRANCH_REMOTE = 2,
|
||||
COLOR_BRANCH_LOCAL = 3,
|
||||
COLOR_BRANCH_CURRENT = 4,
|
||||
};
|
||||
|
||||
static int parse_branch_color_slot(const char *var, int ofs)
|
||||
{
|
||||
struct commit_list *bases, *b;
|
||||
int ret = 0;
|
||||
|
||||
bases = get_merge_bases(rev1, rev2, 1);
|
||||
for (b = bases; b; b = b->next) {
|
||||
if (!hashcmp(sha1, b->item->object.sha1)) {
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free_commit_list(bases);
|
||||
return ret;
|
||||
if (!strcasecmp(var+ofs, "plain"))
|
||||
return COLOR_BRANCH_PLAIN;
|
||||
if (!strcasecmp(var+ofs, "reset"))
|
||||
return COLOR_BRANCH_RESET;
|
||||
if (!strcasecmp(var+ofs, "remote"))
|
||||
return COLOR_BRANCH_REMOTE;
|
||||
if (!strcasecmp(var+ofs, "local"))
|
||||
return COLOR_BRANCH_LOCAL;
|
||||
if (!strcasecmp(var+ofs, "current"))
|
||||
return COLOR_BRANCH_CURRENT;
|
||||
die("bad config variable '%s'", var);
|
||||
}
|
||||
|
||||
static void delete_branches(int argc, const char **argv, int force)
|
||||
int git_branch_config(const char *var, const char *value)
|
||||
{
|
||||
struct commit *rev, *head_rev;
|
||||
if (!strcmp(var, "color.branch")) {
|
||||
branch_use_color = git_config_colorbool(var, value);
|
||||
return 0;
|
||||
}
|
||||
if (!strncmp(var, "color.branch.", 13)) {
|
||||
int slot = parse_branch_color_slot(var, 13);
|
||||
color_parse(value, var, branch_colors[slot]);
|
||||
return 0;
|
||||
}
|
||||
return git_default_config(var, value);
|
||||
}
|
||||
|
||||
const char *branch_get_color(enum color_branch ix)
|
||||
{
|
||||
if (branch_use_color)
|
||||
return branch_colors[ix];
|
||||
return "";
|
||||
}
|
||||
|
||||
static int delete_branches(int argc, const char **argv, int force, int kinds)
|
||||
{
|
||||
struct commit *rev, *head_rev = head_rev;
|
||||
unsigned char sha1[20];
|
||||
char *name;
|
||||
char *name = NULL;
|
||||
const char *fmt, *remote;
|
||||
int i;
|
||||
int ret = 0;
|
||||
|
||||
head_rev = lookup_commit_reference(head_sha1);
|
||||
switch (kinds) {
|
||||
case REF_REMOTE_BRANCH:
|
||||
fmt = "refs/remotes/%s";
|
||||
remote = "remote ";
|
||||
force = 1;
|
||||
break;
|
||||
case REF_LOCAL_BRANCH:
|
||||
fmt = "refs/heads/%s";
|
||||
remote = "";
|
||||
break;
|
||||
default:
|
||||
die("cannot use -a with -d");
|
||||
}
|
||||
|
||||
if (!force) {
|
||||
head_rev = lookup_commit_reference(head_sha1);
|
||||
if (!head_rev)
|
||||
die("Couldn't look up commit object for HEAD");
|
||||
}
|
||||
for (i = 0; i < argc; i++) {
|
||||
if (!strcmp(head, argv[i]))
|
||||
die("Cannot delete the branch you are currently on.");
|
||||
if (kinds == REF_LOCAL_BRANCH && !strcmp(head, argv[i])) {
|
||||
error("Cannot delete the branch '%s' "
|
||||
"which you are currently on.", argv[i]);
|
||||
ret = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
name = xstrdup(mkpath("refs/heads/%s", argv[i]));
|
||||
if (!resolve_ref(name, sha1, 1, NULL))
|
||||
die("Branch '%s' not found.", argv[i]);
|
||||
if (name)
|
||||
free(name);
|
||||
|
||||
name = xstrdup(mkpath(fmt, argv[i]));
|
||||
if (!resolve_ref(name, sha1, 1, NULL)) {
|
||||
error("%sbranch '%s' not found.",
|
||||
remote, argv[i]);
|
||||
ret = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
rev = lookup_commit_reference(sha1);
|
||||
if (!rev || !head_rev)
|
||||
die("Couldn't look up commit objects.");
|
||||
if (!rev) {
|
||||
error("Couldn't look up commit object for '%s'", name);
|
||||
ret = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* This checks whether the merge bases of branch and
|
||||
* HEAD contains branch -- which means that the HEAD
|
||||
@ -62,35 +134,38 @@ static void delete_branches(int argc, const char **argv, int force)
|
||||
*/
|
||||
|
||||
if (!force &&
|
||||
!in_merge_bases(sha1, rev, head_rev)) {
|
||||
fprintf(stderr,
|
||||
"The branch '%s' is not a strict subset of your current HEAD.\n"
|
||||
"If you are sure you want to delete it, run 'git branch -D %s'.\n",
|
||||
argv[i], argv[i]);
|
||||
exit(1);
|
||||
!in_merge_bases(rev, head_rev)) {
|
||||
error("The branch '%s' is not a strict subset of "
|
||||
"your current HEAD.\n"
|
||||
"If you are sure you want to delete it, "
|
||||
"run 'git branch -D %s'.", argv[i], argv[i]);
|
||||
ret = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (delete_ref(name, sha1))
|
||||
printf("Error deleting branch '%s'\n", argv[i]);
|
||||
else
|
||||
printf("Deleted branch %s.\n", argv[i]);
|
||||
if (delete_ref(name, sha1)) {
|
||||
error("Error deleting %sbranch '%s'", remote,
|
||||
argv[i]);
|
||||
ret = 1;
|
||||
} else
|
||||
printf("Deleted %sbranch %s.\n", remote, argv[i]);
|
||||
|
||||
free(name);
|
||||
}
|
||||
}
|
||||
|
||||
#define REF_UNKNOWN_TYPE 0x00
|
||||
#define REF_LOCAL_BRANCH 0x01
|
||||
#define REF_REMOTE_BRANCH 0x02
|
||||
#define REF_TAG 0x04
|
||||
if (name)
|
||||
free(name);
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
struct ref_item {
|
||||
char *name;
|
||||
unsigned int kind;
|
||||
unsigned char sha1[20];
|
||||
};
|
||||
|
||||
struct ref_list {
|
||||
int index, alloc;
|
||||
int index, alloc, maxwidth;
|
||||
struct ref_item *list;
|
||||
int kinds;
|
||||
};
|
||||
@ -100,6 +175,7 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags,
|
||||
struct ref_list *ref_list = (struct ref_list*)(cb_data);
|
||||
struct ref_item *newitem;
|
||||
int kind = REF_UNKNOWN_TYPE;
|
||||
int len;
|
||||
|
||||
/* Detect kind */
|
||||
if (!strncmp(refname, "refs/heads/", 11)) {
|
||||
@ -128,6 +204,10 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags,
|
||||
newitem = &(ref_list->list[ref_list->index++]);
|
||||
newitem->name = xstrdup(refname);
|
||||
newitem->kind = kind;
|
||||
hashcpy(newitem->sha1, sha1);
|
||||
len = strlen(newitem->name);
|
||||
if (len > ref_list->maxwidth)
|
||||
ref_list->maxwidth = len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -151,11 +231,29 @@ static int ref_cmp(const void *r1, const void *r2)
|
||||
return strcmp(c1->name, c2->name);
|
||||
}
|
||||
|
||||
static void print_ref_list(int kinds)
|
||||
static void print_ref_info(const unsigned char *sha1, int abbrev)
|
||||
{
|
||||
struct commit *commit;
|
||||
char subject[256];
|
||||
|
||||
|
||||
commit = lookup_commit(sha1);
|
||||
if (commit && !parse_commit(commit))
|
||||
pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0,
|
||||
subject, sizeof(subject), 0,
|
||||
NULL, NULL, 0);
|
||||
else
|
||||
strcpy(subject, " **** invalid ref ****");
|
||||
|
||||
printf(" %s %s\n", find_unique_abbrev(sha1, abbrev), subject);
|
||||
}
|
||||
|
||||
static void print_ref_list(int kinds, int verbose, int abbrev)
|
||||
{
|
||||
int i;
|
||||
char c;
|
||||
struct ref_list ref_list;
|
||||
int color;
|
||||
|
||||
memset(&ref_list, 0, sizeof(ref_list));
|
||||
ref_list.kinds = kinds;
|
||||
@ -164,12 +262,38 @@ static void print_ref_list(int kinds)
|
||||
qsort(ref_list.list, ref_list.index, sizeof(struct ref_item), ref_cmp);
|
||||
|
||||
for (i = 0; i < ref_list.index; i++) {
|
||||
switch( ref_list.list[i].kind ) {
|
||||
case REF_LOCAL_BRANCH:
|
||||
color = COLOR_BRANCH_LOCAL;
|
||||
break;
|
||||
case REF_REMOTE_BRANCH:
|
||||
color = COLOR_BRANCH_REMOTE;
|
||||
break;
|
||||
default:
|
||||
color = COLOR_BRANCH_PLAIN;
|
||||
break;
|
||||
}
|
||||
|
||||
c = ' ';
|
||||
if (ref_list.list[i].kind == REF_LOCAL_BRANCH &&
|
||||
!strcmp(ref_list.list[i].name, head))
|
||||
!strcmp(ref_list.list[i].name, head)) {
|
||||
c = '*';
|
||||
color = COLOR_BRANCH_CURRENT;
|
||||
}
|
||||
|
||||
printf("%c %s\n", c, ref_list.list[i].name);
|
||||
if (verbose) {
|
||||
printf("%c %s%-*s%s", c,
|
||||
branch_get_color(color),
|
||||
ref_list.maxwidth,
|
||||
ref_list.list[i].name,
|
||||
branch_get_color(COLOR_BRANCH_RESET));
|
||||
print_ref_info(ref_list.list[i].sha1, abbrev);
|
||||
}
|
||||
else
|
||||
printf("%c %s%s%s\n", c,
|
||||
branch_get_color(color),
|
||||
ref_list.list[i].name,
|
||||
branch_get_color(COLOR_BRANCH_RESET));
|
||||
}
|
||||
|
||||
free_ref_list(&ref_list);
|
||||
@ -212,14 +336,47 @@ static void create_branch(const char *name, const char *start,
|
||||
die("Failed to write ref: %s.", strerror(errno));
|
||||
}
|
||||
|
||||
static void rename_branch(const char *oldname, const char *newname, int force)
|
||||
{
|
||||
char oldref[PATH_MAX], newref[PATH_MAX], logmsg[PATH_MAX*2 + 100];
|
||||
unsigned char sha1[20];
|
||||
|
||||
if (snprintf(oldref, sizeof(oldref), "refs/heads/%s", oldname) > sizeof(oldref))
|
||||
die("Old branchname too long");
|
||||
|
||||
if (check_ref_format(oldref))
|
||||
die("Invalid branch name: %s", oldref);
|
||||
|
||||
if (snprintf(newref, sizeof(newref), "refs/heads/%s", newname) > sizeof(newref))
|
||||
die("New branchname too long");
|
||||
|
||||
if (check_ref_format(newref))
|
||||
die("Invalid branch name: %s", newref);
|
||||
|
||||
if (resolve_ref(newref, sha1, 1, NULL) && !force)
|
||||
die("A branch named '%s' already exists.", newname);
|
||||
|
||||
snprintf(logmsg, sizeof(logmsg), "Branch: renamed %s to %s",
|
||||
oldref, newref);
|
||||
|
||||
if (rename_ref(oldref, newref, logmsg))
|
||||
die("Branch rename failed");
|
||||
|
||||
if (!strcmp(oldname, head) && create_symref("HEAD", newref))
|
||||
die("Branch renamed to %s, but HEAD is not updated!", newname);
|
||||
}
|
||||
|
||||
int cmd_branch(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int delete = 0, force_delete = 0, force_create = 0;
|
||||
int rename = 0, force_rename = 0;
|
||||
int verbose = 0, abbrev = DEFAULT_ABBREV;
|
||||
int reflog = 0;
|
||||
int kinds = REF_LOCAL_BRANCH;
|
||||
int i;
|
||||
|
||||
git_config(git_default_config);
|
||||
setup_ident();
|
||||
git_config(git_branch_config);
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
@ -243,6 +400,15 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
|
||||
force_create = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "-m")) {
|
||||
rename = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "-M")) {
|
||||
rename = 1;
|
||||
force_rename = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "-r")) {
|
||||
kinds = REF_REMOTE_BRANCH;
|
||||
continue;
|
||||
@ -255,9 +421,29 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
|
||||
reflog = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(arg, "--abbrev=", 9)) {
|
||||
abbrev = atoi(arg+9);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "-v")) {
|
||||
verbose = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--color")) {
|
||||
branch_use_color = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--no-color")) {
|
||||
branch_use_color = 0;
|
||||
continue;
|
||||
}
|
||||
usage(builtin_branch_usage);
|
||||
}
|
||||
|
||||
if ((delete && rename) || (delete && force_create) ||
|
||||
(rename && force_create))
|
||||
usage(builtin_branch_usage);
|
||||
|
||||
head = xstrdup(resolve_ref("HEAD", head_sha1, 0, NULL));
|
||||
if (!head)
|
||||
die("Failed to resolve HEAD as a valid ref.");
|
||||
@ -266,9 +452,13 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
|
||||
head += 11;
|
||||
|
||||
if (delete)
|
||||
delete_branches(argc - i, argv + i, force_delete);
|
||||
return delete_branches(argc - i, argv + i, force_delete, kinds);
|
||||
else if (i == argc)
|
||||
print_ref_list(kinds);
|
||||
print_ref_list(kinds, verbose, abbrev);
|
||||
else if (rename && (i == argc - 1))
|
||||
rename_branch(head, argv[i], force_rename);
|
||||
else if (rename && (i == argc - 2))
|
||||
rename_branch(argv[i], argv[i + 1], force_rename);
|
||||
else if (i == argc - 1)
|
||||
create_branch(argv[i], head, force_create, reflog);
|
||||
else if (i == argc - 2)
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "commit.h"
|
||||
#include "tree.h"
|
||||
#include "builtin.h"
|
||||
#include "utf8.h"
|
||||
|
||||
#define BLOCKING (1ul << 14)
|
||||
|
||||
@ -32,7 +33,7 @@ static void add_buffer(char **bufp, unsigned int *sizep, const char *fmt, ...)
|
||||
len = vsnprintf(one_line, sizeof(one_line), fmt, args);
|
||||
va_end(args);
|
||||
size = *sizep;
|
||||
newsize = size + len;
|
||||
newsize = size + len + 1;
|
||||
alloc = (size + 32767) & ~32767;
|
||||
buf = *bufp;
|
||||
if (newsize > alloc) {
|
||||
@ -40,7 +41,7 @@ static void add_buffer(char **bufp, unsigned int *sizep, const char *fmt, ...)
|
||||
buf = xrealloc(buf, alloc);
|
||||
*bufp = buf;
|
||||
}
|
||||
*sizep = newsize;
|
||||
*sizep = newsize - 1;
|
||||
memcpy(buf + size, one_line, len);
|
||||
}
|
||||
|
||||
@ -77,6 +78,11 @@ static int new_parent(int idx)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const char commit_utf8_warn[] =
|
||||
"Warning: commit message does not conform to UTF-8.\n"
|
||||
"You may want to amend it after fixing the message, or set the config\n"
|
||||
"variable i18n.commitencoding to the encoding your project uses.\n";
|
||||
|
||||
int cmd_commit_tree(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i;
|
||||
@ -101,14 +107,15 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
|
||||
a = argv[i]; b = argv[i+1];
|
||||
if (!b || strcmp(a, "-p"))
|
||||
usage(commit_tree_usage);
|
||||
|
||||
if (parents >= MAXPARENT)
|
||||
die("Too many parents (%d max)", MAXPARENT);
|
||||
if (get_sha1(b, parent_sha1[parents]))
|
||||
die("Not a valid object name %s", b);
|
||||
check_valid(parent_sha1[parents], commit_type);
|
||||
if (new_parent(parents))
|
||||
parents++;
|
||||
}
|
||||
if (!parents)
|
||||
fprintf(stderr, "Committing initial tree %s\n", argv[1]);
|
||||
|
||||
init_buffer(&buffer, &size);
|
||||
add_buffer(&buffer, &size, "tree %s\n", sha1_to_hex(tree_sha1));
|
||||
@ -129,6 +136,11 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
|
||||
while (fgets(comment, sizeof(comment), stdin) != NULL)
|
||||
add_buffer(&buffer, &size, "%s", comment);
|
||||
|
||||
/* And check the encoding */
|
||||
buffer[size] = '\0';
|
||||
if (!strcmp(git_commit_encoding, "utf-8") && !is_utf8(buffer))
|
||||
fprintf(stderr, commit_utf8_warn);
|
||||
|
||||
if (!write_sha1_file(buffer, size, commit_type, commit_sha1)) {
|
||||
printf("%s\n", sha1_to_hex(commit_sha1));
|
||||
return 0;
|
||||
|
@ -105,16 +105,19 @@ int cmd_count_objects(int ac, const char **av, const char *prefix)
|
||||
}
|
||||
if (verbose) {
|
||||
struct packed_git *p;
|
||||
unsigned long num_pack = 0;
|
||||
if (!packed_git)
|
||||
prepare_packed_git();
|
||||
for (p = packed_git; p; p = p->next) {
|
||||
if (!p->pack_local)
|
||||
continue;
|
||||
packed += num_packed_objects(p);
|
||||
num_pack++;
|
||||
}
|
||||
printf("count: %lu\n", loose);
|
||||
printf("size: %lu\n", loose_size / 2);
|
||||
printf("in-pack: %lu\n", packed);
|
||||
printf("packs: %lu\n", num_pack);
|
||||
printf("prune-packable: %lu\n", packed_loose);
|
||||
printf("garbage: %lu\n", garbage);
|
||||
}
|
||||
|
@ -6,7 +6,6 @@
|
||||
#include "tree.h"
|
||||
#include "blob.h"
|
||||
#include "quote.h"
|
||||
#include <fnmatch.h>
|
||||
|
||||
/* Quoting styles */
|
||||
#define QUOTE_NONE 0
|
||||
|
@ -10,10 +10,7 @@
|
||||
#include "tag.h"
|
||||
#include "tree-walk.h"
|
||||
#include "builtin.h"
|
||||
#include <regex.h>
|
||||
#include "grep.h"
|
||||
#include <fnmatch.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
/*
|
||||
* git grep pathspecs are somewhat different from diff-tree pathspecs;
|
||||
@ -268,7 +265,7 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached)
|
||||
for (i = 0; i < active_nr; i++) {
|
||||
struct cache_entry *ce = active_cache[i];
|
||||
char *name;
|
||||
if (ce_stage(ce) || !S_ISREG(ntohl(ce->ce_mode)))
|
||||
if (!S_ISREG(ntohl(ce->ce_mode)))
|
||||
continue;
|
||||
if (!pathspec_matches(paths, ce->name))
|
||||
continue;
|
||||
@ -280,12 +277,19 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached)
|
||||
memcpy(name + 2, ce->name, len + 1);
|
||||
}
|
||||
argv[argc++] = name;
|
||||
if (argc < MAXARGS)
|
||||
if (argc < MAXARGS && !ce_stage(ce))
|
||||
continue;
|
||||
status = exec_grep(argc, argv);
|
||||
if (0 < status)
|
||||
hit = 1;
|
||||
argc = nr;
|
||||
if (ce_stage(ce)) {
|
||||
do {
|
||||
i++;
|
||||
} while (i < active_nr &&
|
||||
!strcmp(ce->name, active_cache[i]->name));
|
||||
i--; /* compensate for loop control */
|
||||
}
|
||||
}
|
||||
if (argc > nr) {
|
||||
status = exec_grep(argc, argv);
|
||||
@ -316,14 +320,24 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached)
|
||||
|
||||
for (nr = 0; nr < active_nr; nr++) {
|
||||
struct cache_entry *ce = active_cache[nr];
|
||||
if (ce_stage(ce) || !S_ISREG(ntohl(ce->ce_mode)))
|
||||
if (!S_ISREG(ntohl(ce->ce_mode)))
|
||||
continue;
|
||||
if (!pathspec_matches(paths, ce->name))
|
||||
continue;
|
||||
if (cached)
|
||||
if (cached) {
|
||||
if (ce_stage(ce))
|
||||
continue;
|
||||
hit |= grep_sha1(opt, ce->sha1, ce->name, 0);
|
||||
}
|
||||
else
|
||||
hit |= grep_file(opt, ce->name);
|
||||
if (ce_stage(ce)) {
|
||||
do {
|
||||
nr++;
|
||||
} while (nr < active_nr &&
|
||||
!strcmp(ce->name, active_cache[nr]->name));
|
||||
nr--; /* compensate for loop control */
|
||||
}
|
||||
}
|
||||
free_grep_patterns(opt);
|
||||
return hit;
|
||||
|
@ -124,8 +124,11 @@ static void copy_templates(const char *git_dir, int len, const char *template_di
|
||||
int template_len;
|
||||
DIR *dir;
|
||||
|
||||
if (!template_dir)
|
||||
template_dir = DEFAULT_GIT_TEMPLATE_DIR;
|
||||
if (!template_dir) {
|
||||
template_dir = getenv(TEMPLATE_DIR_ENVIRONMENT);
|
||||
if (!template_dir)
|
||||
template_dir = DEFAULT_GIT_TEMPLATE_DIR;
|
||||
}
|
||||
strcpy(template_path, template_dir);
|
||||
template_len = strlen(template_path);
|
||||
if (template_path[template_len-1] != '/') {
|
||||
@ -164,13 +167,14 @@ static void copy_templates(const char *git_dir, int len, const char *template_di
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
static void create_default_files(const char *git_dir, const char *template_path)
|
||||
static int create_default_files(const char *git_dir, const char *template_path)
|
||||
{
|
||||
unsigned len = strlen(git_dir);
|
||||
static char path[PATH_MAX];
|
||||
unsigned char sha1[20];
|
||||
struct stat st1;
|
||||
char repo_version_string[10];
|
||||
int reinit;
|
||||
|
||||
if (len > sizeof(path)-50)
|
||||
die("insane git directory %s", git_dir);
|
||||
@ -218,7 +222,8 @@ static void create_default_files(const char *git_dir, const char *template_path)
|
||||
* branch, if it does not exist yet.
|
||||
*/
|
||||
strcpy(path + len, "HEAD");
|
||||
if (read_ref("HEAD", sha1) < 0) {
|
||||
reinit = !read_ref("HEAD", sha1);
|
||||
if (!reinit) {
|
||||
if (create_symref("HEAD", "refs/heads/master") < 0)
|
||||
exit(1);
|
||||
}
|
||||
@ -239,6 +244,11 @@ static void create_default_files(const char *git_dir, const char *template_path)
|
||||
git_config_set("core.filemode",
|
||||
filemode ? "true" : "false");
|
||||
}
|
||||
|
||||
/* Enable logAllRefUpdates if a working tree is attached */
|
||||
if (!is_bare_git_dir(git_dir))
|
||||
git_config_set("core.logallrefupdates", "true");
|
||||
return reinit;
|
||||
}
|
||||
|
||||
static const char init_db_usage[] =
|
||||
@ -256,7 +266,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
|
||||
const char *sha1_dir;
|
||||
const char *template_dir = NULL;
|
||||
char *path;
|
||||
int len, i;
|
||||
int len, i, reinit;
|
||||
|
||||
for (i = 1; i < argc; i++, argv++) {
|
||||
const char *arg = argv[1];
|
||||
@ -274,10 +284,8 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
|
||||
* Set up the default .git directory contents
|
||||
*/
|
||||
git_dir = getenv(GIT_DIR_ENVIRONMENT);
|
||||
if (!git_dir) {
|
||||
if (!git_dir)
|
||||
git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
|
||||
fprintf(stderr, "defaulting to local storage area\n");
|
||||
}
|
||||
safe_create_dir(git_dir, 0);
|
||||
|
||||
/* Check to see if the repository version is right.
|
||||
@ -287,7 +295,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
|
||||
*/
|
||||
check_repository_format();
|
||||
|
||||
create_default_files(git_dir, template_dir);
|
||||
reinit = create_default_files(git_dir, template_dir);
|
||||
|
||||
/*
|
||||
* And set up the object store.
|
||||
@ -314,5 +322,10 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
|
||||
git_config_set("receive.denyNonFastforwards", "true");
|
||||
}
|
||||
|
||||
printf("%s%s Git repository in %s/\n",
|
||||
reinit ? "Reinitialized existing" : "Initialized empty",
|
||||
shared_repository ? " shared" : "",
|
||||
git_dir);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -10,8 +10,7 @@
|
||||
#include "revision.h"
|
||||
#include "log-tree.h"
|
||||
#include "builtin.h"
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include "tag.h"
|
||||
|
||||
static int default_show_root = 1;
|
||||
|
||||
@ -71,9 +70,43 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix)
|
||||
return cmd_log_walk(&rev);
|
||||
}
|
||||
|
||||
static int show_object(const unsigned char *sha1, int suppress_header)
|
||||
{
|
||||
unsigned long size;
|
||||
char type[20];
|
||||
char *buf = read_sha1_file(sha1, type, &size);
|
||||
int offset = 0;
|
||||
|
||||
if (!buf)
|
||||
return error("Could not read object %s", sha1_to_hex(sha1));
|
||||
|
||||
if (suppress_header)
|
||||
while (offset < size && buf[offset++] != '\n') {
|
||||
int new_offset = offset;
|
||||
while (new_offset < size && buf[new_offset++] != '\n')
|
||||
; /* do nothing */
|
||||
offset = new_offset;
|
||||
}
|
||||
|
||||
if (offset < size)
|
||||
fwrite(buf + offset, size - offset, 1, stdout);
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int show_tree_object(const unsigned char *sha1,
|
||||
const char *base, int baselen,
|
||||
const char *pathname, unsigned mode, int stage)
|
||||
{
|
||||
printf("%s%s\n", pathname, S_ISDIR(mode) ? "/" : "");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmd_show(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct rev_info rev;
|
||||
struct object_array_entry *objects;
|
||||
int i, count, ret = 0;
|
||||
|
||||
git_config(git_log_config);
|
||||
init_revisions(&rev, prefix);
|
||||
@ -85,7 +118,52 @@ int cmd_show(int argc, const char **argv, const char *prefix)
|
||||
rev.ignore_merges = 0;
|
||||
rev.no_walk = 1;
|
||||
cmd_log_init(argc, argv, prefix, &rev);
|
||||
return cmd_log_walk(&rev);
|
||||
|
||||
count = rev.pending.nr;
|
||||
objects = rev.pending.objects;
|
||||
for (i = 0; i < count && !ret; i++) {
|
||||
struct object *o = objects[i].item;
|
||||
const char *name = objects[i].name;
|
||||
switch (o->type) {
|
||||
case OBJ_BLOB:
|
||||
ret = show_object(o->sha1, 0);
|
||||
break;
|
||||
case OBJ_TAG: {
|
||||
struct tag *t = (struct tag *)o;
|
||||
|
||||
printf("%stag %s%s\n\n",
|
||||
diff_get_color(rev.diffopt.color_diff,
|
||||
DIFF_COMMIT),
|
||||
t->tag,
|
||||
diff_get_color(rev.diffopt.color_diff,
|
||||
DIFF_RESET));
|
||||
ret = show_object(o->sha1, 1);
|
||||
objects[i].item = (struct object *)t->tagged;
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
case OBJ_TREE:
|
||||
printf("%stree %s%s\n\n",
|
||||
diff_get_color(rev.diffopt.color_diff,
|
||||
DIFF_COMMIT),
|
||||
name,
|
||||
diff_get_color(rev.diffopt.color_diff,
|
||||
DIFF_RESET));
|
||||
read_tree_recursive((struct tree *)o, "", 0, 0, NULL,
|
||||
show_tree_object);
|
||||
break;
|
||||
case OBJ_COMMIT:
|
||||
rev.pending.nr = rev.pending.alloc = 0;
|
||||
rev.pending.objects = NULL;
|
||||
add_object_array(o, name, &rev.pending);
|
||||
ret = cmd_log_walk(&rev);
|
||||
break;
|
||||
default:
|
||||
ret = error("Unknown type: %d", o->type);
|
||||
}
|
||||
}
|
||||
free(objects);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cmd_log(int argc, const char **argv, const char *prefix)
|
||||
@ -118,7 +196,7 @@ static int git_format_config(const char *var, const char *value)
|
||||
strcat(extra_headers, value);
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(var, "diff.color")) {
|
||||
if (!strcmp(var, "diff.color") || !strcmp(var, "color.diff")) {
|
||||
return 0;
|
||||
}
|
||||
return git_log_config(var, value);
|
||||
|
@ -5,8 +5,6 @@
|
||||
*
|
||||
* Copyright (C) Linus Torvalds, 2005
|
||||
*/
|
||||
#include <fnmatch.h>
|
||||
|
||||
#include "cache.h"
|
||||
#include "quote.h"
|
||||
#include "dir.h"
|
||||
@ -487,10 +485,14 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
|
||||
for (num = 0; pathspec[num]; num++) {
|
||||
if (ps_matched[num])
|
||||
continue;
|
||||
error("pathspec '%s' did not match any.",
|
||||
error("pathspec '%s' did not match any file(s) known to git.",
|
||||
pathspec[num] + prefix_offset);
|
||||
errors++;
|
||||
}
|
||||
|
||||
if (errors)
|
||||
fprintf(stderr, "Did you forget to 'git add'?\n");
|
||||
|
||||
return errors ? 1 : 0;
|
||||
}
|
||||
|
||||
|
@ -2,15 +2,6 @@
|
||||
* Another stupid program, this one parsing the headers of an
|
||||
* email to figure out authorship and subject
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#ifndef NO_ICONV
|
||||
#include <iconv.h>
|
||||
#endif
|
||||
#include "git-compat-util.h"
|
||||
#include "cache.h"
|
||||
#include "builtin.h"
|
||||
|
||||
|
@ -4,13 +4,6 @@
|
||||
* It just splits a mbox into a list of files: "0001" "0002" ..
|
||||
* so you can process them further from there.
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "cache.h"
|
||||
#include "builtin.h"
|
||||
|
||||
|
63
builtin-merge-file.c
Normal file
63
builtin-merge-file.c
Normal file
@ -0,0 +1,63 @@
|
||||
#include "cache.h"
|
||||
#include "xdiff/xdiff.h"
|
||||
#include "xdiff-interface.h"
|
||||
|
||||
static const char merge_file_usage[] =
|
||||
"git merge-file [-p | --stdout] [-q | --quiet] [-L name1 [-L orig [-L name2]]] file1 orig_file file2";
|
||||
|
||||
int cmd_merge_file(int argc, char **argv, char **envp)
|
||||
{
|
||||
char *names[3];
|
||||
mmfile_t mmfs[3];
|
||||
mmbuffer_t result = {NULL, 0};
|
||||
xpparam_t xpp = {XDF_NEED_MINIMAL};
|
||||
int ret = 0, i = 0, to_stdout = 0;
|
||||
|
||||
while (argc > 4) {
|
||||
if (!strcmp(argv[1], "-L") && i < 3) {
|
||||
names[i++] = argv[2];
|
||||
argc--;
|
||||
argv++;
|
||||
} else if (!strcmp(argv[1], "-p") ||
|
||||
!strcmp(argv[1], "--stdout"))
|
||||
to_stdout = 1;
|
||||
else if (!strcmp(argv[1], "-q") ||
|
||||
!strcmp(argv[1], "--quiet"))
|
||||
freopen("/dev/null", "w", stderr);
|
||||
else
|
||||
usage(merge_file_usage);
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
|
||||
if (argc != 4)
|
||||
usage(merge_file_usage);
|
||||
|
||||
for (; i < 3; i++)
|
||||
names[i] = argv[i + 1];
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
if (read_mmfile(mmfs + i, argv[i + 1]))
|
||||
return -1;
|
||||
|
||||
ret = xdl_merge(mmfs + 1, mmfs + 0, names[0], mmfs + 2, names[2],
|
||||
&xpp, XDL_MERGE_ZEALOUS, &result);
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
free(mmfs[i].ptr);
|
||||
|
||||
if (ret >= 0) {
|
||||
char *filename = argv[1];
|
||||
FILE *f = to_stdout ? stdout : fopen(filename, "wb");
|
||||
|
||||
if (!f)
|
||||
ret = error("Could not open %s for writing", filename);
|
||||
else if (fwrite(result.ptr, result.size, 1, f) != 1)
|
||||
ret = error("Could not write to %s", filename);
|
||||
else if (fclose(f))
|
||||
ret = error("Could not close %s", filename);
|
||||
free(result.ptr);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
13
builtin-mv.c
13
builtin-mv.c
@ -3,8 +3,6 @@
|
||||
*
|
||||
* Copyright (C) 2006 Johannes Schindelin
|
||||
*/
|
||||
#include <fnmatch.h>
|
||||
|
||||
#include "cache.h"
|
||||
#include "builtin.h"
|
||||
#include "dir.h"
|
||||
@ -146,21 +144,24 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
|
||||
&& lstat(dst, &st) == 0)
|
||||
bad = "cannot move directory over file";
|
||||
else if (src_is_dir) {
|
||||
const char *src_w_slash = add_slash(src);
|
||||
int len_w_slash = length + 1;
|
||||
int first, last;
|
||||
|
||||
modes[i] = WORKING_DIRECTORY;
|
||||
|
||||
first = cache_name_pos(src, length);
|
||||
first = cache_name_pos(src_w_slash, len_w_slash);
|
||||
if (first >= 0)
|
||||
die ("Huh? %s/ is in index?", src);
|
||||
die ("Huh? %.*s is in index?",
|
||||
len_w_slash, src_w_slash);
|
||||
|
||||
first = -1 - first;
|
||||
for (last = first; last < active_nr; last++) {
|
||||
const char *path = active_cache[last]->name;
|
||||
if (strncmp(path, src, length)
|
||||
|| path[length] != '/')
|
||||
if (strncmp(path, src_w_slash, len_w_slash))
|
||||
break;
|
||||
}
|
||||
free((char *)src_w_slash);
|
||||
|
||||
if (last - first < 1)
|
||||
bad = "source directory is empty";
|
||||
|
@ -1,4 +1,3 @@
|
||||
#include <stdlib.h>
|
||||
#include "builtin.h"
|
||||
#include "cache.h"
|
||||
#include "commit.h"
|
||||
|
@ -12,14 +12,12 @@
|
||||
#include "diff.h"
|
||||
#include "revision.h"
|
||||
#include "list-objects.h"
|
||||
#include <sys/time.h>
|
||||
#include <signal.h>
|
||||
|
||||
static const char pack_usage[] = "\
|
||||
git-pack-objects [{ -q | --progress | --all-progress }] \n\
|
||||
[--local] [--incremental] [--window=N] [--depth=N] \n\
|
||||
[--no-reuse-delta] [--delta-base-offset] [--non-empty] \n\
|
||||
[--revs [--unpacked | --all]*] [--stdout | base-name] \n\
|
||||
[--revs [--unpacked | --all]*] [--reflog] [--stdout | base-name] \n\
|
||||
[<ref-list | <object-list]";
|
||||
|
||||
struct object_entry {
|
||||
@ -514,6 +512,8 @@ static void write_pack_file(void)
|
||||
if (do_progress)
|
||||
fputc('\n', stderr);
|
||||
done:
|
||||
if (written != nr_result)
|
||||
die("wrote %d objects while expecting %d", written, nr_result);
|
||||
sha1close(f, pack_file_sha1, 1);
|
||||
}
|
||||
|
||||
@ -1575,6 +1575,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
if (!strcmp("--unpacked", arg) ||
|
||||
!strncmp("--unpacked=", arg, 11) ||
|
||||
!strcmp("--reflog", arg) ||
|
||||
!strcmp("--all", arg)) {
|
||||
use_internal_rev_list = 1;
|
||||
if (ARRAY_SIZE(rp_av) - 1 <= rp_ac)
|
||||
@ -1662,7 +1663,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
}
|
||||
if (progress)
|
||||
fprintf(stderr, "Total %d, written %d (delta %d), reused %d (delta %d)\n",
|
||||
nr_result, written, written_delta, reused, reused_delta);
|
||||
fprintf(stderr, "Total %d (delta %d), reused %d (delta %d)\n",
|
||||
written, written_delta, reused, reused_delta);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include "cache.h"
|
||||
#include "refs.h"
|
||||
#include "object.h"
|
||||
#include "tag.h"
|
||||
|
||||
static const char builtin_pack_refs_usage[] =
|
||||
"git-pack-refs [--all] [--prune]";
|
||||
@ -29,12 +31,26 @@ static int handle_one_ref(const char *path, const unsigned char *sha1,
|
||||
int flags, void *cb_data)
|
||||
{
|
||||
struct pack_refs_cb_data *cb = cb_data;
|
||||
int is_tag_ref;
|
||||
|
||||
if (!cb->all && strncmp(path, "refs/tags/", 10))
|
||||
return 0;
|
||||
/* Do not pack the symbolic refs */
|
||||
if (!(flags & REF_ISSYMREF))
|
||||
fprintf(cb->refs_file, "%s %s\n", sha1_to_hex(sha1), path);
|
||||
if ((flags & REF_ISSYMREF))
|
||||
return 0;
|
||||
is_tag_ref = !strncmp(path, "refs/tags/", 10);
|
||||
if (!cb->all && !is_tag_ref)
|
||||
return 0;
|
||||
|
||||
fprintf(cb->refs_file, "%s %s\n", sha1_to_hex(sha1), path);
|
||||
if (is_tag_ref) {
|
||||
struct object *o = parse_object(sha1);
|
||||
if (o->type == OBJ_TAG) {
|
||||
o = deref_tag(o, path, 0);
|
||||
if (o)
|
||||
fprintf(cb->refs_file, "^%s\n",
|
||||
sha1_to_hex(o->sha1));
|
||||
}
|
||||
}
|
||||
|
||||
if (cb->prune && !do_not_prune(flags)) {
|
||||
int namelen = strlen(path) + 1;
|
||||
struct ref_to_prune *n = xcalloc(1, sizeof(*n) + namelen);
|
||||
@ -95,6 +111,10 @@ int cmd_pack_refs(int argc, const char **argv, const char *prefix)
|
||||
if (!cbdata.refs_file)
|
||||
die("unable to create ref-pack file structure (%s)",
|
||||
strerror(errno));
|
||||
|
||||
/* perhaps other traits later as well */
|
||||
fprintf(cbdata.refs_file, "# pack-refs with: peeled \n");
|
||||
|
||||
for_each_ref(handle_one_ref, &cbdata);
|
||||
fflush(cbdata.refs_file);
|
||||
fsync(fd);
|
||||
|
@ -181,12 +181,28 @@ static void walk_commit_list(struct rev_info *revs)
|
||||
}
|
||||
}
|
||||
|
||||
static int add_one_reflog_ent(unsigned char *osha1, unsigned char *nsha1, char *datail, void *cb_data)
|
||||
{
|
||||
struct object *object;
|
||||
|
||||
object = parse_object(osha1);
|
||||
if (object)
|
||||
add_pending_object(&revs, object, "");
|
||||
object = parse_object(nsha1);
|
||||
if (object)
|
||||
add_pending_object(&revs, object, "");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_one_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
|
||||
{
|
||||
struct object *object = parse_object(sha1);
|
||||
if (!object)
|
||||
die("bad object ref: %s:%s", path, sha1_to_hex(sha1));
|
||||
add_pending_object(&revs, object, "");
|
||||
|
||||
for_each_reflog_ent(path, add_one_reflog_ent, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -57,11 +57,36 @@ static void expand_refspecs(void)
|
||||
static void set_refspecs(const char **refs, int nr)
|
||||
{
|
||||
if (nr) {
|
||||
size_t bytes = nr * sizeof(char *);
|
||||
|
||||
refspec = xrealloc(refspec, bytes);
|
||||
memcpy(refspec, refs, bytes);
|
||||
refspec_nr = 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
expand_refspecs();
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "tree-walk.h"
|
||||
#include "cache-tree.h"
|
||||
#include "unpack-trees.h"
|
||||
#include "dir.h"
|
||||
#include "builtin.h"
|
||||
|
||||
static struct object_list *trees;
|
||||
@ -84,7 +85,7 @@ static void prime_cache_tree(void)
|
||||
|
||||
}
|
||||
|
||||
static const char read_tree_usage[] = "git-read-tree (<sha> | [[-m [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] <sha1> [<sha2> [<sha3>]])";
|
||||
static const char read_tree_usage[] = "git-read-tree (<sha> | [[-m [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] [--exclude-per-directory=<gitignore>] <sha1> [<sha2> [<sha3>]])";
|
||||
|
||||
static struct lock_file lock_file;
|
||||
|
||||
@ -178,6 +179,23 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strncmp(arg, "--exclude-per-directory=", 24)) {
|
||||
struct dir_struct *dir;
|
||||
|
||||
if (opts.dir)
|
||||
die("more than one --exclude-per-directory are given.");
|
||||
|
||||
dir = calloc(1, sizeof(*opts.dir));
|
||||
dir->show_ignored = 1;
|
||||
dir->exclude_per_dir = arg + 24;
|
||||
opts.dir = dir;
|
||||
/* We do not need to nor want to do read-directory
|
||||
* here; we are merely interested in reusing the
|
||||
* per directory ignore stack mechanism.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
/* using -u and -i at the same time makes no sense */
|
||||
if (1 < opts.index_only + opts.update)
|
||||
usage(read_tree_usage);
|
||||
@ -190,6 +208,8 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
|
||||
}
|
||||
if ((opts.update||opts.index_only) && !opts.merge)
|
||||
usage(read_tree_usage);
|
||||
if ((opts.dir && !opts.update))
|
||||
die("--exclude-per-directory is meaningless unless -u");
|
||||
|
||||
if (opts.prefix) {
|
||||
int pfxlen = strlen(opts.prefix);
|
||||
|
212
builtin-reflog.c
Normal file
212
builtin-reflog.c
Normal file
@ -0,0 +1,212 @@
|
||||
#include "cache.h"
|
||||
#include "builtin.h"
|
||||
#include "commit.h"
|
||||
#include "refs.h"
|
||||
#include "dir.h"
|
||||
#include "tree-walk.h"
|
||||
|
||||
struct expire_reflog_cb {
|
||||
FILE *newlog;
|
||||
const char *ref;
|
||||
struct commit *ref_commit;
|
||||
unsigned long expire_total;
|
||||
unsigned long expire_unreachable;
|
||||
};
|
||||
|
||||
static int tree_is_complete(const unsigned char *sha1)
|
||||
{
|
||||
struct tree_desc desc;
|
||||
void *buf;
|
||||
char type[20];
|
||||
|
||||
buf = read_sha1_file(sha1, type, &desc.size);
|
||||
if (!buf)
|
||||
return 0;
|
||||
desc.buf = buf;
|
||||
while (desc.size) {
|
||||
const unsigned char *elem;
|
||||
const char *name;
|
||||
unsigned mode;
|
||||
|
||||
elem = tree_entry_extract(&desc, &name, &mode);
|
||||
if (!has_sha1_file(elem) ||
|
||||
(S_ISDIR(mode) && !tree_is_complete(elem))) {
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
update_tree_entry(&desc);
|
||||
}
|
||||
free(buf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int keep_entry(struct commit **it, unsigned char *sha1)
|
||||
{
|
||||
struct commit *commit;
|
||||
|
||||
*it = NULL;
|
||||
if (is_null_sha1(sha1))
|
||||
return 1;
|
||||
commit = lookup_commit_reference_gently(sha1, 1);
|
||||
if (!commit)
|
||||
return 0;
|
||||
|
||||
/* Make sure everything in this commit exists. */
|
||||
parse_object(commit->object.sha1);
|
||||
if (!tree_is_complete(commit->tree->object.sha1))
|
||||
return 0;
|
||||
*it = commit;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
|
||||
char *data, void *cb_data)
|
||||
{
|
||||
struct expire_reflog_cb *cb = cb_data;
|
||||
unsigned long timestamp;
|
||||
char *cp, *ep;
|
||||
struct commit *old, *new;
|
||||
|
||||
cp = strchr(data, '>');
|
||||
if (!cp || *++cp != ' ')
|
||||
goto prune;
|
||||
timestamp = strtoul(cp, &ep, 10);
|
||||
if (*ep != ' ')
|
||||
goto prune;
|
||||
if (timestamp < cb->expire_total)
|
||||
goto prune;
|
||||
|
||||
if (!keep_entry(&old, osha1) || !keep_entry(&new, nsha1))
|
||||
goto prune;
|
||||
|
||||
if ((timestamp < cb->expire_unreachable) &&
|
||||
(!cb->ref_commit ||
|
||||
(old && !in_merge_bases(old, cb->ref_commit)) ||
|
||||
(new && !in_merge_bases(new, cb->ref_commit))))
|
||||
goto prune;
|
||||
|
||||
if (cb->newlog)
|
||||
fprintf(cb->newlog, "%s %s %s",
|
||||
sha1_to_hex(osha1), sha1_to_hex(nsha1), data);
|
||||
return 0;
|
||||
prune:
|
||||
if (!cb->newlog)
|
||||
fprintf(stderr, "would prune %s", data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct cmd_reflog_expire_cb {
|
||||
int dry_run;
|
||||
unsigned long expire_total;
|
||||
unsigned long expire_unreachable;
|
||||
};
|
||||
|
||||
static int expire_reflog(const char *ref, const unsigned char *sha1, int unused, void *cb_data)
|
||||
{
|
||||
struct cmd_reflog_expire_cb *cmd = cb_data;
|
||||
struct expire_reflog_cb cb;
|
||||
struct ref_lock *lock;
|
||||
char *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);
|
||||
if (!lock)
|
||||
return error("cannot lock ref '%s'", ref);
|
||||
if (!file_exists(lock->log_file))
|
||||
goto finish;
|
||||
if (!cmd->dry_run) {
|
||||
newlog_path = xstrdup(git_path("logs/%s.lock", ref));
|
||||
cb.newlog = fopen(newlog_path, "w");
|
||||
}
|
||||
|
||||
cb.ref_commit = lookup_commit_reference_gently(sha1, 1);
|
||||
if (!cb.ref_commit)
|
||||
fprintf(stderr,
|
||||
"warning: ref '%s' does not point at a commit\n", ref);
|
||||
cb.ref = ref;
|
||||
cb.expire_total = cmd->expire_total;
|
||||
cb.expire_unreachable = cmd->expire_unreachable;
|
||||
for_each_reflog_ent(ref, expire_reflog_ent, &cb);
|
||||
finish:
|
||||
if (cb.newlog) {
|
||||
if (fclose(cb.newlog))
|
||||
status |= error("%s: %s", strerror(errno),
|
||||
newlog_path);
|
||||
if (rename(newlog_path, lock->log_file)) {
|
||||
status |= error("cannot rename %s to %s",
|
||||
newlog_path, lock->log_file);
|
||||
unlink(newlog_path);
|
||||
}
|
||||
}
|
||||
free(newlog_path);
|
||||
unlock_ref(lock);
|
||||
return status;
|
||||
}
|
||||
|
||||
static const char reflog_expire_usage[] =
|
||||
"git-reflog expire [--dry-run] [--expire=<time>] [--expire-unreachable=<time>] [--all] <refs>...";
|
||||
|
||||
static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct cmd_reflog_expire_cb cb;
|
||||
unsigned long now = time(NULL);
|
||||
int i, status, do_all;
|
||||
|
||||
save_commit_buffer = 0;
|
||||
do_all = status = 0;
|
||||
memset(&cb, 0, sizeof(cb));
|
||||
cb.expire_total = now - 90 * 24 * 3600;
|
||||
cb.expire_unreachable = now - 30 * 24 * 3600;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
if (!strcmp(arg, "--dry-run") || !strcmp(arg, "-n"))
|
||||
cb.dry_run = 1;
|
||||
else if (!strncmp(arg, "--expire=", 9))
|
||||
cb.expire_total = approxidate(arg + 9);
|
||||
else if (!strncmp(arg, "--expire-unreachable=", 21))
|
||||
cb.expire_unreachable = approxidate(arg + 21);
|
||||
else if (!strcmp(arg, "--all"))
|
||||
do_all = 1;
|
||||
else if (!strcmp(arg, "--")) {
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
else if (arg[0] == '-')
|
||||
usage(reflog_expire_usage);
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (do_all)
|
||||
status |= for_each_ref(expire_reflog, &cb);
|
||||
while (i < argc) {
|
||||
const char *ref = argv[i++];
|
||||
unsigned char sha1[20];
|
||||
if (!resolve_ref(ref, sha1, 1, NULL)) {
|
||||
status |= error("%s points nowhere!", ref);
|
||||
continue;
|
||||
}
|
||||
status |= expire_reflog(ref, sha1, 0, &cb);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static const char reflog_usage[] =
|
||||
"git-reflog (expire | ...)";
|
||||
|
||||
int cmd_reflog(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
if (argc < 2)
|
||||
usage(reflog_usage);
|
||||
else if (!strcmp(argv[1], "expire"))
|
||||
return cmd_reflog_expire(argc - 1, argv + 1, prefix);
|
||||
else
|
||||
usage(reflog_usage);
|
||||
}
|
@ -1,9 +1,8 @@
|
||||
#include "builtin.h"
|
||||
#include "cache.h"
|
||||
#include <regex.h>
|
||||
|
||||
static const char git_config_set_usage[] =
|
||||
"git-repo-config [ --global ] [ --bool | --int ] [--get | --get-all | --get-regexp | --replace-all | --unset | --unset-all] name [value [value_regex]] | --list";
|
||||
"git-repo-config [ --global ] [ --bool | --int ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --list";
|
||||
|
||||
static char *key;
|
||||
static regex_t *key_regexp;
|
||||
@ -67,10 +66,10 @@ static int get_value(const char* key_, const char* regex_)
|
||||
char *global = NULL, *repo_config = NULL;
|
||||
const char *local;
|
||||
|
||||
local = getenv("GIT_CONFIG");
|
||||
local = getenv(CONFIG_ENVIRONMENT);
|
||||
if (!local) {
|
||||
const char *home = getenv("HOME");
|
||||
local = getenv("GIT_CONFIG_LOCAL");
|
||||
local = getenv(CONFIG_LOCAL_ENVIRONMENT);
|
||||
if (!local)
|
||||
local = repo_config = xstrdup(git_path("config"));
|
||||
if (home)
|
||||
@ -148,6 +147,18 @@ int cmd_repo_config(int argc, const char **argv, const char *prefix)
|
||||
} else {
|
||||
die("$HOME not set");
|
||||
}
|
||||
} else if (!strcmp(argv[1], "--rename-section")) {
|
||||
int ret;
|
||||
if (argc != 4)
|
||||
usage(git_config_set_usage);
|
||||
ret = git_config_rename_section(argv[2], argv[3]);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret == 0) {
|
||||
fprintf(stderr, "No such section!\n");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
} else
|
||||
break;
|
||||
argc--;
|
||||
@ -190,7 +201,9 @@ int cmd_repo_config(int argc, const char **argv, const char *prefix)
|
||||
use_key_regexp = 1;
|
||||
do_all = 1;
|
||||
return get_value(argv[2], argv[3]);
|
||||
} else if (!strcmp(argv[1], "--replace-all"))
|
||||
} else if (!strcmp(argv[1], "--add"))
|
||||
return git_config_set_multivar(argv[2], argv[3], "^$", 0);
|
||||
else if (!strcmp(argv[1], "--replace-all"))
|
||||
|
||||
return git_config_set_multivar(argv[2], argv[3], NULL, 1);
|
||||
else
|
||||
|
406
builtin-rerere.c
Normal file
406
builtin-rerere.c
Normal file
@ -0,0 +1,406 @@
|
||||
#include "cache.h"
|
||||
#include "path-list.h"
|
||||
#include "xdiff/xdiff.h"
|
||||
#include "xdiff-interface.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
static const char git_rerere_usage[] =
|
||||
"git-rerere [clear | status | diff | gc]";
|
||||
|
||||
/* these values are days */
|
||||
static int cutoff_noresolve = 15;
|
||||
static int cutoff_resolve = 60;
|
||||
|
||||
static char *merge_rr_path;
|
||||
|
||||
static const char *rr_path(const char *name, const char *file)
|
||||
{
|
||||
return git_path("rr-cache/%s/%s", name, file);
|
||||
}
|
||||
|
||||
static void read_rr(struct path_list *rr)
|
||||
{
|
||||
unsigned char sha1[20];
|
||||
char buf[PATH_MAX];
|
||||
FILE *in = fopen(merge_rr_path, "r");
|
||||
if (!in)
|
||||
return;
|
||||
while (fread(buf, 40, 1, in) == 1) {
|
||||
int i;
|
||||
char *name;
|
||||
if (get_sha1_hex(buf, sha1))
|
||||
die("corrupt MERGE_RR");
|
||||
buf[40] = '\0';
|
||||
name = xstrdup(buf);
|
||||
if (fgetc(in) != '\t')
|
||||
die("corrupt MERGE_RR");
|
||||
for (i = 0; i < sizeof(buf) && (buf[i] = fgetc(in)); i++)
|
||||
; /* do nothing */
|
||||
if (i == sizeof(buf))
|
||||
die("filename too long");
|
||||
path_list_insert(buf, rr)->util = xstrdup(name);
|
||||
}
|
||||
fclose(in);
|
||||
}
|
||||
|
||||
static struct lock_file write_lock;
|
||||
|
||||
static int write_rr(struct path_list *rr, int out_fd)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < rr->nr; i++) {
|
||||
const char *path = rr->items[i].path;
|
||||
write(out_fd, rr->items[i].util, 40);
|
||||
write(out_fd, "\t", 1);
|
||||
write(out_fd, path, strlen(path) + 1);
|
||||
}
|
||||
close(out_fd);
|
||||
return commit_lock_file(&write_lock);
|
||||
}
|
||||
|
||||
struct buffer {
|
||||
char *ptr;
|
||||
int nr, alloc;
|
||||
};
|
||||
|
||||
static void append_line(struct buffer *buffer, const char *line)
|
||||
{
|
||||
int len = strlen(line);
|
||||
|
||||
if (buffer->nr + len > buffer->alloc) {
|
||||
buffer->alloc = alloc_nr(buffer->nr + len);
|
||||
buffer->ptr = xrealloc(buffer->ptr, buffer->alloc);
|
||||
}
|
||||
memcpy(buffer->ptr + buffer->nr, line, len);
|
||||
buffer->nr += len;
|
||||
}
|
||||
|
||||
static int handle_file(const char *path,
|
||||
unsigned char *sha1, const char *output)
|
||||
{
|
||||
SHA_CTX ctx;
|
||||
char buf[1024];
|
||||
int hunk = 0, hunk_no = 0;
|
||||
struct buffer minus = { NULL, 0, 0 }, plus = { NULL, 0, 0 };
|
||||
struct buffer *one = &minus, *two = +
|
||||
FILE *f = fopen(path, "r");
|
||||
FILE *out;
|
||||
|
||||
if (!f)
|
||||
return error("Could not open %s", path);
|
||||
|
||||
if (output) {
|
||||
out = fopen(output, "w");
|
||||
if (!out) {
|
||||
fclose(f);
|
||||
return error("Could not write %s", output);
|
||||
}
|
||||
} else
|
||||
out = NULL;
|
||||
|
||||
if (sha1)
|
||||
SHA1_Init(&ctx);
|
||||
|
||||
while (fgets(buf, sizeof(buf), f)) {
|
||||
if (!strncmp("<<<<<<< ", buf, 8))
|
||||
hunk = 1;
|
||||
else if (!strncmp("=======", buf, 7))
|
||||
hunk = 2;
|
||||
else if (!strncmp(">>>>>>> ", buf, 8)) {
|
||||
hunk_no++;
|
||||
hunk = 0;
|
||||
if (memcmp(one->ptr, two->ptr, one->nr < two->nr ?
|
||||
one->nr : two->nr) > 0) {
|
||||
struct buffer *swap = one;
|
||||
one = two;
|
||||
two = swap;
|
||||
}
|
||||
if (out) {
|
||||
fputs("<<<<<<<\n", out);
|
||||
fwrite(one->ptr, one->nr, 1, out);
|
||||
fputs("=======\n", out);
|
||||
fwrite(two->ptr, two->nr, 1, out);
|
||||
fputs(">>>>>>>\n", out);
|
||||
}
|
||||
if (sha1) {
|
||||
SHA1_Update(&ctx, one->ptr, one->nr);
|
||||
SHA1_Update(&ctx, "\0", 1);
|
||||
SHA1_Update(&ctx, two->ptr, two->nr);
|
||||
SHA1_Update(&ctx, "\0", 1);
|
||||
}
|
||||
} else if (hunk == 1)
|
||||
append_line(one, buf);
|
||||
else if (hunk == 2)
|
||||
append_line(two, buf);
|
||||
else if (out)
|
||||
fputs(buf, out);
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
if (out)
|
||||
fclose(out);
|
||||
if (sha1)
|
||||
SHA1_Final(sha1, &ctx);
|
||||
return hunk_no;
|
||||
}
|
||||
|
||||
static int find_conflict(struct path_list *conflict)
|
||||
{
|
||||
int i;
|
||||
if (read_cache() < 0)
|
||||
return error("Could not read index");
|
||||
for (i = 0; i + 2 < active_nr; i++) {
|
||||
struct cache_entry *e1 = active_cache[i];
|
||||
struct cache_entry *e2 = active_cache[i + 1];
|
||||
struct cache_entry *e3 = active_cache[i + 2];
|
||||
if (ce_stage(e1) == 1 && ce_stage(e2) == 2 &&
|
||||
ce_stage(e3) == 3 && ce_same_name(e1, e2) &&
|
||||
ce_same_name(e1, e3)) {
|
||||
path_list_insert((const char *)e1->name, conflict);
|
||||
i += 3;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int merge(const char *name, const char *path)
|
||||
{
|
||||
int ret;
|
||||
mmfile_t cur, base, other;
|
||||
mmbuffer_t result = {NULL, 0};
|
||||
xpparam_t xpp = {XDF_NEED_MINIMAL};
|
||||
|
||||
if (handle_file(path, NULL, rr_path(name, "thisimage")) < 0)
|
||||
return 1;
|
||||
|
||||
if (read_mmfile(&cur, rr_path(name, "thisimage")) ||
|
||||
read_mmfile(&base, rr_path(name, "preimage")) ||
|
||||
read_mmfile(&other, rr_path(name, "postimage")))
|
||||
return 1;
|
||||
ret = xdl_merge(&base, &cur, "", &other, "",
|
||||
&xpp, XDL_MERGE_ZEALOUS, &result);
|
||||
if (!ret) {
|
||||
FILE *f = fopen(path, "w");
|
||||
if (!f)
|
||||
return error("Could not write to %s", path);
|
||||
fwrite(result.ptr, result.size, 1, f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
free(cur.ptr);
|
||||
free(base.ptr);
|
||||
free(other.ptr);
|
||||
free(result.ptr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void unlink_rr_item(const char *name)
|
||||
{
|
||||
unlink(rr_path(name, "thisimage"));
|
||||
unlink(rr_path(name, "preimage"));
|
||||
unlink(rr_path(name, "postimage"));
|
||||
rmdir(git_path("rr-cache/%s", name));
|
||||
}
|
||||
|
||||
static void garbage_collect(struct path_list *rr)
|
||||
{
|
||||
struct path_list to_remove = { NULL, 0, 0, 1 };
|
||||
char buf[1024];
|
||||
DIR *dir;
|
||||
struct dirent *e;
|
||||
int len, i, cutoff;
|
||||
time_t now = time(NULL), then;
|
||||
|
||||
strlcpy(buf, git_path("rr-cache"), sizeof(buf));
|
||||
len = strlen(buf);
|
||||
dir = opendir(buf);
|
||||
strcpy(buf + len++, "/");
|
||||
while ((e = readdir(dir))) {
|
||||
const char *name = e->d_name;
|
||||
struct stat st;
|
||||
if (name[0] == '.' && (name[1] == '\0' ||
|
||||
(name[1] == '.' && name[2] == '\0')))
|
||||
continue;
|
||||
i = snprintf(buf + len, sizeof(buf) - len, "%s", name);
|
||||
strlcpy(buf + len + i, "/preimage", sizeof(buf) - len - i);
|
||||
if (stat(buf, &st))
|
||||
continue;
|
||||
then = st.st_mtime;
|
||||
strlcpy(buf + len + i, "/postimage", sizeof(buf) - len - i);
|
||||
cutoff = stat(buf, &st) ? cutoff_noresolve : cutoff_resolve;
|
||||
if (then < now - cutoff * 86400) {
|
||||
buf[len + i] = '\0';
|
||||
path_list_insert(xstrdup(name), &to_remove);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < to_remove.nr; i++)
|
||||
unlink_rr_item(to_remove.items[i].path);
|
||||
path_list_clear(&to_remove, 0);
|
||||
}
|
||||
|
||||
static int outf(void *dummy, mmbuffer_t *ptr, int nbuf)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < nbuf; i++)
|
||||
write(1, ptr[i].ptr, ptr[i].size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int diff_two(const char *file1, const char *label1,
|
||||
const char *file2, const char *label2)
|
||||
{
|
||||
xpparam_t xpp;
|
||||
xdemitconf_t xecfg;
|
||||
xdemitcb_t ecb;
|
||||
mmfile_t minus, plus;
|
||||
|
||||
if (read_mmfile(&minus, file1) || read_mmfile(&plus, file2))
|
||||
return 1;
|
||||
|
||||
printf("--- a/%s\n+++ b/%s\n", label1, label2);
|
||||
fflush(stdout);
|
||||
xpp.flags = XDF_NEED_MINIMAL;
|
||||
xecfg.ctxlen = 3;
|
||||
xecfg.flags = 0;
|
||||
ecb.outf = outf;
|
||||
xdl_diff(&minus, &plus, &xpp, &xecfg, &ecb);
|
||||
|
||||
free(minus.ptr);
|
||||
free(plus.ptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int copy_file(const char *src, const char *dest)
|
||||
{
|
||||
FILE *in, *out;
|
||||
char buffer[32768];
|
||||
int count;
|
||||
|
||||
if (!(in = fopen(src, "r")))
|
||||
return error("Could not open %s", src);
|
||||
if (!(out = fopen(dest, "w")))
|
||||
return error("Could not open %s", dest);
|
||||
while ((count = fread(buffer, 1, sizeof(buffer), in)))
|
||||
fwrite(buffer, 1, count, out);
|
||||
fclose(in);
|
||||
fclose(out);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_plain_rerere(struct path_list *rr, int fd)
|
||||
{
|
||||
struct path_list conflict = { NULL, 0, 0, 1 };
|
||||
int i;
|
||||
|
||||
find_conflict(&conflict);
|
||||
|
||||
/*
|
||||
* MERGE_RR records paths with conflicts immediately after merge
|
||||
* failed. Some of the conflicted paths might have been hand resolved
|
||||
* in the working tree since then, but the initial run would catch all
|
||||
* and register their preimages.
|
||||
*/
|
||||
|
||||
for (i = 0; i < conflict.nr; i++) {
|
||||
const char *path = conflict.items[i].path;
|
||||
if (!path_list_has_path(rr, path)) {
|
||||
unsigned char sha1[20];
|
||||
char *hex;
|
||||
int ret;
|
||||
ret = handle_file(path, sha1, NULL);
|
||||
if (ret < 1)
|
||||
continue;
|
||||
hex = xstrdup(sha1_to_hex(sha1));
|
||||
path_list_insert(path, rr)->util = hex;
|
||||
if (mkdir(git_path("rr-cache/%s", hex), 0755))
|
||||
continue;;
|
||||
handle_file(path, NULL, rr_path(hex, "preimage"));
|
||||
fprintf(stderr, "Recorded preimage for '%s'\n", path);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now some of the paths that had conflicts earlier might have been
|
||||
* hand resolved. Others may be similar to a conflict already that
|
||||
* was resolved before.
|
||||
*/
|
||||
|
||||
for (i = 0; i < rr->nr; i++) {
|
||||
struct stat st;
|
||||
int ret;
|
||||
const char *path = rr->items[i].path;
|
||||
const char *name = (const char *)rr->items[i].util;
|
||||
|
||||
if (!stat(rr_path(name, "preimage"), &st) &&
|
||||
!stat(rr_path(name, "postimage"), &st)) {
|
||||
if (!merge(name, path)) {
|
||||
fprintf(stderr, "Resolved '%s' using "
|
||||
"previous resolution.\n", path);
|
||||
goto tail_optimization;
|
||||
}
|
||||
}
|
||||
|
||||
/* Let's see if we have resolved it. */
|
||||
ret = handle_file(path, NULL, NULL);
|
||||
if (ret)
|
||||
continue;
|
||||
|
||||
fprintf(stderr, "Recorded resolution for '%s'.\n", path);
|
||||
copy_file(path, rr_path(name, "postimage"));
|
||||
tail_optimization:
|
||||
if (i < rr->nr - 1) {
|
||||
memmove(rr->items + i,
|
||||
rr->items + i + 1,
|
||||
rr->nr - i - 1);
|
||||
}
|
||||
rr->nr--;
|
||||
i--;
|
||||
}
|
||||
|
||||
return write_rr(rr, fd);
|
||||
}
|
||||
|
||||
int cmd_rerere(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct path_list merge_rr = { NULL, 0, 0, 1 };
|
||||
int i, fd = -1;
|
||||
struct stat st;
|
||||
|
||||
if (stat(git_path("rr-cache"), &st) || !S_ISDIR(st.st_mode))
|
||||
return 0;
|
||||
|
||||
merge_rr_path = xstrdup(git_path("rr-cache/MERGE_RR"));
|
||||
fd = hold_lock_file_for_update(&write_lock, merge_rr_path, 1);
|
||||
read_rr(&merge_rr);
|
||||
|
||||
if (argc < 2)
|
||||
return do_plain_rerere(&merge_rr, fd);
|
||||
else if (!strcmp(argv[1], "clear")) {
|
||||
for (i = 0; i < merge_rr.nr; i++) {
|
||||
const char *name = (const char *)merge_rr.items[i].util;
|
||||
if (!stat(git_path("rr-cache/%s", name), &st) &&
|
||||
S_ISDIR(st.st_mode) &&
|
||||
stat(rr_path(name, "postimage"), &st))
|
||||
unlink_rr_item(name);
|
||||
}
|
||||
unlink(merge_rr_path);
|
||||
} else if (!strcmp(argv[1], "gc"))
|
||||
garbage_collect(&merge_rr);
|
||||
else if (!strcmp(argv[1], "status"))
|
||||
for (i = 0; i < merge_rr.nr; i++)
|
||||
printf("%s\n", merge_rr.items[i].path);
|
||||
else if (!strcmp(argv[1], "diff"))
|
||||
for (i = 0; i < merge_rr.nr; i++) {
|
||||
const char *path = merge_rr.items[i].path;
|
||||
const char *name = (const char *)merge_rr.items[i].util;
|
||||
diff_two(rr_path(name, "preimage"), path, path, path);
|
||||
}
|
||||
else
|
||||
usage(git_rerere_usage);
|
||||
|
||||
path_list_clear(&merge_rr, 1);
|
||||
return 0;
|
||||
}
|
||||
|
@ -54,6 +54,12 @@ static void show_commit(struct commit *commit)
|
||||
fputs(header_prefix, stdout);
|
||||
if (commit->object.flags & BOUNDARY)
|
||||
putchar('-');
|
||||
else if (revs.left_right) {
|
||||
if (commit->object.flags & SYMMETRIC_LEFT)
|
||||
putchar('<');
|
||||
else
|
||||
putchar('>');
|
||||
}
|
||||
if (revs.abbrev_commit && revs.abbrev)
|
||||
fputs(find_unique_abbrev(commit->object.sha1, revs.abbrev),
|
||||
stdout);
|
||||
|
123
builtin-rm.c
123
builtin-rm.c
@ -7,9 +7,10 @@
|
||||
#include "builtin.h"
|
||||
#include "dir.h"
|
||||
#include "cache-tree.h"
|
||||
#include "tree-walk.h"
|
||||
|
||||
static const char builtin_rm_usage[] =
|
||||
"git-rm [-n] [-v] [-f] <filepattern>...";
|
||||
"git-rm [-n] [-f] [--cached] <filepattern>...";
|
||||
|
||||
static struct {
|
||||
int nr, alloc;
|
||||
@ -41,12 +42,75 @@ static int remove_file(const char *name)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int check_local_mod(unsigned char *head)
|
||||
{
|
||||
/* items in list are already sorted in the cache order,
|
||||
* so we could do this a lot more efficiently by using
|
||||
* tree_desc based traversal if we wanted to, but I am
|
||||
* lazy, and who cares if removal of files is a tad
|
||||
* slower than the theoretical maximum speed?
|
||||
*/
|
||||
int i, no_head;
|
||||
int errs = 0;
|
||||
|
||||
no_head = is_null_sha1(head);
|
||||
for (i = 0; i < list.nr; i++) {
|
||||
struct stat st;
|
||||
int pos;
|
||||
struct cache_entry *ce;
|
||||
const char *name = list.name[i];
|
||||
unsigned char sha1[20];
|
||||
unsigned mode;
|
||||
|
||||
pos = cache_name_pos(name, strlen(name));
|
||||
if (pos < 0)
|
||||
continue; /* removing unmerged entry */
|
||||
ce = active_cache[pos];
|
||||
|
||||
if (lstat(ce->name, &st) < 0) {
|
||||
if (errno != ENOENT)
|
||||
fprintf(stderr, "warning: '%s': %s",
|
||||
ce->name, strerror(errno));
|
||||
/* It already vanished from the working tree */
|
||||
continue;
|
||||
}
|
||||
else if (S_ISDIR(st.st_mode)) {
|
||||
/* if a file was removed and it is now a
|
||||
* directory, that is the same as ENOENT as
|
||||
* far as git is concerned; we do not track
|
||||
* directories.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
if (ce_match_stat(ce, &st, 0))
|
||||
errs = error("'%s' has local modifications "
|
||||
"(hint: try -f)", ce->name);
|
||||
if (no_head)
|
||||
continue;
|
||||
/*
|
||||
* It is Ok to remove a newly added path, as long as
|
||||
* it is cache-clean.
|
||||
*/
|
||||
if (get_tree_entry(head, name, sha1, &mode))
|
||||
continue;
|
||||
/*
|
||||
* Otherwise make sure the version from the HEAD
|
||||
* matches the index.
|
||||
*/
|
||||
if (ce->ce_mode != create_ce_mode(mode) ||
|
||||
hashcmp(ce->sha1, sha1))
|
||||
errs = error("'%s' has changes staged in the index "
|
||||
"(hint: try -f)", name);
|
||||
}
|
||||
return errs;
|
||||
}
|
||||
|
||||
static struct lock_file lock_file;
|
||||
|
||||
int cmd_rm(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i, newfd;
|
||||
int verbose = 0, show_only = 0, force = 0;
|
||||
int show_only = 0, force = 0, index_only = 0, recursive = 0;
|
||||
const char **pathspec;
|
||||
char *seen;
|
||||
|
||||
@ -62,23 +126,20 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
|
||||
|
||||
if (*arg != '-')
|
||||
break;
|
||||
if (!strcmp(arg, "--")) {
|
||||
else if (!strcmp(arg, "--")) {
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
if (!strcmp(arg, "-n")) {
|
||||
else if (!strcmp(arg, "-n"))
|
||||
show_only = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "-v")) {
|
||||
verbose = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "-f")) {
|
||||
else if (!strcmp(arg, "--cached"))
|
||||
index_only = 1;
|
||||
else if (!strcmp(arg, "-f"))
|
||||
force = 1;
|
||||
continue;
|
||||
}
|
||||
usage(builtin_rm_usage);
|
||||
else if (!strcmp(arg, "-r"))
|
||||
recursive = 1;
|
||||
else
|
||||
usage(builtin_rm_usage);
|
||||
}
|
||||
if (argc <= i)
|
||||
usage(builtin_rm_usage);
|
||||
@ -99,14 +160,36 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
|
||||
if (pathspec) {
|
||||
const char *match;
|
||||
for (i = 0; (match = pathspec[i]) != NULL ; i++) {
|
||||
if (*match && !seen[i])
|
||||
die("pathspec '%s' did not match any files", match);
|
||||
if (!seen[i])
|
||||
die("pathspec '%s' did not match any files",
|
||||
match);
|
||||
if (!recursive && seen[i] == MATCHED_RECURSIVELY)
|
||||
die("not removing '%s' recursively without -r",
|
||||
*match ? match : ".");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If not forced, the file, the index and the HEAD (if exists)
|
||||
* must match; but the file can already been removed, since
|
||||
* this sequence is a natural "novice" way:
|
||||
*
|
||||
* rm F; git fm F
|
||||
*
|
||||
* Further, if HEAD commit exists, "diff-index --cached" must
|
||||
* report no changes unless forced.
|
||||
*/
|
||||
if (!force) {
|
||||
unsigned char sha1[20];
|
||||
if (get_sha1("HEAD", sha1))
|
||||
hashclr(sha1);
|
||||
if (check_local_mod(sha1))
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* First remove the names from the index: we won't commit
|
||||
* the index unless all of them succeed
|
||||
* the index unless all of them succeed.
|
||||
*/
|
||||
for (i = 0; i < list.nr; i++) {
|
||||
const char *path = list.name[i];
|
||||
@ -121,14 +204,14 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Then, if we used "-f", remove the filenames from the
|
||||
* workspace. If we fail to remove the first one, we
|
||||
* Then, unless we used "--cache", remove the filenames from
|
||||
* the workspace. If we fail to remove the first one, we
|
||||
* abort the "git rm" (but once we've successfully removed
|
||||
* any file at all, we'll go ahead and commit to it all:
|
||||
* by then we've already committed ourselves and can't fail
|
||||
* in the middle)
|
||||
*/
|
||||
if (force) {
|
||||
if (!index_only) {
|
||||
int removed = 0;
|
||||
for (i = 0; i < list.nr; i++) {
|
||||
const char *path = list.name[i];
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include "wt-status.h"
|
||||
#include "cache.h"
|
||||
#include "wt-status.h"
|
||||
|
||||
extern int wt_status_use_color;
|
||||
|
||||
|
341
builtin-shortlog.c
Normal file
341
builtin-shortlog.c
Normal file
@ -0,0 +1,341 @@
|
||||
#include "builtin.h"
|
||||
#include "cache.h"
|
||||
#include "commit.h"
|
||||
#include "diff.h"
|
||||
#include "path-list.h"
|
||||
#include "revision.h"
|
||||
|
||||
static const char shortlog_usage[] =
|
||||
"git-shortlog [-n] [-s] [<commit-id>... ]";
|
||||
|
||||
static char *common_repo_prefix;
|
||||
|
||||
static int compare_by_number(const void *a1, const void *a2)
|
||||
{
|
||||
const struct path_list_item *i1 = a1, *i2 = a2;
|
||||
const struct path_list *l1 = i1->util, *l2 = i2->util;
|
||||
|
||||
if (l1->nr < l2->nr)
|
||||
return 1;
|
||||
else if (l1->nr == l2->nr)
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
static struct path_list mailmap = {NULL, 0, 0, 0};
|
||||
|
||||
static int read_mailmap(const char *filename)
|
||||
{
|
||||
char buffer[1024];
|
||||
FILE *f = fopen(filename, "r");
|
||||
|
||||
if (f == NULL)
|
||||
return 1;
|
||||
while (fgets(buffer, sizeof(buffer), f) != NULL) {
|
||||
char *end_of_name, *left_bracket, *right_bracket;
|
||||
char *name, *email;
|
||||
int i;
|
||||
if (buffer[0] == '#') {
|
||||
static const char abbrev[] = "# repo-abbrev:";
|
||||
int abblen = sizeof(abbrev) - 1;
|
||||
int len = strlen(buffer);
|
||||
|
||||
if (len && buffer[len - 1] == '\n')
|
||||
buffer[--len] = 0;
|
||||
if (!strncmp(buffer, abbrev, abblen)) {
|
||||
char *cp;
|
||||
|
||||
if (common_repo_prefix)
|
||||
free(common_repo_prefix);
|
||||
common_repo_prefix = xmalloc(len);
|
||||
|
||||
for (cp = buffer + abblen; isspace(*cp); cp++)
|
||||
; /* nothing */
|
||||
strcpy(common_repo_prefix, cp);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if ((left_bracket = strchr(buffer, '<')) == NULL)
|
||||
continue;
|
||||
if ((right_bracket = strchr(left_bracket + 1, '>')) == NULL)
|
||||
continue;
|
||||
if (right_bracket == left_bracket + 1)
|
||||
continue;
|
||||
for (end_of_name = left_bracket; end_of_name != buffer
|
||||
&& isspace(end_of_name[-1]); end_of_name--)
|
||||
/* keep on looking */
|
||||
if (end_of_name == buffer)
|
||||
continue;
|
||||
name = xmalloc(end_of_name - buffer + 1);
|
||||
strlcpy(name, buffer, end_of_name - buffer + 1);
|
||||
email = xmalloc(right_bracket - left_bracket);
|
||||
for (i = 0; i < right_bracket - left_bracket - 1; i++)
|
||||
email[i] = tolower(left_bracket[i + 1]);
|
||||
email[right_bracket - left_bracket - 1] = '\0';
|
||||
path_list_insert(email, &mailmap)->util = name;
|
||||
}
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int map_email(char *email, char *name, int maxlen)
|
||||
{
|
||||
char *p;
|
||||
struct path_list_item *item;
|
||||
|
||||
/* autocomplete common developers */
|
||||
p = strchr(email, '>');
|
||||
if (!p)
|
||||
return 0;
|
||||
|
||||
*p = '\0';
|
||||
/* downcase the email address */
|
||||
for (p = email; *p; p++)
|
||||
*p = tolower(*p);
|
||||
item = path_list_lookup(email, &mailmap);
|
||||
if (item != NULL) {
|
||||
const char *realname = (const char *)item->util;
|
||||
strncpy(name, realname, maxlen);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void insert_author_oneline(struct path_list *list,
|
||||
const char *author, int authorlen,
|
||||
const char *oneline, int onelinelen)
|
||||
{
|
||||
const char *dot3 = common_repo_prefix;
|
||||
char *buffer, *p;
|
||||
struct path_list_item *item;
|
||||
struct path_list *onelines;
|
||||
|
||||
while (authorlen > 0 && isspace(author[authorlen - 1]))
|
||||
authorlen--;
|
||||
|
||||
buffer = xmalloc(authorlen + 1);
|
||||
memcpy(buffer, author, authorlen);
|
||||
buffer[authorlen] = '\0';
|
||||
|
||||
item = path_list_insert(buffer, list);
|
||||
if (item->util == NULL)
|
||||
item->util = xcalloc(1, sizeof(struct path_list));
|
||||
else
|
||||
free(buffer);
|
||||
|
||||
if (!strncmp(oneline, "[PATCH", 6)) {
|
||||
char *eob = strchr(oneline, ']');
|
||||
|
||||
if (eob) {
|
||||
while (isspace(eob[1]) && eob[1] != '\n')
|
||||
eob++;
|
||||
if (eob - oneline < onelinelen) {
|
||||
onelinelen -= eob - oneline;
|
||||
oneline = eob;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (onelinelen > 0 && isspace(oneline[0])) {
|
||||
oneline++;
|
||||
onelinelen--;
|
||||
}
|
||||
|
||||
while (onelinelen > 0 && isspace(oneline[onelinelen - 1]))
|
||||
onelinelen--;
|
||||
|
||||
buffer = xmalloc(onelinelen + 1);
|
||||
memcpy(buffer, oneline, onelinelen);
|
||||
buffer[onelinelen] = '\0';
|
||||
|
||||
if (dot3) {
|
||||
int dot3len = strlen(dot3);
|
||||
if (dot3len > 5) {
|
||||
while ((p = strstr(buffer, dot3)) != NULL) {
|
||||
int taillen = strlen(p) - dot3len;
|
||||
memcpy(p, "/.../", 5);
|
||||
memmove(p + 5, p + dot3len, taillen + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onelines = item->util;
|
||||
if (onelines->nr >= onelines->alloc) {
|
||||
onelines->alloc = alloc_nr(onelines->nr);
|
||||
onelines->items = xrealloc(onelines->items,
|
||||
onelines->alloc
|
||||
* sizeof(struct path_list_item));
|
||||
}
|
||||
|
||||
onelines->items[onelines->nr].util = NULL;
|
||||
onelines->items[onelines->nr++].path = buffer;
|
||||
}
|
||||
|
||||
static void read_from_stdin(struct path_list *list)
|
||||
{
|
||||
char buffer[1024];
|
||||
|
||||
while (fgets(buffer, sizeof(buffer), stdin) != NULL) {
|
||||
char *bob;
|
||||
if ((buffer[0] == 'A' || buffer[0] == 'a') &&
|
||||
!strncmp(buffer + 1, "uthor: ", 7) &&
|
||||
(bob = strchr(buffer + 7, '<')) != NULL) {
|
||||
char buffer2[1024], offset = 0;
|
||||
|
||||
if (map_email(bob + 1, buffer, sizeof(buffer)))
|
||||
bob = buffer + strlen(buffer);
|
||||
else {
|
||||
offset = 8;
|
||||
while (buffer + offset < bob &&
|
||||
isspace(bob[-1]))
|
||||
bob--;
|
||||
}
|
||||
|
||||
while (fgets(buffer2, sizeof(buffer2), stdin) &&
|
||||
buffer2[0] != '\n')
|
||||
; /* chomp input */
|
||||
if (fgets(buffer2, sizeof(buffer2), stdin)) {
|
||||
int l2 = strlen(buffer2);
|
||||
int i;
|
||||
for (i = 0; i < l2; i++)
|
||||
if (!isspace(buffer2[i]))
|
||||
break;
|
||||
insert_author_oneline(list,
|
||||
buffer + offset,
|
||||
bob - buffer - offset,
|
||||
buffer2 + i, l2 - i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void get_from_rev(struct rev_info *rev, struct path_list *list)
|
||||
{
|
||||
char scratch[1024];
|
||||
struct commit *commit;
|
||||
|
||||
prepare_revision_walk(rev);
|
||||
while ((commit = get_revision(rev)) != NULL) {
|
||||
char *author = NULL, *oneline, *buffer;
|
||||
int authorlen = authorlen, onelinelen;
|
||||
|
||||
/* get author and oneline */
|
||||
for (buffer = commit->buffer; buffer && *buffer != '\0' &&
|
||||
*buffer != '\n'; ) {
|
||||
char *eol = strchr(buffer, '\n');
|
||||
|
||||
if (eol == NULL)
|
||||
eol = buffer + strlen(buffer);
|
||||
else
|
||||
eol++;
|
||||
|
||||
if (!strncmp(buffer, "author ", 7)) {
|
||||
char *bracket = strchr(buffer, '<');
|
||||
|
||||
if (bracket == NULL || bracket > eol)
|
||||
die("Invalid commit buffer: %s",
|
||||
sha1_to_hex(commit->object.sha1));
|
||||
|
||||
if (map_email(bracket + 1, scratch,
|
||||
sizeof(scratch))) {
|
||||
author = scratch;
|
||||
authorlen = strlen(scratch);
|
||||
} else {
|
||||
if (bracket[-1] == ' ')
|
||||
bracket--;
|
||||
|
||||
author = buffer + 7;
|
||||
authorlen = bracket - buffer - 7;
|
||||
}
|
||||
}
|
||||
buffer = eol;
|
||||
}
|
||||
|
||||
if (author == NULL)
|
||||
die ("Missing author: %s",
|
||||
sha1_to_hex(commit->object.sha1));
|
||||
|
||||
if (buffer == NULL || *buffer == '\0') {
|
||||
oneline = "<none>";
|
||||
onelinelen = sizeof(oneline) + 1;
|
||||
} else {
|
||||
char *eol;
|
||||
|
||||
oneline = buffer + 1;
|
||||
eol = strchr(oneline, '\n');
|
||||
if (eol == NULL)
|
||||
onelinelen = strlen(oneline);
|
||||
else
|
||||
onelinelen = eol - oneline;
|
||||
}
|
||||
|
||||
insert_author_oneline(list,
|
||||
author, authorlen, oneline, onelinelen);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int cmd_shortlog(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct rev_info rev;
|
||||
struct path_list list = { NULL, 0, 0, 1 };
|
||||
int i, j, sort_by_number = 0, summary = 0;
|
||||
|
||||
/* since -n is a shadowed rev argument, parse our args first */
|
||||
while (argc > 1) {
|
||||
if (!strcmp(argv[1], "-n") || !strcmp(argv[1], "--numbered"))
|
||||
sort_by_number = 1;
|
||||
else if (!strcmp(argv[1], "-s") ||
|
||||
!strcmp(argv[1], "--summary"))
|
||||
summary = 1;
|
||||
else if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
|
||||
usage(shortlog_usage);
|
||||
else
|
||||
break;
|
||||
argv++;
|
||||
argc--;
|
||||
}
|
||||
init_revisions(&rev, prefix);
|
||||
argc = setup_revisions(argc, argv, &rev, NULL);
|
||||
if (argc > 1)
|
||||
die ("unrecognized argument: %s", argv[1]);
|
||||
|
||||
if (!access(".mailmap", R_OK))
|
||||
read_mailmap(".mailmap");
|
||||
|
||||
if (rev.pending.nr == 0)
|
||||
read_from_stdin(&list);
|
||||
else
|
||||
get_from_rev(&rev, &list);
|
||||
|
||||
if (sort_by_number)
|
||||
qsort(list.items, list.nr, sizeof(struct path_list_item),
|
||||
compare_by_number);
|
||||
|
||||
for (i = 0; i < list.nr; i++) {
|
||||
struct path_list *onelines = list.items[i].util;
|
||||
|
||||
if (summary) {
|
||||
printf("%s: %d\n", list.items[i].path, onelines->nr);
|
||||
} else {
|
||||
printf("%s (%d):\n", list.items[i].path, onelines->nr);
|
||||
for (j = onelines->nr - 1; j >= 0; j--)
|
||||
printf(" %s\n", onelines->items[j].path);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
onelines->strdup_paths = 1;
|
||||
path_list_clear(onelines, 1);
|
||||
free(onelines);
|
||||
list.items[i].util = NULL;
|
||||
}
|
||||
|
||||
list.strdup_paths = 1;
|
||||
path_list_clear(&list, 1);
|
||||
mailmap.strdup_paths = 1;
|
||||
path_list_clear(&mailmap, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,12 +1,10 @@
|
||||
#include <stdlib.h>
|
||||
#include <fnmatch.h>
|
||||
#include "cache.h"
|
||||
#include "commit.h"
|
||||
#include "refs.h"
|
||||
#include "builtin.h"
|
||||
|
||||
static const char show_branch_usage[] =
|
||||
"git-show-branch [--sparse] [--current] [--all] [--heads] [--tags] [--topo-order] [--more=count | --list | --independent | --merge-base ] [--topics] [<refs>...]";
|
||||
"git-show-branch [--sparse] [--current] [--all] [--remotes] [--topo-order] [--more=count | --list | --independent | --merge-base ] [--topics] [<refs>...] | --reflog[=n] <branch>";
|
||||
|
||||
static int default_num;
|
||||
static int default_alloc;
|
||||
@ -17,6 +15,8 @@ static const char **default_arg;
|
||||
#define REV_SHIFT 2
|
||||
#define MAX_REVS (FLAG_BITS - REV_SHIFT) /* should not exceed bits_per_int - REV_SHIFT */
|
||||
|
||||
#define DEFAULT_REFLOG 4
|
||||
|
||||
static struct commit *interesting(struct commit_list *list)
|
||||
{
|
||||
while (list) {
|
||||
@ -383,6 +383,20 @@ static int append_head_ref(const char *refname, const unsigned char *sha1, int f
|
||||
return append_ref(refname + ofs, sha1, flag, cb_data);
|
||||
}
|
||||
|
||||
static int append_remote_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
|
||||
{
|
||||
unsigned char tmp[20];
|
||||
int ofs = 13;
|
||||
if (strncmp(refname, "refs/remotes/", ofs))
|
||||
return 0;
|
||||
/* If both heads/foo and tags/foo exists, get_sha1 would
|
||||
* get confused.
|
||||
*/
|
||||
if (get_sha1(refname + ofs, tmp) || hashcmp(tmp, sha1))
|
||||
ofs = 5;
|
||||
return append_ref(refname + ofs, sha1, flag, cb_data);
|
||||
}
|
||||
|
||||
static int append_tag_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
|
||||
{
|
||||
if (strncmp(refname, "refs/tags/", 10))
|
||||
@ -423,16 +437,16 @@ static int append_matching_ref(const char *refname, const unsigned char *sha1, i
|
||||
return append_ref(refname, sha1, flag, cb_data);
|
||||
}
|
||||
|
||||
static void snarf_refs(int head, int tag)
|
||||
static void snarf_refs(int head, int remotes)
|
||||
{
|
||||
if (head) {
|
||||
int orig_cnt = ref_name_cnt;
|
||||
for_each_ref(append_head_ref, NULL);
|
||||
sort_ref_range(orig_cnt, ref_name_cnt);
|
||||
}
|
||||
if (tag) {
|
||||
if (remotes) {
|
||||
int orig_cnt = ref_name_cnt;
|
||||
for_each_ref(append_tag_ref, NULL);
|
||||
for_each_ref(append_remote_ref, NULL);
|
||||
sort_ref_range(orig_cnt, ref_name_cnt);
|
||||
}
|
||||
}
|
||||
@ -554,7 +568,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
|
||||
struct commit_list *list = NULL, *seen = NULL;
|
||||
unsigned int rev_mask[MAX_REVS];
|
||||
int num_rev, i, extra = 0;
|
||||
int all_heads = 0, all_tags = 0;
|
||||
int all_heads = 0, all_remotes = 0;
|
||||
int all_mask, all_revs;
|
||||
int lifo = 1;
|
||||
char head[128];
|
||||
@ -570,6 +584,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
|
||||
int head_at = -1;
|
||||
int topics = 0;
|
||||
int dense = 1;
|
||||
int reflog = 0;
|
||||
|
||||
git_config(git_show_branch_config);
|
||||
|
||||
@ -585,12 +600,10 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
|
||||
ac--; av++;
|
||||
break;
|
||||
}
|
||||
else if (!strcmp(arg, "--all"))
|
||||
all_heads = all_tags = 1;
|
||||
else if (!strcmp(arg, "--heads"))
|
||||
all_heads = 1;
|
||||
else if (!strcmp(arg, "--tags"))
|
||||
all_tags = 1;
|
||||
else if (!strcmp(arg, "--all") || !strcmp(arg, "-a"))
|
||||
all_heads = all_remotes = 1;
|
||||
else if (!strcmp(arg, "--remotes") || !strcmp(arg, "-r"))
|
||||
all_remotes = 1;
|
||||
else if (!strcmp(arg, "--more"))
|
||||
extra = 1;
|
||||
else if (!strcmp(arg, "--list"))
|
||||
@ -615,6 +628,15 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
|
||||
dense = 0;
|
||||
else if (!strcmp(arg, "--date-order"))
|
||||
lifo = 0;
|
||||
else if (!strcmp(arg, "--reflog")) {
|
||||
reflog = DEFAULT_REFLOG;
|
||||
}
|
||||
else if (!strncmp(arg, "--reflog=", 9)) {
|
||||
char *end;
|
||||
reflog = strtoul(arg + 9, &end, 10);
|
||||
if (*end != '\0')
|
||||
die("unrecognized reflog count '%s'", arg + 9);
|
||||
}
|
||||
else
|
||||
usage(show_branch_usage);
|
||||
ac--; av++;
|
||||
@ -622,18 +644,31 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
|
||||
ac--; av++;
|
||||
|
||||
/* Only one of these is allowed */
|
||||
if (1 < independent + merge_base + (extra != 0))
|
||||
if (1 < independent + merge_base + (extra != 0) + (!!reflog))
|
||||
usage(show_branch_usage);
|
||||
|
||||
/* If nothing is specified, show all branches by default */
|
||||
if (ac + all_heads + all_tags == 0)
|
||||
if (ac + all_heads + all_remotes == 0)
|
||||
all_heads = 1;
|
||||
|
||||
if (all_heads + all_tags)
|
||||
snarf_refs(all_heads, all_tags);
|
||||
while (0 < ac) {
|
||||
append_one_rev(*av);
|
||||
ac--; av++;
|
||||
if (all_heads + all_remotes)
|
||||
snarf_refs(all_heads, all_remotes);
|
||||
if (reflog) {
|
||||
int reflen;
|
||||
if (!ac)
|
||||
die("--reflog option needs one branch name");
|
||||
reflen = strlen(*av);
|
||||
for (i = 0; i < reflog; i++) {
|
||||
char *name = xmalloc(reflen + 20);
|
||||
sprintf(name, "%s@{%d}", *av, i);
|
||||
append_one_rev(name);
|
||||
}
|
||||
}
|
||||
else {
|
||||
while (0 < ac) {
|
||||
append_one_rev(*av);
|
||||
ac--; av++;
|
||||
}
|
||||
}
|
||||
|
||||
head_p = resolve_ref("HEAD", head_sha1, 1, NULL);
|
||||
|
@ -2,17 +2,28 @@
|
||||
#include "refs.h"
|
||||
#include "object.h"
|
||||
#include "tag.h"
|
||||
#include "path-list.h"
|
||||
|
||||
static const char show_ref_usage[] = "git show-ref [-q|--quiet] [--verify] [-h|--head] [-d|--dereference] [-s|--hash[=<length>]] [--abbrev[=<length>]] [--tags] [--heads] [--] [pattern*]";
|
||||
static const char show_ref_usage[] = "git show-ref [-q|--quiet] [--verify] [-h|--head] [-d|--dereference] [-s|--hash[=<length>]] [--abbrev[=<length>]] [--tags] [--heads] [--] [pattern*] < ref-list";
|
||||
|
||||
static int deref_tags = 0, show_head = 0, tags_only = 0, heads_only = 0,
|
||||
found_match = 0, verify = 0, quiet = 0, hash_only = 0, abbrev = 0;
|
||||
static const char **pattern;
|
||||
|
||||
static void show_one(const char *refname, const unsigned char *sha1)
|
||||
{
|
||||
const char *hex = find_unique_abbrev(sha1, abbrev);
|
||||
if (hash_only)
|
||||
printf("%s\n", hex);
|
||||
else
|
||||
printf("%s %s\n", hex, refname);
|
||||
}
|
||||
|
||||
static int show_ref(const char *refname, const unsigned char *sha1, int flag, void *cbdata)
|
||||
{
|
||||
struct object *obj;
|
||||
const char *hex;
|
||||
unsigned char peeled[20];
|
||||
|
||||
if (tags_only || heads_only) {
|
||||
int match;
|
||||
@ -44,24 +55,93 @@ static int show_ref(const char *refname, const unsigned char *sha1, int flag, vo
|
||||
|
||||
match:
|
||||
found_match++;
|
||||
obj = parse_object(sha1);
|
||||
if (!obj) {
|
||||
if (quiet)
|
||||
return 0;
|
||||
die("git-show-ref: bad ref %s (%s)", refname, sha1_to_hex(sha1));
|
||||
}
|
||||
|
||||
/* This changes the semantics slightly that even under quiet we
|
||||
* detect and return error if the repository is corrupt and
|
||||
* ref points at a nonexistent object.
|
||||
*/
|
||||
if (!has_sha1_file(sha1))
|
||||
die("git-show-ref: bad ref %s (%s)", refname,
|
||||
sha1_to_hex(sha1));
|
||||
|
||||
if (quiet)
|
||||
return 0;
|
||||
|
||||
hex = find_unique_abbrev(sha1, abbrev);
|
||||
if (hash_only)
|
||||
printf("%s\n", hex);
|
||||
else
|
||||
printf("%s %s\n", hex, refname);
|
||||
if (deref_tags && obj->type == OBJ_TAG) {
|
||||
obj = deref_tag(obj, refname, 0);
|
||||
hex = find_unique_abbrev(obj->sha1, abbrev);
|
||||
printf("%s %s^{}\n", hex, refname);
|
||||
show_one(refname, sha1);
|
||||
|
||||
if (!deref_tags)
|
||||
return 0;
|
||||
|
||||
if ((flag & REF_ISPACKED) && !peel_ref(refname, peeled)) {
|
||||
if (!is_null_sha1(peeled)) {
|
||||
hex = find_unique_abbrev(peeled, abbrev);
|
||||
printf("%s %s^{}\n", hex, refname);
|
||||
}
|
||||
}
|
||||
else {
|
||||
obj = parse_object(sha1);
|
||||
if (!obj)
|
||||
die("git-show-ref: bad ref %s (%s)", refname,
|
||||
sha1_to_hex(sha1));
|
||||
if (obj->type == OBJ_TAG) {
|
||||
obj = deref_tag(obj, refname, 0);
|
||||
hex = find_unique_abbrev(obj->sha1, abbrev);
|
||||
printf("%s %s^{}\n", hex, refname);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_existing(const char *refname, const unsigned char *sha1, int flag, void *cbdata)
|
||||
{
|
||||
struct path_list *list = (struct path_list *)cbdata;
|
||||
path_list_insert(refname, list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* read "^(?:<anything>\s)?<refname>(?:\^\{\})?$" from the standard input,
|
||||
* and
|
||||
* (1) strip "^{}" at the end of line if any;
|
||||
* (2) ignore if match is provided and does not head-match refname;
|
||||
* (3) warn if refname is not a well-formed refname and skip;
|
||||
* (4) ignore if refname is a ref that exists in the local repository;
|
||||
* (5) otherwise output the line.
|
||||
*/
|
||||
static int exclude_existing(const char *match)
|
||||
{
|
||||
static struct path_list existing_refs = { NULL, 0, 0, 0 };
|
||||
char buf[1024];
|
||||
int matchlen = match ? strlen(match) : 0;
|
||||
|
||||
for_each_ref(add_existing, &existing_refs);
|
||||
while (fgets(buf, sizeof(buf), stdin)) {
|
||||
char *ref;
|
||||
int len = strlen(buf);
|
||||
|
||||
if (len > 0 && buf[len - 1] == '\n')
|
||||
buf[--len] = '\0';
|
||||
if (3 <= len && !strcmp(buf + len - 3, "^{}")) {
|
||||
len -= 3;
|
||||
buf[len] = '\0';
|
||||
}
|
||||
for (ref = buf + len; buf < ref; ref--)
|
||||
if (isspace(ref[-1]))
|
||||
break;
|
||||
if (match) {
|
||||
int reflen = buf + len - ref;
|
||||
if (reflen < matchlen)
|
||||
continue;
|
||||
if (strncmp(ref, match, matchlen))
|
||||
continue;
|
||||
}
|
||||
if (check_ref_format(ref)) {
|
||||
fprintf(stderr, "warning: ref '%s' ignored\n", ref);
|
||||
continue;
|
||||
}
|
||||
if (!path_list_has_path(&existing_refs, ref)) {
|
||||
printf("%s\n", buf);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -101,13 +181,13 @@ int cmd_show_ref(int argc, const char **argv, const char *prefix)
|
||||
if (!strncmp(arg, "--hash=", 7) ||
|
||||
(!strncmp(arg, "--abbrev", 8) &&
|
||||
(arg[8] == '=' || arg[8] == '\0'))) {
|
||||
if (arg[3] != 'h' && !arg[8])
|
||||
if (arg[2] != 'h' && !arg[8])
|
||||
/* --abbrev only */
|
||||
abbrev = DEFAULT_ABBREV;
|
||||
else {
|
||||
/* --hash= or --abbrev= */
|
||||
char *end;
|
||||
if (arg[3] == 'h') {
|
||||
if (arg[2] == 'h') {
|
||||
hash_only = 1;
|
||||
arg += 7;
|
||||
}
|
||||
@ -133,8 +213,31 @@ int cmd_show_ref(int argc, const char **argv, const char *prefix)
|
||||
heads_only = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--exclude-existing"))
|
||||
return exclude_existing(NULL);
|
||||
if (!strncmp(arg, "--exclude-existing=", 19))
|
||||
return exclude_existing(arg + 19);
|
||||
usage(show_ref_usage);
|
||||
}
|
||||
|
||||
if (verify) {
|
||||
unsigned char sha1[20];
|
||||
|
||||
while (*pattern) {
|
||||
if (!strncmp(*pattern, "refs/", 5) &&
|
||||
resolve_ref(*pattern, sha1, 1, NULL)) {
|
||||
if (!quiet)
|
||||
show_one(*pattern, sha1);
|
||||
}
|
||||
else if (!quiet)
|
||||
die("'%s' - not a valid ref", *pattern);
|
||||
else
|
||||
return 1;
|
||||
pattern++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (show_head)
|
||||
head_ref(show_ref, NULL);
|
||||
for_each_ref(show_ref, NULL);
|
||||
|
@ -1,6 +1,3 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "builtin.h"
|
||||
|
||||
/*
|
||||
|
@ -1,7 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2006 Rene Scharfe
|
||||
*/
|
||||
#include <time.h>
|
||||
#include "cache.h"
|
||||
#include "commit.h"
|
||||
#include "tar.h"
|
||||
|
@ -8,8 +8,6 @@
|
||||
#include "tag.h"
|
||||
#include "tree.h"
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
static int dry_run, quiet, recover, has_errors;
|
||||
static const char unpack_usage[] = "git-unpack-objects [-n] [-q] [-r] < pack-file";
|
||||
|
||||
|
@ -1,9 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2006 Franck Bui-Huu
|
||||
*/
|
||||
#include <time.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/poll.h>
|
||||
#include "cache.h"
|
||||
#include "builtin.h"
|
||||
#include "archive.h"
|
||||
|
@ -42,6 +42,7 @@ 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);
|
||||
extern int cmd_mailsplit(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_merge_file(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_mv(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_name_rev(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_pack_objects(int argc, const char **argv, const char *prefix);
|
||||
@ -50,11 +51,14 @@ extern int cmd_prune(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_prune_packed(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_push(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_read_tree(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_reflog(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_repo_config(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_rerere(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_rev_list(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_rev_parse(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_rm(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_runstatus(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_shortlog(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_show(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_show_branch(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_stripspace(int argc, const char **argv, const char *prefix);
|
||||
|
7
cache.h
7
cache.h
@ -122,7 +122,12 @@ extern int cache_errno;
|
||||
#define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
|
||||
#define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
|
||||
#define GRAFT_ENVIRONMENT "GIT_GRAFT_FILE"
|
||||
#define TEMPLATE_DIR_ENVIRONMENT "GIT_TEMPLATE_DIR"
|
||||
#define CONFIG_ENVIRONMENT "GIT_CONFIG"
|
||||
#define CONFIG_LOCAL_ENVIRONMENT "GIT_CONFIG_LOCAL"
|
||||
#define EXEC_PATH_ENVIRONMENT "GIT_EXEC_PATH"
|
||||
|
||||
extern int is_bare_git_dir(const char *dir);
|
||||
extern const char *get_git_dir(void);
|
||||
extern char *get_object_directory(void);
|
||||
extern char *get_refs_directory(void);
|
||||
@ -308,6 +313,7 @@ void datestamp(char *buf, int bufsize);
|
||||
unsigned long approxidate(const char *);
|
||||
|
||||
extern int setup_ident(void);
|
||||
extern void ignore_missing_committer_name();
|
||||
extern const char *git_author_info(int);
|
||||
extern const char *git_committer_info(int);
|
||||
|
||||
@ -403,6 +409,7 @@ extern int git_config_int(const char *, const char *);
|
||||
extern int git_config_bool(const char *, const char *);
|
||||
extern int git_config_set(const char *, const char *);
|
||||
extern int git_config_set_multivar(const char *, const char *, const char *, int);
|
||||
extern int git_config_rename_section(const char *, const char *);
|
||||
extern int check_repository_format_version(const char *var, const char *value);
|
||||
|
||||
#define MAX_GITNAME (1000)
|
||||
|
5
color.c
5
color.c
@ -1,8 +1,5 @@
|
||||
#include "color.h"
|
||||
#include "cache.h"
|
||||
#include "git-compat-util.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include "color.h"
|
||||
|
||||
#define COLOR_RESET "\033[m"
|
||||
|
||||
|
27
commit.c
27
commit.c
@ -902,11 +902,11 @@ void sort_in_topological_order_fn(struct commit_list ** list, int lifo,
|
||||
|
||||
/* merge-rebase stuff */
|
||||
|
||||
/* bits #0..7 in revision.h */
|
||||
#define PARENT1 (1u<< 8)
|
||||
#define PARENT2 (1u<< 9)
|
||||
#define STALE (1u<<10)
|
||||
#define RESULT (1u<<11)
|
||||
/* bits #0..15 in revision.h */
|
||||
#define PARENT1 (1u<<16)
|
||||
#define PARENT2 (1u<<17)
|
||||
#define STALE (1u<<18)
|
||||
#define RESULT (1u<<19)
|
||||
|
||||
static struct commit *interesting(struct commit_list *list)
|
||||
{
|
||||
@ -1043,3 +1043,20 @@ struct commit_list *get_merge_bases(struct commit *one,
|
||||
free(rslt);
|
||||
return result;
|
||||
}
|
||||
|
||||
int in_merge_bases(struct commit *rev1, struct commit *rev2)
|
||||
{
|
||||
struct commit_list *bases, *b;
|
||||
int ret = 0;
|
||||
|
||||
bases = get_merge_bases(rev1, rev2, 1);
|
||||
for (b = bases; b; b = b->next) {
|
||||
if (!hashcmp(rev1->object.sha1, b->item->object.sha1)) {
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free_commit_list(bases);
|
||||
return ret;
|
||||
}
|
||||
|
1
commit.h
1
commit.h
@ -114,4 +114,5 @@ extern int is_repository_shallow();
|
||||
extern struct commit_list *get_shallow_commits(struct object_array *heads,
|
||||
int depth, int shallow_flag, int not_shallow_flag);
|
||||
|
||||
int in_merge_bases(struct commit *rev1, struct commit *rev2);
|
||||
#endif /* COMMIT_H */
|
||||
|
@ -93,7 +93,7 @@ inet_ntop6(src, dst, size)
|
||||
*/
|
||||
char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
|
||||
struct { int base, len; } best, cur;
|
||||
u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
|
||||
unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ];
|
||||
int i;
|
||||
|
||||
/*
|
||||
|
@ -1,21 +1,11 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include "../git-compat-util.h"
|
||||
|
||||
void *gitfakemmap(void *start, size_t length, int prot , int flags, int fd, off_t offset)
|
||||
void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset)
|
||||
{
|
||||
int n = 0;
|
||||
off_t current_offset = lseek(fd, 0, SEEK_CUR);
|
||||
size_t n = 0;
|
||||
|
||||
if (start != NULL || !(flags & MAP_PRIVATE))
|
||||
die("Invalid usage of gitfakemmap.");
|
||||
|
||||
if (lseek(fd, offset, SEEK_SET) < 0) {
|
||||
errno = EINVAL;
|
||||
return MAP_FAILED;
|
||||
}
|
||||
die("Invalid usage of mmap when built with NO_MMAP");
|
||||
|
||||
start = xmalloc(length);
|
||||
if (start == NULL) {
|
||||
@ -24,14 +14,16 @@ void *gitfakemmap(void *start, size_t length, int prot , int flags, int fd, off_
|
||||
}
|
||||
|
||||
while (n < length) {
|
||||
int count = read(fd, start+n, length-n);
|
||||
ssize_t count = pread(fd, (char *)start + n, length - n, offset + n);
|
||||
|
||||
if (count == 0) {
|
||||
memset(start+n, 0, length-n);
|
||||
memset((char *)start+n, 0, length-n);
|
||||
break;
|
||||
}
|
||||
|
||||
if (count < 0) {
|
||||
if (errno == EAGAIN || errno == EINTR)
|
||||
continue;
|
||||
free(start);
|
||||
errno = EACCES;
|
||||
return MAP_FAILED;
|
||||
@ -40,15 +32,10 @@ void *gitfakemmap(void *start, size_t length, int prot , int flags, int fd, off_
|
||||
n += count;
|
||||
}
|
||||
|
||||
if (current_offset != lseek(fd, current_offset, SEEK_SET)) {
|
||||
errno = EINVAL;
|
||||
return MAP_FAILED;
|
||||
}
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
int gitfakemunmap(void *start, size_t length)
|
||||
int git_munmap(void *start, size_t length)
|
||||
{
|
||||
free(start);
|
||||
return 0;
|
||||
|
@ -1,5 +1,4 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "../git-compat-util.h"
|
||||
|
||||
int gitsetenv(const char *name, const char *value, int replace)
|
||||
{
|
||||
|
@ -1,4 +1,4 @@
|
||||
#include <string.h>
|
||||
#include "../git-compat-util.h"
|
||||
|
||||
size_t gitstrlcpy(char *dest, const char *src, size_t size)
|
||||
{
|
||||
|
1149
compat/subprocess.py
1149
compat/subprocess.py
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,4 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "../git-compat-util.h"
|
||||
|
||||
void gitunsetenv (const char *name)
|
||||
{
|
||||
|
82
config.c
82
config.c
@ -6,7 +6,6 @@
|
||||
*
|
||||
*/
|
||||
#include "cache.h"
|
||||
#include <regex.h>
|
||||
|
||||
#define MAXNAME (256)
|
||||
|
||||
@ -314,7 +313,7 @@ int git_default_config(const char *var, const char *value)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(var, "pager.color")) {
|
||||
if (!strcmp(var, "pager.color") || !strcmp(var, "color.pager")) {
|
||||
pager_use_color = git_config_bool(var,value);
|
||||
return 0;
|
||||
}
|
||||
@ -350,10 +349,10 @@ int git_config(config_fn_t fn)
|
||||
* $GIT_CONFIG_LOCAL will make it process it in addition to the
|
||||
* global config file, the same way it would the per-repository
|
||||
* config file otherwise. */
|
||||
filename = getenv("GIT_CONFIG");
|
||||
filename = getenv(CONFIG_ENVIRONMENT);
|
||||
if (!filename) {
|
||||
home = getenv("HOME");
|
||||
filename = getenv("GIT_CONFIG_LOCAL");
|
||||
filename = getenv(CONFIG_LOCAL_ENVIRONMENT);
|
||||
if (!filename)
|
||||
filename = repo_config = xstrdup(git_path("config"));
|
||||
}
|
||||
@ -544,9 +543,9 @@ int git_config_set_multivar(const char* key, const char* value,
|
||||
char* lock_file;
|
||||
const char* last_dot = strrchr(key, '.');
|
||||
|
||||
config_filename = getenv("GIT_CONFIG");
|
||||
config_filename = getenv(CONFIG_ENVIRONMENT);
|
||||
if (!config_filename) {
|
||||
config_filename = getenv("GIT_CONFIG_LOCAL");
|
||||
config_filename = getenv(CONFIG_LOCAL_ENVIRONMENT);
|
||||
if (!config_filename)
|
||||
config_filename = git_path("config");
|
||||
}
|
||||
@ -746,4 +745,75 @@ out_free:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int git_config_rename_section(const char *old_name, const char *new_name)
|
||||
{
|
||||
int ret = 0;
|
||||
char *config_filename;
|
||||
struct lock_file *lock = xcalloc(sizeof(struct lock_file), 1);
|
||||
int out_fd;
|
||||
char buf[1024];
|
||||
|
||||
config_filename = getenv(CONFIG_ENVIRONMENT);
|
||||
if (!config_filename) {
|
||||
config_filename = getenv(CONFIG_LOCAL_ENVIRONMENT);
|
||||
if (!config_filename)
|
||||
config_filename = git_path("config");
|
||||
}
|
||||
config_filename = xstrdup(config_filename);
|
||||
out_fd = hold_lock_file_for_update(lock, config_filename, 0);
|
||||
if (out_fd < 0) {
|
||||
ret = error("Could not lock config file!");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(config_file = fopen(config_filename, "rb"))) {
|
||||
ret = error("Could not open config file!");
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (fgets(buf, sizeof(buf), config_file)) {
|
||||
int i;
|
||||
for (i = 0; buf[i] && isspace(buf[i]); i++)
|
||||
; /* do nothing */
|
||||
if (buf[i] == '[') {
|
||||
/* it's a section */
|
||||
int j = 0, dot = 0;
|
||||
for (i++; buf[i] && buf[i] != ']'; i++) {
|
||||
if (!dot && isspace(buf[i])) {
|
||||
dot = 1;
|
||||
if (old_name[j++] != '.')
|
||||
break;
|
||||
for (i++; isspace(buf[i]); i++)
|
||||
; /* do nothing */
|
||||
if (buf[i] != '"')
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
if (buf[i] == '\\' && dot)
|
||||
i++;
|
||||
else if (buf[i] == '"' && dot) {
|
||||
for (i++; isspace(buf[i]); i++)
|
||||
; /* do_nothing */
|
||||
break;
|
||||
}
|
||||
if (buf[i] != old_name[j++])
|
||||
break;
|
||||
}
|
||||
if (buf[i] == ']') {
|
||||
/* old_name matches */
|
||||
ret++;
|
||||
store.baselen = strlen(new_name);
|
||||
store_write_section(out_fd, new_name);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
write(out_fd, buf, strlen(buf));
|
||||
}
|
||||
fclose(config_file);
|
||||
if (close(out_fd) || commit_lock_file(lock) < 0)
|
||||
ret = error("Cannot commit config file!");
|
||||
out:
|
||||
free(config_filename);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,6 @@ bindir = @bindir@
|
||||
#gitexecdir = @libexecdir@/git-core/
|
||||
datarootdir = @datarootdir@
|
||||
template_dir = @datadir@/git-core/templates/
|
||||
GIT_PYTHON_DIR = @datadir@/git-core/python
|
||||
|
||||
mandir=@mandir@
|
||||
|
||||
@ -23,7 +22,6 @@ VPATH = @srcdir@
|
||||
export exec_prefix mandir
|
||||
export srcdir VPATH
|
||||
|
||||
NO_PYTHON=@NO_PYTHON@
|
||||
NEEDS_SSL_WITH_CRYPTO=@NEEDS_SSL_WITH_CRYPTO@
|
||||
NO_OPENSSL=@NO_OPENSSL@
|
||||
NO_CURL=@NO_CURL@
|
||||
|
46
configure.ac
46
configure.ac
@ -75,20 +75,6 @@ GIT_ARG_SET_PATH(shell)
|
||||
# Define PERL_PATH to provide path to Perl.
|
||||
GIT_ARG_SET_PATH(perl)
|
||||
#
|
||||
# Define PYTHON_PATH to provide path to Python.
|
||||
AC_ARG_WITH(python,[AS_HELP_STRING([--with-python=PATH], [provide PATH to python])
|
||||
AS_HELP_STRING([--without-python], [don't use python scripts])],
|
||||
[if test "$withval" = "no"; then \
|
||||
NO_PYTHON=YesPlease; \
|
||||
elif test "$withval" = "yes"; then \
|
||||
NO_PYTHON=; \
|
||||
else \
|
||||
NO_PYTHON=; \
|
||||
PYTHON_PATH=$withval; \
|
||||
fi; \
|
||||
])
|
||||
AC_SUBST(NO_PYTHON)
|
||||
AC_SUBST(PYTHON_PATH)
|
||||
|
||||
|
||||
## Checks for programs.
|
||||
@ -98,18 +84,6 @@ AC_PROG_CC([cc gcc])
|
||||
#AC_PROG_INSTALL # needs install-sh or install.sh in sources
|
||||
AC_CHECK_TOOL(AR, ar, :)
|
||||
AC_CHECK_PROGS(TAR, [gtar tar])
|
||||
#
|
||||
# Define PYTHON_PATH to provide path to Python.
|
||||
if test -z "$NO_PYTHON"; then
|
||||
if test -z "$PYTHON_PATH"; then
|
||||
AC_PATH_PROGS(PYTHON_PATH, [python python2.4 python2.3 python2])
|
||||
fi
|
||||
if test -n "$PYTHON_PATH"; then
|
||||
GIT_CONF_APPEND_LINE([PYTHON_PATH=@PYTHON_PATH@])
|
||||
NO_PYTHON=""
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
## Checks for libraries.
|
||||
AC_MSG_NOTICE([CHECKS for libraries])
|
||||
@ -261,22 +235,6 @@ AC_SUBST(NO_SETENV)
|
||||
#
|
||||
# Define NO_SYMLINK_HEAD if you never want .git/HEAD to be a symbolic link.
|
||||
# Enable it on Windows. By default, symrefs are still used.
|
||||
#
|
||||
# Define WITH_OWN_SUBPROCESS_PY if you want to use with python 2.3.
|
||||
AC_CACHE_CHECK([for subprocess.py],
|
||||
[ac_cv_python_has_subprocess_py],
|
||||
[if $PYTHON_PATH -c 'import subprocess' 2>/dev/null; then
|
||||
ac_cv_python_has_subprocess_py=yes
|
||||
else
|
||||
ac_cv_python_has_subprocess_py=no
|
||||
fi])
|
||||
if test $ac_cv_python_has_subprocess_py != yes; then
|
||||
GIT_CONF_APPEND_LINE([WITH_OWN_SUBPROCESS_PY=YesPlease])
|
||||
fi
|
||||
#
|
||||
# Define NO_ACCURATE_DIFF if your diff program at least sometimes misses
|
||||
# a missing newline at the end of the file.
|
||||
|
||||
|
||||
## Site configuration (override autodetection)
|
||||
## --with-PACKAGE[=ARG] and --without-PACKAGE
|
||||
@ -355,10 +313,6 @@ GIT_PARSE_WITH(iconv))
|
||||
|
||||
## --enable-FEATURE[=ARG] and --disable-FEATURE
|
||||
#
|
||||
# Define COLLISION_CHECK below if you believe that SHA1's
|
||||
# 1461501637330902918203684832716283019655932542976 hashes do not give you
|
||||
# sufficient guarantee that no collisions between objects will ever happen.
|
||||
#
|
||||
# Define USE_NSEC below if you want git to care about sub-second file mtimes
|
||||
# and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and
|
||||
# it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely
|
||||
|
17
connect.c
17
connect.c
@ -3,12 +3,6 @@
|
||||
#include "pkt-line.h"
|
||||
#include "quote.h"
|
||||
#include "refs.h"
|
||||
#include <sys/wait.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <signal.h>
|
||||
|
||||
static char *server_capabilities;
|
||||
|
||||
@ -144,6 +138,7 @@ struct refspec {
|
||||
* +A:B means overwrite remote B with local A.
|
||||
* +A is a shorthand for +A:A.
|
||||
* A is a shorthand for A:A.
|
||||
* :B means delete remote B.
|
||||
*/
|
||||
static struct refspec *parse_ref_spec(int nr_refspec, char **refspec)
|
||||
{
|
||||
@ -240,6 +235,13 @@ static struct ref *try_explicit_object_name(const char *name)
|
||||
unsigned char sha1[20];
|
||||
struct ref *ref;
|
||||
int len;
|
||||
|
||||
if (!*name) {
|
||||
ref = xcalloc(1, sizeof(*ref) + 20);
|
||||
strcpy(ref->name, "(delete)");
|
||||
hashclr(ref->new_sha1);
|
||||
return ref;
|
||||
}
|
||||
if (get_sha1(name, sha1))
|
||||
return NULL;
|
||||
len = strlen(name) + 1;
|
||||
@ -262,7 +264,8 @@ static int match_explicit_refs(struct ref *src, struct ref *dst,
|
||||
break;
|
||||
case 0:
|
||||
/* The source could be in the get_sha1() format
|
||||
* not a reference name.
|
||||
* not a reference name. :refs/other is a
|
||||
* way to delete 'other' ref at the remote end.
|
||||
*/
|
||||
matched_src = try_explicit_object_name(rs[i].src);
|
||||
if (matched_src)
|
||||
|
@ -18,26 +18,94 @@
|
||||
# 2) Added the following line to your .bashrc:
|
||||
# source ~/.git-completion.sh
|
||||
#
|
||||
# 3) You may want to make sure the git executable is available
|
||||
# in your PATH before this script is sourced, as some caching
|
||||
# is performed while the script loads. If git isn't found
|
||||
# at source time then all lookups will be done on demand,
|
||||
# which may be slightly slower.
|
||||
#
|
||||
# 4) Consider changing your PS1 to also show the current branch:
|
||||
# PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
|
||||
#
|
||||
# The argument to __git_ps1 will be displayed only if you
|
||||
# are currently in a git repository. The %s token will be
|
||||
# the name of the current branch.
|
||||
#
|
||||
|
||||
__gitdir ()
|
||||
{
|
||||
echo "${__git_dir:-$(git rev-parse --git-dir 2>/dev/null)}"
|
||||
if [ -z "$1" ]; then
|
||||
if [ -n "$__git_dir" ]; then
|
||||
echo "$__git_dir"
|
||||
elif [ -d .git ]; then
|
||||
echo .git
|
||||
else
|
||||
git rev-parse --git-dir 2>/dev/null
|
||||
fi
|
||||
elif [ -d "$1/.git" ]; then
|
||||
echo "$1/.git"
|
||||
else
|
||||
echo "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
__git_ps1 ()
|
||||
{
|
||||
local b="$(git symbolic-ref HEAD 2>/dev/null)"
|
||||
if [ -n "$b" ]; then
|
||||
if [ -n "$1" ]; then
|
||||
printf "$1" "${b##refs/heads/}"
|
||||
else
|
||||
printf " (%s)" "${b##refs/heads/}"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
__git_heads ()
|
||||
{
|
||||
local cmd i is_hash=y dir="$(__gitdir "$1")"
|
||||
if [ -d "$dir" ]; then
|
||||
for i in $(git --git-dir="$dir" \
|
||||
for-each-ref --format='%(refname)' \
|
||||
refs/heads ); do
|
||||
echo "${i#refs/heads/}"
|
||||
done
|
||||
return
|
||||
fi
|
||||
for i in $(git-ls-remote "$1" 2>/dev/null); do
|
||||
case "$is_hash,$i" in
|
||||
y,*) is_hash=n ;;
|
||||
n,*^{}) is_hash=y ;;
|
||||
n,refs/heads/*) is_hash=y; echo "${i#refs/heads/}" ;;
|
||||
n,*) is_hash=y; echo "$i" ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
__git_refs ()
|
||||
{
|
||||
local cmd i is_hash=y dir="${1:-$(__gitdir)}"
|
||||
local cmd i is_hash=y dir="$(__gitdir "$1")"
|
||||
if [ -d "$dir" ]; then
|
||||
cmd=git-peek-remote
|
||||
else
|
||||
cmd=git-ls-remote
|
||||
if [ -e "$dir/HEAD" ]; then echo HEAD; fi
|
||||
for i in $(git --git-dir="$dir" \
|
||||
for-each-ref --format='%(refname)' \
|
||||
refs/tags refs/heads refs/remotes); do
|
||||
case "$i" in
|
||||
refs/tags/*) echo "${i#refs/tags/}" ;;
|
||||
refs/heads/*) echo "${i#refs/heads/}" ;;
|
||||
refs/remotes/*) echo "${i#refs/remotes/}" ;;
|
||||
*) echo "$i" ;;
|
||||
esac
|
||||
done
|
||||
return
|
||||
fi
|
||||
for i in $($cmd "$dir" 2>/dev/null); do
|
||||
for i in $(git-ls-remote "$dir" 2>/dev/null); do
|
||||
case "$is_hash,$i" in
|
||||
y,*) is_hash=n ;;
|
||||
n,*^{}) is_hash=y ;;
|
||||
n,refs/tags/*) is_hash=y; echo "${i#refs/tags/}" ;;
|
||||
n,refs/heads/*) is_hash=y; echo "${i#refs/heads/}" ;;
|
||||
n,refs/remotes/*) is_hash=y; echo "${i#refs/remotes/}" ;;
|
||||
n,*) is_hash=y; echo "$i" ;;
|
||||
esac
|
||||
done
|
||||
@ -45,19 +113,25 @@ __git_refs ()
|
||||
|
||||
__git_refs2 ()
|
||||
{
|
||||
local cmd i is_hash=y dir="${1:-$(__gitdir)}"
|
||||
if [ -d "$dir" ]; then
|
||||
cmd=git-peek-remote
|
||||
else
|
||||
cmd=git-ls-remote
|
||||
fi
|
||||
for i in $($cmd "$dir" 2>/dev/null); do
|
||||
local i
|
||||
for i in $(__git_refs "$1"); do
|
||||
echo "$i:$i"
|
||||
done
|
||||
}
|
||||
|
||||
__git_refs_remotes ()
|
||||
{
|
||||
local cmd i is_hash=y
|
||||
for i in $(git-ls-remote "$1" 2>/dev/null); do
|
||||
case "$is_hash,$i" in
|
||||
n,refs/heads/*)
|
||||
is_hash=y
|
||||
echo "$i:refs/remotes/$1/${i#refs/heads/}"
|
||||
;;
|
||||
y,*) is_hash=n ;;
|
||||
n,*^{}) is_hash=y ;;
|
||||
n,refs/tags/*) is_hash=y; echo "${i#refs/tags/}:${i#refs/tags/}" ;;
|
||||
n,refs/heads/*) is_hash=y; echo "${i#refs/heads/}:${i#refs/heads/}" ;;
|
||||
n,*) is_hash=y; echo "$i:$i" ;;
|
||||
n,refs/tags/*) is_hash=y;;
|
||||
n,*) is_hash=y; ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
@ -81,6 +155,22 @@ __git_remotes ()
|
||||
done
|
||||
}
|
||||
|
||||
__git_merge_strategies ()
|
||||
{
|
||||
if [ -n "$__git_merge_strategylist" ]; then
|
||||
echo "$__git_merge_strategylist"
|
||||
return
|
||||
fi
|
||||
sed -n "/^all_strategies='/{
|
||||
s/^all_strategies='//
|
||||
s/'//
|
||||
p
|
||||
q
|
||||
}" "$(git --exec-path)/git-merge"
|
||||
}
|
||||
__git_merge_strategylist=
|
||||
__git_merge_strategylist="$(__git_merge_strategies 2>/dev/null)"
|
||||
|
||||
__git_complete_file ()
|
||||
{
|
||||
local pfx ls ref cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
@ -115,6 +205,84 @@ __git_complete_file ()
|
||||
esac
|
||||
}
|
||||
|
||||
__git_complete_revlist ()
|
||||
{
|
||||
local pfx cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
case "$cur" in
|
||||
*...*)
|
||||
pfx="${cur%...*}..."
|
||||
cur="${cur#*...}"
|
||||
COMPREPLY=($(compgen -P "$pfx" -W "$(__git_refs)" -- "$cur"))
|
||||
;;
|
||||
*..*)
|
||||
pfx="${cur%..*}.."
|
||||
cur="${cur#*..}"
|
||||
COMPREPLY=($(compgen -P "$pfx" -W "$(__git_refs)" -- "$cur"))
|
||||
;;
|
||||
*)
|
||||
COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
__git_commands ()
|
||||
{
|
||||
if [ -n "$__git_commandlist" ]; then
|
||||
echo "$__git_commandlist"
|
||||
return
|
||||
fi
|
||||
local i IFS=" "$'\n'
|
||||
for i in $(git help -a|egrep '^ ')
|
||||
do
|
||||
case $i in
|
||||
check-ref-format) : plumbing;;
|
||||
commit-tree) : plumbing;;
|
||||
convert-objects) : plumbing;;
|
||||
cvsserver) : daemon;;
|
||||
daemon) : daemon;;
|
||||
fetch-pack) : plumbing;;
|
||||
hash-object) : plumbing;;
|
||||
http-*) : transport;;
|
||||
index-pack) : plumbing;;
|
||||
local-fetch) : plumbing;;
|
||||
mailinfo) : plumbing;;
|
||||
mailsplit) : plumbing;;
|
||||
merge-*) : plumbing;;
|
||||
mktree) : plumbing;;
|
||||
mktag) : plumbing;;
|
||||
pack-objects) : plumbing;;
|
||||
pack-redundant) : plumbing;;
|
||||
pack-refs) : plumbing;;
|
||||
parse-remote) : plumbing;;
|
||||
patch-id) : plumbing;;
|
||||
peek-remote) : plumbing;;
|
||||
read-tree) : plumbing;;
|
||||
receive-pack) : plumbing;;
|
||||
rerere) : plumbing;;
|
||||
rev-list) : plumbing;;
|
||||
rev-parse) : plumbing;;
|
||||
runstatus) : plumbing;;
|
||||
sh-setup) : internal;;
|
||||
shell) : daemon;;
|
||||
send-pack) : plumbing;;
|
||||
show-index) : plumbing;;
|
||||
ssh-*) : transport;;
|
||||
stripspace) : plumbing;;
|
||||
symbolic-ref) : plumbing;;
|
||||
unpack-file) : plumbing;;
|
||||
unpack-objects) : plumbing;;
|
||||
update-ref) : plumbing;;
|
||||
update-server-info) : daemon;;
|
||||
upload-archive) : plumbing;;
|
||||
upload-pack) : plumbing;;
|
||||
write-tree) : plumbing;;
|
||||
*) echo $i;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
__git_commandlist=
|
||||
__git_commandlist="$(__git_commands 2>/dev/null)"
|
||||
|
||||
__git_aliases ()
|
||||
{
|
||||
local i IFS=$'\n'
|
||||
@ -140,6 +308,54 @@ __git_aliased_command ()
|
||||
done
|
||||
}
|
||||
|
||||
__git_whitespacelist="nowarn warn error error-all strip"
|
||||
|
||||
_git_am ()
|
||||
{
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
if [ -d .dotest ]; then
|
||||
COMPREPLY=($(compgen -W "
|
||||
--skip --resolved
|
||||
" -- "$cur"))
|
||||
return
|
||||
fi
|
||||
case "$cur" in
|
||||
--whitespace=*)
|
||||
COMPREPLY=($(compgen -W "$__git_whitespacelist" \
|
||||
-- "${cur##--whitespace=}"))
|
||||
return
|
||||
;;
|
||||
--*)
|
||||
COMPREPLY=($(compgen -W "
|
||||
--signoff --utf8 --binary --3way --interactive
|
||||
--whitespace=
|
||||
" -- "$cur"))
|
||||
return
|
||||
esac
|
||||
COMPREPLY=()
|
||||
}
|
||||
|
||||
_git_apply ()
|
||||
{
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
case "$cur" in
|
||||
--whitespace=*)
|
||||
COMPREPLY=($(compgen -W "$__git_whitespacelist" \
|
||||
-- "${cur##--whitespace=}"))
|
||||
return
|
||||
;;
|
||||
--*)
|
||||
COMPREPLY=($(compgen -W "
|
||||
--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 ()
|
||||
{
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
@ -168,6 +384,35 @@ _git_checkout ()
|
||||
COMPREPLY=($(compgen -W "-l -b $(__git_refs)" -- "$cur"))
|
||||
}
|
||||
|
||||
_git_cherry_pick ()
|
||||
{
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
case "$cur" in
|
||||
--*)
|
||||
COMPREPLY=($(compgen -W "
|
||||
--edit --no-commit
|
||||
" -- "$cur"))
|
||||
;;
|
||||
*)
|
||||
COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
_git_commit ()
|
||||
{
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
case "$cur" in
|
||||
--*)
|
||||
COMPREPLY=($(compgen -W "
|
||||
--all --author= --signoff --verify --no-verify
|
||||
--edit --amend --include --only
|
||||
" -- "$cur"))
|
||||
return
|
||||
esac
|
||||
COMPREPLY=()
|
||||
}
|
||||
|
||||
_git_diff ()
|
||||
{
|
||||
__git_complete_file
|
||||
@ -209,6 +454,26 @@ _git_fetch ()
|
||||
esac
|
||||
}
|
||||
|
||||
_git_format_patch ()
|
||||
{
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
case "$cur" in
|
||||
--*)
|
||||
COMPREPLY=($(compgen -W "
|
||||
--stdout --attach --thread
|
||||
--output-directory
|
||||
--numbered --start-number
|
||||
--keep-subject
|
||||
--signoff
|
||||
--in-reply-to=
|
||||
--full-index --binary
|
||||
" -- "$cur"))
|
||||
return
|
||||
;;
|
||||
esac
|
||||
__git_complete_revlist
|
||||
}
|
||||
|
||||
_git_ls_remote ()
|
||||
{
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
@ -222,22 +487,53 @@ _git_ls_tree ()
|
||||
|
||||
_git_log ()
|
||||
{
|
||||
local pfx cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
case "$cur" in
|
||||
*...*)
|
||||
pfx="${cur%...*}..."
|
||||
cur="${cur#*...}"
|
||||
COMPREPLY=($(compgen -P "$pfx" -W "$(__git_refs)" -- "$cur"))
|
||||
--pretty=*)
|
||||
COMPREPLY=($(compgen -W "
|
||||
oneline short medium full fuller email raw
|
||||
" -- "${cur##--pretty=}"))
|
||||
return
|
||||
;;
|
||||
*..*)
|
||||
pfx="${cur%..*}.."
|
||||
cur="${cur#*..}"
|
||||
COMPREPLY=($(compgen -P "$pfx" -W "$(__git_refs)" -- "$cur"))
|
||||
;;
|
||||
*)
|
||||
COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
|
||||
--*)
|
||||
COMPREPLY=($(compgen -W "
|
||||
--max-count= --max-age= --since= --after=
|
||||
--min-age= --before= --until=
|
||||
--root --not --topo-order --date-order
|
||||
--no-merges
|
||||
--abbrev-commit --abbrev=
|
||||
--relative-date
|
||||
--author= --committer= --grep=
|
||||
--all-match
|
||||
--pretty= --name-status --name-only
|
||||
" -- "$cur"))
|
||||
return
|
||||
;;
|
||||
esac
|
||||
__git_complete_revlist
|
||||
}
|
||||
|
||||
_git_merge ()
|
||||
{
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
case "${COMP_WORDS[COMP_CWORD-1]}" in
|
||||
-s|--strategy)
|
||||
COMPREPLY=($(compgen -W "$(__git_merge_strategies)" -- "$cur"))
|
||||
return
|
||||
esac
|
||||
case "$cur" in
|
||||
--strategy=*)
|
||||
COMPREPLY=($(compgen -W "$(__git_merge_strategies)" \
|
||||
-- "${cur##--strategy=}"))
|
||||
return
|
||||
;;
|
||||
--*)
|
||||
COMPREPLY=($(compgen -W "
|
||||
--no-commit --no-summary --squash --strategy
|
||||
" -- "$cur"))
|
||||
return
|
||||
esac
|
||||
COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
|
||||
}
|
||||
|
||||
_git_merge_base ()
|
||||
@ -246,6 +542,12 @@ _git_merge_base ()
|
||||
COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
|
||||
}
|
||||
|
||||
_git_name_rev ()
|
||||
{
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
COMPREPLY=($(compgen -W "--tags --all --stdin" -- "$cur"))
|
||||
}
|
||||
|
||||
_git_pull ()
|
||||
{
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
@ -298,6 +600,151 @@ _git_push ()
|
||||
esac
|
||||
}
|
||||
|
||||
_git_rebase ()
|
||||
{
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
if [ -d .dotest ]; then
|
||||
COMPREPLY=($(compgen -W "
|
||||
--continue --skip --abort
|
||||
" -- "$cur"))
|
||||
return
|
||||
fi
|
||||
case "${COMP_WORDS[COMP_CWORD-1]}" in
|
||||
-s|--strategy)
|
||||
COMPREPLY=($(compgen -W "$(__git_merge_strategies)" -- "$cur"))
|
||||
return
|
||||
esac
|
||||
case "$cur" in
|
||||
--strategy=*)
|
||||
COMPREPLY=($(compgen -W "$(__git_merge_strategies)" \
|
||||
-- "${cur##--strategy=}"))
|
||||
return
|
||||
;;
|
||||
--*)
|
||||
COMPREPLY=($(compgen -W "
|
||||
--onto --merge --strategy
|
||||
" -- "$cur"))
|
||||
return
|
||||
esac
|
||||
COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
|
||||
}
|
||||
|
||||
_git_repo_config ()
|
||||
{
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
local prv="${COMP_WORDS[COMP_CWORD-1]}"
|
||||
case "$prv" in
|
||||
branch.*.remote)
|
||||
COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
|
||||
return
|
||||
;;
|
||||
branch.*.merge)
|
||||
COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
|
||||
return
|
||||
;;
|
||||
remote.*.fetch)
|
||||
local remote="${prv#remote.}"
|
||||
remote="${remote%.fetch}"
|
||||
COMPREPLY=($(compgen -W "$(__git_refs_remotes "$remote")" \
|
||||
-- "$cur"))
|
||||
return
|
||||
;;
|
||||
remote.*.push)
|
||||
local remote="${prv#remote.}"
|
||||
remote="${remote%.push}"
|
||||
COMPREPLY=($(compgen -W "$(git --git-dir="$(__gitdir)" \
|
||||
for-each-ref --format='%(refname):%(refname)' \
|
||||
refs/heads)" -- "$cur"))
|
||||
return
|
||||
;;
|
||||
*.*)
|
||||
COMPREPLY=()
|
||||
return
|
||||
;;
|
||||
esac
|
||||
case "$cur" in
|
||||
--*)
|
||||
COMPREPLY=($(compgen -W "
|
||||
--global --list --replace-all
|
||||
--get --get-all --get-regexp
|
||||
--unset --unset-all
|
||||
" -- "$cur"))
|
||||
return
|
||||
;;
|
||||
branch.*.*)
|
||||
local pfx="${cur%.*}."
|
||||
cur="${cur##*.}"
|
||||
COMPREPLY=($(compgen -P "$pfx" -W "remote merge" -- "$cur"))
|
||||
return
|
||||
;;
|
||||
branch.*)
|
||||
local pfx="${cur%.*}."
|
||||
cur="${cur#*.}"
|
||||
COMPREPLY=($(compgen -P "$pfx" -S . \
|
||||
-W "$(__git_heads)" -- "$cur"))
|
||||
return
|
||||
;;
|
||||
remote.*.*)
|
||||
local pfx="${cur%.*}."
|
||||
cur="${cur##*.}"
|
||||
COMPREPLY=($(compgen -P "$pfx" -W "url fetch push" -- "$cur"))
|
||||
return
|
||||
;;
|
||||
remote.*)
|
||||
local pfx="${cur%.*}."
|
||||
cur="${cur#*.}"
|
||||
COMPREPLY=($(compgen -P "$pfx" -S . \
|
||||
-W "$(__git_remotes)" -- "$cur"))
|
||||
return
|
||||
;;
|
||||
esac
|
||||
COMPREPLY=($(compgen -W "
|
||||
apply.whitespace
|
||||
core.fileMode
|
||||
core.gitProxy
|
||||
core.ignoreStat
|
||||
core.preferSymlinkRefs
|
||||
core.logAllRefUpdates
|
||||
core.repositoryFormatVersion
|
||||
core.sharedRepository
|
||||
core.warnAmbiguousRefs
|
||||
core.compression
|
||||
core.legacyHeaders
|
||||
i18n.commitEncoding
|
||||
diff.color
|
||||
color.diff
|
||||
diff.renameLimit
|
||||
diff.renames
|
||||
pager.color
|
||||
color.pager
|
||||
status.color
|
||||
color.status
|
||||
log.showroot
|
||||
show.difftree
|
||||
showbranch.default
|
||||
whatchanged.difftree
|
||||
http.sslVerify
|
||||
http.sslCert
|
||||
http.sslKey
|
||||
http.sslCAInfo
|
||||
http.sslCAPath
|
||||
http.maxRequests
|
||||
http.lowSpeedLimit http.lowSpeedTime
|
||||
http.noEPSV
|
||||
pack.window
|
||||
repack.useDeltaBaseOffset
|
||||
pull.octopus pull.twohead
|
||||
merge.summary
|
||||
receive.unpackLimit
|
||||
receive.denyNonFastForwards
|
||||
user.name user.email
|
||||
tar.umask
|
||||
gitcvs.enabled
|
||||
gitcvs.logfile
|
||||
branch. remote.
|
||||
" -- "$cur"))
|
||||
}
|
||||
|
||||
_git_reset ()
|
||||
{
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
@ -308,7 +755,19 @@ _git_reset ()
|
||||
_git_show ()
|
||||
{
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
|
||||
case "$cur" in
|
||||
--pretty=*)
|
||||
COMPREPLY=($(compgen -W "
|
||||
oneline short medium full fuller email raw
|
||||
" -- "${cur##--pretty=}"))
|
||||
return
|
||||
;;
|
||||
--*)
|
||||
COMPREPLY=($(compgen -W "--pretty=" -- "$cur"))
|
||||
return
|
||||
;;
|
||||
esac
|
||||
__git_complete_file
|
||||
}
|
||||
|
||||
_git ()
|
||||
@ -327,11 +786,11 @@ _git ()
|
||||
done
|
||||
|
||||
if [ $c -eq $COMP_CWORD -a -z "$command" ]; then
|
||||
COMPREPLY=($(compgen \
|
||||
-W "--git-dir= --version \
|
||||
$(git help -a|egrep '^ ') \
|
||||
$(__git_aliases)" \
|
||||
-- "${COMP_WORDS[COMP_CWORD]}"))
|
||||
COMPREPLY=($(compgen -W "
|
||||
--git-dir= --version --exec-path
|
||||
$(__git_commands)
|
||||
$(__git_aliases)
|
||||
" -- "${COMP_WORDS[COMP_CWORD]}"))
|
||||
return;
|
||||
fi
|
||||
|
||||
@ -339,18 +798,27 @@ _git ()
|
||||
[ "$expansion" ] && command="$expansion"
|
||||
|
||||
case "$command" in
|
||||
am) _git_am ;;
|
||||
apply) _git_apply ;;
|
||||
branch) _git_branch ;;
|
||||
cat-file) _git_cat_file ;;
|
||||
checkout) _git_checkout ;;
|
||||
cherry-pick) _git_cherry_pick ;;
|
||||
commit) _git_commit ;;
|
||||
diff) _git_diff ;;
|
||||
diff-tree) _git_diff_tree ;;
|
||||
fetch) _git_fetch ;;
|
||||
format-patch) _git_format_patch ;;
|
||||
log) _git_log ;;
|
||||
ls-remote) _git_ls_remote ;;
|
||||
ls-tree) _git_ls_tree ;;
|
||||
merge) _git_merge;;
|
||||
merge-base) _git_merge_base ;;
|
||||
name-rev) _git_name_rev ;;
|
||||
pull) _git_pull ;;
|
||||
push) _git_push ;;
|
||||
rebase) _git_rebase ;;
|
||||
repo-config) _git_repo_config ;;
|
||||
reset) _git_reset ;;
|
||||
show) _git_show ;;
|
||||
show-branch) _git_log ;;
|
||||
@ -367,20 +835,29 @@ _gitk ()
|
||||
|
||||
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 _git_diff git-diff
|
||||
complete -o default -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_log git-log
|
||||
complete -o default -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_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_repo_config git-repo-config
|
||||
complete -o default -F _git_reset git-reset
|
||||
complete -o default -F _git_show git-show
|
||||
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
|
||||
|
||||
@ -389,15 +866,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 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_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_push git-push.exe
|
||||
complete -o default -F _git_repo_config git-repo-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
|
||||
fi
|
||||
|
@ -58,8 +58,9 @@
|
||||
(with-temp-buffer
|
||||
(let* ((dir (file-name-directory file))
|
||||
(name (file-relative-name file dir)))
|
||||
(when dir (cd dir))
|
||||
(and (ignore-errors (eq 0 (call-process "git" nil '(t nil) nil "ls-files" "-c" "-z" "--" name)))
|
||||
(and (ignore-errors
|
||||
(when dir (cd dir))
|
||||
(eq 0 (call-process "git" nil '(t nil) nil "ls-files" "-c" "-z" "--" name)))
|
||||
(let ((str (buffer-string)))
|
||||
(and (> (length str) (length name))
|
||||
(string= (substring str 0 (1+ (length name))) (concat name "\0"))))))))
|
||||
|
42
contrib/mailmap.linux
Normal file
42
contrib/mailmap.linux
Normal file
@ -0,0 +1,42 @@
|
||||
#
|
||||
# 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>
|
@ -1,7 +1,7 @@
|
||||
syn region gitLine start=/^#/ end=/$/
|
||||
syn region gitCommit start=/^# Updated but not checked in:$/ end=/^#$/ contains=gitHead,gitCommitFile
|
||||
syn region gitCommit start=/^# Added but not yet committed:$/ end=/^#$/ contains=gitHead,gitCommitFile
|
||||
syn region gitHead contained start=/^# (.*)/ end=/^#$/
|
||||
syn region gitChanged start=/^# Changed but not updated:/ end=/^#$/ contains=gitHead,gitChangedFile
|
||||
syn region gitChanged start=/^# Changed but not added:/ end=/^#$/ contains=gitHead,gitChangedFile
|
||||
syn region gitUntracked start=/^# Untracked files:/ end=/^#$/ contains=gitHead,gitUntrackedFile
|
||||
|
||||
syn match gitCommitFile contained /^#\t.*/hs=s+2
|
||||
|
@ -1,7 +1,3 @@
|
||||
#define _XOPEN_SOURCE 600 /* glibc2 and AIX 5.3L need 500, OpenBSD needs 600 for S_ISLNK() */
|
||||
#define _XOPEN_SOURCE_EXTENDED 1 /* AIX 5.3L needs this */
|
||||
#define _GNU_SOURCE
|
||||
#include <time.h>
|
||||
#include "cache.h"
|
||||
#include "blob.h"
|
||||
#include "commit.h"
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user