Compare commits

...

116 Commits

Author SHA1 Message Date
60d64db461 GIT 0.99.9i aka 1.0rc2
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-14 18:39:18 -08:00
d7bba81575 Update topo-order test.
The recently we updated rev-list --topo-order to show the heads
in date order, but we had a test that expected to see the old
behaviour.

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-14 18:15:30 -08:00
08db81a9f1 allow git-update-ref create refs with slashes in names
Make git-update-ref create references with slashes in them. git-branch
and git-checkout already support such reference names.

git-branch can use git-update-ref to create the references in a more
formal manner now.

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-14 17:15:32 -08:00
7acab8f167 Documentation nitpicking
This patch fixes some small problems with the documentation.

Signed-off-by: Nikolai Weibull <nikolai@bitwi.se>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-14 17:15:32 -08:00
2db0bfbc04 Document a couple of missing command-line options.
This patch adds documentation to quite a few command-line options.

Signed-off-by: Nikolai Weibull <nikolai@bitwi.se>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-14 17:15:32 -08:00
b2309b7019 Document the -n command-line option to git-unpack-objects
This patch documents the -n command-line option to git-unpack-objects,
as it was previously undocumented.

Signed-off-by: Nikolai Weibull <nikolai@bitwi.se>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-14 17:15:32 -08:00
9add69b1b1 apply: fix binary patch detection.
The comparison to find "Binary files " string was looking at a
wrong place when offset != 0.

Also, we may have the full 40-byte textual sha1 on the index
line; two off-by-one errors prevented it.

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-14 17:15:07 -08:00
2ed02887bd Fix git-rev-list "date order" with --topo-order
This fixes git-rev-list so that when there are multiple branches, we still
sort the heads in proper approximate date order even when sorting the
output topologically.

This makes things like

	gitk --all -d

work sanely and show the branches in date order (where "date order" is
obviously modified by the paren-child dependency requirements of the
topological sort).

The trivial fix is to just build the "work" list in date order rather than
inserting the new work entries at the beginning.

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-14 14:16:38 -08:00
d4072c9722 git-branch: Mention -d and -D in man-page.
Signed-off-by: Andreas Ericsson <ae@op5.se>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-14 14:16:37 -08:00
b6ebac9e43 Merge branch 'svnup' of http://netz.smurf.noris.de/git/git
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-14 13:50:05 -08:00
0f3f5e3f69 Depend on asciidoc 7 (at least). 2005-11-14 17:41:31 +01:00
1331df8781 Remove git-rename. git-mv does the same
Signed-off-by: Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-14 00:50:18 -08:00
b0c698a6e4 Bugfix: stop if directory already exists
Fix a typo: We do not want to run the directory as command,
and want to terminate if the directory exists
Additionally, update the usage message

Signed-off-by: Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-14 00:50:17 -08:00
94d2331770 Separate LDFLAGS and CFLAGS.
Stuffing -L flag and friends meant for the linking phase into
ALL_CFLAGS is not right; honor LDFLAGS and introduce ALL_LDFLAGS
to separate them out.

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-14 00:26:49 -08:00
6d5410d651 Merge branch 'svnup' of http://netz.smurf.noris.de/git/git 2005-11-14 00:25:48 -08:00
4b1ca25e42 Remove trailing slashes
SVN dies a messy death when passed a path with trailing slashes.
2005-11-14 08:31:00 +01:00
0086e2c854 Rename lost+found to lost-found.
Because we use "lost-found" as the directory name to hold
dangling object names, it is confusing to call the command
git-lost+found, although it makes sense and is even cute ;-).

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-13 02:07:02 -08:00
abacbe4166 Fix compilation warnings in pack-redundant.c
This fixes compilation warnings where "%ld" was used to print values of
type size_t.

Signed-off-by: Kai Ruemmler <kai.ruemmler@gmx.net>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-13 02:00:36 -08:00
ac0b86dadf Debian: build-depend on libexpat-dev.
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-13 01:57:33 -08:00
ba1dbb61ea Split gitk into seperate RPM package
I don't want to have to install x11-libs and all it's dependencies on
my headless machines, so this patch splits gitk out of the RPM.

The .deb already appears to have gitk split out.

Signed-off-by: Thomas Matysik <thomas@matysik.co.nz>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-13 01:33:26 -08:00
8614e92323 Add expat and expat-devel dependencies (for http-push) to RPM spec.
Signed-off-by: Thomas Matysik <thomas@matysik.co.nz>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-13 01:32:21 -08:00
54a9ba0d44 Fix fd leak in http-fetch
Added a call to finish_request to clean up resources if the server
returned a 404 and there are no alternates left to try.

Signed-off-by: Nick Hengeveld <nickh@reactrix.com>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-12 23:43:11 -08:00
acc075a8ad Fix for multiple alternates requests in http-fetch
Stop additional alternates requests from starting if one is already in
progress.  This adds an optional callback which is processed after a slot
has finished running.

Signed-off-by: Nick Hengeveld <nickh@reactrix.com>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-12 23:43:11 -08:00
ceae78b438 debian packaging: git-cvs needs cvsps 2005-11-12 23:15:50 +01:00
f7a2eb7359 GIT 0.99.9h
This is GIT 1.0-rc1 in disguise.  It is plausible that
relatively new parts of the system still need tweaking and
fixing, but that is why it is not 1.0 but rc ;-).

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 22:37:38 -08:00
7765e7ebda Ignore built git-lost+found.
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 22:28:03 -08:00
e6bd23911e Documentation: asciidoc sources are utf-8
git-pack-redundant documentation was encoded in latin1, which caused
asciidoc to barf, which expected to see utf-8.  Run tcs to re-encode
it in utf-8.

Also just for fun try my name in Japanese in git-lost+found
documentation ;-)

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 22:16:59 -08:00
07203659d0 Rename .git/lost+found to .git/lost-found.
Just to avoid confusion that scripts poorly written by somebody
else ;-) might mistake this as a mount point, or backup tools
ignoring the directory.  The latter is probably not a big loss,
however, considering that this directory's contents are to be
used while fresh anyway.

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 21:52:21 -08:00
04e7ca1a1b git-lost+found
This command helps you resurrect accidentally lost tags and commits.

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 21:52:20 -08:00
d7b1a1ddbe git-prune: prune redundant packs
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 21:19:11 -08:00
1c3039e8f1 Make git-pack-redundant consider alt-odbs
This patch changes git-pack-redundant so that packfiles
in alternate object directories also are considered when
deciding which objects are redundant.

This functionality is controlled by the flag '--alt-odb'.

Also convert the other flags to the long form, and update
docs and git-repack accordingly.

Signed-off-by: Lukas Sandström <lukass@etek.chalmers.se>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 21:19:11 -08:00
9bc0f32c77 Rename git-pack-intersect to git-pack-redundant
This patch renames git-pack-intersect to git-pack-redundant
as suggested by Petr Baudis. The new name reflects what the
program does, rather than how it does it.

Also fix a small argument parsing bug.

Signed-off-by: Lukas Sandström <lukass@etek.chalmers.se>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 21:19:11 -08:00
b4ad3552de Make git-repack use git-pack-intersect.
Signed-off-by: Lukas Sandström <lukass@etek.chalmers.se>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 21:19:11 -08:00
5231148202 Add git-pack-intersect to .gitignore
Signed-off-by: Lukas Sandström <lukass@etek.chalmers.se>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 21:19:10 -08:00
2a444781b1 Add documentation for git-pack-intersect
Signed-off-by: Lukas Sandström <lukass@etek.chalmers.se>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 21:19:10 -08:00
c283ab21c1 Add git-pack-intersect
This patch adds the program git-pack-intersect. It is
used to find redundant packs in git repositories.

Signed-off-by: Lukas Sandström <lukass@etek.chalmers.se>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 21:19:10 -08:00
fd66dbf529 merge-one-file: use empty- or common-base condintionally in two-stage merge.
If two sides added the same path completely different thing, it is
easier to see the merge pivoting on /dev/null.  So check the size of
the common section we have found, and empty it if it is too small.

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 21:18:18 -08:00
e433705dd4 Documentation: git-apply --no-add
This is a specialized hack to help no-base merges, but other
people might find it useful, so let's document it.

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 21:18:18 -08:00
cb93c19365 merge-one-file: use common as base, instead of emptiness.
Unlike the previous round that merged the path added differently
in each branches using emptiness as the base, compute a common
version and use it as input to 'merge' program.

This would show the resulting (still conflicting) file left in
the working tree as:

	common file contents...
	<<<<<< FILENAME
	version from our branch...
	======
	version from their branch...
	>>>>>> .merge_file_XXXXXX
	more common file contents...

when both sides added similar contents.

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 21:18:17 -08:00
f7d24bbefb merge with /dev/null as base, instead of punting O==empty case
Instead of leaving the path unmerged in a case where each side
adds different version of the same path, attempt to merge it
with empty base and leave "our" version in the index file, just
like we do for the case in conflicting merge.

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 21:18:17 -08:00
6fd72e39af Show URL in the "Getting <foo> list" http-fetch messages
Signed-off-by: Petr Baudis <pasky@suse.cz>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 21:14:46 -08:00
e9af60c88b merge-recursive: Use '~' instead of '_' to separate file names from branch names
Makes it less probable that we get a clash with an existing file,
furthermore Cogito already uses '~' for this purpose.

Signed-off-by: Fredrik Kuivinen <freku045@student.liu.se>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 21:14:39 -08:00
857f26d2f4 merge-recursive: Add copyright notice
Signed-off-by: Fredrik Kuivinen <freku045@student.liu.se>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 21:14:36 -08:00
46e651743a merge-recursive: Indent the output properly
If we have multiple common ancestors and have to recursively merge
them then the output will be much more readable with this commit.

Signed-off-by: Fredrik Kuivinen <freku045@student.liu.se>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 21:14:34 -08:00
5f3aa197ac Change 'cache' to 'index' in the docs
This patch makes the documentation refer to the index
as index instead of cache, but some references still
remain. (e.g. git-update-index.txt)

Signed-off-by: Lukas Sandström <lukass@etek.chalmers.se>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 15:12:29 -08:00
3cab3594e9 INSTALL: duplicate python requirements from Makefile
... and refer the reader to Makefile for other things that can be
tweaked.

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 11:27:03 -08:00
631ba30907 Merge branches 'jc/sb' and 'jc/mb' 2005-11-11 10:52:59 -08:00
4bc51db0fe t1200: use --topo-order to keep the show-branch output stable.
Because a batch-oriented script creates many commits within a second
on a fast machine, show-branch output of the test results are unstable
without topo-order.

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 10:52:39 -08:00
6b209d4733 Fully detect uninteresting commits.
With the change in the previous round, we are guaranteed to come up
with the list of all relevant merge bases, but sometimes we do not
fully mark unintersting ones due to a horizon effect.  Add a phase to
postprocess, so that we mark all ancestor of "interesting" commit.

This also changes the default ordering of shown commits back to
chronological order, and adds --topo-order flag to show them in
topological order.

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 10:52:38 -08:00
9ce7028531 git-show-branch: tighten merge-base computation.
This makes the merge-base computation resistant to the pathological
case discussed on the list earlier, by doing the same logic as
git-merge-base.  As a side effect, it breaks the command's primary
function to list non-merge commit sequences, which needs to be fixed
separately.

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 10:52:38 -08:00
53de71f88b Add test case for merge-base.
Although it was shown that the "full contamination" was not really full
during the list discussion, the series improves things without incurring
extra parsing cost, and here is a test to check that.

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 10:52:31 -08:00
9e5f4a5539 merge-base: avoid unnecessary postprocessing.
When we have only one merge-base candidates in the result list,
there is no point going back to mark the reachable commits
again.  And that is the most common case, so try not to waste
time on it.  Suggested by Linus.

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 10:52:31 -08:00
ed9a540b2b merge-base: fully contaminate the well.
The discussion on the list demonstrated a pathological case where
an ancestor of a merge-base can be left interesting.  This commit
introduces a postprocessing phase to fix it.

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 10:52:30 -08:00
592ee97d8f RPM: arch submodule needs tla.
Noticed by Horst von Brand.

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 09:33:47 -08:00
7f10f7c4e4 git-clone: Allow cloning into directories other than child of current dir.
This patch adds -p to mkdir and an explicit check to see if the target
directory exists (since mkdir -p doesn't throw an error if it does).

Signed-off-by: Andreas Ericsson <ae@op5.se>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 01:34:27 -08:00
0879aa2870 git-clone: Keep remote names when cloning unless explicitly told not to.
With this patch the following commands all clone into the local directory
"repo". If repo exists, it will still barf.

	git-clone git://host.xz/repo.git
	git-clone /path/to/repo/.git
	git-clone host.xz:repo.git

I ended up doing the same source-to-target sed'ing for all our company
projects, so it was easier to add it directly to git-clone.

Signed-off-by: Andreas Ericsson <ae@op5.se>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 01:34:26 -08:00
0867b0125a specfile cleanups
Some specfile cleanups after the split.
- zlib dependency fix, current method is inconsistent, you can
  potentially build a package that you can't install on machine you
  built it on
- Add proper defattr
- Remove trailing '.' in summary
- Add docs to split up packages
- Add git-core dependency for each subpackage
- Move arch import to separate package as well

Signed-off-by: Chris Wright <chrisw@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 01:24:31 -08:00
f84f9d38eb archimport: handle pika escaping
Arch uses pika escaping in some places (but not all!). Specifically, commits of
the type 'patch' use pika escaping in the log entries, which we parse to know
what to add/delete and what to commit.

This patch checks for hints of pika escaping and asks tla to unescape for us.

Originally implemented by Penny Leach <penny@catalyst.net.nz>

Signed-off-by: Martin Langhoff <martin@catalyst.net.nz>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 01:15:26 -08:00
0e9ab02da7 git-clone: quote destination directory name
git-clone doesn't quote the full path to the destination directory,
which causes it to fail if the path contains spaces or other characters
interpreted by the shell.

[jc: obviously I was not careful enough.  Pavel, thanks for catching.]

Signed-off-by: Pavel Roskin <proski@gnu.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 01:15:00 -08:00
601c978c1b Add --no-commit-id option for git-diff-tree, use it in gitk
This patch introduces -no-commit-id option for git-diff-tree, which
suppresses commit ID output.

[jc: dropped gitk part for now.]

Signed-off-by: Pavel Roskin <proski@gnu.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 01:13:05 -08:00
17cf939724 octopus: do not do AND'ed merge base.
When doing an octopus, we incorrectly used the previous merge
base as the reference to compute next merge base.  This was
unnecessary, because that can never be better than using the
original HEAD.  And that is far simpler as well ;-).

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 00:50:24 -08:00
ff56fe1ca7 Add --pretty=fuller
git log without --pretty showed author and author-date, while
with --pretty=full showed author and committer but no dates.
The new formatting option, --pretty=fuller, shows both name and
timestamp for author and committer.

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 00:42:52 -08:00
e3e291fc07 Do not lose author name information to locale gotchas.
I noticed format-patch loses authorship information of Lukas' patch
when I run git tools with LC_LANG set to ja_JP.  It turns out that
the sed script to set environment variables were not working on his
name (encoded in UTF-8), which is unfortunate but technically correct.

Force sed invocation under C locale because we always want literal byte
semantics.

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 00:37:34 -08:00
605607cc62 Documentation: "host:path/to/repo" is git native over ssh.
You could also spell it ssh://host:/path/to/repo (or git+ssh,
ssh+git), but without method:// is shorter to type, so mention
only that one in the short and sweet list.

Noticed by Pasky.

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-11 00:37:34 -08:00
66c9ec2555 Let git-clone/git-fetch follow HTTP redirections
Otherwise, git-clone silently failed to clone a remote
repository where redirections (ie. a response with a
"Location" header line) are used.

This includes the fixes from Nick Hengeveld.

Signed-off-by: Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-10 15:57:56 -08:00
ad7db62113 Fix confusing git-update-ref error message
When git-update-ref has hit the "Ref %s changed to %s" error, I just stare
at it, left puzzled. This patch attempts to reword that to a more useful
and less confusing error message.

Signed-off-by: Petr Baudis <pasky@suse.cz>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-10 15:57:21 -08:00
14df4c4188 Add missing git-core and cvsps RPM dependencies.
Signed-off-by: Jim Radford <radford@blackbean.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-10 15:57:09 -08:00
23ea3e201c GIT 0.99.9g
Another snapshot, as slow and steady marth towards 1.0 continues.
Major changes include:

 - Jim Radford's RPM split.
 - Fredrik's recursive merge strategy is now default for two heads merge.
 - Yaacov's SVN importer updates.

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-09 21:09:43 -08:00
a1c292958f Make git-recursive the default strategy for git-pull.
This does two things:

 - It changes the hardcoded default merge strategy for two-head
   git-pull from resolve to recursive.

 - .git/config file acquires two configuration items.
   pull.twohead names the strategy for two-head case, and
   pull.octopus names the strategy for octopus merge.

IOW you are paranoid, you can have the following lines in your
.git/config file and keep using git-merge-resolve when pulling
one remote:

	[pull]
		twohead = resolve

OTOH, you can say this:

	[pull]
		twohead = resolve
		twohead = recursive

to try quicker resolve first, and when it fails, fall back to
recursive.

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-09 18:56:29 -08:00
13956670a7 Use 'merge-base --all' where applicable.
It may get extra merge base on truly pathological commit histories,
but is a lot easier to understand, explain, and prove correctness.

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-09 18:54:14 -08:00
a489352e3d Merge branch 'hold/svn' 2005-11-09 18:44:42 -08:00
68afd5fab7 Merge branch 'hold/rpm' 2005-11-09 18:44:18 -08:00
ff36de0847 git-apply: do not fail on binary diff when not applying nor checking.
We run git-apply with --stat and --summary at the end of the pull
by default, which causes it to barf when the pull brought in changes
to binary files.  Just mark them as binary patch and proceed when
not applying nor checking.

[jc: I almost missed --check until I saw Linus did something similar.]

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-09 15:19:50 -08:00
c44922a781 Update INSTALL
Explicitly mention how to install by hand in build-as-user and
install-as-root steps.

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-09 12:40:03 -08:00
186f855fc6 merge-recursive: Fix support for branch names containing slashes
A branch name could have a slash in it.

Signed-off-by: Fredrik Kuivinen <freku045@student.liu.se>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-09 12:32:36 -08:00
c8a4f5e542 merge-recursive: Fix limited output of rename messages
The previous code did the right thing, but it did it by accident.

Signed-off-by: Fredrik Kuivinen <freku045@student.liu.se>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-09 12:32:34 -08:00
e09f5d7b07 Fix cvsexportcommit syntax error
There is a syntax error in cvsexport script:

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-08 23:34:29 -08:00
f37d0cc3ff Update howto using-topic-branches
"git resolve" is being deprecated in favour of "git merge".
Update the documentation to reflect this.

Signed-off-by: Tony Luck <tony.luck@intel.com>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-08 21:33:36 -08:00
f4f440a039 sparse fixes for http-{fetch,push}.c
Make a bunch of needlessly global functions static, and replace two
K&R-style declarations.

Signed-off-by: Peter Hagervall <hager@cs.umu.se>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-08 21:33:32 -08:00
61f81518a2 git-tag -d <tag>: delete tag <tag>
This adds option '-d' to git-tag.sh and documents it.

Signed-off-by: Kai Ruemmler <kai.ruemmler@gmx.net>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-08 11:26:10 -08:00
23fc63bf8f make tests ignorable with "make -i"
Allow failed tests to be ignored using make's "-i". The patch also
disables parallel make in t/. This doesn't make the testing any
different as before: the tests were run sequentially before.

It also allows to run more tests, ignoring the ones usually failing
just to figure out if something else broke.  (Or to ignore plainly
uninteresting situations because of the testing being done on say...
cygwin ;)

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-08 11:26:07 -08:00
cb34882bd6 fix t5000-tar-tree.sh when $TAR isn't set
$TAR isn't set everywhere. Provide a default (tar)

Signed-off-by: Alex Riesen <raa.lkml@gmail.com>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-08 11:26:03 -08:00
f8d294f0a4 Clean build annoyance.
As Pasky pointed out, building in templates directory showed
list of built template files which was unneeded.  This commit
also fixes another build annoyance I recently left in by
accident.

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-08 08:58:52 -08:00
5ca15b8af7 GIT 0.99.9f
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-08 01:25:59 -08:00
7d4de59b17 Separate RPMS for programs with non-standard dependencies.
Signed-off-by: Jim Radford <radford@blackbean.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-08 01:24:54 -08:00
f3ad062560 Fix a couple of obvious and insignificant typo.
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-08 01:24:50 -08:00
01d4f0e775 Lift the default limit of number of revs.
Now that the leak is gone, there is by default no limit of revisions to
import.  No more message about leak when the limit (given by the -l
parameter) is reached.

Signed-off-by: Yaacov Akiba Slama <ya@slamail.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-08 01:24:50 -08:00
a16db4f472 Handle a revision that only creates a new tag correctly.
Fix an error when a svn revision consists only of the creation of a new tag
directory (/tags/this_is_a_tag).

Signed-off-by: Yaacov Akiba Slama <ya@slamail.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-08 01:24:49 -08:00
109fc2b97b Bundle file copies from multiple branches into a merge.
When copying files and/or directories from several branches in one single
revision, all these branches are used as parents of the commit.

Signed-off-by: Yaacov Akiba Slama <ya@slamail.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-08 01:24:49 -08:00
8168373fe7 copy_dir becomes copy_path and handles both files and directories
The A (Add) and R (Replace) actions handling are unified.

Signed-off-by: Yaacov Akiba Slama <ya@slamail.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-08 01:24:48 -08:00
c2c07a5c2a Don't output error on changes in the nodes /, /tags or /branches
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-08 01:24:48 -08:00
cbce5d8961 Add node_kind function to differentiate between file and directory
Signed-off-by: Yaacov Akiba Slama <ya@slamail.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-08 01:24:48 -08:00
fcfa32b9e1 Use svn pools to solve the memory leak problem.
Signed-off-by: Yaacov Akiba Slama <ya@slamail.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-08 01:24:47 -08:00
4bfb6b62ff git-am: do not lose already edited final-commit when resuming.
The last round stopped munging the patch when resuming, but
failed to preserve final-commit.

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-08 01:23:53 -08:00
39b4ac9968 ls-files and read-tree need core.filemode
ls-files.c and read-tree.c miss the default configuration, in
particular the filemode=false part.  The recent +x bit flip made me
notice that, because git-merge refused to merge anything saying that
git-pull.sh is not up to date.

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-08 01:23:52 -08:00
76bca9d1a9 Debian: packaging updates.
Do not scatter txt and html documentation into feature subpackages.
Do place man pages into them.

Capture more cvs stuff into git-cvs package.

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-08 01:20:24 -08:00
f2416c27ef Use consistent shell prompts and example style.
Signed-off-by: Jon Loeliger <jdl@freescale.com>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-08 00:23:13 -08:00
d0fde471ab Add --tags documentation, scraped from JC mail.
Signed-off-by: Jon Loeliger <jdl@freescale.com>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-08 00:23:12 -08:00
df8171ccb3 Add support for git-http-push to git-push script
Signed-off-by: Nick Hengeveld <nickh@reactrix.com>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-08 00:23:12 -08:00
067744bd5d Tutorial: do not use 'git resolve'.
Use 'git merge' instead.

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-08 00:23:12 -08:00
fb612d54c1 Documentation: fix dependency generation.
The previous rule misses the case where git.txt or tutorial.txt
includes new files.

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-08 00:23:12 -08:00
b2d09f063a Add bug isolation howto, scraped from Linus.
Signed-off-by: Jon Loeliger <jdl@freescale.com>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-07 22:18:48 -08:00
77131db585 Merge branch 'master' 2005-11-07 18:23:45 -08:00
390cb0c17a Ignore more generated files.
List new commands cvsexportcommit and http-push to .gitignore list.
Also cover the test programs (test-date and test-delta).

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-07 18:23:10 -08:00
a5ae8e64cf Fix documentation dependency generation.
Documentation/Makefile spent a lot of time to generate include
dependencies, which was quite noticeable especially during "make clean".

Rewrite it to generate just a single dependency file.

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-07 18:21:51 -08:00
79f6ac77d9 Documentation: asciidoc formatting fix for git-cvsexportcommit doc.
Annoyingly enough, asciidoc wants the same number of '=' on the second
line as there are characters on the first line.

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-07 17:53:06 -08:00
d1745afa2f merge-recursive: Only print relevant rename messages
It isn't really interesting to know about the renames that have
already been committed to the branch you are working on. Furthermore,
the 'git-apply --stat' at the end of git-(merge|pull) will tell us
about any renames in the other branch.

With this commit only renames which require a file-level merge will
be printed.

Signed-off-by: Fredrik Kuivinen <freku045@student.liu.se>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-07 17:13:10 -08:00
52963a7a3f Do not fail on hierarchical tagnames.
This is a companion patch to 13d1cc3604
commit, which made hierarchical branch name possible.  "git tag
v0.99.9/a" would fail otherwise.

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-07 16:34:04 -08:00
92e2eb9c0a Small bugfixes for http-push.c
This patch fixes three things:

- older libexpat does not know about enum XML_Status
- as in my patch for http-fetch, do not rely on a curl result in
	free()d data
- calloc the new_lock structure

Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-07 13:29:41 -08:00
0dd276b871 Make http-push smarter about creating remote dirs
Remember object directories known to exist in the remote repo and don't
bother trying to create them.

Signed-off-by: Nick Hengeveld <nickh@reactrix.com>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-07 13:29:39 -08:00
5e0306adfa Introducing: git-cvsexportcommit
A script that can replay commits git into a CVS checkout. Tries to ensure the
sanity of the operation and supports mainly manual usage.

If you are reckless enough, you can ask it to autocommit when everything has
applied cleanly. Combined with a couple more scripts could become part of
a git2cvs gateway.

Should support adds/removes and binary files.

Signed-off-by: Martin Langhoff <martin@catalyst.net.nz>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-07 13:28:37 -08:00
e66ab03fcf Documentation update: use git branch -d foo where applicable
This updates documentation to use git branch -d foo in favour of
rm .git/refs/heads/foo

Signed-off-by: Kai Ruemmler <kai.ruemmler@gmx.net>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-07 13:28:31 -08:00
31b9755a65 Recover dropped +x bit from git-pull.sh by accident.
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-07 12:52:07 -08:00
7141b3b780 Merge branch 'master' 2005-11-06 23:33:38 -08:00
44760f1d55 Documentation: talk about guts of merge in tutorial.
While discussing Jon's ASCII art on merge operations with him, I
realized that the tutorial stops talking about the plumbing
details halfway.  So fill in the gory details, and update the
examples to use 'git-merge', not 'git-resolve'.

Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-06 23:32:33 -08:00
93d69d8691 Refactored merge options into separate merge-options.txt.
Refactored fetch options into separate fetch-options.txt.
Made git-merge use merge-options.
Made git-fetch use fetch-options.
Made git-pull use merge-options and fetch-options.
Added --help option to git-pull and git-format-patch scripts.
Rewrote Documentation/Makefile to dynamically determine
include dependencies.

Signed-off-by: Jon Loeliger <jdl@freescale.com>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-06 23:32:04 -08:00
99 changed files with 2696 additions and 715 deletions

7
.gitignore vendored
View File

@ -19,6 +19,7 @@ git-commit
git-commit-tree
git-convert-objects
git-count-objects
git-cvsexportcommit
git-cvsimport
git-daemon
git-diff
@ -36,10 +37,12 @@ git-get-tar-commit-id
git-grep
git-hash-object
git-http-fetch
git-http-push
git-index-pack
git-init-db
git-local-fetch
git-log
git-lost-found
git-ls-files
git-ls-remote
git-ls-tree
@ -58,6 +61,7 @@ git-mktag
git-name-rev
git-mv
git-octopus
git-pack-redundant
git-pack-objects
git-parse-remote
git-patch-id
@ -70,7 +74,6 @@ git-read-tree
git-rebase
git-receive-pack
git-relink
git-rename
git-repack
git-request-pull
git-reset
@ -107,6 +110,8 @@ git-verify-tag
git-whatchanged
git-write-tree
git-core-*/?*
test-date
test-delta
*.tar.gz
*.dsc
*.deb

View File

@ -3,3 +3,4 @@
*.1
*.7
howto-index.txt
doc.dep

View File

@ -49,22 +49,22 @@ install: man
$(INSTALL) $(DOC_MAN1) $(DESTDIR)/$(man1)
$(INSTALL) $(DOC_MAN7) $(DESTDIR)/$(man7)
# 'include' dependencies
$(patsubst %.txt,%.1,$(wildcard git-diff-*.txt)): \
diff-format.txt diff-options.txt
$(patsubst %.txt,%.html,$(wildcard git-diff-*.txt)): \
diff-format.txt diff-options.txt
$(patsubst %,%.1,git-fetch git-pull git-push): pull-fetch-param.txt
$(patsubst %,%.html,git-fetch git-pull git-push): pull-fetch-param.txt
#
# Determine "include::" file references in asciidoc files.
#
doc.dep : $(wildcard *.txt) build-docdep.perl
rm -f $@+ $@
perl ./build-docdep.perl >$@+
mv $@+ $@
$(patsubst %,%.1,git-merge git-pull): merge-pull-opts.txt
$(patsubst %,%.html,git-merge git-pull): merge-pull-opts.txt
-include doc.dep
git.7: ../README
clean:
rm -f *.xml *.html *.1 *.7 howto-index.txt howto/*.html
rm -f *.xml *.html *.1 *.7 howto-index.txt howto/*.html doc.dep
%.html : %.txt
asciidoc -b xhtml11 -d manpage -f asciidoc.conf $<

50
Documentation/build-docdep.perl Executable file
View File

@ -0,0 +1,50 @@
#!/usr/bin/perl
my %include = ();
my %included = ();
for my $text (<*.txt>) {
open I, '<', $text || die "cannot read: $text";
while (<I>) {
if (/^include::/) {
chomp;
s/^include::\s*//;
s/\[\]//;
$include{$text}{$_} = 1;
$included{$_} = 1;
}
}
close I;
}
# Do we care about chained includes???
my $changed = 1;
while ($changed) {
$changed = 0;
while (my ($text, $included) = each %include) {
for my $i (keys %$included) {
# $text has include::$i; if $i includes $j
# $text indirectly includes $j.
if (exists $include{$i}) {
for my $j (keys %{$include{$i}}) {
if (!exists $include{$text}{$j}) {
$include{$text}{$j} = 1;
$included{$j} = 1;
$changed = 1;
}
}
}
}
}
}
while (my ($text, $included) = each %include) {
if (! exists $included{$text} &&
(my $base = $text) =~ s/\.txt$//) {
my ($suffix) = '1';
if ($base eq 'git') {
$suffix = '7'; # yuck...
}
print "$base.html $base.$suffix : ", join(" ", keys %$included), "\n";
}
}

View File

@ -8,13 +8,13 @@ git-diff-index <tree-ish>::
compares the <tree-ish> and the files on the filesystem.
git-diff-index --cached <tree-ish>::
compares the <tree-ish> and the cache.
compares the <tree-ish> and the index.
git-diff-tree [-r] <tree-ish-1> <tree-ish-2> [<pattern>...]::
compares the trees named by the two arguments.
git-diff-files [<pattern>...]::
compares the cache and the files on the filesystem.
compares the index and the files on the filesystem.
An output line is formatted this way:
@ -47,7 +47,7 @@ That is, from the left to the right:
. an LF or a NUL when '-z' option is used, to terminate the record.
<sha1> is shown as all 0's if a file is new on the filesystem
and it is out of sync with the cache.
and it is out of sync with the index.
Example:
@ -104,7 +104,7 @@ where:
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
cache). 'GIT_EXTERNAL_DIFF' should not worry about unlinking 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

View File

@ -50,7 +50,7 @@
<orderfile>, which has one shell glob pattern per line.
-R::
Swap two inputs; that is, show differences from cache or
Swap two inputs; that is, show differences from index or
on-disk file to tree contents.
For more detailed explanation on these common options, see also

View File

@ -0,0 +1,17 @@
-a, \--append::
Append ref names and object names of fetched refs to the
existing contents of `.git/FETCH_HEAD`. Without this
option old data in `.git/FETCH_HEAD` will be overwritten.
-f, \--force::
-t, \--tags::
By default, the git core utilities will not fetch and store
tags under the same name as the remote repository; ask it
to do so using `--tags`.
-u, \--update-head-ok::
By default `git-fetch` refuses to update the head which
corresponds to the current branch. This flag disables the
check. Note that fetching into the current branch will not
update the index and working directory, so use it with care.

View File

@ -8,7 +8,7 @@ git-apply - Apply patch on a git index file and a work tree
SYNOPSIS
--------
'git-apply' [--stat] [--numstat] [--summary] [--check] [--index] [--apply] [--index-info] [-z] [<patch>...]
'git-apply' [--stat] [--numstat] [--summary] [--check] [--index] [--apply] [--no-add] [--index-info] [-z] [<patch>...]
DESCRIPTION
-----------
@ -72,6 +72,12 @@ OPTIONS
patch. Give this flag after those flags to also apply
the patch.
--no-add::
When applying a patch, ignore additions made by the
patch. This can be used to extract common part between
two files by first running `diff` on them and applying
the result with this option, which would apply the
deletion part but not addition part.
Author
------

View File

@ -3,11 +3,11 @@ git-branch(1)
NAME
----
git-branch - Create a new branch.
git-branch - Create a new branch, or remove an old one.
SYNOPSIS
--------
'git-branch' [<branchname> [start-point]]
'git-branch' [-d | -D] [<branchname> [start-point]]
DESCRIPTION
-----------
@ -19,11 +19,18 @@ created, otherwise it will be created at the current HEAD.
OPTIONS
-------
-d::
Delete a branch. The branch must be fully merged.
-D::
Delete a branch irrespective of its index status.
<branchname>::
The name of the branch to create.
The name of the branch to create or delete.
start-point::
Where to create the branch; defaults to HEAD.
Where to create the branch; defaults to HEAD. This
option has no meaning with -d and -D.
Author
------

View File

@ -3,7 +3,7 @@ git-checkout-index(1)
NAME
----
git-checkout-index - Copy files from the cache to the working directory
git-checkout-index - Copy files from the index to the working directory
SYNOPSIS
@ -13,26 +13,26 @@ SYNOPSIS
DESCRIPTION
-----------
Will copy all files listed from the cache to the working directory
Will copy all files listed from the index to the working directory
(not overwriting existing files).
OPTIONS
-------
-u::
-u|--index::
update stat information for the checked out entries in
the cache file.
the index file.
-q::
be quiet if files exist or are not in the cache
-q|--quiet::
be quiet if files exist or are not in the index
-f::
-f|--force::
forces overwrite of existing files
-a::
checks out all files in the cache. Cannot be used
-a|--all::
checks out all files in the index. Cannot be used
together with explicit filenames.
-n::
-n|--no-create::
Don't checkout new files, only refresh files already checked
out.
@ -57,7 +57,7 @@ supposed to be able to do things like:
which will force all existing `*.h` files to be replaced with their
cached copies. If an empty command line implied "all", then this would
force-refresh everything in the cache, which was not the point.
force-refresh everything in the index, which was not the point.
To update and refresh only the files already checked out:
@ -74,7 +74,7 @@ desired tree into the index, and do a
git-checkout-index --prefix=git-export-dir/ -a
and git-checkout-index will "export" the cache into the specified
and git-checkout-index will "export" the index into the specified
directory.
NOTE The final "/" is important. The exported name is literally just

View File

@ -8,7 +8,7 @@ git-clone - Clones a repository.
SYNOPSIS
--------
'git-clone' [-l [-s]] [-q] [-n] [-u <upload-pack>] <repository> <directory>
'git-clone' [-l [-s]] [-q] [-n] [-u <upload-pack>] <repository> [<directory>]
DESCRIPTION
-----------
@ -68,9 +68,11 @@ OPTIONS
be any URL git-fetch supports.
<directory>::
The name of a new directory to be cloned into. It is an
error to specify an existing directory.
The name of a new directory to clone into. The "humanish"
part of the source repository is used if no directory is
explicitly given ("repo" for "/path/to/repo.git" and "foo"
for "host.xz:foo/.git"). Cloning into an existing directory
is not allowed.
Author
------
@ -78,7 +80,7 @@ Written by Linus Torvalds <torvalds@osdl.org>
Documentation
--------------
Documentation by Junio C Hamano.
Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
GIT

View File

@ -8,7 +8,7 @@ git-commit-tree - Creates a new commit object
SYNOPSIS
--------
'git-commit-tree' <tree> [-p <parent commit>]\ < changelog
'git-commit-tree' <tree> [-p <parent commit>]\* < changelog
DESCRIPTION
-----------

View File

@ -0,0 +1,56 @@
git-cvsexportcommit(1)
======================
NAME
----
git-cvsexportcommit - Export a commit to a CVS checkout
SYNOPSIS
--------
git-cvsapplycommmit.perl
[ -h ] [ -v ] [ -c ] [ -p ] [PARENTCOMMIT] COMMITID
DESCRIPTION
-----------
Exports a commit from GIT to a CVS checkout, making it easier
to merge patches from a git repository into a CVS repository.
Execute it from the root of the CVS working copy. GIT_DIR must be defined.
It does its best to do the safe thing, it will check that the files are
unchanged and up to date in the CVS checkout, and it will not autocommit
by default.
Supports file additions, removals, and commits that affect binary files.
If the commit is a merge commit, you must tell git-cvsapplycommit what parent
should the changeset be done against.
OPTIONS
-------
-c::
Commit automatically if the patch applied cleanly. It will not
commit if any hunks fail to apply or there were other problems.
-p::
Be pedantic (paranoid) when applying patches. Invokes patch with
--fuzz=0
-v::
Verbose.
Author
------
Written by Martin Langhoff <martin@catalyst.net.nz>
Documentation
--------------
Documentation by Martin Langhoff <martin@catalyst.net.nz>
GIT
---
Part of the gitlink:git[7] suite

View File

@ -35,7 +35,7 @@ OPTIONS
-i::
Import-only: don't perform a checkout after importing. This option
ensures the working directory and cache remain untouched and will
ensures the working directory and index remain untouched and will
not create them if they do not exist.
-k::

View File

@ -3,7 +3,7 @@ git-diff-files(1)
NAME
----
git-diff-files - Compares files in the working tree and the cache
git-diff-files - Compares files in the working tree and the index
SYNOPSIS
@ -12,9 +12,9 @@ SYNOPSIS
DESCRIPTION
-----------
Compares the files in the working tree and the cache. When paths
Compares the files in the working tree and the index. When paths
are specified, compares only those named paths. Otherwise all
entries in the cache are compared. The output format is the
entries in the index are compared. The output format is the
same as "git-diff-index" and "git-diff-tree".
OPTIONS

View File

@ -3,7 +3,7 @@ git-diff-index(1)
NAME
----
git-diff-index - Compares content and mode of blobs between the cache and repository
git-diff-index - Compares content and mode of blobs between the index and repository
SYNOPSIS
@ -13,10 +13,10 @@ SYNOPSIS
DESCRIPTION
-----------
Compares the content and mode of the blobs found via a tree
object with the content of the current cache and, optionally
object with the content of the current index and, optionally
ignoring the stat state of the file on disk. When paths are
specified, compares only those named paths. Otherwise all
entries in the cache are compared.
entries in the index are compared.
OPTIONS
-------
@ -49,11 +49,11 @@ Cached Mode
-----------
If '--cached' is specified, it allows you to ask:
show me the differences between HEAD and the current cache
show me the differences between HEAD and the current index
contents (the ones I'd write with a "git-write-tree")
For example, let's say that you have worked on your working directory, updated
some files in the cache and are ready to commit. You want to see eactly
some files in the index and are ready to commit. You want to see eactly
*what* you are going to commit is without having to write a new tree
object and compare it that way, and to do that, you just do
@ -92,7 +92,7 @@ which is obviously a very useful question too, since that tells you what
you *could* commit. Again, the output matches the "git-diff-tree -r"
output to a tee, but with a twist.
The twist is that if some file doesn't match the cache, we don't have
The twist is that if some file doesn't match the index, we don't have
a backing store thing for it, and we use the magic "all-zero" sha1 to
show that. So let's say that you have edited `kernel/sched.c`, but
have not actually done a "git-update-index" on it yet - there is no
@ -110,7 +110,7 @@ NOTE: As with other commands of this type, "git-diff-index" does not
actually look at the contents of the file at all. So maybe
`kernel/sched.c` hasn't actually changed, and it's just that you
touched it. In either case, it's a note that you need to
"git-upate-cache" it to make the cache be in sync.
"git-upate-index" it to make the index be in sync.
NOTE: You can have a mixture of files show up as "has been updated"
and "is still dirty in the working directory" together. You can always

View File

@ -8,7 +8,7 @@ git-diff-tree - Compares the content and mode of blobs found via two tree object
SYNOPSIS
--------
'git-diff-tree' [--stdin] [-m] [-s] [-v] [--pretty] [-t] [-r] [--root] [<common diff options>] <tree-ish> [<tree-ish>] [<path>...]
'git-diff-tree' [--stdin] [-m] [-s] [-v] [--no-commit-id] [--pretty] [-t] [-r] [--root] [<common diff options>] <tree-ish> [<tree-ish>] [<path>...]
DESCRIPTION
-----------
@ -74,6 +74,10 @@ separated with a single space are given.
commit message. Without "=<style>", it defaults to
medium.
--no-commit-id::
git-diff-tree outputs a line with the commit ID when
applicable. This flag suppressed the commit ID output.
Limiting Output
---------------

View File

@ -8,7 +8,7 @@ git-fetch - Download objects and a head from another repository.
SYNOPSIS
--------
'git-fetch' <repository> <refspec>...
'git-fetch' <options> <repository> <refspec>...
DESCRIPTION
@ -17,24 +17,16 @@ Fetches named heads or tags from another repository, along with
the objects necessary to complete them.
The ref names and their object names of fetched refs are stored
in $GIT_DIR/FETCH_HEAD. This information is left for a later merge
in `.git/FETCH_HEAD`. This information is left for a later merge
operation done by "git resolve" or "git octopus".
OPTIONS
-------
include::fetch-options.txt[]
include::pull-fetch-param.txt[]
-a, \--append::
Append ref names and object names of fetched refs to the
existing contents of $GIT_DIR/FETCH_HEAD. Without this
option old data in $GIT_DIR/FETCH_HEAD will be overwritten.
-u, \--update-head-ok::
By default 'git-fetch' refuses to update the head which
corresponds to the current branch. This flag disables the
check. Note that fetching into the current branch will not
update the index and working directory, so use it with care.
SEE ALSO

View File

@ -33,7 +33,7 @@ index file and all SHA1 references in .git/refs/* as heads.
Report tags.
--cache::
Consider any object recorded in the cache also as a head node for
Consider any object recorded in the index also as a head node for
an unreachability trace.
--standalone::
@ -125,7 +125,7 @@ GIT_OBJECT_DIRECTORY::
used to specify the object database root (usually $GIT_DIR/objects)
GIT_INDEX_FILE::
used to specify the index file of the cache
used to specify the index file of the index
GIT_ALTERNATE_OBJECT_DIRECTORIES::
used to specify additional object database roots (usually unset)

View File

@ -16,7 +16,7 @@ Computes the object ID value for an object with specified type
with the contents of the named file (which can be outside of the
work tree), and optionally writes the resulting object into the
object database. Reports its object ID to its standard output.
This is used by "git-cvsimport" to update the cache
This is used by "git-cvsimport" to update the index
without modifying files in the work tree. When <type> is not
specified, it defaults to "blob".

View File

@ -0,0 +1,78 @@
git-lost-found(1)
=================
NAME
----
git-lost-found - Recover lost refs that luckily have not yet been pruned.
SYNOPSIS
--------
'git-lost-found'
DESCRIPTION
-----------
Finds dangling commits and tags from the object database, and
creates refs to them in .git/lost-found/ directory. Commits and
tags that dereference to commits go to .git/lost-found/commit
and others are stored in .git/lost-found/other directory.
OUTPUT
------
One line description from the commit and tag found along with
their object name are printed on the standard output.
EXAMPLE
-------
Suppose you run 'git tag -f' and mistyped the tag to overwrite.
The ref to your tag is overwritten, but until you run 'git
prune', it is still there.
------------
$ git lost-found
[1ef2b196d909eed523d4f3c9bf54b78cdd6843c6] GIT 0.99.9c
...
------------
Also you can use gitk to browse how they relate to each other
and existing (probably old) tags.
------------
$ gitk $(cd .git/lost-found/commit && echo ??*)
------------
After making sure that it is the object you are looking for, you
can reconnect it to your regular .git/refs hierarchy.
------------
$ git cat-file -t 1ef2b196
tag
$ git cat-file tag 1ef2b196
object fa41bbce8e38c67a218415de6cfa510c7e50032a
type commit
tag v0.99.9c
tagger Junio C Hamano <junkio@cox.net> 1131059594 -0800
GIT 0.99.9c
This contains the following changes from the "master" branch, since
...
$ git update-ref refs/tags/not-lost-anymore 1ef2b196
$ git rev-parse not-lost-anymore
1ef2b196d909eed523d4f3c9bf54b78cdd6843c6
------------
Author
------
Written by Junio C Hamano 濱野 純 <junkio@cox.net>
Documentation
--------------
Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
GIT
---
Part of the gitlink:git[7] suite

View File

@ -3,7 +3,7 @@ git-ls-files(1)
NAME
----
git-ls-files - Information about files in the cache/working directory
git-ls-files - Information about files in the index/working directory
SYNOPSIS

View File

@ -12,7 +12,7 @@ SYNOPSIS
DESCRIPTION
-----------
This looks up the <file>(s) in the cache and, if there are any merge
This looks up the <file>(s) in the index and, if there are any merge
entries, passes the SHA1 hash for those files as arguments 1, 2, 3 (empty
argument if no file), and <file> as argument 4. File modes for the three
files are passed as arguments 5, 6 and 7.
@ -23,7 +23,7 @@ OPTIONS
Interpret all following arguments as filenames.
-a::
Run merge against all files in the cache that need merging.
Run merge against all files in the index that need merging.
-o::
Instead of stopping at the first failed merge, do all of them

View File

@ -19,7 +19,7 @@ which drives multiple merge strategy scripts.
OPTIONS
-------
include::merge-pull-opts.txt[]
include::merge-options.txt[]
<msg>::
The commit message to be used for the merge commit (in case

View File

@ -0,0 +1,50 @@
git-pack-redundant(1)
=====================
NAME
----
git-pack-redundant - Program used to find redundant pack files.
SYNOPSIS
--------
'git-pack-redundant [ --verbose ] [ --alt-odb ] < --all | .pack filename ... >'
DESCRIPTION
-----------
This program computes which packs in your repository
are redundant. The output is suitable for piping to
'xargs rm' if you are in the root of the repository.
OPTIONS
-------
--all::
Processes all packs. Any filenames on the commandline are ignored.
--alt-odb::
Don't require objects present in packs from alternate object
directories to be present in local packs.
--verbose::
Outputs some statistics to stderr. Has a small performance penalty.
Author
------
Written by Lukas Sandström <lukass@etek.chalmers.se>
Documentation
--------------
Documentation by Lukas Sandström <lukass@etek.chalmers.se>
See-Also
--------
gitlink:git-pack-objects[1]
gitlink:git-repack[1]
gitlink:git-prune-packed[1]
GIT
---
Part of the gitlink:git[7] suite

View File

@ -23,6 +23,12 @@ compression applied, stored in a single file, with an associated index file.
Packs are used to reduce the load on mirror systems, backup engines, disk storage, etc.
OPTIONS
-------
-n::
Don't actually remove any objects, only show those that would have been
removed.
Author
------
Written by Linus Torvalds <torvalds@osdl.org>

View File

@ -20,21 +20,18 @@ Note that you can use `.` (current directory) as the
<repository> to pull from the local repository -- this is useful
when merging local branches into the current branch.
OPTIONS
-------
include::merge-options.txt[]
include::fetch-options.txt[]
include::pull-fetch-param.txt[]
-a, \--append::
Append ref names and object names of fetched refs to the
existing contents of `$GIT_DIR/FETCH_HEAD`. Without this
option old data in `$GIT_DIR/FETCH_HEAD` will be overwritten.
include::merge-pull-opts.txt[]
include::merge-strategies.txt[]
EXAMPLES
--------
@ -72,7 +69,7 @@ $ git fetch origin master:origin +pu:pu maint:maint
$ git pull . origin
------------------------------------------------
+
Here, a typical `$GIT_DIR/remotes/origin` file from a
Here, a typical `.git/remotes/origin` file from a
`git-clone` operation is used in combination with
command line options to `git-fetch` to first update
multiple branches of the local repository and then
@ -85,7 +82,7 @@ known to have already obtained and made available
all the necessary objects.
Pull of multiple branches from one repository using `$GIT_DIR/remotes` file::
Pull of multiple branches from one repository using `.git/remotes` file::
+
------------------------------------------------
$ cat .git/remotes/origin
@ -98,7 +95,7 @@ $ git checkout master
$ git pull origin
------------------------------------------------
+
Here, a typical `$GIT_DIR/remotes/origin` file from a
Here, a typical `.git/remotes/origin` file from a
`git-clone` operation has been hand-modified to include
the branch-mapping of additional remote and local
heads directly. A single `git-pull` operation while

View File

@ -3,7 +3,7 @@ git-read-tree(1)
NAME
----
git-read-tree - Reads tree information into the directory cache
git-read-tree - Reads tree information into the index
SYNOPSIS
@ -13,11 +13,11 @@ SYNOPSIS
DESCRIPTION
-----------
Reads the tree information given by <tree-ish> into the directory cache,
Reads the tree information given by <tree-ish> into the index,
but does not actually *update* any of the files it "caches". (see:
git-checkout-index)
Optionally, it can merge a tree into the cache, perform a
Optionally, it can merge a tree into the index, perform a
fast-forward (i.e. 2-way) merge, or a 3-way merge, with the -m
flag. When used with -m, the -u flag causes it to also update
the files in the work tree with the result of the merge.
@ -30,6 +30,10 @@ OPTIONS
-m::
Perform a merge, not just a read.
--reset::
Same as -m except that unmerged entries will be silently ignored.
-u::
After a successful merge, update the files in the work
tree with the result of the merge.
@ -59,10 +63,10 @@ provided.
Single Tree Merge
~~~~~~~~~~~~~~~~~
If only 1 tree is specified, git-read-tree operates as if the user did not
specify '-m', except that if the original cache has an entry for a
specify '-m', except that if the original index has an entry for a
given pathname, and the contents of the path matches with the tree
being read, the stat info from the cache is used. (In other words, the
cache's stat()s take precedence over the merged tree's).
being read, the stat info from the index is used. (In other words, the
index's stat()s take precedence over the merged tree's).
That means that if you do a "git-read-tree -m <newtree>" followed by a
"git-checkout-index -f -u -a", the "git-checkout-index" only checks out
@ -96,7 +100,7 @@ Here are the "carry forward" rules:
-------------------------------------------------------
0 nothing nothing nothing (does not happen)
1 nothing nothing exists use M
2 nothing exists nothing remove path from cache
2 nothing exists nothing remove path from index
3 nothing exists exists use M
clean I==H I==M
@ -109,7 +113,7 @@ Here are the "carry forward" rules:
8 yes N/A no nothing exists fail
9 no N/A no nothing exists fail
10 yes yes N/A exists nothing remove path from cache
10 yes yes N/A exists nothing remove path from index
11 no yes N/A exists nothing fail
12 yes no N/A exists nothing fail
13 no no N/A exists nothing fail
@ -128,7 +132,7 @@ Here are the "carry forward" rules:
20 yes yes no exists exists use M
21 no yes no exists exists fail
In all "keep index" cases, the cache entry stays as in the
In all "keep index" cases, the index entry stays as in the
original index file. If the entry were not up to date,
git-read-tree keeps the copy in the work tree intact when
operating under the -u flag.
@ -245,7 +249,7 @@ since you pulled from him:
Your work tree is still based on your HEAD ($JC), but you have
some edits since. Three-way merge makes sure that you have not
added or modified cache entries since $JC, and if you haven't,
added or modified index entries since $JC, and if you haven't,
then does the right thing. So with the following sequence:
$ git-read-tree -m -u `git-merge-base $JC $LT` $JC $LT

View File

@ -1,32 +0,0 @@
git-rename(1)
=============
NAME
----
git-rename - Script used to rename a file, directory or symlink.
SYNOPSIS
--------
'git-rename' <source> <destination>
DESCRIPTION
-----------
This script is used to rename a file, directory or symlink.
The index is updated after successful completion, but the change must still be
committed.
Author
------
Written by Linus Torvalds <torvalds@osdl.org>
Rewritten by Ryan Anderson <ryan@michonline.com>
Documentation
--------------
Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
GIT
---
Part of the gitlink:git[7] suite

View File

@ -44,7 +44,7 @@ When importing incementally, you might need to edit the .git/svn2git file.
-i::
Import-only: don't perform a checkout after importing. This option
ensures the working directory and cache remain untouched and will
ensures the working directory and index remain untouched and will
not create them if they do not exist.
-t <trunk_subdir>::

View File

@ -8,7 +8,7 @@ git-tag - Create a tag object signed with GPG
SYNOPSIS
--------
'git-tag' [-a | -s | -u <key-id>] [-f] [-m <msg>] <name> [<head>]
'git-tag' [-a | -s | -u <key-id>] [-f | -d] [-m <msg>] <name> [<head>]
DESCRIPTION
-----------
@ -30,6 +30,8 @@ A GnuPG signed tag object will be created when `-s` or `-u
committer identity for the current user is used to find the
GnuPG key for signing.
`-d <tag>` deletes the tag.
Author
------

View File

@ -8,7 +8,7 @@ git-unpack-objects - Unpack objects from a packed archive.
SYNOPSIS
--------
'git-unpack-objects' [-q] <pack-file
'git-unpack-objects' [-n] [-q] <pack-file
DESCRIPTION
@ -19,6 +19,10 @@ one-object" format in $GIT_OBJECT_DIRECTORY.
OPTIONS
-------
-n::
Only list the objects that would be unpacked, don't actually unpack
them.
-q::
The command usually shows percentage progress. This
flag suppresses it.

View File

@ -21,7 +21,7 @@ SYNOPSIS
DESCRIPTION
-----------
Modifies the index or directory cache. Each file mentioned is updated
into the cache and any 'unmerged' or 'needs updating' state is
into the index and any 'unmerged' or 'needs updating' state is
cleared.
The way "git-update-index" handles files it is told about can be modified
@ -30,26 +30,26 @@ using the various options:
OPTIONS
-------
--add::
If a specified file isn't in the cache already then it's
If a specified file isn't in the index already then it's
added.
Default behaviour is to ignore new files.
--remove::
If a specified file is in the cache but is missing then it's
If a specified file is in the index but is missing then it's
removed.
Default behaviour is to ignore removed file.
--refresh::
Looks at the current cache and checks to see if merges or
Looks at the current index and checks to see if merges or
updates are needed by checking stat() information.
-q::
Quiet. If --refresh finds that the cache needs an update, the
Quiet. If --refresh finds that the index needs an update, the
default behavior is to error out. This option makes
git-update-index continue anyway.
--unmerged::
If --refresh finds unmerged changes in the cache, the default
If --refresh finds unmerged changes in the index, the default
behavior is to error out. This option makes git-update-index
continue anyway.
@ -57,10 +57,10 @@ OPTIONS
Ignores missing files during a --refresh
--cacheinfo <mode> <object> <path>::
Directly insert the specified info into the cache.
Directly insert the specified info into the index.
--index-info::
Read index info from stdin.
Read index information from stdin.
--chmod=(+|-)x::
Set the execute permissions on the updated files.
@ -68,7 +68,7 @@ OPTIONS
--info-only::
Do not create objects in the object database for all
<file> arguments that follow this flag; just insert
their object IDs into the cache.
their object IDs into the index.
--force-remove::
Remove the file from the index even when the working directory
@ -106,14 +106,14 @@ OPTIONS
Using --refresh
---------------
'--refresh' does not calculate a new sha1 file or bring the cache
'--refresh' does not calculate a new sha1 file or bring the index
up-to-date for mode/content changes. But what it *does* do is to
"re-match" the stat information of a file with the cache, so that you
can refresh the cache for a file that hasn't been changed but where
"re-match" the stat information of a file with the index, so that you
can refresh the index for a file that hasn't been changed but where
the stat entry is out of date.
For example, you'd want to do this after doing a "git-read-tree", to link
up the stat cache details with the proper files.
up the stat index details with the proper files.
Using --cacheinfo or --info-only
--------------------------------

View File

@ -3,7 +3,7 @@ git-write-tree(1)
NAME
----
git-write-tree - Creates a tree object from the current cache
git-write-tree - Creates a tree object from the current index
SYNOPSIS
@ -12,11 +12,11 @@ SYNOPSIS
DESCRIPTION
-----------
Creates a tree object using the current cache.
Creates a tree object using the current index.
The cache must be merged.
The index must be merged.
Conceptually, "git-write-tree" sync()s the current directory cache contents
Conceptually, "git-write-tree" sync()s the current index contents
into a set of tree files.
In order to have that match what is actually in your directory right
now, you need to have done a "git-update-index" phase before you did the

View File

@ -40,7 +40,7 @@ reflect recent changes.
Commands Overview
-----------------
The git commands can helpfully be split into those that manipulate
the repository, the cache and the working fileset, those that
the repository, the index and the working fileset, those that
interrogate and compare them, and those that moves objects and
references between repositories.
@ -59,7 +59,7 @@ gitlink:git-apply[1]::
applies it to the working tree.
gitlink:git-checkout-index[1]::
Copy files from the cache to the working directory
Copy files from the index to the working directory
gitlink:git-commit-tree[1]::
Creates a new commit object
@ -86,7 +86,7 @@ gitlink:git-prune-packed[1]::
Remove extra objects that are already in pack files.
gitlink:git-read-tree[1]::
Reads tree information into the directory cache
Reads tree information into the directory index
gitlink:git-unpack-objects[1]::
Unpacks objects out of a packed archive.
@ -95,7 +95,7 @@ gitlink:git-update-index[1]::
Modifies the index or directory cache
gitlink:git-write-tree[1]::
Creates a tree from the current cache
Creates a tree from the current index
Interrogation commands
@ -105,10 +105,10 @@ gitlink:git-cat-file[1]::
Provide content or type information for repository objects
gitlink:git-diff-index[1]::
Compares content and mode of blobs between the cache and repository
Compares content and mode of blobs between the index and repository
gitlink:git-diff-files[1]::
Compares files in the working tree and the cache
Compares files in the working tree and the index
gitlink:git-diff-stages[1]::
Compares two "merge stages" in the index file.
@ -120,7 +120,7 @@ gitlink:git-fsck-objects[1]::
Verifies the connectivity and validity of the objects in the database
gitlink:git-ls-files[1]::
Information about files in the cache/working directory
Information about files in the index/working directory
gitlink:git-ls-tree[1]::
Displays a tree object in human readable form
@ -262,9 +262,6 @@ gitlink:git-push[1]::
gitlink:git-rebase[1]::
Rebase local commits to new upstream head.
gitlink:git-rename[1]::
Rename files and directories.
gitlink:git-repack[1]::
Pack unpacked objects in a repository.
@ -309,6 +306,9 @@ gitlink:git-convert-objects[1]::
gitlink:git-cvsimport[1]::
Salvage your data out of another SCM people love to hate.
gitlink:git-lost-found[1]::
Recover lost refs that luckily have not yet been pruned.
gitlink:git-merge-one-file[1]::
The standard helper program to use with "git-merge-index"
@ -490,8 +490,8 @@ git so take care if using Cogito etc
'GIT_INDEX_FILE'::
This environment allows the specification of an alternate
cache/index file. If not specified, the default of
`$GIT_DIR/index` is used.
index file. If not specified, the default of `$GIT_DIR/index`
is used.
'GIT_OBJECT_DIRECTORY'::
If the object storage directory is specified via this

View File

@ -43,14 +43,14 @@ DAG::
index::
A collection of files with stat information, whose contents are
stored as objects. The cache is a stored version of your working
stored as objects. The index is a stored version of your working
tree. Truth be told, it can also contain a second, and even a third
version of a working tree, which are used when merging.
index entry::
The information regarding a particular file, stored in the index.
An index entry can be unmerged, if a merge was started, but not
yet finished (i.e. if the cache contains multiple versions of
yet finished (i.e. if the index contains multiple versions of
that file).
unmerged index:
@ -75,7 +75,7 @@ checkout::
stored in the object database.
commit::
As a verb: The action of storing the current state of the cache in the
As a verb: The action of storing the current state of the index in the
object database. The result is a revision.
As a noun: Short hand for commit object.

View File

@ -0,0 +1,65 @@
From: Linus Torvalds <torvalds () osdl ! org>
To: git@vger.kernel.org
Date: 2005-11-08 1:31:34
Subject: Real-life kernel debugging scenario
Abstract: Short-n-sweet, Linus tells us how to leverage `git-bisect` to perform
bug isolation on a repository where "good" and "bad" revisions are known
in order to identify a suspect commit.
How To Use git-bisect To Isolate a Bogus Commit
===============================================
The way to use "git bisect" couldn't be easier.
Figure out what the oldest bad state you know about is (that's usually the
head of "master", since that's what you just tried to boot and failed at).
Also, figure out the most recent known-good commit (usually the _previous_
kernel you ran: and if you've only done a single "pull" in between, it
will be ORIG_HEAD).
Then do
git bisect start
git bisect bad master <- mark "master" as the bad state
git bisect good ORIG_HEAD <- mark ORIG_HEAD as good (or
whatever other known-good
thing you booted laste)
and at this point "git bisect" will churn for a while, and tell you what
the mid-point between those two commits are, and check that state out as
the head of the bew "bisect" branch.
Compile and reboot.
If it's good, just do
git bisect good <- mark current head as good
otherwise, reboot into a good kernel instead, and do (surprise surprise,
git really is very intuitive):
git bisect bad <- mark current head as bad
and whatever you do, git will select a new half-way point. Do this for a
while, until git tells you exactly which commit was the first bad commit.
That's your culprit.
It really works wonderfully well, except for the case where there was
_another_ commit that broke something in between, like introduced some
stupid compile error. In that case you should not mark that commit good or
bad: you should try to find another commit close-by, and do a "git reset
--hard <newcommit>" to try out _that_ commit instead, and then test that
instead (and mark it good or bad).
You can do "git bisect visualize" while you do all this to see what's
going on by starting up gitk on the bisection range.
Finally, once you've figured out exactly which commit was bad, you can
then go back to the master branch, and try reverting just that commit:
git checkout master
git revert <bad-commit-id>
to verify that the top-of-kernel works with that single commit reverted.

View File

@ -63,7 +63,7 @@ And then, you can just remove the broken branch if you decide you really
don't want it:
# remove 'broken' branch
rm .git/refs/heads/broken
git branch -d broken
# Prune old objects if you're really really sure
git prune

View File

@ -153,7 +153,8 @@ Everything is in the good order. I do not need the temporary branch
nor tag anymore, so remove them:
------------------------------------------------
$ rm -f .git/refs/tags/pu-anchor .git/refs/heads/revert-c99
$ rm -f .git/refs/tags/pu-anchor
$ git branch -d revert-c99
------------------------------------------------
It was an emergency fix, so we might as well merge it into the

View File

@ -9,7 +9,7 @@ GIT as a Linux subsystem maintainer.
-Tony
Last updated w.r.t. GIT 0.99.5
Last updated w.r.t. GIT 0.99.9f
Linux subsystem maintenance using GIT
-------------------------------------
@ -89,8 +89,8 @@ out at the current tip of the linus branch.
These can be easily kept up to date by merging from the "linus" branch:
$ git checkout test && git resolve test linus "Auto-update from upstream"
$ git checkout release && git resolve release linus "Auto-update from upstream"
$ git checkout test && git merge "Auto-update from upstream" test linus
$ git checkout release && git merge "Auto-update from upstream" release linus
Set up so that you can push upstream to your public tree (you need to
log-in to the remote system and create an empty tree there before the
@ -128,7 +128,7 @@ commit to this branch.
When you are happy with the state of this change, you can pull it into the
"test" branch in preparation to make it public:
$ git checkout test && git resolve test speed-up-spinlocks "Pull speed-up-spinlock changes"
$ git checkout test && git merge "Pull speed-up-spinlock changes" test speed-up-spinlocks
It is unlikely that you would have any conflicts here ... but you might if you
spent a while on this step and had also pulled new versions from upstream.
@ -138,7 +138,7 @@ same branch into the "release" tree ready to go upstream. This is where you
see the value of keeping each patch (or patch series) in its own branch. It
means that the patches can be moved into the "release" tree in any order.
$ git checkout release && git resolve release speed-up-spinlocks "Pull speed-up-spinlock changes"
$ git checkout release && git merge "Pull speed-up-spinlock changes" release speed-up-spinlocks
After a while, you will have a number of branches, and despite the
well chosen names you picked for each of them, you may forget what
@ -166,7 +166,7 @@ output from:
is empty. At this point the branch can be deleted:
$ rm .git/refs/heads/branchname
$ git branch -d branchname
Some changes are so trivial that it is not necessary to create a separate
branch and then merge into each of the test and release branches. For
@ -190,7 +190,7 @@ Here are some of the scripts that I use to simplify all this even further.
case "$1" in
test|release)
git checkout $1 && git resolve $1 linus "Auto-update from upstream"
git checkout $1 && git merge "Auto-update from upstream" $1 linus
;;
linus)
before=$(cat .git/refs/heads/linus)
@ -231,7 +231,7 @@ test|release)
echo $1 already merged into $2 1>&2
exit 1
fi
git checkout $2 && git resolve $2 $1 "Pull $1 into $2 branch"
git checkout $2 && git merge "Pull $1 into $2 branch" $2 $1
;;
*)
usage

View File

@ -0,0 +1,16 @@
-n, \--no-summary::
Do not show diffstat at the end of the merge.
--no-commit::
Perform the merge but pretend the merge failed and do
not autocommit, to give the user a chance to inspect and
further tweak the merge result before committing.
-s <strategy>, \--strategy=<strategy>::
Use the given merge strategy; can be supplied more than
once to specify them in the order they should be tried.
If there is no `-s` option, a built-in list of strategies
is used instead (`git-merge-resolve` when merging a single
head, `git-merge-octopus` otherwise).

View File

@ -1,14 +0,0 @@
-n, --no-summary::
Do not show diffstat at the end of the merge.
--no-commit::
Perform the merge but pretend the merge failed and do
not autocommit, to give the user a chance to inspect and
further tweak the merge result before committing.
-s <strategy>::
use that merge strategy; can be given more than once to
specify them in the order they should be tried. If
there is no `-s` option, built-in list of strategies is
used instead (`git-merge-resolve` when merging a single
head, `git-merge-octopus` otherwise).

View File

@ -8,7 +8,7 @@
- Rsync URL: rsync://remote.machine/path/to/repo.git/
- HTTP(s) URL: http://remote.machine/path/to/repo.git/
- git URL: git://remote.machine/path/to/repo.git/
or remote.machine:/path/to/repo.git/
- ssh URL: remote.machine:/path/to/repo.git/
- Local directory: /path/to/repo.git/
===============================================================
+

View File

@ -36,14 +36,16 @@ To start up, create a subdirectory for it, change into that
subdirectory, and initialize the git infrastructure with `git-init-db`:
------------------------------------------------
mkdir git-tutorial
cd git-tutorial
git-init-db
$ mkdir git-tutorial
$ cd git-tutorial
$ git-init-db
------------------------------------------------
to which git will reply
defaulting to local storage area
----------------
defaulting to local storage area
----------------
which is just git's way of saying that you haven't been doing anything
strange, and that it will have created a local `.git` directory setup for
@ -114,8 +116,8 @@ in your git repository. We'll start off with a few bad examples, just to
get a feel for how this works:
------------------------------------------------
echo "Hello World" >hello
echo "Silly example" >example
$ echo "Hello World" >hello
$ echo "Silly example" >example
------------------------------------------------
you have now created two files in your working tree (aka 'working directory'), but to
@ -129,7 +131,7 @@ actually check in your hard work, you will have to go through two steps:
The first step is trivial: when you want to tell git about any changes
to your working tree, you use the `git-update-index` program. That
program normally just takes a list of filenames you want to update, but
to avoid trivial mistakes, it refuses to add new entries to the cache
to avoid trivial mistakes, it refuses to add new entries to the index
(or remove existing ones) unless you explicitly tell it that you're
adding a new entry with the `\--add` flag (or removing an entry with the
`\--remove`) flag.
@ -137,7 +139,7 @@ adding a new entry with the `\--add` flag (or removing an entry with the
So to populate the index with the two files you just created, you can do
------------------------------------------------
git-update-index --add hello example
$ git-update-index --add hello example
------------------------------------------------
and you have now told git to track those two files.
@ -146,12 +148,17 @@ In fact, as you did that, if you now look into your object directory,
you'll notice that git will have added two new objects to the object
database. If you did exactly the steps above, you should now be able to do
ls .git/objects/??/*
----------------
$ ls .git/objects/??/*
----------------
and see two files:
.git/objects/55/7db03de997c86a4a028e1ebd3a1ceb225be238
.git/objects/f2/4c74a2e500f5ee1332c86b94199f52b1d1d962
----------------
.git/objects/55/7db03de997c86a4a028e1ebd3a1ceb225be238
.git/objects/f2/4c74a2e500f5ee1332c86b94199f52b1d1d962
----------------
which correspond with the objects with names of 557db... and f24c7..
respectively.
@ -159,13 +166,17 @@ respectively.
If you want to, you can use `git-cat-file` to look at those objects, but
you'll have to use the object name, not the filename of the object:
git-cat-file -t 557db03de997c86a4a028e1ebd3a1ceb225be238
----------------
$ git-cat-file -t 557db03de997c86a4a028e1ebd3a1ceb225be238
----------------
where the `-t` tells `git-cat-file` to tell you what the "type" of the
object is. git will tell you that you have a "blob" object (ie just a
regular file), and you can see the contents with
git-cat-file "blob" 557db03
----------------
$ git-cat-file "blob" 557db03
----------------
which will print out "Hello World". The object 557db03 is nothing
more than the contents of your file `hello`.
@ -188,7 +199,7 @@ was just to show that `git-update-index` did something magical, and
actually saved away the contents of your files into the git object
database.
Updating the cache did something else too: it created a `.git/index`
Updating the index did something else too: it created a `.git/index`
file. This is the index that describes your current working tree, and
something you should be very aware of. Again, you normally never worry
about the index file itself, but you should be aware of the fact that
@ -202,7 +213,7 @@ In particular, let's not even check in the two files into git yet, we'll
start off by adding another line to `hello` first:
------------------------------------------------
echo "It's a new day for git" >>hello
$ echo "It's a new day for git" >>hello
------------------------------------------------
and you can now, since you told git about the previous state of `hello`, ask
@ -210,7 +221,7 @@ git what has changed in the tree compared to your old index, using the
`git-diff-files` command:
------------
git-diff-files
$ git-diff-files
------------
Oops. That wasn't very readable. It just spit out its own internal
@ -222,12 +233,7 @@ To make it readable, we can tell git-diff-files to output the
differences as a patch, using the `-p` flag:
------------
git-diff-files -p
------------
which will spit out
------------
$ git-diff-files -p
diff --git a/hello b/hello
index 557db03..263414f 100644
--- a/hello
@ -264,13 +270,15 @@ filenames with their contents (and their permissions), and we're
creating the equivalent of a git "directory" object:
------------------------------------------------
git-write-tree
$ git-write-tree
------------------------------------------------
and this will just output the name of the resulting tree, in this case
(if you have done exactly as I've described) it should be
8988da15d077d4829fc51d8544c097def6644dbb
----------------
8988da15d077d4829fc51d8544c097def6644dbb
----------------
which is another incomprehensible object name. Again, if you want to,
you can use `git-cat-file -t 8988d\...` to see that this time the object
@ -299,14 +307,16 @@ that's exactly what `git-commit-tree` spits out, we can do this
all with a sequence of simple shell commands:
------------------------------------------------
tree=$(git-write-tree)
commit=$(echo 'Initial commit' | git-commit-tree $tree)
git-update-ref HEAD $(commit)
$ tree=$(git-write-tree)
$ commit=$(echo 'Initial commit' | git-commit-tree $tree)
$ git-update-ref HEAD $commit
------------------------------------------------
which will say:
Committing initial tree 8988da15d077d4829fc51d8544c097def6644dbb
----------------
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*
@ -349,7 +359,9 @@ didn't have anything to diff against.
But now we can do
git-diff-index -p HEAD
----------------
$ git-diff-index -p HEAD
----------------
(where `-p` has the same meaning as it did in `git-diff-files`), and it
will show us the same difference, but for a totally different reason.
@ -360,7 +372,9 @@ are obviously the same, so we get the same result.
Again, because this is a common operation, you can also just shorthand
it with
git diff HEAD
----------------
$ git diff HEAD
----------------
which ends up doing the above for you.
@ -396,7 +410,7 @@ work through the index file, so the first thing we need to do is to
update the index cache:
------------------------------------------------
git-update-index hello
$ git-update-index hello
------------------------------------------------
(note how we didn't need the `\--add` flag this time, since git knew
@ -417,7 +431,7 @@ this wasn't an initial commit any more), but you've done that once
already, so let's just use the helpful script this time:
------------------------------------------------
git commit
$ git commit
------------------------------------------------
which starts an editor for you to write the commit message and tells you
@ -426,7 +440,7 @@ a bit about what you have done.
Write whatever message you want, and all the lines that start with '#'
will be pruned out, and the rest will be used as the commit message for
the change. If you decide you don't want to commit anything after all at
this point (you can continue to edit things and update the cache), you
this point (you can continue to edit things and update the index), you
can just leave an empty message. Otherwise `git commit` will commit
the change for you.
@ -450,7 +464,9 @@ give it just a single commit object, and it will figure out the parent
of that commit itself, and show the difference directly. Thus, to get
the same diff that we've already seen several times, we can now do
git-diff-tree -p HEAD
----------------
$ git-diff-tree -p HEAD
----------------
(again, `-p` means to show the difference as a human-readable patch),
and it will show what the last commit (in `HEAD`) actually changed.
@ -505,13 +521,17 @@ activities.
To see the whole history of our pitiful little git-tutorial project, you
can do
git log
----------------
$ git log
----------------
which shows just the log messages, or if we want to see the log together
with the associated patches use the more complex (and much more
powerful)
git-whatchanged -p --root
----------------
$ git-whatchanged -p --root
----------------
and you will see exactly what has changed in the repository over its
short history.
@ -547,14 +567,16 @@ it in the `.git/refs/tags/` subdirectory instead of calling it a `head`.
So the simplest form of tag involves nothing more than
------------------------------------------------
git tag my-first-tag
$ git tag my-first-tag
------------------------------------------------
which just writes the current `HEAD` into the `.git/refs/tags/my-first-tag`
file, after which point you can then use this symbolic name for that
particular state. You can, for example, do
git diff my-first-tag
----------------
$ git diff my-first-tag
----------------
to diff your current state against that tag (which at this point will
obviously be an empty diff, but if you continue to develop and commit
@ -568,7 +590,9 @@ you really did
that tag. You create these annotated tags with either the `-a` or
`-s` flag to `git tag`:
git tag -s <tagname>
----------------
$ git tag -s <tagname>
----------------
which will sign the current `HEAD` (but you can also give it another
argument that specifies the thing to tag, ie you could have tagged the
@ -584,8 +608,8 @@ name for the state at that point.
Copying repositories
--------------------
git repositories are normally totally self-sufficient, and it's worth noting
that unlike CVS, for example, there is no separate notion of
git repositories are normally totally self-sufficient and relocatable
Unlike CVS, for example, there is no separate notion of
"repository" and "working tree". A git repository normally *is* the
working tree, with the local git information hidden in the `.git`
subdirectory. There is nothing else. What you see is what you got.
@ -602,8 +626,10 @@ This has two implications:
- if you grow bored with the tutorial repository you created (or you've
made a mistake and want to start all over), you can just do simple
rm -rf git-tutorial
+
----------------
$ rm -rf git-tutorial
----------------
+
and it will be gone. There's no external repository, and there's no
history outside the project you created.
@ -618,8 +644,10 @@ Note that when you've moved or copied a git repository, your git index
file (which caches various information, notably some of the "stat"
information for the files involved) will likely need to be refreshed.
So after you do a `cp -a` to create a new copy, you'll want to do
git-update-index --refresh
+
----------------
$ git-update-index --refresh
----------------
+
in the new repository to make sure that the index file is up-to-date.
@ -633,8 +661,10 @@ repositories you often want to make sure that the index cache is in some
known state (you don't know *what* they've done and not yet checked in),
so usually you'll precede the `git-update-index` with a
git-read-tree --reset HEAD
git-update-index --refresh
----------------
$ git-read-tree --reset HEAD
$ git-update-index --refresh
----------------
which will force a total index re-build from the tree pointed to by `HEAD`.
It resets the index contents to `HEAD`, and then the `git-update-index`
@ -645,7 +675,9 @@ tells you they need to be updated.
The above can also be written as simply
git reset
----------------
$ git reset
----------------
and in fact a lot of the common git command combinations can be scripted
with the `git xyz` interfaces. You can learn things by just looking
@ -665,20 +697,26 @@ first create your own subdirectory for the project, and then copy the
raw repository contents into the `.git` directory. For example, to
create your own copy of the git repository, you'd do the following
mkdir my-git
cd my-git
rsync -rL rsync://rsync.kernel.org/pub/scm/git/git.git/ .git
----------------
$ mkdir my-git
$ cd my-git
$ rsync -rL rsync://rsync.kernel.org/pub/scm/git/git.git/ .git
----------------
followed by
git-read-tree HEAD
----------------
$ git-read-tree HEAD
----------------
to populate the index. However, now you have populated the index, and
you have all the git internal files, but you will notice that you don't
actually have any of the working tree files to work on. To get
those, you'd check them out with
git-checkout-index -u -a
----------------
$ git-checkout-index -u -a
----------------
where the `-u` flag means that you want the checkout to keep the index
up-to-date (so that you don't have to refresh it afterward), and the
@ -689,9 +727,11 @@ files).
Again, this can all be simplified with
git clone rsync://rsync.kernel.org/pub/scm/git/git.git/ my-git
cd my-git
git checkout
----------------
$ git clone rsync://rsync.kernel.org/pub/scm/git/git.git/ my-git
$ cd my-git
$ git checkout
----------------
which will end up doing all of the above for you.
@ -719,7 +759,7 @@ used earlier, and create a branch in it. You do that by simply just
saying that you want to check out a new branch:
------------
git checkout -b mybranch
$ git checkout -b mybranch
------------
will create a new branch based at the current `HEAD` position, and switch
@ -733,7 +773,7 @@ just telling `git checkout` what the base of the checkout would be.
In other words, if you have an earlier tag or branch, you'd just do
------------
git checkout -b mybranch earlier-commit
$ git checkout -b mybranch earlier-commit
------------
and it would create the new branch `mybranch` at the earlier commit,
@ -743,27 +783,27 @@ and check out the state at that time.
You can always just jump back to your original `master` branch by doing
------------
git checkout master
$ git checkout master
------------
(or any other branch-name, for that matter) and if you forget which
branch you happen to be on, a simple
------------
ls -l .git/HEAD
$ ls -l .git/HEAD
------------
will tell you where it's pointing (Note that on platforms with bad or no
symlink support, you have to execute
------------
cat .git/HEAD
$ cat .git/HEAD
------------
instead). To get the list of branches you have, you can say
------------
git branch
$ git branch
------------
which is nothing more than a simple script around `ls .git/refs/heads`.
@ -773,7 +813,7 @@ Sometimes you may wish to create a new branch _without_ actually
checking it out and switching to it. If so, just use the command
------------
git branch <branchname> [startingpoint]
$ git branch <branchname> [startingpoint]
------------
which will simply _create_ the branch, but will not do anything further.
@ -792,9 +832,9 @@ being the same as the original `master` branch, let's make sure we're in
that branch, and do some work there.
------------------------------------------------
git checkout mybranch
echo "Work, work, work" >>hello
git commit -m 'Some work.' hello
$ git checkout mybranch
$ echo "Work, work, work" >>hello
$ git commit -m 'Some work.' hello
------------------------------------------------
Here, we just added another line to `hello`, and we used a shorthand for
@ -807,7 +847,7 @@ does some work in the original branch, and simulate that by going back
to the master branch, and editing the same file differently there:
------------
git checkout master
$ git checkout master
------------
Here, take a moment to look at the contents of `hello`, and notice how they
@ -815,9 +855,9 @@ don't contain the work we just did in `mybranch` -- because that work
hasn't happened in the `master` branch at all. Then do
------------
echo "Play, play, play" >>hello
echo "Lots of fun" >>example
git commit -m 'Some fun.' hello example
$ echo "Play, play, play" >>hello
$ echo "Lots of fun" >>example
$ git commit -m 'Some fun.' hello example
------------
since the master branch is obviously in a much better mood.
@ -826,7 +866,9 @@ Now, you've got two branches, and you decide that you want to merge the
work done. Before we do that, let's introduce a cool graphical tool that
helps you view what's going on:
gitk --all
----------------
$ gitk --all
----------------
will show you graphically both of your branches (that's what the `\--all`
means: normally it will just show you your current `HEAD`) and their
@ -836,14 +878,14 @@ source.
Anyway, let's exit `gitk` (`^Q` or the File menu), and decide that we want
to merge the work we did on the `mybranch` branch into the `master`
branch (which is currently our `HEAD` too). To do that, there's a nice
script called `git resolve`, which wants to know which branches you want
script called `git merge`, which wants to know which branches you want
to resolve and what the merge is all about:
------------
git resolve HEAD mybranch "Merge work in mybranch"
$ git merge "Merge work in mybranch" HEAD mybranch
------------
where the third argument is going to be used as the commit message if
where the first argument is going to be used as the commit message if
the merge can be resolved automatically.
Now, in this case we've intentionally created a situation where the
@ -851,12 +893,16 @@ merge will need to be fixed up by hand, though, so git will do as much
of it as it can automatically (which in this case is just merge the `example`
file, which had no differences in the `mybranch` branch), and say:
Simple merge failed, trying Automatic merge
Auto-merging hello.
----------------
Trying really trivial in-index merge...
fatal: Merge requires file-level merging
Nope.
...
merge: warning: conflicts during merge
ERROR: Merge conflict in hello.
fatal: merge program failed
Automatic merge failed, fix up by hand
Automatic merge failed/prevented; fix up by hand
----------------
which is way too verbose, but it basically tells you that it failed the
really trivial merge ("Simple merge") and did an "Automatic merge"
@ -877,7 +923,7 @@ Work, work, work
and once you're happy with your manual merge, just do a
------------
git commit hello
$ git commit hello
------------
which will very loudly warn you that you're now committing a merge
@ -927,17 +973,19 @@ to the `master` branch. Let's go back to `mybranch`, and run
resolve to get the "upstream changes" back to your branch.
------------
git checkout mybranch
git resolve HEAD master "Merge upstream changes."
$ git checkout mybranch
$ git merge "Merge upstream changes." HEAD master
------------
This outputs something like this (the actual commit object names
would be different)
Updating from ae3a2da... to a80b4aa....
example | 1 +
hello | 1 +
2 files changed, 2 insertions(+), 0 deletions(-)
----------------
Updating from ae3a2da... to a80b4aa....
example | 1 +
hello | 1 +
2 files changed, 2 insertions(+), 0 deletions(-)
----------------
Because your branch did not contain anything more than what are
already merged into the `master` branch, the resolve operation did
@ -963,14 +1011,16 @@ Merging external work
It's usually much more common that you merge with somebody else than
merging with your own branches, so it's worth pointing out that git
makes that very easy too, and in fact, it's not that different from
doing a `git resolve`. In fact, a remote merge ends up being nothing
doing a `git merge`. In fact, a remote merge ends up being nothing
more than "fetch the work from a remote repository into a temporary tag"
followed by a `git resolve`.
followed by a `git merge`.
Fetching from a remote repository is done by, unsurprisingly,
`git fetch`:
git fetch <remote-repository>
----------------
$ git fetch <remote-repository>
----------------
One of the following transports can be used to name the
repository to download from:
@ -1015,7 +1065,7 @@ This transport was designed for anonymous downloading. Like SSH
transport, it finds out the set of objects the downstream side
lacks and transfers (close to) minimum set of objects.
HTTP(s)::
HTTP(S)::
`http://remote.machine/path/to/repo.git/`
+
HTTP and HTTPS transport are used only for downloading. They
@ -1045,7 +1095,9 @@ However -- it's such a common thing to `fetch` and then
immediately `resolve`, that it's called `git pull`, and you can
simply do
git pull <remote-repository>
----------------
$ git pull <remote-repository>
----------------
and optionally give a branch-name for the remote end as a second
argument.
@ -1073,8 +1125,8 @@ the remote repository URL in a file under .git/remotes/
directory, like this:
------------------------------------------------
mkdir -p .git/remotes/
cat >.git/remotes/linus <<\EOF
$ mkdir -p .git/remotes/
$ cat >.git/remotes/linus <<\EOF
URL: http://www.kernel.org/pub/scm/git/git.git/
EOF
------------------------------------------------
@ -1084,7 +1136,7 @@ The URL specified in such file can even be a prefix
of a full URL, like this:
------------------------------------------------
cat >.git/remotes/jgarzik <<\EOF
$ cat >.git/remotes/jgarzik <<\EOF
URL: http://www.kernel.org/pub/scm/linux/git/jgarzik/
EOF
------------------------------------------------
@ -1103,6 +1155,156 @@ the above are equivalent to:
. `git pull http://www.kernel.org/pub/.../jgarzik/netdev-2.6.git e100`
How does the merge work?
------------------------
We said this tutorial shows what plumbing does to help you cope
with the porcelain that isn't flushing, but we so far did not
talk about how the merge really works. If you are following
this tutorial the first time, I'd suggest to skip to "Publishing
your work" section and come back here later.
OK, still with me? To give us an example to look at, let's go
back to the earlier repository with "hello" and "example" file,
and bring ourselves back to the pre-merge state:
------------
$ git show-branch --more=3 master mybranch
! [master] Merge work in mybranch
* [mybranch] Merge work in mybranch
--
++ [master] Merge work in mybranch
++ [master^2] Some work.
++ [master^] Some fun.
------------
Remember, before running `git merge`, our `master` head was at
"Some fun." commit, while our `mybranch` head was at "Some
work." commit.
------------
$ git checkout mybranch
$ git reset --hard master^2
$ git checkout master
$ git reset --hard master^
------------
After rewinding, the commit structure should look like this:
------------
$ git show-branch
* [master] Some fun.
! [mybranch] Some work.
--
+ [mybranch] Some work.
+ [master] Some fun.
++ [mybranch^] New day.
------------
Now we are ready to experiment with the merge by hand.
`git merge` command, when merging two branches, uses 3-way merge
algorithm. First, it finds the common ancestor between them.
The command it uses is `git-merge-base`:
------------
$ mb=$(git-merge-base HEAD mybranch)
------------
The command writes the commit object name of the common ancestor
to the standard output, so we captured its output to a variable,
because we will be using it in the next step. BTW, the common
ancestor commit is the "New day." commit in this case. You can
tell it by:
------------
$ git-name-rev $mb
my-first-tag
------------
After finding out a common ancestor commit, the second step is
this:
------------
$ git-read-tree -m -u $mb HEAD mybranch
------------
This is the same `git-read-tree` command we have already seen,
but it takes three trees, unlike previous examples. This reads
the contents of each tree into different 'stage' in the index
file (the first tree goes to stage 1, the second stage 2,
etc.). After reading three trees into three stages, the paths
that are the same in all three stages are 'collapsed' into stage
0. Also paths that are the same in two of three stages are
collapsed into stage 0, taking the SHA1 from either stage 2 or
stage 3, whichever is different from stage 1 (i.e. only one side
changed from the common ancestor).
After 'collapsing' operation, paths that are different in three
trees are left in non-zero stages. At this point, you can
inspect the index file with this command:
------------
$ git-ls-files --stage
100644 7f8b141b65fdcee47321e399a2598a235a032422 0 example
100644 263414f423d0e4d70dae8fe53fa34614ff3e2860 1 hello
100644 06fa6a24256dc7e560efa5687fa84b51f0263c3a 2 hello
100644 cc44c73eb783565da5831b4d820c962954019b69 3 hello
------------
In our example of only two files, we did not have unchanged
files so only 'example' resulted in collapsing, but in real-life
large projects, only small number of files change in one commit,
and this 'collapsing' tends to trivially merge most of the paths
fairly quickly, leaving only a handful the real changes in non-zero
stages.
To look at only non-zero stages, use `\--unmerged` flag:
------------
$ git-ls-files --unmerged
100644 263414f423d0e4d70dae8fe53fa34614ff3e2860 1 hello
100644 06fa6a24256dc7e560efa5687fa84b51f0263c3a 2 hello
100644 cc44c73eb783565da5831b4d820c962954019b69 3 hello
------------
The next step of merging is to merge these three versions of the
file, using 3-way merge. This is done by giving
`git-merge-one-file` command as one of the arguments to
`git-merge-index` command:
------------
$ git-merge-index git-merge-one-file hello
Auto-merging hello.
merge: warning: conflicts during merge
ERROR: Merge conflict in hello.
fatal: merge program failed
------------
`git-merge-one-file` script is called with parameters to
describe those three versions, and is responsible to leave the
merge results in the working tree and register it in the index
file. It is a fairly straightforward shell script, and
eventually calls `merge` program from RCS suite to perform the
file-level 3-way merge. In this case, `merge` detects
conflicts, and the merge result with conflict marks is left in
the working tree, while the index file is updated with the
version from the current branch (this is to make `git diff`
useful after this step). This can be seen if you run `ls-files
--stage` again at this point:
------------
$ git-ls-files --stage
100644 7f8b141b65fdcee47321e399a2598a235a032422 0 example
100644 06fa6a24256dc7e560efa5687fa84b51f0263c3a 0 hello
------------
As you can see, there is no unmerged paths in the index file.
This is the state of the index file and the working file after
`git merge` returns control back to you, leaving the conflicting
merge for you to resolve.
Publishing your work
--------------------
@ -1148,7 +1350,7 @@ project `my-git`. After logging into the remote machine, create
an empty directory:
------------
mkdir my-git.git
$ mkdir my-git.git
------------
Then, make that directory into a git repository by running
@ -1156,7 +1358,7 @@ Then, make that directory into a git repository by running
`.git`, we do things slightly differently:
------------
GIT_DIR=my-git.git git-init-db
$ GIT_DIR=my-git.git git-init-db
------------
Make sure this directory is available for others you want your
@ -1182,7 +1384,7 @@ Come back to the machine you have your private repository. From
there, run this command:
------------
git push <public-host>:/path/to/my-git.git master
$ git push <public-host>:/path/to/my-git.git master
------------
This synchronizes your public repository to match the named
@ -1194,7 +1396,7 @@ repository. Kernel.org mirror network takes care of the
propagation to other publicly visible machines:
------------
git push master.kernel.org:/pub/scm/git/git.git/
$ git push master.kernel.org:/pub/scm/git/git.git/
------------
@ -1209,7 +1411,7 @@ immutable once they are created, there is a way to optimize the
storage by "packing them together". The command
------------
git repack
$ git repack
------------
will do it for you. If you followed the tutorial examples, you
@ -1235,7 +1437,7 @@ Once you have packed objects, you do not need to leave the
unpacked objects that are contained in the pack file anymore.
------------
git prune-packed
$ git prune-packed
------------
would remove them for you.
@ -1464,8 +1666,8 @@ in both of them. You could merge in 'diff-fix' first and then
'commit-fix' next, like this:
------------
$ git resolve master diff-fix 'Merge fix in diff-fix'
$ git resolve master commit-fix 'Merge fix in commit-fix'
$ git merge 'Merge fix in diff-fix' master diff-fix
$ git merge 'Merge fix in commit-fix' master commit-fix
------------
Which would result in:
@ -1498,8 +1700,8 @@ $ git reset --hard master~2
------------
You can make sure 'git show-branch' matches the state before
those two 'git resolve' you just did. Then, instead of running
two 'git resolve' commands in a row, you would pull these two
those two 'git merge' you just did. Then, instead of running
two 'git merge' commands in a row, you would pull these two
branch heads (this is known as 'making an Octopus'):
------------

21
INSTALL
View File

@ -5,10 +5,13 @@ Normally you can just do "make" followed by "make install", and that
will install the git programs in your own ~/bin/ directory. If you want
to do a global install, you can do
make prefix=/usr install
$ make prefix=/usr ;# as yourself
# make prefix=/usr install ;# as root
(or prefix=/usr/local, of course). Some day somebody may send me a RPM
spec file or something, and you can do "make rpm" or whatever.
(or prefix=/usr/local, of course). Just like any program suite
that uses $prefix, the built results have some paths encoded,
which are derived from $prefix, so "make all; make prefix=/usr
install" would not work.
Issues of note:
@ -72,3 +75,15 @@ Issues of note:
history graphically
- "ssh" is used to push and pull over the net
- "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
necessary libraries at unusual locations. Please look at the
top of the Makefile to see what can be adjusted for your needs.

View File

@ -50,11 +50,14 @@
# 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.
GIT_VERSION = 0.99.9e
GIT_VERSION = 0.99.9i
# CFLAGS and LDFLAGS are for the users to override from the command line.
# CFLAGS is for the users to override from the command line.
CFLAGS = -g -O2 -Wall
LDFLAGS =
ALL_CFLAGS = $(CFLAGS)
ALL_LDFLAGS = $(LDFLAGS)
prefix = $(HOME)
bindir = $(prefix)/bin
@ -88,12 +91,13 @@ SCRIPT_SH = \
git-tag.sh git-verify-tag.sh git-whatchanged.sh git.sh \
git-applymbox.sh git-applypatch.sh git-am.sh \
git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \
git-merge-resolve.sh git-merge-ours.sh git-grep.sh
git-merge-resolve.sh git-merge-ours.sh git-grep.sh \
git-lost-found.sh
SCRIPT_PERL = \
git-archimport.perl git-cvsimport.perl git-relink.perl \
git-rename.perl git-shortlog.perl git-fmt-merge-msg.perl \
git-svnimport.perl git-mv.perl
git-shortlog.perl git-fmt-merge-msg.perl \
git-svnimport.perl git-mv.perl git-cvsexportcommit.perl
SCRIPT_PYTHON = \
git-merge-recursive.py
@ -121,7 +125,7 @@ PROGRAMS = \
git-unpack-objects$X git-update-index$X git-update-server-info$X \
git-upload-pack$X git-verify-pack$X git-write-tree$X \
git-update-ref$X git-symbolic-ref$X git-check-ref-format$X \
git-name-rev$X $(SIMPLE_PROGRAMS)
git-name-rev$X git-pack-redundant$X $(SIMPLE_PROGRAMS)
# Backward compatibility -- to be removed after 1.0
PROGRAMS += git-ssh-pull$X git-ssh-push$X
@ -185,9 +189,11 @@ ifeq ($(uname_S),Darwin)
NEEDS_SSL_WITH_CRYPTO = YesPlease
NEEDS_LIBICONV = YesPlease
## fink
ALL_CFLAGS += -I/sw/include -L/sw/lib
ALL_CFLAGS += -I/sw/include
ALL_LDFLAGS += -L/sw/lib
## darwinports
ALL_CFLAGS += -I/opt/local/include -L/opt/local/lib
ALL_CFLAGS += -I/opt/local/include
ALL_LDFLAGS += -L/opt/local/lib
endif
ifeq ($(uname_S),SunOS)
NEEDS_SOCKET = YesPlease
@ -209,7 +215,13 @@ endif
ifeq ($(uname_S),OpenBSD)
NO_STRCASESTR = YesPlease
NEEDS_LIBICONV = YesPlease
ALL_CFLAGS += -I/usr/local/include -L/usr/local/lib
ALL_CFLAGS += -I/usr/local/include
ALL_LDFLAGS += -L/usr/local/lib
endif
ifeq ($(uname_S),NetBSD)
NEEDS_LIBICONV = YesPlease
ALL_CFLAGS += -I/usr/pkg/include
ALL_LDFLAGS += -L/usr/pkg/lib -Wl,-rpath,/usr/pkg/lib
endif
ifneq (,$(findstring arm,$(uname_M)))
ARM_SHA1 = YesPlease
@ -219,7 +231,7 @@ endif
ifndef NO_CURL
ifdef CURLDIR
# This is still problematic -- gcc does not want -R.
# This is still problematic -- gcc does not always want -R.
ALL_CFLAGS += -I$(CURLDIR)/include
CURL_LIBCURL = -L$(CURLDIR)/lib -R$(CURLDIR)/lib -lcurl
else
@ -367,12 +379,13 @@ git-cherry-pick: git-revert
$(CC) -o $*.o -c $(ALL_CFLAGS) $<
git-%$X: %.o $(LIB_FILE)
$(CC) $(ALL_CFLAGS) -o $@ $(filter %.o,$^) $(LIBS)
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
git-mailinfo$X : SIMPLE_LIB += $(LIB_4_ICONV)
$(SIMPLE_PROGRAMS) : $(LIB_FILE)
$(SIMPLE_PROGRAMS) : git-%$X : %.o
$(CC) $(ALL_CFLAGS) -o $@ $(filter %.o,$^) $(LIB_FILE) $(SIMPLE_LIB)
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
$(LIB_FILE) $(SIMPLE_LIB)
git-http-fetch$X: fetch.o
git-local-fetch$X: fetch.o
@ -406,10 +419,10 @@ test: all
$(MAKE) -C t/ all
test-date$X: test-date.c date.o ctype.o
$(CC) $(ALL_CFLAGS) -o $@ 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 $@ $^
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $^
check:
for i in *.c; do sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i; done

43
apply.c
View File

@ -23,10 +23,11 @@ static int numstat = 0;
static int summary = 0;
static int check = 0;
static int apply = 1;
static int no_add = 0;
static int show_index_info = 0;
static int line_termination = '\n';
static const char apply_usage[] =
"git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--apply] [--index-info] [-z] <patch>...";
"git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--apply] [--no-add] [--index-info] [-z] <patch>...";
/*
* For "diff-stat" like behaviour, we keep track of the biggest change
@ -53,7 +54,7 @@ struct fragment {
struct patch {
char *new_name, *old_name, *def_name;
unsigned int old_mode, new_mode;
int is_rename, is_copy, is_new, is_delete;
int is_rename, is_copy, is_new, is_delete, is_binary;
int lines_added, lines_deleted;
int score;
struct fragment *fragments;
@ -369,7 +370,7 @@ static int gitdiff_index(const char *line, struct patch *patch)
int len;
ptr = strchr(line, '.');
if (!ptr || ptr[1] != '.' || 40 <= ptr - line)
if (!ptr || ptr[1] != '.' || 40 < ptr - line)
return 0;
len = ptr - line;
memcpy(patch->old_sha1_prefix, line, len);
@ -383,7 +384,7 @@ static int gitdiff_index(const char *line, struct patch *patch)
ptr = eol;
len = ptr - line;
if (40 <= len)
if (40 < len)
return 0;
memcpy(patch->new_sha1_prefix, line, len);
patch->new_sha1_prefix[len] = 0;
@ -890,8 +891,19 @@ static int parse_chunk(char *buffer, unsigned long size, struct patch *patch)
patchsize = parse_single_patch(buffer + offset + hdrsize, size - offset - hdrsize, patch);
if (!patchsize && !metadata_changes(patch))
die("patch with only garbage at line %d", linenr);
if (!patchsize && !metadata_changes(patch)) {
static const char binhdr[] = "Binary files ";
if (sizeof(binhdr) - 1 < size - offset - hdrsize &&
!memcmp(binhdr, buffer + hdrsize + offset,
sizeof(binhdr)-1))
patch->is_binary = 1;
if (patch->is_binary && !apply && !check)
;
else
die("patch with only garbage at line %d", linenr);
}
return offset + hdrsize + patchsize;
}
@ -949,9 +961,12 @@ static void show_stats(struct patch *patch)
add = (add * max + max_change / 2) / max_change;
del = total - add;
}
printf(" %s%-*s |%5d %.*s%.*s\n", prefix,
len, name, patch->lines_added + patch->lines_deleted,
add, pluses, del, minuses);
if (patch->is_binary)
printf(" %s%-*s | Bin\n", prefix, len, name);
else
printf(" %s%-*s |%5d %.*s%.*s\n", prefix,
len, name, patch->lines_added + patch->lines_deleted,
add, pluses, del, minuses);
if (qname)
free(qname);
}
@ -1099,8 +1114,10 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag)
break;
/* Fall-through for ' ' */
case '+':
memcpy(new + newsize, patch + 1, plen);
newsize += plen;
if (*patch != '+' || !no_add) {
memcpy(new + newsize, patch + 1, plen);
newsize += plen;
}
break;
case '@': case '\\':
/* Ignore it, we already handled it */
@ -1697,6 +1714,10 @@ int main(int argc, char **argv)
excludes = x;
continue;
}
if (!strcmp(arg, "--no-add")) {
no_add = 1;
continue;
}
if (!strcmp(arg, "--stat")) {
apply = 0;
diffstat = 1;

View File

@ -34,6 +34,8 @@ enum cmit_fmt get_commit_format(const char *arg)
return CMIT_FMT_SHORT;
if (!strcmp(arg, "=full"))
return CMIT_FMT_FULL;
if (!strcmp(arg, "=fuller"))
return CMIT_FMT_FULLER;
if (!strcmp(arg, "=oneline"))
return CMIT_FMT_ONELINE;
die("invalid --pretty format");
@ -361,6 +363,7 @@ static int add_user_info(const char *what, enum cmit_fmt fmt, char *buf, const c
int namelen;
unsigned long time;
int tz, ret;
const char *filler = " ";
if (fmt == CMIT_FMT_ONELINE)
return 0;
@ -371,9 +374,20 @@ static int add_user_info(const char *what, enum cmit_fmt fmt, char *buf, const c
time = strtoul(date, &date, 10);
tz = strtol(date, NULL, 10);
ret = sprintf(buf, "%s: %.*s\n", what, namelen, line);
if (fmt == CMIT_FMT_MEDIUM)
ret = sprintf(buf, "%s: %.*s%.*s\n", what,
(fmt == CMIT_FMT_FULLER) ? 4 : 0,
filler, namelen, line);
switch (fmt) {
case CMIT_FMT_MEDIUM:
ret += sprintf(buf + ret, "Date: %s\n", show_date(time, tz));
break;
case CMIT_FMT_FULLER:
ret += sprintf(buf + ret, "%sDate: %s\n", what, show_date(time, tz));
break;
default:
/* notin' */
break;
}
return ret;
}
@ -448,12 +462,21 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt, const char *msg, unsigned l
die("bad parent line in commit");
offset += add_parent_info(fmt, buf + offset, line, ++parents);
}
/*
* MEDIUM == DEFAULT shows only author with dates.
* FULL shows both authors but not dates.
* FULLER shows both authors and dates.
*/
if (!memcmp(line, "author ", 7))
offset += add_user_info("Author", fmt, buf + offset, line + 7);
if (fmt == CMIT_FMT_FULL) {
if (!memcmp(line, "committer ", 10))
offset += add_user_info("Commit", fmt, buf + offset, line + 10);
}
offset += add_user_info("Author", fmt,
buf + offset,
line + 7);
if (!memcmp(line, "committer ", 10) &&
(fmt == CMIT_FMT_FULL || fmt == CMIT_FMT_FULLER))
offset += add_user_info("Commit", fmt,
buf + offset,
line + 10);
continue;
}
@ -513,7 +536,7 @@ int count_parents(struct commit * commit)
void sort_in_topological_order(struct commit_list ** list)
{
struct commit_list * next = *list;
struct commit_list * work = NULL;
struct commit_list * work = NULL, **insert;
struct commit_list ** pptr = list;
struct sort_node * nodes;
struct sort_node * next_nodes;
@ -557,11 +580,12 @@ void sort_in_topological_order(struct commit_list ** list)
* the tips serve as a starting set for the work queue.
*/
next=*list;
insert = &work;
while (next) {
struct sort_node * node = (struct sort_node *)next->item->object.util;
if (node->indegree == 0) {
commit_list_insert(next->item, &work);
insert = &commit_list_insert(next->item, insert)->next;
}
next=next->next;
}

View File

@ -43,6 +43,7 @@ enum cmit_fmt {
CMIT_FMT_DEFAULT = CMIT_FMT_MEDIUM,
CMIT_FMT_SHORT,
CMIT_FMT_FULL,
CMIT_FMT_FULLER,
CMIT_FMT_ONELINE,
};

38
debian/changelog vendored
View File

@ -1,3 +1,27 @@
git-core (0.99.9i-0) unstable; urgency=low
* GIT 0.99.9i aka 1.0rc2
-- Junio C Hamano <junkio@cox.net> Mon, 14 Nov 2005 18:38:27 -0800
git-core (0.99.9h-0) unstable; urgency=low
* GIT 0.99.9h
-- Junio C Hamano <junkio@cox.net> Fri, 11 Nov 2005 22:33:18 -0800
git-core (0.99.9g-0) unstable; urgency=low
* GIT 0.99.9g
-- Junio C Hamano <junkio@cox.net> Wed, 9 Nov 2005 21:01:55 -0800
git-core (0.99.9f-0) unstable; urgency=low
* GIT 0.99.9f
-- Junio C Hamano <junkio@cox.net> Tue, 8 Nov 2005 01:21:52 -0800
git-core (0.99.9e-0) unstable; urgency=low
* GIT 0.99.9e
@ -28,6 +52,20 @@ git-core (0.99.9a-0) unstable; urgency=low
-- Junio C Hamano <junkio@cox.net> Sun, 30 Oct 2005 15:03:32 -0800
git-core (0.99.9.GIT-2) unstable; urgency=low
* Build Dependency did not include libexpat-dev.
-- Junio C Hamano <junkio@cox.net> Sun, 13 Nov 2005 01:55:34 -0800
git-core (0.99.9.GIT-1) unstable; urgency=low
* Do not scatter txt and html documentation into feature
subpackages. Do place man pages into them.
* Capture more cvs stuff into git-cvs package.
-- Junio C Hamano <junkio@cox.net> Tue, 8 Nov 2005 01:19:06 -0800
git-core (0.99.9.GIT-0) unstable; urgency=low
* Test Build.

4
debian/control vendored
View File

@ -2,7 +2,7 @@ Source: git-core
Section: devel
Priority: optional
Maintainer: Junio C Hamano <junkio@cox.net>
Build-Depends-Indep: libz-dev, libssl-dev, libcurl3-dev|libcurl3-gnutls-dev|libcurl3-openssl-dev, asciidoc (>= 6.0.3), xmlto, debhelper (>= 4.0.0), bc
Build-Depends-Indep: libz-dev, libssl-dev, libcurl3-dev|libcurl3-gnutls-dev|libcurl3-openssl-dev, asciidoc (>= 7), xmlto, debhelper (>= 4.0.0), bc, libexpat-dev
Standards-Version: 3.6.1
Package: git-core
@ -48,7 +48,7 @@ Description: The git content addressable filesystem, GNUArch interoperability
Package: git-cvs
Architecture: all
Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}, git-core
Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}, git-core, cvsps (>= 2.1)
Suggests: cvs
Description: The git content addressable filesystem, CVS interoperability
This package contains 'git-cvsimport', to import development history from

View File

@ -1,2 +1,2 @@
/usr/bin/git-archimport
/usr/share/doc/git-core/git-archimport.*
/usr/bin/git-arch*
/usr/share/man/*/git-arch*

View File

@ -6,6 +6,8 @@ Section: Devel
Format: HTML
Index: /usr/share/doc/git-core/git.html
Files: /usr/share/doc/git-core/*.html
/usr/share/doc/git-core/*/*.html
Format: text
Files: /usr/share/doc/git-core/git.txt*
Files: /usr/share/doc/git-core/*.txt
/usr/share/doc/git-core/*/*.txt

View File

@ -1,2 +1,2 @@
/usr/bin/git-cvsimport
/usr/share/doc/git-core/git-cvsimport.*
/usr/bin/git-cvs*
/usr/share/man/*/git-cvs*

View File

@ -2,6 +2,3 @@
/usr/share/doc/git-core/*.html
/usr/share/doc/git-core/*/*.html
/usr/share/doc/git-core/*/*.txt

View File

@ -1,2 +1,2 @@
/usr/bin/git-send-email
/usr/share/doc/git-core/git-send-email.*
/usr/share/man/*/git-send-email.*

View File

@ -1,2 +1,2 @@
/usr/bin/git-svnimport
/usr/share/doc/git-core/git-svnimport.*
/usr/bin/git-svn*
/usr/share/man/*/git-svn*

1
debian/git-tk.files vendored
View File

@ -1,3 +1,2 @@
/usr/bin/gitk
/usr/share/man/man1/gitk.*
/usr/share/doc/git-core/gitk.*

View File

@ -3,6 +3,7 @@
#include "commit.h"
static int show_root_diff = 0;
static int no_commit_id = 0;
static int verbose_header = 0;
static int ignore_merges = 1;
static int read_stdin = 0;
@ -29,7 +30,8 @@ static int call_diff_flush(void)
return 0;
}
if (header) {
printf("%s%c", header, diff_options.line_termination);
if (!no_commit_id)
printf("%s%c", header, diff_options.line_termination);
header = NULL;
}
diff_flush(&diff_options);
@ -231,6 +233,10 @@ int main(int argc, const char **argv)
show_root_diff = 1;
continue;
}
if (!strcmp(arg, "--no-commit-id")) {
no_commit_id = 1;
continue;
}
usage(diff_tree_usage);
}
if (diff_options.output_format == DIFF_FORMAT_PATCH)

View File

@ -224,29 +224,33 @@ do
git-stripspace < "$dotest/msg" > "$dotest/msg-clean"
;;
esac
resume=
GIT_AUTHOR_NAME="$(sed -n '/^Author/ s/Author: //p' "$dotest/info")"
GIT_AUTHOR_EMAIL="$(sed -n '/^Email/ s/Email: //p' "$dotest/info")"
GIT_AUTHOR_DATE="$(sed -n '/^Date/ s/Date: //p' "$dotest/info")"
SUBJECT="$(sed -n '/^Subject/ s/Subject: //p' "$dotest/info")"
export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE
SUBJECT="$(sed -n '/^Subject/ s/Subject: //p' "$dotest/info")"
case "$keep_subject" in -k) SUBJECT="[PATCH] $SUBJECT" ;; esac
if test '' != "$SIGNOFF"
then
case "$resume" in
'')
if test '' != "$SIGNOFF"
then
LAST_SIGNED_OFF_BY=`
sed -ne '/^Signed-off-by: /p' "$dotest/msg-clean" |
tail -n 1
sed -ne '/^Signed-off-by: /p' \
"$dotest/msg-clean" |
tail -n 1
`
ADD_SIGNOFF=$(test "$LAST_SIGNED_OFF_BY" = "$SIGNOFF" || {
ADD_SIGNOFF=`
test "$LAST_SIGNED_OFF_BY" = "$SIGNOFF" || {
test '' = "$LAST_SIGNED_OFF_BY" && echo
echo "$SIGNOFF"
})
else
}`
else
ADD_SIGNOFF=
fi
{
fi
{
echo "$SUBJECT"
if test -s "$dotest/msg-clean"
then
@ -257,8 +261,11 @@ do
then
echo "$ADD_SIGNOFF"
fi
} >"$dotest/final-commit"
} >"$dotest/final-commit"
;;
esac
resume=
if test "$interactive" = t
then
test -t 0 ||

View File

@ -565,6 +565,11 @@ sub parselog {
next if $t =~ m!\{arch\}/!;
next if $t =~ m!\.arch-ids/!;
next if $t =~ m!\.arch-inventory$!;
# tla cat-archive-log will give us filenames with spaces as file\(sp)name - why?
# we can assume that any filename with \ indicates some pika escaping that we want to get rid of.
if ($t =~ /\\/ ){
$t = `tla escape --unescaped '$t'`;
}
push (@tmp, shell_quote($t));
}
@$ref = @tmp;

View File

@ -102,6 +102,5 @@ rev=$(git-rev-parse --verify "$head") || exit
git-check-ref-format "heads/$branchname" ||
die "we do not like '$branchname' as a branch name."
leading=`expr "refs/heads/$branchname" : '\(.*\)/'` &&
mkdir -p "$GIT_DIR/$leading" &&
echo $rev > "$GIT_DIR/refs/heads/$branchname"
git update-ref "refs/heads/$branchname" $rev

View File

@ -9,7 +9,7 @@
unset CDPATH
usage() {
echo >&2 "* git clone [-l [-s]] [-q] [-u <upload-pack>] [-n] <repo> <dir>"
echo >&2 "* git clone [-l [-s]] [-q] [-u <upload-pack>] [-n] <repo> [<dir>]"
exit 1
}
@ -23,7 +23,7 @@ fi
http_fetch () {
# $1 = Remote, $2 = Local
curl -nsf $curl_extra_args "$1" >"$2"
curl -nsfL $curl_extra_args "$1" >"$2"
}
clone_dumb_http () {
@ -96,7 +96,10 @@ if base=$(get_repo_base "$repo"); then
fi
dir="$2"
mkdir "$dir" &&
# Try using "humanish" part of source repo if user didn't specify one
[ -z "$dir" ] && dir=$(echo "$repo" | sed -e 's|/$||' -e 's|:*/*\.git$||' -e 's|.*/||g')
[ -e "$dir" ] && echo "$dir already exists." && usage
mkdir -p "$dir" &&
D=$(
(cd "$dir" && git-init-db && pwd)
) &&
@ -163,7 +166,7 @@ yes,yes)
rm -f "$D/.git/TMP_ALT"
if test -f "$D/.git/TMP_ALT"
then
( cd $D &&
( cd "$D" &&
. git-parse-remote &&
resolve_alternates "$repo" <"./.git/TMP_ALT" ) |
while read alt
@ -191,7 +194,7 @@ yes,yes)
;;
esac
cd $D || exit
cd "$D" || exit
if test -f ".git/HEAD"
then

View File

@ -184,7 +184,7 @@ then
}
'
set_author_env=`git-cat-file commit "$use_commit" |
sed -ne "$pick_author_script"`
LANG=C LC_ALL=C sed -ne "$pick_author_script"`
eval "$set_author_env"
export GIT_AUTHOR_NAME
export GIT_AUTHOR_EMAIL

View File

@ -1,4 +1,4 @@
# Pass --without docs to rpmbuild if you don't want the documetnation
# Pass --without docs to rpmbuild if you don't want the documentation
Name: git-core
Version: @@VERSION@@
Release: 1%{?dist}
@ -7,9 +7,9 @@ License: GPL
Group: Development/Tools
URL: http://kernel.org/pub/software/scm/git/
Source: http://kernel.org/pub/software/scm/git/%{name}-%{version}.tar.gz
BuildRequires: zlib-devel, openssl-devel, curl-devel %{!?_without_docs:, xmlto, asciidoc > 6.0.3}
BuildRequires: zlib-devel >= 1.2, openssl-devel, curl-devel, expat-devel %{!?_without_docs:, xmlto, asciidoc > 6.0.3}
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
Requires: zlib >= 1.2, rsync, rcs, curl, less, openssh-clients, python >= 2.3, tk >= 8.4
Requires: zlib >= 1.2, rsync, rcs, curl, less, openssh-clients, python >= 2.3, expat
%description
This is a stupid (but extremely fast) directory content manager. It
@ -19,32 +19,113 @@ distributed source code management system. This package includes
rudimentary tools that can be used as a SCM, but you should look
elsewhere for tools for ordinary humans layered on top of this.
%package svn
Summary: Git tools for importing Subversion repositories
Group: Development/Tools
Requires: git-core = %{version}-%{release}, subversion
%description svn
Git tools for importing Subversion repositories.
%package cvs
Summary: Git tools for importing CVS repositories
Group: Development/Tools
Requires: git-core = %{version}-%{release}, cvs, cvsps
%description cvs
Git tools for importing CVS repositories.
%package arch
Summary: Git tools for importing Arch repositories
Group: Development/Tools
Requires: git-core = %{version}-%{release}, tla
%description arch
Git tools for importing Arch repositories.
%package email
Summary: Git tools for sending email
Group: Development/Tools
Requires: git-core = %{version}-%{release}
%description email
Git tools for sending email.
%package tk
Summary: Git revision tree visualiser ('gitk')
Group: Development/Tools
Requires: git-core = %{version}-%{release}, tk >= 8.4
%description tk
Git revision tree visualiser ('gitk')
%prep
%setup -q
%build
make %{_smp_mflags} CFLAGS="$RPM_OPT_FLAGS" WITH_OWN_SUBPROCESS_PY=YesPlease \
make %{_smp_mflags} CFLAGS="$RPM_OPT_FLAGS" WITH_OWN_SUBPROCESS_PY=YesPlease WITH_SEND_EMAIL=1 \
prefix=%{_prefix} all %{!?_without_docs: doc}
%install
rm -rf $RPM_BUILD_ROOT
make %{_smp_mflags} DESTDIR=$RPM_BUILD_ROOT WITH_OWN_SUBPROCESS_PY=YesPlease \
make %{_smp_mflags} DESTDIR=$RPM_BUILD_ROOT WITH_OWN_SUBPROCESS_PY=YesPlease WITH_SEND_EMAIL=1 \
prefix=%{_prefix} mandir=%{_mandir} \
install %{!?_without_docs: install-doc}
(find $RPM_BUILD_ROOT%{_bindir} -type f | grep -vE "arch|svn|cvs|email|gitk" | sed -e s@^$RPM_BUILD_ROOT@@) > bin-man-doc-files
%if %{!?_without_docs:1}0
(find $RPM_BUILD_ROOT%{_mandir} $RPM_BUILD_ROOT/Documentation -type f | grep -vE "arch|svn|git-cvs|email|gitk" | sed -e s@^$RPM_BUILD_ROOT@@ -e 's/$/*/' ) >> bin-man-doc-files
%endif
%clean
rm -rf $RPM_BUILD_ROOT
%files
%files svn
%defattr(-,root,root)
%{_bindir}/*svn*
%doc Documentation/*svn*.txt
%{!?_without_docs: %{_mandir}/man1/*svn*.1*}
%{!?_without_docs: %doc Documentation/*svn*.html }
%files cvs
%defattr(-,root,root)
%doc Documentation/*git-cvs*.txt
%{_bindir}/*cvs*
%{!?_without_docs: %{_mandir}/man1/*cvs*.1*}
%{!?_without_docs: %doc Documentation/*git-cvs*.html }
%files arch
%defattr(-,root,root)
%doc Documentation/*arch*.txt
%{_bindir}/*arch*
%{!?_without_docs: %{_mandir}/man1/*arch*.1*}
%{!?_without_docs: %doc Documentation/*arch*.html }
%files email
%defattr(-,root,root)
%doc Documentation/*email*.txt
%{_bindir}/*email*
%{!?_without_docs: %{_mandir}/man1/*email*.1*}
%{!?_without_docs: %doc Documentation/*email*.html }
%files tk
%defattr(-,root,root)
%doc Documentation/*gitk*.txt
%{_bindir}/*gitk*
%{!?_without_docs: %{_mandir}/man1/*gitk*.1*}
%{!?_without_docs: %doc Documentation/*gitk*.html }
%files -f bin-man-doc-files
%defattr(-,root,root)
%{_bindir}/*
%{_datadir}/git-core/
%doc README COPYING Documentation/*.txt
%{!?_without_docs: %doc Documentation/*.html }
%{!?_without_docs: %{_mandir}/man1/*.1*}
%{!?_without_docs: %{_mandir}/man7/*.7*}
%changelog
* Thu Nov 10 2005 Chris Wright <chrisw@osdl.org> 0.99.9g-1
- zlib dependency fix
- Minor cleanups from split
- Move arch import to separate package as well
* Tue Sep 27 2005 Jim Radford <radford@blackbean.org>
- Move programs with non-standard dependencies (svn, cvs, email)
into separate packages
* Tue Sep 27 2005 H. Peter Anvin <hpa@zytor.com>
- parallelize build
- COPTS -> CFLAGS

225
git-cvsexportcommit.perl Executable file
View File

@ -0,0 +1,225 @@
#!/usr/bin/perl -w
use strict;
use Getopt::Std;
use File::Temp qw(tempdir);
use Data::Dumper;
unless ($ENV{GIT_DIR} && -r $ENV{GIT_DIR}){
die "GIT_DIR is not defined or is unreadable";
}
our ($opt_h, $opt_p, $opt_v, $opt_c );
getopt('hpvc');
$opt_h && usage();
die "Need at least one commit identifier!" unless @ARGV;
# setup a tempdir
our ($tmpdir, $tmpdirname) = tempdir('git-cvsapplycommit-XXXXXX',
TMPDIR => 1,
CLEANUP => 1);
print Dumper(@ARGV);
# resolve target commit
my $commit;
$commit = pop @ARGV;
$commit = `git-rev-parse --verify "$commit"^0`;
chomp $commit;
if ($?) {
die "The commit reference $commit did not resolve!";
}
# resolve what parent we want
my $parent;
if (@ARGV) {
$parent = pop @ARGV;
$parent = `git-rev-parse --verify "$parent"^0"`;
chomp $parent;
if ($?) {
die "The parent reference did not resolve!";
}
}
# find parents from the commit itself
my @commit = `git-cat-file commit $commit`;
my @parents;
foreach my $p (@commit) {
if ($p =~ m/^$/) { # end of commit headers, we're done
last;
}
if ($p =~ m/^parent (\w{40})$/) { # found a parent
push @parents, $1;
}
}
if ($parent) {
# double check that it's a valid parent
foreach my $p (@parents) {
my $found;
if ($p eq $parent) {
$found = 1;
last;
}; # found it
die "Did not find $parent in the parents for this commit!";
}
} else { # we don't have a parent from the cmdline...
if (@parents == 1) { # it's safe to get it from the commit
$parent = $parents[0];
} else { # or perhaps not!
die "This commit has more than one parent -- please name the parent you want to use explicitly";
}
}
$opt_v && print "Applying to CVS commit $commit from parent $parent\n";
# grab the commit message
`git-cat-file commit $commit | sed -e '1,/^\$/d' > .msg`;
$? && die "Error extraction the commit message";
my (@afiles, @dfiles, @mfiles);
my @files = `git-diff-tree -r $parent $commit`;
print @files;
$? && die "Error in git-diff-tree";
foreach my $f (@files) {
chomp $f;
my @fields = split(m/\s+/, $f);
if ($fields[4] eq 'A') {
push @afiles, $fields[5];
}
if ($fields[4] eq 'M') {
push @mfiles, $fields[5];
}
if ($fields[4] eq 'R') {
push @dfiles, $fields[5];
}
}
$opt_v && print "The commit affects:\n ";
$opt_v && print join ("\n ", @afiles,@mfiles,@dfiles) . "\n\n";
undef @files; # don't need it anymore
# check that the files are clean and up to date according to cvs
my $dirty;
foreach my $f (@afiles, @mfiles, @dfiles) {
# TODO:we need to handle removed in cvs and/or new (from git)
my $status = `cvs -q status "$f" | grep '^File: '`;
unless ($status =~ m/Status: Up-to-date$/) {
$dirty = 1;
warn "File $f not up to date in your CVS checkout!\n";
}
}
if ($dirty) {
die "Exiting: your CVS tree is not clean for this merge.";
}
###
### NOTE: if you are planning to die() past this point
### you MUST call cleanupcvs(@files) before die()
###
print "'Patching' binary files\n";
my @bfiles = `git-diff-tree -p $parent $commit | grep '^Binary'`;
@bfiles = map { chomp } @bfiles;
foreach my $f (@bfiles) {
# check that the file in cvs matches the "old" file
# extract the file to $tmpdir and comparre with cmp
my $tree = `git-rev-parse $parent^{tree} `;
chomp $tree;
my $blob = `git-ls-tree $tree "$f" | cut -f 1 | cut -d ' ' -f 3`;
chomp $blob;
`git-cat-file blob $blob > $tmpdir/blob`;
`cmp -q $f $tmpdir/blob`;
if ($?) {
warn "Binary file $f in CVS does not match parent.\n";
$dirty = 1;
next;
}
# replace with the new file
`git-cat-file blob $blob > $f`;
# TODO: something smart with file modes
}
if ($dirty) {
cleanupcvs(@files);
die "Exiting: Binary files in CVS do not match parent";
}
## apply non-binary changes
my $fuzz = $opt_p ? 0 : 2;
print "Patching non-binary files\n";
print `(git-diff-tree -p $parent -p $commit | patch -p1 -F $fuzz ) 2>&1`;
my $dirtypatch = 0;
if (($? >> 8) == 2) {
cleanupcvs(@files);
die "Exiting: Patch reported serious trouble -- you will have to apply this patch manually";
} elsif (($? >> 8) == 1) { # some hunks failed to apply
$dirtypatch = 1;
}
foreach my $f (@afiles) {
`cvs add $f`;
if ($?) {
$dirty = 1;
warn "Failed to cvs add $f -- you may need to do it manually";
}
}
foreach my $f (@dfiles) {
`cvs rm -f $f`;
if ($?) {
$dirty = 1;
warn "Failed to cvs rm -f $f -- you may need to do it manually";
}
}
print "Commit to CVS\n";
my $commitfiles = join(' ', @afiles, @mfiles, @dfiles);
my $cmd = "cvs commit -F .msg $commitfiles";
if ($dirtypatch) {
print "NOTE: One or more hunks failed to apply cleanly.\n";
print "Resolve the conflicts and then commit using:n";
print "\n $cmd\n\n";
exit;
}
if ($opt_c) {
print "Autocommit\n $cmd\n";
print `cvs commit -F .msg $commitfiles 2>&1`;
if ($?) {
cleanupcvs(@files);
die "Exiting: The commit did not succeed";
}
print "Committed successfully to CVS\n";
} else {
print "Ready for you to commit, just run:\n\n $cmd\n";
}
sub usage {
print STDERR <<END;
Usage: GIT_DIR=/path/to/.gi ${\basename $0} # fetch/update GIT from CVS
[-h] [-p] [ parent ] commit
END
exit(1);
}
# ensure cvs is clean before we die
sub cleanupcvs {
my @files = @_;
foreach my $f (@files) {
`cvs -q update -C "$f"`;
if ($?) {
warn "Warning! Failed to cleanup state of $f\n";
}
}
}

View File

@ -230,7 +230,7 @@ do
$u =~ s{([^-a-zA-Z0-9/.])}{sprintf"%%%02x",ord($1)}eg;
print "$u";
' "$remote_name")
head=$(curl -nsf $curl_extra_args "$remote/$remote_name_quoted") &&
head=$(curl -nsfL $curl_extra_args "$remote/$remote_name_quoted") &&
expr "$head" : "$_x40\$" >/dev/null ||
die "Failed to fetch $remote_name from $remote"
echo >&2 Fetching "$remote_name from $remote" using http

View File

@ -8,6 +8,7 @@
usage () {
echo >&2 "usage: $0"' [-n] [-o dir | --stdout] [--keep-subject] [--mbox]
[--check] [--signoff] [-<diff options>...]
[--help]
( from..to ... | upstream [ our-head ] )
Prepare each commit with its patch since our-head forked from upstream,
@ -63,6 +64,9 @@ do
--output-directo|--output-director|--output-directory)
case "$#" in 1) usage ;; esac; shift
outdir="$1" ;;
-h|--h|--he|--hel|--help)
usage
;;
-*' '* | -*"$LF"* | -*' '*)
# Ignore diff option that has whitespace for now.
;;
@ -197,7 +201,7 @@ process_one () {
;;
esac
eval "$(sed -ne "$whosepatchScript" $commsg)"
eval "$(LANG=C LC_ALL=C sed -ne "$whosepatchScript" $commsg)"
test "$author,$au" = ",$me" || {
mailScript="$mailScript"'
a\

23
git-lost-found.sh Executable file
View File

@ -0,0 +1,23 @@
#!/bin/sh
. git-sh-setup || die "Not a git archive."
laf="$GIT_DIR/lost-found"
rm -fr "$laf" && mkdir -p "$laf/commit" "$laf/other" || exit
git fsck-objects |
while read dangling type sha1
do
case "$dangling" in
dangling)
if git-rev-parse --verify "$sha1^0" >/dev/null 2>/dev/null
then
dir="$laf/commit"
git-show-branch "$sha1"
else
dir="$laf/other"
fi
echo "$sha1" >"$dir/$sha1"
;;
esac
done

View File

@ -5,6 +5,9 @@
# Resolve two or more trees.
#
LF='
'
# The first parameters up to -- are merge bases; the rest are heads.
bases= head= remotes= sep_seen=
for arg
@ -42,14 +45,18 @@ CNT=1 ;# counting our head
NON_FF_MERGE=0
for SHA1 in $remotes
do
common=$(git-merge-base $MRC $SHA1) ||
common=$(git-merge-base --all $MRC $SHA1) ||
die "Unable to find common commit with $SHA1"
if test "$common" = $SHA1
then
case "$common" in
?*"$LF"?*)
die "Not trivially mergeable."
;;
$SHA1)
echo "Already up-to-date with $SHA1"
continue
fi
;;
esac
CNT=`expr $CNT + 1`
PARENT="$PARENT -p $SHA1"
@ -79,7 +86,15 @@ do
exit 2 ; # Automatic merge failed; should not be doing Octopus
next=$(git-write-tree 2>/dev/null)
fi
MRC=$common
# We have merged the other branch successfully. Ideally
# we could implement OR'ed heads in merge-base, and keep
# a list of commits we have merged so far in MRC to feed
# them to merge-base, but we approximate it by keep using
# the current MRC. We used to update it to $common, which
# was incorrectly doing AND'ed merge-base here, which was
# unneeded.
MRT=$next
done

View File

@ -40,7 +40,7 @@ case "${1:-.}${2:-.}${3:-.}" in
;;
#
# Added in both (check for same permissions).
# Added in both, identically (check for same permissions).
#
".$3$2")
if [ "$6" != "$7" ]; then
@ -56,10 +56,27 @@ case "${1:-.}${2:-.}${3:-.}" in
#
# Modified in both, but differently.
#
"$1$2$3")
echo "Auto-merging $4."
orig=`git-unpack-file $1`
"$1$2$3" | ".$2$3")
src2=`git-unpack-file $3`
case "$1" in
'')
echo "Added $4 in both, but differently."
# This extracts OUR file in $orig, and uses git-apply to
# remove lines that are unique to ours.
orig=`git-unpack-file $2`
sz0=`wc -c <"$orig"`
diff -u -La/$orig -Lb/$orig $orig $src2 | git-apply --no-add
sz1=`wc -c <"$orig"`
# If we do not have enough common material, it is not
# worth trying two-file merge using common subsections.
expr "$sz0" \< "$sz1" \* 2 >/dev/null || : >$orig
;;
*)
echo "Auto-merging $4."
orig=`git-unpack-file $1`
;;
esac
# We reset the index to the first branch, making
# git-diff-file useful
@ -73,6 +90,9 @@ case "${1:-.}${2:-.}${3:-.}" in
echo "ERROR: Permissions conflict: $5->$6,$7."
ret=1
fi
if [ "$1" = '' ]; then
ret=1
fi
if [ $ret -ne 0 ]; then
echo "ERROR: Merge conflict in $4."

View File

@ -1,4 +1,7 @@
#!/usr/bin/python
#
# Copyright (C) 2005 Fredrik Kuivinen
#
import sys, math, random, os, re, signal, tempfile, stat, errno, traceback
from heapq import heappush, heappop
@ -7,6 +10,11 @@ from sets import Set
sys.path.append('''@@GIT_PYTHON_PATH@@''')
from gitMergeCommon import *
outputIndent = 0
def output(*args):
sys.stdout.write(' '*outputIndent)
printList(args)
originalIndexFile = os.environ.get('GIT_INDEX_FILE',
os.environ.get('GIT_DIR', '.git') + '/index')
temporaryIndexFile = os.environ.get('GIT_DIR', '.git') + \
@ -41,27 +49,27 @@ def merge(h1, h2, branch1Name, branch2Name, graph, callDepth=0):
assert(isinstance(h1, Commit) and isinstance(h2, Commit))
assert(isinstance(graph, Graph))
def infoMsg(*args):
sys.stdout.write(' '*callDepth)
printList(args)
global outputIndent
infoMsg('Merging:')
infoMsg(h1)
infoMsg(h2)
output('Merging:')
output(h1)
output(h2)
sys.stdout.flush()
ca = getCommonAncestors(graph, h1, h2)
infoMsg('found', len(ca), 'common ancestor(s):')
output('found', len(ca), 'common ancestor(s):')
for x in ca:
infoMsg(x)
output(x)
sys.stdout.flush()
mergedCA = ca[0]
for h in ca[1:]:
outputIndent = callDepth+1
[mergedCA, dummy] = merge(mergedCA, h,
'Temporary shared merge branch 1',
'Temporary shared merge branch 2',
'Temporary merge branch 1',
'Temporary merge branch 2',
graph, callDepth+1)
outputIndent = callDepth
assert(isinstance(mergedCA, Commit))
global cacheOnly
@ -116,7 +124,7 @@ def mergeTrees(head, merge, common, branch1Name, branch2Name):
assert(isSha(head) and isSha(merge) and isSha(common))
if common == merge:
print 'Already uptodate!'
output('Already uptodate!')
return [head, True]
if cacheOnly:
@ -207,7 +215,7 @@ def mergeFile(oPath, oSha, oMode, aPath, aSha, aMode, bPath, bSha, bMode,
os.unlink(orig)
os.unlink(src1)
os.unlink(src2)
clean = (code == 0)
else:
assert(stat.S_ISLNK(aMode) and stat.S_ISLNK(bMode))
@ -295,13 +303,14 @@ def uniquePath(path, branch):
else:
raise
newPath = path + '_' + branch
branch = branch.replace('/', '_')
newPath = path + '~' + branch
suffix = 0
while newPath in currentFileSet or \
newPath in currentDirectorySet or \
fileExists(newPath):
suffix += 1
newPath = path + '_' + branch + '_' + str(suffix)
newPath = path + '~' + branch + '_' + str(suffix)
currentFileSet.add(newPath)
return newPath
@ -553,23 +562,24 @@ def processRenames(renamesA, renamesB, branchNameA, branchNameB):
ren2.processed = True
if ren1.dstName != ren2.dstName:
print 'CONFLICT (rename/rename): Rename', \
fmtRename(path, ren1.dstName), 'in branch', branchName1, \
'rename', fmtRename(path, ren2.dstName), 'in', branchName2
output('CONFLICT (rename/rename): Rename',
fmtRename(path, ren1.dstName), 'in branch', branchName1,
'rename', fmtRename(path, ren2.dstName), 'in',
branchName2)
cleanMerge = False
if ren1.dstName in currentDirectorySet:
dstName1 = uniquePath(ren1.dstName, branchName1)
print ren1.dstName, 'is a directory in', branchName2, \
'adding as', dstName1, 'instead.'
output(ren1.dstName, 'is a directory in', branchName2,
'adding as', dstName1, 'instead.')
removeFile(False, ren1.dstName)
else:
dstName1 = ren1.dstName
if ren2.dstName in currentDirectorySet:
dstName2 = uniquePath(ren2.dstName, branchName2)
print ren2.dstName, 'is a directory in', branchName1, \
'adding as', dstName2, 'instead.'
output(ren2.dstName, 'is a directory in', branchName1,
'adding as', dstName2, 'instead.')
removeFile(False, ren2.dstName)
else:
dstName2 = ren1.dstName
@ -577,18 +587,21 @@ def processRenames(renamesA, renamesB, branchNameA, branchNameB):
updateFile(False, ren1.dstSha, ren1.dstMode, dstName1)
updateFile(False, ren2.dstSha, ren2.dstMode, dstName2)
else:
print 'Renaming', fmtRename(path, ren1.dstName)
[resSha, resMode, clean, merge] = \
mergeFile(ren1.srcName, ren1.srcSha, ren1.srcMode,
ren1.dstName, ren1.dstSha, ren1.dstMode,
ren2.dstName, ren2.dstSha, ren2.dstMode,
branchName1, branchName2)
if merge or not clean:
output('Renaming', fmtRename(path, ren1.dstName))
if merge:
print 'Auto-merging', ren1.dstName
output('Auto-merging', ren1.dstName)
if not clean:
print 'CONFLICT (content): merge conflict in', ren1.dstName
output('CONFLICT (content): merge conflict in',
ren1.dstName)
cleanMerge = False
if not cacheOnly:
@ -612,25 +625,25 @@ def processRenames(renamesA, renamesB, branchNameA, branchNameB):
if ren1.dstName in currentDirectorySet:
newPath = uniquePath(ren1.dstName, branchName1)
print 'CONFLICT (rename/directory): Rename', \
fmtRename(ren1.srcName, ren1.dstName), 'in', branchName1,\
'directory', ren1.dstName, 'added in', branchName2
print 'Renaming', ren1.srcName, 'to', newPath, 'instead'
output('CONFLICT (rename/directory): Rename',
fmtRename(ren1.srcName, ren1.dstName), 'in', branchName1,
'directory', ren1.dstName, 'added in', branchName2)
output('Renaming', ren1.srcName, 'to', newPath, 'instead')
cleanMerge = False
removeFile(False, ren1.dstName)
updateFile(False, ren1.dstSha, ren1.dstMode, newPath)
elif srcShaOtherBranch == None:
print 'CONFLICT (rename/delete): Rename', \
fmtRename(ren1.srcName, ren1.dstName), 'in', \
branchName1, 'and deleted in', branchName2
output('CONFLICT (rename/delete): Rename',
fmtRename(ren1.srcName, ren1.dstName), 'in',
branchName1, 'and deleted in', branchName2)
cleanMerge = False
updateFile(False, ren1.dstSha, ren1.dstMode, ren1.dstName)
elif dstShaOtherBranch:
newPath = uniquePath(ren1.dstName, branchName2)
print 'CONFLICT (rename/add): Rename', \
fmtRename(ren1.srcName, ren1.dstName), 'in', \
branchName1 + '.', ren1.dstName, 'added in', branchName2
print 'Adding as', newPath, 'instead'
output('CONFLICT (rename/add): Rename',
fmtRename(ren1.srcName, ren1.dstName), 'in',
branchName1 + '.', ren1.dstName, 'added in', branchName2)
output('Adding as', newPath, 'instead')
updateFile(False, dstShaOtherBranch, dstModeOtherBranch, newPath)
cleanMerge = False
tryMerge = True
@ -638,12 +651,12 @@ def processRenames(renamesA, renamesB, branchNameA, branchNameB):
dst2 = renames2.getDst(ren1.dstName)
newPath1 = uniquePath(ren1.dstName, branchName1)
newPath2 = uniquePath(dst2.dstName, branchName2)
print 'CONFLICT (rename/rename): Rename', \
fmtRename(ren1.srcName, ren1.dstName), 'in', \
branchName1+'. Rename', \
fmtRename(dst2.srcName, dst2.dstName), 'in', branchName2
print 'Renaming', ren1.srcName, 'to', newPath1, 'and', \
dst2.srcName, 'to', newPath2, 'instead'
output('CONFLICT (rename/rename): Rename',
fmtRename(ren1.srcName, ren1.dstName), 'in',
branchName1+'. Rename',
fmtRename(dst2.srcName, dst2.dstName), 'in', branchName2)
output('Renaming', ren1.srcName, 'to', newPath1, 'and',
dst2.srcName, 'to', newPath2, 'instead')
removeFile(False, ren1.dstName)
updateFile(False, ren1.dstSha, ren1.dstMode, newPath1)
updateFile(False, dst2.dstSha, dst2.dstMode, newPath2)
@ -653,18 +666,21 @@ def processRenames(renamesA, renamesB, branchNameA, branchNameB):
tryMerge = True
if tryMerge:
print 'Renaming', fmtRename(ren1.srcName, ren1.dstName)
[resSha, resMode, clean, merge] = \
mergeFile(ren1.srcName, ren1.srcSha, ren1.srcMode,
ren1.dstName, ren1.dstSha, ren1.dstMode,
ren1.srcName, srcShaOtherBranch, srcModeOtherBranch,
branchName1, branchName2)
if merge or not clean:
output('Renaming', fmtRename(ren1.srcName, ren1.dstName))
if merge:
print 'Auto-merging', ren1.dstName
output('Auto-merging', ren1.dstName)
if not clean:
print 'CONFLICT (rename/modify): Merge conflict in', ren1.dstName
output('CONFLICT (rename/modify): Merge conflict in',
ren1.dstName)
cleanMerge = False
if not cacheOnly:
@ -709,21 +725,21 @@ def processEntry(entry, branch1Name, branch2Name):
(not aSha and bSha == oSha):
# Deleted in both or deleted in one and unchanged in the other
if aSha:
print 'Removing', path
output('Removing', path)
removeFile(True, path)
else:
# Deleted in one and changed in the other
cleanMerge = False
if not aSha:
print 'CONFLICT (delete/modify):', path, 'deleted in', \
branch1Name, 'and modified in', branch2Name + '.', \
'Version', branch2Name, 'of', path, 'left in tree.'
output('CONFLICT (delete/modify):', path, 'deleted in',
branch1Name, 'and modified in', branch2Name + '.',
'Version', branch2Name, 'of', path, 'left in tree.')
mode = bMode
sha = bSha
else:
print 'CONFLICT (modify/delete):', path, 'deleted in', \
branch2Name, 'and modified in', branch1Name + '.', \
'Version', branch1Name, 'of', path, 'left in tree.'
output('CONFLICT (modify/delete):', path, 'deleted in',
branch2Name, 'and modified in', branch1Name + '.',
'Version', branch1Name, 'of', path, 'left in tree.')
mode = aMode
sha = aSha
@ -750,14 +766,14 @@ def processEntry(entry, branch1Name, branch2Name):
if path in currentDirectorySet:
cleanMerge = False
newPath = uniquePath(path, addBranch)
print 'CONFLICT (' + conf + '):', \
'There is a directory with name', path, 'in', \
otherBranch + '. Adding', path, 'as', newPath
output('CONFLICT (' + conf + '):',
'There is a directory with name', path, 'in',
otherBranch + '. Adding', path, 'as', newPath)
removeFile(False, path)
updateFile(False, sha, mode, newPath)
else:
print 'Adding', path
output('Adding', path)
updateFile(True, sha, mode, path)
elif not oSha and aSha and bSha:
@ -767,10 +783,10 @@ def processEntry(entry, branch1Name, branch2Name):
if aSha == bSha:
if aMode != bMode:
cleanMerge = False
print 'CONFLICT: File', path, \
'added identically in both branches, but permissions', \
'conflict', '0%o' % aMode, '->', '0%o' % bMode
print 'CONFLICT: adding with permission:', '0%o' % aMode
output('CONFLICT: File', path,
'added identically in both branches, but permissions',
'conflict', '0%o' % aMode, '->', '0%o' % bMode)
output('CONFLICT: adding with permission:', '0%o' % aMode)
updateFile(False, aSha, aMode, path)
else:
@ -780,9 +796,9 @@ def processEntry(entry, branch1Name, branch2Name):
cleanMerge = False
newPath1 = uniquePath(path, branch1Name)
newPath2 = uniquePath(path, branch2Name)
print 'CONFLICT (add/add): File', path, \
'added non-identically in both branches. Adding as', \
newPath1, 'and', newPath2, 'instead.'
output('CONFLICT (add/add): File', path,
'added non-identically in both branches. Adding as',
newPath1, 'and', newPath2, 'instead.')
removeFile(False, path)
updateFile(False, aSha, aMode, newPath1)
updateFile(False, bSha, bMode, newPath2)
@ -791,7 +807,7 @@ def processEntry(entry, branch1Name, branch2Name):
#
# case D: Modified in both, but differently.
#
print 'Auto-merging', path
output('Auto-merging', path)
[sha, mode, clean, dummy] = \
mergeFile(path, oSha, oMode,
path, aSha, aMode,
@ -801,7 +817,7 @@ def processEntry(entry, branch1Name, branch2Name):
updateFile(True, sha, mode, path)
else:
cleanMerge = False
print 'CONFLICT (content): Merge conflict in', path
output('CONFLICT (content): Merge conflict in', path)
if cacheOnly:
updateFile(False, sha, mode, path)

View File

@ -110,7 +110,14 @@ do
die "$remote - not something we can merge"
done
common=$(git-show-branch --merge-base $head "$@")
case "$#" in
1)
common=$(git-merge-base --all $head "$@")
;;
*)
common=$(git-show-branch --merge-base $head "$@")
;;
esac
echo "$head" >"$GIT_DIR/ORIG_HEAD"
case "$#,$common,$no_commit" in
@ -162,7 +169,7 @@ case "$#,$common,$no_commit" in
up_to_date=t
for remote
do
common_one=$(git-merge-base $head $remote)
common_one=$(git-merge-base --all $head $remote)
if test "$common_one" != "$remote"
then
up_to_date=f

View File

@ -27,3 +27,14 @@ sed -ne '/unreachable /{
}
git-prune-packed $dryrun
redundant=$(git-pack-redundant --all)
if test "" != "$redundant"
then
if test "" = $dryrun
then
echo "$redundant" | xargs rm -f
else
echo rm -f "$redundant"
fi
fi

View File

@ -7,7 +7,14 @@
. git-sh-setup || die "Not a git archive"
usage () {
die "git pull [-n] [--no-commit] [-s strategy]... <repo> <head>..."
echo >&2 "usage: $0"' [-n] [--no-commit] [--no-summary] [--help]
[-s strategy]...
[<fetch-options>]
<repo> <head>...
Fetch one or more remote refs and merge it/them into the current HEAD.
'
exit 1
}
strategy_args= no_summary= no_commit=
@ -33,6 +40,9 @@ do
esac
strategy_args="${strategy_args}-s $strategy "
;;
-h|--h|--he|--hel|--help)
usage
;;
-*)
# Pass thru anything that is meant for fetch.
break
@ -69,10 +79,22 @@ case "$merge_head" in
exit 0
;;
?*' '?*)
strategy_default_args='-s octopus'
var=`git-var -l | sed -ne 's/^pull\.octopus=/-s /p'`
if test '' = "$var"
then
strategy_default_args='-s octopus'
else
strategy_default_args=$var
fi
;;
*)
strategy_default_args='-s resolve'
var=`git-var -l | sed -ne 's/^pull\.twohead=/-s /p'`
if test '' = "$var"
then
strategy_default_args='-s recursive'
else
strategy_default_args=$var
fi
;;
esac

View File

@ -46,7 +46,7 @@ esac
shift
case "$remote" in
http://* | https://* | git://*)
git://*)
die "Cannot use READ-ONLY transport to push to $remote" ;;
rsync://*)
die "Pushing with rsync transport is deprecated" ;;
@ -57,4 +57,9 @@ test "$has_all" && set x "$has_all" "$@" && shift
test "$has_force" && set x "$has_force" "$@" && shift
test "$has_exec" && set x "$has_exec" "$@" && shift
exec git-send-pack "$@"
case "$remote" in
http://* | https://*)
exec git-http-push "$@";;
*)
exec git-send-pack "$@";;
esac

View File

@ -1,70 +0,0 @@
#!/usr/bin/perl
#
# Copyright 2005, Ryan Anderson <ryan@michonline.com>
#
# This file is licensed under the GPL v2, or a later version
# at the discretion of Linus Torvalds.
use warnings;
use strict;
sub usage($);
# Sanity checks:
my $GIT_DIR = $ENV{'GIT_DIR'} || ".git";
unless ( -d $GIT_DIR && -d $GIT_DIR . "/objects" &&
-d $GIT_DIR . "/objects/" && -d $GIT_DIR . "/refs") {
usage("Git repository not found.");
}
usage("") if scalar @ARGV != 2;
my ($src,$dst) = @ARGV;
unless (-f $src || -l $src || -d $src) {
usage("git rename: bad source '$src'");
}
if (-e $dst) {
usage("git rename: destinations '$dst' already exists");
}
my (@allfiles,@srcfiles,@dstfiles);
$/ = "\0";
open(F,"-|","git-ls-files","-z")
or die "Failed to open pipe from git-ls-files: " . $!;
@allfiles = map { chomp; $_; } <F>;
close(F);
my $safesrc = quotemeta($src);
@srcfiles = grep /^$safesrc/, @allfiles;
@dstfiles = @srcfiles;
s#^$safesrc(/|$)#$dst$1# for @dstfiles;
rename($src,$dst)
or die "rename failed: $!";
my $rc = system("git-update-index","--add","--",@dstfiles);
die "git-update-index failed to add new name with code $?\n" if $rc;
$rc = system("git-update-index","--remove","--",@srcfiles);
die "git-update-index failed to remove old name with code $?\n" if $rc;
sub usage($) {
my $s = shift;
print $s, "\n" if (length $s != 0);
print <<EOT;
$0 <source> <dest>
source must exist and be either a file, symlink or directory.
dest must NOT exist.
Renames source to dest, and updates the git cache to reflect the change.
Use "git commit" to make record the change permanently.
EOT
exit(1);
}

View File

@ -32,10 +32,6 @@ case ",$all_into_one," in
rev_list=
rev_parse='--all'
pack_objects=
# This part is a stop-gap until we have proper pack redundancy
# checker.
existing=`cd "$PACKDIR" && \
find . -type f \( -name '*.pack' -o -name '*.idx' \) -print`
;;
esac
if [ "$local" ]; then
@ -46,6 +42,14 @@ name=$(git-rev-list --objects $rev_list $(git-rev-parse $rev_parse) |
exit 1
if [ -z "$name" ]; then
echo Nothing new to pack.
if test "$remove_redandant" = t ; then
echo "Removing redundant packs."
sync
redundant=$(git-pack-redundant --all)
if test "$redundant" != "" ; then
echo $redundant | xargs rm
fi
fi
exit 0
fi
echo "Pack pack-$name created."
@ -58,20 +62,10 @@ exit
if test "$remove_redandant" = t
then
# We know $existing are all redandant only when
# all-into-one is used.
if test "$all_into_one" != '' && test "$existing" != ''
then
sync
( cd "$PACKDIR" &&
for e in $existing
do
case "$e" in
./pack-$name.pack | ./pack-$name.idx) ;;
*) rm -f $e ;;
esac
done
)
sync
redundant=$(git-pack-redundant --all)
if test "$redundant" != "" ; then
echo $redundant | xargs rm
fi
fi

View File

@ -112,7 +112,7 @@ cherry-pick)
q
}'
set_author_env=`git-cat-file commit "$commit" |
sed -ne "$pick_author_script"`
LANG=C LC_ALL=C sed -ne "$pick_author_script"`
eval "$set_author_env"
export GIT_AUTHOR_NAME
export GIT_AUTHOR_EMAIL

View File

@ -25,7 +25,7 @@ use IPC::Open2;
use SVN::Core;
use SVN::Ra;
die "Need CVN:Core 1.2.1 or better" if $SVN::Core::VERSION lt "1.2.1";
die "Need SVN:Core 1.2.1 or better" if $SVN::Core::VERSION lt "1.2.1";
$SIG{'PIPE'}="IGNORE";
$ENV{'TZ'}="UTC";
@ -34,7 +34,7 @@ our($opt_h,$opt_o,$opt_v,$opt_u,$opt_C,$opt_i,$opt_m,$opt_M,$opt_t,$opt_T,$opt_b
sub usage() {
print STDERR <<END;
Usage: ${\basename $0} # fetch/update GIT from CVS
Usage: ${\basename $0} # fetch/update GIT from SVN
[-o branch-for-HEAD] [-h] [-v] [-l max_num_changes]
[-C GIT_repository] [-t tagname] [-T trunkname] [-b branchname]
[-d|-D] [-i] [-u] [-s start_chg] [-m] [-M regex] [SVN_URL]
@ -53,7 +53,6 @@ my $branch_name = $opt_b || "branches";
$opt_o ||= "origin";
$opt_s ||= 1;
$opt_l = 100 unless defined $opt_l;
my $git_tree = $opt_C;
$git_tree ||= ".";
@ -112,7 +111,9 @@ sub file {
DIR => File::Spec->tmpdir(), UNLINK => 1);
print "... $rev $path ...\n" if $opt_v;
eval { $self->{'svn'}->get_file($path,$rev,$fh); };
my $pool = SVN::Pool->new();
eval { $self->{'svn'}->get_file($path,$rev,$fh,$pool); };
$pool->clear;
if($@) {
return undef if $@ =~ /Attempted to get checksum/;
die $@;
@ -258,10 +259,17 @@ EOM
open BRANCHES,">>", "$git_dir/svn2git";
sub get_file($$$) {
my($rev,$branch,$path) = @_;
sub node_kind($$$) {
my ($branch, $path, $revision) = @_;
my $pool=SVN::Pool->new;
my $kind = $svn->{'svn'}->check_path(revert_split_path($branch,$path),$revision,$pool);
$pool->clear;
return $kind;
}
sub revert_split_path($$) {
my($branch,$path) = @_;
# revert split_path(), below
my $svnpath;
$path = "" if $path eq "/"; # this should not happen, but ...
if($branch eq "/") {
@ -272,6 +280,15 @@ sub get_file($$$) {
$svnpath = "$branch_name/$branch/$path";
}
$svnpath =~ s#/+$##;
return $svnpath;
}
sub get_file($$$) {
my($rev,$branch,$path) = @_;
my $svnpath = revert_split_path($branch,$path);
# now get it
my $name;
if($opt_d) {
@ -319,28 +336,61 @@ sub split_path($$) {
} elsif($path =~ s#^/\Q$branch_name\E/([^/]+)/?##) {
$branch = $1;
} else {
print STDERR "$rev: Unrecognized path: $path\n";
my %no_error = (
"/" => 1,
"/$tag_name" => 1,
"/$branch_name" => 1
);
print STDERR "$rev: Unrecognized path: $path\n" unless (defined $no_error{$path});
return ()
}
$path = "/" if $path eq "";
return ($branch,$path);
}
sub copy_subdir($$$$$$) {
sub branch_rev($$) {
my ($srcbranch,$uptorev) = @_;
my $bbranches = $branches{$srcbranch};
my @revs = reverse sort { ($a eq 'LAST' ? 0 : $a) <=> ($b eq 'LAST' ? 0 : $b) } keys %$bbranches;
my $therev;
foreach my $arev(@revs) {
next if ($arev eq 'LAST');
if ($arev <= $uptorev) {
$therev = $arev;
last;
}
}
return $therev;
}
sub copy_path($$$$$$$$) {
# Somebody copied a whole subdirectory.
# We need to find the index entries from the old version which the
# SVN log entry points to, and add them to the new place.
my($newrev,$newbranch,$path,$oldpath,$rev,$new) = @_;
my($branch,$srcpath) = split_path($rev,$oldpath);
my($newrev,$newbranch,$path,$oldpath,$rev,$node_kind,$new,$parents) = @_;
my $gitrev = $branches{$branch}{$rev};
my($srcbranch,$srcpath) = split_path($rev,$oldpath);
unless(defined $srcbranch) {
print "Path not found when copying from $oldpath @ $rev\n";
return;
}
my $therev = branch_rev($srcbranch, $rev);
my $gitrev = $branches{$srcbranch}{$therev};
unless($gitrev) {
print STDERR "$newrev:$newbranch: could not find $oldpath \@ $rev\n";
return;
}
print "$newrev:$newbranch:$path: copying from $branch:$srcpath @ $rev\n" if $opt_v;
$srcpath =~ s#/*$#/#;
if ($srcbranch ne $newbranch) {
push(@$parents, $branches{$srcbranch}{'LAST'});
}
print "$newrev:$newbranch:$path: copying from $srcbranch:$srcpath @ $rev\n" if $opt_v;
if ($node_kind eq $SVN::Node::dir) {
$srcpath =~ s#/*$#/#;
}
open my $f,"-|","git-ls-tree","-r","-z",$gitrev,$srcpath;
local $/ = "\0";
while(<$f>) {
@ -348,9 +398,12 @@ sub copy_subdir($$$$$$) {
my($m,$p) = split(/\t/,$_,2);
my($mode,$type,$sha1) = split(/ /,$m);
next if $type ne "blob";
$p = substr($p,length($srcpath)-1);
print "... found $path$p ...\n" if $opt_v;
push(@$new,[$mode,$sha1,$path.$p]);
if ($node_kind eq $SVN::Node::dir) {
$p = $path . substr($p,length($srcpath)-1);
} else {
$p = $path;
}
push(@$new,[$mode,$sha1,$p]);
}
close($f) or
print STDERR "$newrev:$newbranch: could not list files in $oldpath \@ $rev\n";
@ -359,7 +412,7 @@ sub copy_subdir($$$$$$) {
sub commit {
my($branch, $changed_paths, $revision, $author, $date, $message) = @_;
my($author_name,$author_email,$dest);
my(@old,@new);
my(@old,@new,@parents);
if (not defined $author) {
$author_name = $author_email = "unknown";
@ -446,6 +499,8 @@ sub commit {
$last_rev = $rev;
}
push (@parents, $rev) if defined $rev;
my $cid;
if($tag and not %$changed_paths) {
$cid = $rev;
@ -454,39 +509,31 @@ sub commit {
foreach my $path(@paths) {
my $action = $changed_paths->{$path};
if ($action->[0] eq "A") {
my $f = get_file($revision,$branch,$path);
if($f) {
push(@new,$f) if $f;
} elsif($action->[1]) {
copy_subdir($revision,$branch,$path,$action->[1],$action->[2],\@new);
} else {
my $opath = $action->[3];
print STDERR "$revision: $branch: could not fetch '$opath'\n";
if ($action->[0] eq "R") {
# refer to a file/tree in an earlier commit
push(@old,$path); # remove any old stuff
}
if(($action->[0] eq "A") || ($action->[0] eq "R")) {
my $node_kind = node_kind($branch,$path,$revision);
if($action->[1]) {
copy_path($revision,$branch,$path,$action->[1],$action->[2],$node_kind,\@new,\@parents);
} elsif ($node_kind eq $SVN::Node::file) {
my $f = get_file($revision,$branch,$path);
if ($f) {
push(@new,$f) if $f;
} else {
my $opath = $action->[3];
print STDERR "$revision: $branch: could not fetch '$opath'\n";
}
}
} elsif ($action->[0] eq "D") {
push(@old,$path);
} elsif ($action->[0] eq "M") {
my $f = get_file($revision,$branch,$path);
push(@new,$f) if $f;
} elsif ($action->[0] eq "R") {
# refer to a file/tree in an earlier commit
push(@old,$path); # remove any old stuff
# ... and add any new stuff
my($b,$srcpath) = split_path($revision,$action->[1]);
$srcpath =~ s#/*$#/#;
open my $F,"-|","git-ls-tree","-r","-z", $branches{$b}{$action->[2]}, $srcpath;
local $/ = "\0";
while(<$F>) {
chomp;
my($m,$p) = split(/\t/,$_,2);
my($mode,$type,$sha1) = split(/ /,$m);
next if $type ne "blob";
$p = substr($p,length($srcpath)-1);
push(@new,[$mode,$sha1,$path.$p]);
my $node_kind = node_kind($branch,$path,$revision);
if ($node_kind eq $SVN::Node::file) {
my $f = get_file($revision,$branch,$path);
push(@new,$f) if $f;
}
close($F);
} else {
die "$revision: unknown action '".$action->[0]."' for $path\n";
}
@ -554,7 +601,6 @@ sub commit {
$pw->close();
my @par = ();
@par = ("-p",$rev) if defined $rev;
# loose detection of merges
# based on the commit msg
@ -564,11 +610,17 @@ sub commit {
if ($mparent eq 'HEAD') { $mparent = $opt_o };
if ( -e "$git_dir/refs/heads/$mparent") {
$mparent = get_headref($mparent, $git_dir);
push @par, '-p', $mparent;
push (@parents, $mparent);
print OUT "Merge parent branch: $mparent\n" if $opt_v;
}
}
}
my %seen_parents = ();
my @unique_parents = grep { ! $seen_parents{$_} ++ } @parents;
foreach my $bparent (@unique_parents) {
push @par, '-p', $bparent;
print OUT "Merge parent branch: $bparent\n" if $opt_v;
}
exec("env",
"GIT_AUTHOR_NAME=$author_name",
@ -600,6 +652,10 @@ sub commit {
die "Error running git-commit-tree: $?\n" if $?;
}
if (not defined $cid) {
$cid = $branches{"/"}{"LAST"};
}
if(not defined $dest) {
print "... no known parent\n" if $opt_v;
} elsif(not $tag) {
@ -616,6 +672,7 @@ sub commit {
# the tag was 'complex', i.e. did not refer to a "real" revision
$dest =~ tr/_/\./ if $opt_u;
$branch = $dest;
my $pid = open2($in, $out, 'git-mktag');
print $out ("object $cid\n".
@ -674,13 +731,16 @@ sub commit_all {
}
while(++$current_rev <= $svn->{'maxrev'}) {
$svn->{'svn'}->get_log("/",$current_rev,$current_rev,$current_rev,1,1,\&_commit_all,"");
commit_all();
if($opt_l and not --$opt_l) {
print STDERR "Stopping, because there is a memory leak (in the SVN library).\n";
print STDERR "Please repeat this command; it will continue safely\n";
last;
if (defined $opt_l) {
$opt_l--;
if ($opt_l < 0) {
last;
}
}
my $pool=SVN::Pool->new;
$svn->{'svn'}->get_log("/",$current_rev,$current_rev,1,1,1,\&_commit_all,$pool);
$pool->clear;
commit_all();
}

View File

@ -4,7 +4,7 @@
. git-sh-setup || die "Not a git archive"
usage () {
echo >&2 "Usage: git-tag [-a | -s | -u <key-id>] [-f] [-m <msg>] <tagname> [<head>]"
echo >&2 "Usage: git-tag [-a | -s | -u <key-id>] [-f | -d] [-m <msg>] <tagname> [<head>]"
exit 1
}
@ -37,6 +37,13 @@ do
shift
username="$1"
;;
-d)
shift
tag_name="$1"
rm "$GIT_DIR/refs/tags/$tag_name" && \
echo "Deleted tag $tag_name."
exit $?
;;
-*)
usage
;;
@ -92,5 +99,6 @@ if [ "$annotate" ]; then
object=$(git-mktag < "$GIT_DIR"/TAG_TMP)
fi
mkdir -p "$GIT_DIR/refs/tags"
leading=`expr "refs/tags/$name" : '\(.*\)/'` &&
mkdir -p "$GIT_DIR/$leading" &&
echo $object > "$GIT_DIR/refs/tags/$name"

View File

@ -1,3 +1,7 @@
#
# Copyright (C) 2005 Fredrik Kuivinen
#
import sys, re, os, traceback
from sets import Set

View File

@ -25,7 +25,7 @@
#define PREV_BUF_SIZE 4096
#define RANGE_HEADER_SIZE 30
static int got_alternates = 0;
static int got_alternates = -1;
static int active_requests = 0;
static int data_received;
@ -87,9 +87,19 @@ struct active_request_slot
int done;
CURLcode curl_result;
long http_code;
void *callback_data;
void (*callback_func)(void *data);
struct active_request_slot *next;
};
struct alt_request {
char *base;
char *url;
struct buffer *buffer;
struct active_request_slot *slot;
int http_specific;
};
static struct transfer_request *request_queue_head = NULL;
static struct active_request_slot *active_queue_head = NULL;
@ -237,7 +247,7 @@ static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb,
static void process_curl_messages(void);
static void process_request_queue(void);
#endif
static int fetch_alternates(char *base);
static void fetch_alternates(char *base);
static CURL* get_curl_handle(void)
{
@ -269,6 +279,8 @@ static CURL* get_curl_handle(void)
curl_low_speed_time);
}
curl_easy_setopt(result, CURLOPT_FOLLOWLOCATION, 1);
return result;
}
@ -322,6 +334,8 @@ static struct active_request_slot *get_active_slot(void)
slot->in_use = 1;
slot->done = 0;
slot->local = NULL;
slot->callback_data = NULL;
slot->callback_func = NULL;
curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, pragma_header);
curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, no_range_header);
curl_easy_setopt(slot->curl, CURLOPT_ERRORBUFFER, curl_errorstr);
@ -569,7 +583,7 @@ static void release_request(struct transfer_request *request)
}
#ifdef USE_CURL_MULTI
void process_curl_messages(void)
static void process_curl_messages(void)
{
int num_messages;
struct active_request_slot *slot;
@ -599,6 +613,12 @@ void process_curl_messages(void)
} else {
fprintf(stderr, "Received DONE message for unknown request!\n");
}
/* Process slot callback if appropriate */
if (slot->callback_func != NULL) {
slot->callback_func(slot->callback_data);
}
if (request != NULL) {
request->curl_result = curl_result;
request->http_code = slot->http_code;
@ -612,6 +632,8 @@ void process_curl_messages(void)
request->repo =
request->repo->next;
start_request(request);
} else {
finish_request(request);
}
} else {
finish_request(request);
@ -625,7 +647,7 @@ void process_curl_messages(void)
}
}
void process_request_queue(void)
static void process_request_queue(void)
{
struct transfer_request *request = request_queue_head;
struct active_request_slot *slot = active_queue_head;
@ -764,72 +786,51 @@ static int setup_index(struct alt_base *repo, unsigned char *sha1)
return 0;
}
static int fetch_alternates(char *base)
static void process_alternates(void *callback_data)
{
int ret = 0;
struct buffer buffer;
char *url;
struct alt_request *alt_req = (struct alt_request *)callback_data;
struct active_request_slot *slot = alt_req->slot;
struct alt_base *tail = alt;
char *base = alt_req->base;
static const char null_byte = '\0';
char *data;
int i = 0;
int http_specific = 1;
struct alt_base *tail = alt;
static const char null_byte = '\0';
struct active_request_slot *slot;
if (alt_req->http_specific) {
if (slot->curl_result != CURLE_OK ||
!alt_req->buffer->posn) {
if (got_alternates)
return 0;
data = xmalloc(4096);
buffer.size = 4096;
buffer.posn = 0;
buffer.buffer = data;
if (get_verbosely)
fprintf(stderr, "Getting alternates list\n");
url = xmalloc(strlen(base) + 31);
sprintf(url, "%s/objects/info/http-alternates", base);
slot = get_active_slot();
curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION,
fwrite_buffer_dynamic);
curl_easy_setopt(slot->curl, CURLOPT_URL, url);
if (start_active_slot(slot)) {
run_active_slot(slot);
if (slot->curl_result != CURLE_OK || !buffer.posn) {
http_specific = 0;
sprintf(url, "%s/objects/info/alternates", base);
slot = get_active_slot();
curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION,
fwrite_buffer_dynamic);
curl_easy_setopt(slot->curl, CURLOPT_URL, url);
/* Try reusing the slot to get non-http alternates */
alt_req->http_specific = 0;
sprintf(alt_req->url, "%s/objects/info/alternates",
base);
curl_easy_setopt(slot->curl, CURLOPT_URL,
alt_req->url);
active_requests++;
slot->in_use = 1;
slot->done = 0;
if (start_active_slot(slot)) {
run_active_slot(slot);
if (slot->curl_result != CURLE_OK) {
free(buffer.buffer);
if (slot->http_code == 404)
got_alternates = 1;
return 0;
}
return;
} else {
got_alternates = -1;
slot->done = 1;
return;
}
}
} else {
free(buffer.buffer);
return 0;
} else if (slot->curl_result != CURLE_OK) {
if (slot->http_code != 404) {
got_alternates = -1;
return;
}
}
fwrite_buffer_dynamic(&null_byte, 1, 1, &buffer);
buffer.posn--;
data = buffer.buffer;
fwrite_buffer_dynamic(&null_byte, 1, 1, alt_req->buffer);
alt_req->buffer->posn--;
data = alt_req->buffer->buffer;
while (i < buffer.posn) {
while (i < alt_req->buffer->posn) {
int posn = i;
while (posn < buffer.posn && data[posn] != '\n')
while (posn < alt_req->buffer->posn && data[posn] != '\n')
posn++;
if (data[posn] == '\n') {
int okay = 0;
@ -853,7 +854,7 @@ static int fetch_alternates(char *base)
// If the server got removed, give up.
okay = strchr(base, ':') - base + 3 <
serverlen;
} else if (http_specific) {
} else if (alt_req->http_specific) {
char *colon = strchr(data + i, ':');
char *slash = strchr(data + i, '/');
if (colon && slash && colon < data + posn &&
@ -879,15 +880,74 @@ static int fetch_alternates(char *base)
while (tail->next != NULL)
tail = tail->next;
tail->next = newalt;
ret++;
}
}
i = posn + 1;
}
got_alternates = 1;
free(buffer.buffer);
return ret;
}
static void fetch_alternates(char *base)
{
struct buffer buffer;
char *url;
char *data;
struct active_request_slot *slot;
static struct alt_request alt_req;
int num_transfers;
/* If another request has already started fetching alternates,
wait for them to arrive and return to processing this request's
curl message */
while (got_alternates == 0) {
curl_multi_perform(curlm, &num_transfers);
process_curl_messages();
process_request_queue();
}
/* Nothing to do if they've already been fetched */
if (got_alternates == 1)
return;
/* Start the fetch */
got_alternates = 0;
data = xmalloc(4096);
buffer.size = 4096;
buffer.posn = 0;
buffer.buffer = data;
if (get_verbosely)
fprintf(stderr, "Getting alternates list for %s\n", base);
url = xmalloc(strlen(base) + 31);
sprintf(url, "%s/objects/info/http-alternates", base);
/* Use a callback to process the result, since another request
may fail and need to have alternates loaded before continuing */
slot = get_active_slot();
slot->callback_func = process_alternates;
slot->callback_data = &alt_req;
curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION,
fwrite_buffer_dynamic);
curl_easy_setopt(slot->curl, CURLOPT_URL, url);
alt_req.base = base;
alt_req.url = url;
alt_req.buffer = &buffer;
alt_req.http_specific = 1;
alt_req.slot = slot;
if (start_active_slot(slot))
run_active_slot(slot);
else
got_alternates = -1;
free(data);
free(url);
}
static int fetch_indices(struct alt_base *repo)
@ -909,7 +969,7 @@ static int fetch_indices(struct alt_base *repo)
buffer.buffer = data;
if (get_verbosely)
fprintf(stderr, "Getting pack list\n");
fprintf(stderr, "Getting pack list for %s\n", repo->base);
url = xmalloc(strlen(repo->base) + 21);
sprintf(url, "%s/objects/info/packs", repo->base);

View File

@ -28,6 +28,15 @@ static const char http_push_usage[] =
#define NO_CURL_EASY_DUPHANDLE
#endif
#ifndef XML_STATUS_OK
enum XML_Status {
XML_STATUS_OK = 1,
XML_STATUS_ERROR = 0
};
#define XML_STATUS_OK 1
#define XML_STATUS_ERROR 0
#endif
#define RANGE_HEADER_SIZE 30
/* DAV method names and request body templates */
@ -47,6 +56,7 @@ static int active_requests = 0;
static int data_received;
static int pushing = 0;
static int aborted = 0;
static char remote_dir_exists[256];
#ifdef USE_CURL_MULTI
static int max_requests = -1;
@ -585,7 +595,7 @@ static void start_move(struct transfer_request *request)
}
}
int refresh_lock(struct active_lock *lock)
static int refresh_lock(struct active_lock *lock)
{
struct active_request_slot *slot;
char *if_header;
@ -650,6 +660,7 @@ static void finish_request(struct transfer_request *request)
if (request->http_code == 404) {
request->state = NEED_PUSH;
} else if (request->curl_result == CURLE_OK) {
remote_dir_exists[request->sha1[0]] = 1;
request->state = COMPLETE;
} else {
fprintf(stderr, "HEAD %s failed, aborting (%d/%ld)\n",
@ -661,6 +672,7 @@ static void finish_request(struct transfer_request *request)
} else if (request->state == RUN_MKCOL) {
if (request->curl_result == CURLE_OK ||
request->http_code == 405) {
remote_dir_exists[request->sha1[0]] = 1;
start_put(request);
} else {
fprintf(stderr, "MKCOL %s failed, aborting (%d/%ld)\n",
@ -714,7 +726,7 @@ static void release_request(struct transfer_request *request)
}
#ifdef USE_CURL_MULTI
void process_curl_messages(void)
static void process_curl_messages(void)
{
int num_messages;
struct active_request_slot *slot;
@ -728,11 +740,12 @@ void process_curl_messages(void)
slot->curl != curl_message->easy_handle)
slot = slot->next;
if (slot != NULL) {
int curl_result = curl_message->data.result;
curl_multi_remove_handle(curlm, slot->curl);
active_requests--;
slot->done = 1;
slot->in_use = 0;
slot->curl_result = curl_message->data.result;
slot->curl_result = curl_result;
curl_easy_getinfo(slot->curl,
CURLINFO_HTTP_CODE,
&slot->http_code);
@ -753,7 +766,7 @@ void process_curl_messages(void)
}
}
void process_request_queue(void)
static void process_request_queue(void)
{
struct transfer_request *request = request_queue_head;
struct active_request_slot *slot = active_queue_head;
@ -767,7 +780,10 @@ void process_request_queue(void)
start_check(request);
curl_multi_perform(curlm, &num_transfers);
} else if (pushing && request->state == NEED_PUSH) {
start_mkcol(request);
if (remote_dir_exists[request->sha1[0]])
start_put(request);
else
start_mkcol(request);
curl_multi_perform(curlm, &num_transfers);
}
request = request->next;
@ -783,7 +799,7 @@ void process_request_queue(void)
}
#endif
void process_waiting_requests(void)
static void process_waiting_requests(void)
{
struct active_request_slot *slot = active_queue_head;
@ -796,7 +812,7 @@ void process_waiting_requests(void)
}
}
void add_request(unsigned char *sha1, struct active_lock *lock)
static void add_request(unsigned char *sha1, struct active_lock *lock)
{
struct transfer_request *request = request_queue_head;
struct packed_git *target;
@ -923,7 +939,7 @@ static int setup_index(unsigned char *sha1)
return 0;
}
static int fetch_indices()
static int fetch_indices(void)
{
unsigned char sha1[20];
char *url;
@ -1173,7 +1189,7 @@ end_lockprop_element(void *userData, const char *name)
}
}
struct active_lock *lock_remote(char *file, long timeout)
static struct active_lock *lock_remote(char *file, long timeout)
{
struct active_request_slot *slot;
struct buffer out_buffer;
@ -1230,7 +1246,7 @@ struct active_lock *lock_remote(char *file, long timeout)
in_buffer.posn = 0;
in_buffer.buffer = in_data;
new_lock = xmalloc(sizeof(*new_lock));
new_lock = xcalloc(1, sizeof(*new_lock));
new_lock->owner = NULL;
new_lock->token = NULL;
new_lock->timeout = -1;
@ -1302,7 +1318,7 @@ struct active_lock *lock_remote(char *file, long timeout)
return new_lock;
}
int unlock_remote(struct active_lock *lock)
static int unlock_remote(struct active_lock *lock)
{
struct active_request_slot *slot;
char *lock_token_header;
@ -1343,7 +1359,7 @@ int unlock_remote(struct active_lock *lock)
return rc;
}
int check_locking()
static int check_locking(void)
{
struct active_request_slot *slot;
struct buffer in_buffer;
@ -1409,7 +1425,7 @@ int check_locking()
return 1;
}
int is_ancestor(unsigned char *sha1, struct commit *commit)
static int is_ancestor(unsigned char *sha1, struct commit *commit)
{
struct commit_list *parents;
@ -1430,8 +1446,8 @@ int is_ancestor(unsigned char *sha1, struct commit *commit)
return 0;
}
void get_delta(unsigned char *sha1, struct object *obj,
struct active_lock *lock)
static void get_delta(unsigned char *sha1, struct object *obj,
struct active_lock *lock)
{
struct commit *commit;
struct commit_list *parents;
@ -1487,7 +1503,7 @@ void get_delta(unsigned char *sha1, struct object *obj,
}
}
int update_remote(unsigned char *sha1, struct active_lock *lock)
static int update_remote(unsigned char *sha1, struct active_lock *lock)
{
struct active_request_slot *slot;
char *out_data;
@ -1599,6 +1615,8 @@ int main(int argc, char **argv)
break;
}
memset(remote_dir_exists, 0, 256);
curl_global_init(CURL_GLOBAL_ALL);
#ifdef USE_CURL_MULTI

View File

@ -570,6 +570,7 @@ int main(int argc, const char **argv)
prefix = setup_git_directory();
if (prefix)
prefix_offset = strlen(prefix);
git_config(git_default_config);
for (i = 1; i < argc; i++) {
const char *arg = argv[i];

View File

@ -80,14 +80,95 @@ static struct commit *interesting(struct commit_list *list)
* Now, list does not have any interesting commit. So we find the newest
* commit from the result list that is not marked uninteresting. Which is
* commit B.
*
*
* Another pathological example how this thing can fail to mark an ancestor
* of a merge base as UNINTERESTING without the postprocessing phase.
*
* 2
* H
* 1 / \
* G A \
* |\ / \
* | B \
* | \ \
* \ C F
* \ \ /
* \ D /
* \ | /
* \| /
* E
*
* list A B C D E F G H
* G1 H2 - - - - - - 1 2
* H2 E1 B1 - 1 - - 1 - 1 2
* F2 E1 B1 A2 2 1 - - 1 2 1 2
* E3 B1 A2 2 1 - - 3 2 1 2
* B1 A2 2 1 - - 3 2 1 2
* C1 A2 2 1 1 - 3 2 1 2
* D1 A2 2 1 1 1 3 2 1 2
* A2 2 1 1 1 3 2 1 2
* B3 2 3 1 1 3 2 1 2
* C7 2 3 7 1 3 2 1 2
*
* At this point, unfortunately, everybody in the list is
* uninteresting, so we fail to complete the following two
* steps to fully marking uninteresting commits.
*
* D7 2 3 7 7 3 2 1 2
* E7 2 3 7 7 7 2 1 2
*
* and we end up showing E as an interesting merge base.
*/
static int show_all = 0;
static void mark_reachable_commits(struct commit_list *result,
struct commit_list *list)
{
struct commit_list *tmp;
/*
* Postprocess to fully contaminate the well.
*/
for (tmp = result; tmp; tmp = tmp->next) {
struct commit *c = tmp->item;
/* Reinject uninteresting ones to list,
* so we can scan their parents.
*/
if (c->object.flags & UNINTERESTING)
commit_list_insert(c, &list);
}
while (list) {
struct commit *c = list->item;
struct commit_list *parents;
tmp = list;
list = list->next;
free(tmp);
/* Anything taken out of the list is uninteresting, so
* mark all its parents uninteresting. We do not
* parse new ones (we already parsed all the relevant
* ones).
*/
parents = c->parents;
while (parents) {
struct commit *p = parents->item;
parents = parents->next;
if (!(p->object.flags & UNINTERESTING)) {
p->object.flags |= UNINTERESTING;
commit_list_insert(p, &list);
}
}
}
}
static int merge_base(struct commit *rev1, struct commit *rev2)
{
struct commit_list *list = NULL;
struct commit_list *result = NULL;
struct commit_list *tmp = NULL;
if (rev1 == rev2) {
printf("%s\n", sha1_to_hex(rev1->object.sha1));
@ -104,9 +185,10 @@ static int merge_base(struct commit *rev1, struct commit *rev2)
while (interesting(list)) {
struct commit *commit = list->item;
struct commit_list *tmp = list, *parents;
struct commit_list *parents;
int flags = commit->object.flags & 7;
tmp = list;
list = list->next;
free(tmp);
if (flags == 3) {
@ -130,6 +212,9 @@ static int merge_base(struct commit *rev1, struct commit *rev2)
if (!result)
return 1;
if (result->next && list)
mark_reachable_commits(result, list);
while (result) {
struct commit *commit = result->item;
result = result->next;

621
pack-redundant.c Normal file
View File

@ -0,0 +1,621 @@
/*
*
* Copyright 2005, Lukas Sandstrom <lukass@etek.chalmers.se>
*
* This file is licensed under the GPL v2.
*
*/
#include "cache.h"
static const char pack_redundant_usage[] =
"git-pack-redundant [ --verbose ] [ --alt-odb ] < --all | <.pack filename> ...>";
int load_all_packs = 0, verbose = 0, alt_odb = 0;
struct llist_item {
struct llist_item *next;
char *sha1;
};
struct llist {
struct llist_item *front;
struct llist_item *back;
size_t size;
} *all_objects; /* all objects which must be present in local packfiles */
struct pack_list {
struct pack_list *next;
struct packed_git *pack;
struct llist *unique_objects;
struct llist *all_objects;
} *local_packs = NULL, *altodb_packs = NULL;
struct pll {
struct pll *next;
struct pack_list *pl;
};
inline void llist_free(struct llist *list)
{
while((list->back = list->front)) {
list->front = list->front->next;
free(list->back);
}
free(list);
}
inline void llist_init(struct llist **list)
{
*list = xmalloc(sizeof(struct llist));
(*list)->front = (*list)->back = NULL;
(*list)->size = 0;
}
struct llist * llist_copy(struct llist *list)
{
struct llist *ret;
struct llist_item *new, *old, *prev;
llist_init(&ret);
if ((ret->size = list->size) == 0)
return ret;
new = ret->front = xmalloc(sizeof(struct llist_item));
new->sha1 = list->front->sha1;
old = list->front->next;
while (old) {
prev = new;
new = xmalloc(sizeof(struct llist_item));
prev->next = new;
new->sha1 = old->sha1;
old = old->next;
}
new->next = NULL;
ret->back = new;
return ret;
}
inline struct llist_item * llist_insert(struct llist *list,
struct llist_item *after, char *sha1)
{
struct llist_item *new = xmalloc(sizeof(struct llist_item));
new->sha1 = sha1;
new->next = NULL;
if (after != NULL) {
new->next = after->next;
after->next = new;
if (after == list->back)
list->back = new;
} else {/* insert in front */
if (list->size == 0)
list->back = new;
else
new->next = list->front;
list->front = new;
}
list->size++;
return new;
}
inline struct llist_item * llist_insert_back(struct llist *list, char *sha1)
{
return llist_insert(list, list->back, sha1);
}
inline struct llist_item * llist_insert_sorted_unique(struct llist *list,
char *sha1, struct llist_item *hint)
{
struct llist_item *prev = NULL, *l;
l = (hint == NULL) ? list->front : hint;
while (l) {
int cmp = memcmp(l->sha1, sha1, 20);
if (cmp > 0) { /* we insert before this entry */
return llist_insert(list, prev, sha1);
}
if(!cmp) { /* already exists */
return l;
}
prev = l;
l = l->next;
}
/* insert at the end */
return llist_insert_back(list, sha1);
}
/* computes A\B */
void llist_sorted_difference_inplace(struct llist *A,
struct llist *B)
{
struct llist_item *prev, *a, *b, *x;
prev = a = A->front;
b = B->front;
while (a != NULL && b != NULL) {
int cmp = memcmp(a->sha1, b->sha1, 20);
if (!cmp) {
x = a;
if (a == A->front)
A->front = a->next;
a = prev->next = a->next;
if (a == NULL) /* end of list */
A->back = prev;
A->size--;
free(x);
b = b->next;
} else
if (cmp > 0)
b = b->next;
else {
prev = a;
a = a->next;
}
}
}
/* returns a pointer to an item in front of sha1 */
inline struct llist_item * llist_sorted_remove(struct llist *list, char *sha1,
struct llist_item *hint)
{
struct llist_item *prev, *l;
redo_from_start:
l = (hint == NULL) ? list->front : hint;
prev = NULL;
while (l) {
int cmp = memcmp(l->sha1, sha1, 20);
if (cmp > 0) /* not in list, since sorted */
return prev;
if(!cmp) { /* found */
if (prev == NULL) {
if (hint != NULL && hint != list->front) {
/* we don't know the previous element */
hint = NULL;
goto redo_from_start;
}
list->front = l->next;
} else
prev->next = l->next;
if (l == list->back)
list->back = prev;
free(l);
list->size--;
return prev;
}
prev = l;
l = l->next;
}
return prev;
}
inline struct pack_list * pack_list_insert(struct pack_list **pl,
struct pack_list *entry)
{
struct pack_list *p = xmalloc(sizeof(struct pack_list));
memcpy(p, entry, sizeof(struct pack_list));
p->next = *pl;
*pl = p;
return p;
}
inline size_t pack_list_size(struct pack_list *pl)
{
size_t ret = 0;
while(pl) {
ret++;
pl = pl->next;
}
return ret;
}
struct pack_list * pack_list_difference(struct pack_list *A,
struct pack_list *B)
{
struct pack_list *ret, *pl;
if (A == NULL)
return NULL;
pl = B;
while (pl != NULL) {
if (A->pack == pl->pack)
return pack_list_difference(A->next, B);
pl = pl->next;
}
ret = xmalloc(sizeof(struct pack_list));
memcpy(ret, A, sizeof(struct pack_list));
ret->next = pack_list_difference(A->next, B);
return ret;
}
void cmp_two_packs(struct pack_list *p1, struct pack_list *p2)
{
int p1_off, p2_off;
void *p1_base, *p2_base;
struct llist_item *p1_hint = NULL, *p2_hint = NULL;
p1_off = p2_off = 256 * 4 + 4;
p1_base = (void *)p1->pack->index_base;
p2_base = (void *)p2->pack->index_base;
while (p1_off <= p1->pack->index_size - 3 * 20 &&
p2_off <= p2->pack->index_size - 3 * 20)
{
int cmp = memcmp(p1_base + p1_off, p2_base + p2_off, 20);
/* cmp ~ p1 - p2 */
if (cmp == 0) {
p1_hint = llist_sorted_remove(p1->unique_objects,
p1_base + p1_off, p1_hint);
p2_hint = llist_sorted_remove(p2->unique_objects,
p1_base + p1_off, p2_hint);
p1_off+=24;
p2_off+=24;
continue;
}
if (cmp < 0) { /* p1 has the object, p2 doesn't */
p1_off+=24;
} else { /* p2 has the object, p1 doesn't */
p2_off+=24;
}
}
}
/* all the permutations have to be free()d at the same time,
* since they refer to each other
*/
struct pll * get_all_permutations(struct pack_list *list)
{
struct pll *subset, *pll, *new_pll = NULL; /*silence warning*/
if (list == NULL)
return NULL;
if (list->next == NULL) {
new_pll = xmalloc(sizeof(struct pll));
new_pll->next = NULL;
new_pll->pl = list;
return new_pll;
}
pll = subset = get_all_permutations(list->next);
while (pll) {
new_pll = xmalloc(sizeof(struct pll));
new_pll->next = pll->next;
pll->next = new_pll;
new_pll->pl = xmalloc(sizeof(struct pack_list));
memcpy(new_pll->pl, list, sizeof(struct pack_list));
new_pll->pl->next = pll->pl;
pll = new_pll->next;
}
/* add ourself to the end */
new_pll->next = xmalloc(sizeof(struct pll));
new_pll->next->pl = xmalloc(sizeof(struct pack_list));
new_pll->next->next = NULL;
memcpy(new_pll->next->pl, list, sizeof(struct pack_list));
new_pll->next->pl->next = NULL;
return subset;
}
int is_superset(struct pack_list *pl, struct llist *list)
{
struct llist *diff;
diff = llist_copy(list);
while (pl) {
llist_sorted_difference_inplace(diff,
pl->all_objects);
if (diff->size == 0) { /* we're done */
llist_free(diff);
return 1;
}
pl = pl->next;
}
llist_free(diff);
return 0;
}
size_t sizeof_union(struct packed_git *p1, struct packed_git *p2)
{
size_t ret = 0;
int p1_off, p2_off;
void *p1_base, *p2_base;
p1_off = p2_off = 256 * 4 + 4;
p1_base = (void *)p1->index_base;
p2_base = (void *)p2->index_base;
while (p1_off <= p1->index_size - 3 * 20 &&
p2_off <= p2->index_size - 3 * 20)
{
int cmp = memcmp(p1_base + p1_off, p2_base + p2_off, 20);
/* cmp ~ p1 - p2 */
if (cmp == 0) {
ret++;
p1_off+=24;
p2_off+=24;
continue;
}
if (cmp < 0) { /* p1 has the object, p2 doesn't */
p1_off+=24;
} else { /* p2 has the object, p1 doesn't */
p2_off+=24;
}
}
return ret;
}
/* another O(n^2) function ... */
size_t get_pack_redundancy(struct pack_list *pl)
{
struct pack_list *subset;
if (pl == NULL)
return 0;
size_t ret = 0;
while ((subset = pl->next)) {
while(subset) {
ret += sizeof_union(pl->pack, subset->pack);
subset = subset->next;
}
pl = pl->next;
}
return ret;
}
inline size_t pack_set_bytecount(struct pack_list *pl)
{
size_t ret = 0;
while (pl) {
ret += pl->pack->pack_size;
ret += pl->pack->index_size;
pl = pl->next;
}
return ret;
}
void minimize(struct pack_list **min)
{
struct pack_list *pl, *unique = NULL,
*non_unique = NULL, *min_perm = NULL;
struct pll *perm, *perm_all, *perm_ok = NULL, *new_perm;
struct llist *missing;
size_t min_perm_size = (size_t)-1, perm_size;
pl = local_packs;
while (pl) {
if(pl->unique_objects->size)
pack_list_insert(&unique, pl);
else
pack_list_insert(&non_unique, pl);
pl = pl->next;
}
/* find out which objects are missing from the set of unique packs */
missing = llist_copy(all_objects);
pl = unique;
while (pl) {
llist_sorted_difference_inplace(missing,
pl->all_objects);
pl = pl->next;
}
/* return if there are no objects missing from the unique set */
if (missing->size == 0) {
*min = unique;
return;
}
/* find the permutations which contain all missing objects */
perm_all = perm = get_all_permutations(non_unique);
while (perm) {
if (is_superset(perm->pl, missing)) {
new_perm = xmalloc(sizeof(struct pll));
new_perm->pl = perm->pl;
new_perm->next = perm_ok;
perm_ok = new_perm;
}
perm = perm->next;
}
if (perm_ok == NULL)
die("Internal error: No complete sets found!\n");
/* find the permutation with the smallest size */
perm = perm_ok;
while (perm) {
perm_size = pack_set_bytecount(perm->pl);
if (min_perm_size > perm_size) {
min_perm_size = perm_size;
min_perm = perm->pl;
}
perm = perm->next;
}
*min = min_perm;
/* add the unique packs to the list */
pl = unique;
while(pl) {
pack_list_insert(min, pl);
pl = pl->next;
}
}
void load_all_objects()
{
struct pack_list *pl = local_packs;
struct llist_item *hint, *l;
int i;
llist_init(&all_objects);
while (pl) {
i = 0;
hint = NULL;
l = pl->all_objects->front;
while (l) {
hint = llist_insert_sorted_unique(all_objects,
l->sha1, hint);
l = l->next;
}
pl = pl->next;
}
/* remove objects present in remote packs */
pl = altodb_packs;
while (pl) {
llist_sorted_difference_inplace(all_objects, pl->all_objects);
pl = pl->next;
}
}
/* this scales like O(n^2) */
void cmp_packs()
{
struct pack_list *subset, *pl = local_packs;
while ((subset = pl)) {
while((subset = subset->next))
cmp_two_packs(pl, subset);
pl = pl->next;
}
pl = altodb_packs;
while (pl) {
subset = local_packs;
while (subset) {
llist_sorted_difference_inplace(subset->unique_objects,
pl->all_objects);
subset = subset->next;
}
pl = pl->next;
}
}
struct pack_list * add_pack(struct packed_git *p)
{
struct pack_list l;
size_t off;
void *base;
l.pack = p;
llist_init(&l.all_objects);
off = 256 * 4 + 4;
base = (void *)p->index_base;
while (off <= p->index_size - 3 * 20) {
llist_insert_back(l.all_objects, base + off);
off+=24;
}
/* this list will be pruned in cmp_two_packs later */
l.unique_objects = llist_copy(l.all_objects);
if (p->pack_local)
return pack_list_insert(&local_packs, &l);
else
return alt_odb ? pack_list_insert(&altodb_packs, &l) : NULL;
}
struct pack_list * add_pack_file(char *filename)
{
struct packed_git *p = packed_git;
if (strlen(filename) < 40)
die("Bad pack filename: %s\n", filename);
while (p) {
if (strstr(p->pack_name, filename))
return add_pack(p);
p = p->next;
}
die("Filename %s not found in packed_git\n", filename);
}
void load_all()
{
struct packed_git *p = packed_git;
while (p) {
add_pack(p);
p = p->next;
}
}
int main(int argc, char **argv)
{
int i;
struct pack_list *min, *red, *pl;
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
if(!strcmp(arg, "--")) {
i++;
break;
}
if(!strcmp(arg, "--all")) {
load_all_packs = 1;
continue;
}
if(!strcmp(arg, "--verbose")) {
verbose = 1;
continue;
}
if(!strcmp(arg, "--alt-odb")) {
alt_odb = 1;
continue;
}
if(*arg == '-')
usage(pack_redundant_usage);
else
break;
}
prepare_packed_git();
if (load_all_packs)
load_all();
else
while (*(argv + i) != NULL)
add_pack_file(*(argv + i++));
if (local_packs == NULL)
die("Zero packs found!\n");
cmp_packs();
load_all_objects();
minimize(&min);
if (verbose) {
fprintf(stderr, "There are %lu packs available in alt-odbs.\n",
(unsigned long)pack_list_size(altodb_packs));
fprintf(stderr, "The smallest (bytewise) set of packs is:\n");
pl = min;
while (pl) {
fprintf(stderr, "\t%s\n", pl->pack->pack_name);
pl = pl->next;
}
fprintf(stderr, "containing %lu duplicate objects "
"with a total size of %lukb.\n",
(unsigned long)get_pack_redundancy(min),
(unsigned long)pack_set_bytecount(min)/1024);
fprintf(stderr, "A total of %lu unique objects were considered.\n",
(unsigned long)all_objects->size);
fprintf(stderr, "Redundant packs (with indexes):\n");
}
pl = red = pack_list_difference(local_packs, min);
while (pl) {
printf("%s\n%s\n",
sha1_pack_index_name(pl->pack->sha1),
pl->pack->pack_name);
pl = pl->next;
}
return 0;
}

View File

@ -633,6 +633,8 @@ int main(int argc, char **argv)
if (newfd < 0)
die("unable to create new cachefile");
git_config(git_default_config);
merge = 0;
reset = 0;
for (i = 1; i < argc; i++) {

View File

@ -424,6 +424,7 @@ struct packed_git *add_packed_git(char *path, int path_len, int local)
struct packed_git *p;
unsigned long idx_size;
void *idx_map;
char sha1[20];
if (check_packed_git_idx(path, &idx_size, &idx_map))
return NULL;
@ -447,6 +448,8 @@ struct packed_git *add_packed_git(char *path, int path_len, int local)
p->pack_last_used = 0;
p->pack_use_cnt = 0;
p->pack_local = local;
if (!get_sha1_hex(path + path_len - 40 - 4, sha1))
memcpy(p->sha1, sha1, 20);
return p;
}

View File

@ -181,11 +181,11 @@ static void join_revs(struct commit_list **list_p,
while (*list_p) {
struct commit_list *parents;
int still_interesting = !!interesting(*list_p);
struct commit *commit = pop_one_commit(list_p);
int flags = commit->object.flags & all_mask;
int still_interesting = !!interesting(*list_p);
if (!still_interesting && extra < 0)
if (!still_interesting && extra <= 0)
break;
mark_seen(commit, seen_p);
@ -199,18 +199,58 @@ static void join_revs(struct commit_list **list_p,
parents = parents->next;
if ((this_flag & flags) == flags)
continue;
parse_commit(p);
if (!p->object.parsed)
parse_commit(p);
if (mark_seen(p, seen_p) && !still_interesting)
extra--;
p->object.flags |= flags;
insert_by_date(p, list_p);
}
}
/*
* Postprocess to complete well-poisoning.
*
* At this point we have all the commits we have seen in
* seen_p list (which happens to be sorted chronologically but
* it does not really matter). Mark anything that can be
* reached from uninteresting commits not interesting.
*/
for (;;) {
int changed = 0;
struct commit_list *s;
for (s = *seen_p; s; s = s->next) {
struct commit *c = s->item;
struct commit_list *parents;
if (((c->object.flags & all_revs) != all_revs) &&
!(c->object.flags & UNINTERESTING))
continue;
/* The current commit is either a merge base or
* already uninteresting one. Mark its parents
* as uninteresting commits _only_ if they are
* already parsed. No reason to find new ones
* here.
*/
parents = c->parents;
while (parents) {
struct commit *p = parents->item;
parents = parents->next;
if (!(p->object.flags & UNINTERESTING)) {
p->object.flags |= UNINTERESTING;
changed = 1;
}
}
}
if (!changed)
break;
}
}
static void show_one_commit(struct commit *commit, int no_name)
{
char pretty[128], *cp;
char pretty[256], *cp;
struct commit_name *name = commit->object.util;
if (commit->object.parsed)
pretty_print_commit(CMIT_FMT_ONELINE, commit->buffer, ~0,
@ -360,7 +400,7 @@ int main(int ac, char **av)
unsigned int rev_mask[MAX_REVS];
int num_rev, i, extra = 0;
int all_heads = 0, all_tags = 0;
int all_mask, all_revs, shown_merge_point;
int all_mask, all_revs;
char head_path[128];
const char *head_path_p;
int head_path_len;
@ -369,6 +409,8 @@ int main(int ac, char **av)
int independent = 0;
int no_name = 0;
int sha1_name = 0;
int shown_merge_point = 0;
int topo_order = 0;
setup_git_directory();
@ -394,6 +436,8 @@ int main(int ac, char **av)
merge_base = 1;
else if (!strcmp(arg, "--independent"))
independent = 1;
else if (!strcmp(arg, "--topo-order"))
topo_order = 1;
else
usage(show_branch_usage);
ac--; av++;
@ -496,7 +540,8 @@ int main(int ac, char **av)
exit(0);
/* Sort topologically */
sort_in_topological_order(&seen);
if (topo_order)
sort_in_topological_order(&seen);
/* Give names to commits */
if (!sha1_name && !no_name)
@ -504,15 +549,12 @@ int main(int ac, char **av)
all_mask = ((1u << (REV_SHIFT + num_rev)) - 1);
all_revs = all_mask & ~((1u << REV_SHIFT) - 1);
shown_merge_point = 0;
while (seen) {
struct commit *commit = pop_one_commit(&seen);
int this_flag = commit->object.flags;
int is_merge_point = (this_flag & all_revs) == all_revs;
if (is_merge_point)
shown_merge_point = 1;
shown_merge_point |= ((this_flag & all_revs) == all_revs);
if (1 < num_rev) {
for (i = 0; i < num_rev; i++)
@ -521,9 +563,9 @@ int main(int ac, char **av)
putchar(' ');
}
show_one_commit(commit, no_name);
if (shown_merge_point && is_merge_point)
if (--extra < 0)
break;
if (shown_merge_point && --extra < 0)
break;
}
return 0;
}

View File

@ -15,9 +15,14 @@ shellquote = '$(call shq,$(1))'
T = $(wildcard t[0-9][0-9][0-9][0-9]-*.sh)
all:
@$(foreach t,$T,echo "*** $t ***"; $(call shellquote,$(SHELL_PATH)) $t $(GIT_TEST_OPTS) || exit; )
@rm -fr trash
all: $(T) clean
$(T):
@echo "*** $@ ***"; $(call shellquote,$(SHELL_PATH)) $@ $(GIT_TEST_OPTS)
clean:
rm -fr trash
.PHONY: $(T) clean
.NOPARALLEL:

View File

@ -122,7 +122,7 @@ cat > show-branch.expect << EOF
++ [mybranch] Some work.
EOF
git show-branch master mybranch > show-branch.output
git show-branch --topo-order master mybranch > show-branch.output
test_expect_success 'git show-branch' 'cmp show-branch.expect show-branch.output'
git checkout mybranch
@ -145,7 +145,7 @@ cat > show-branch2.expect << EOF
++ [master] Merged "mybranch" changes.
EOF
git show-branch master mybranch > show-branch2.output
git show-branch --topo-order master mybranch > show-branch2.output
test_expect_success 'git show-branch' 'cmp show-branch2.expect show-branch2.output'
# TODO: test git fetch

View File

@ -24,4 +24,12 @@ test_expect_failure \
'git branch --help should not have created a bogus branch' \
'test -f .git/refs/heads/--help'
test_expect_success \
'git branch abc should create a branch' \
'git-branch abc && test -f .git/refs/heads/abc'
test_expect_success \
'git branch a/b/c should create a branch' \
'git-branch a/b/c && test -f .git/refs/heads/a/b/c'
test_done

View File

@ -25,6 +25,7 @@ commit id embedding:
'
. ./test-lib.sh
TAR=${TAR:-tar}
test_expect_success \
'populate workdir' \

View File

@ -25,7 +25,7 @@ on_committer_date "1971-08-16 00:00:05" save_tag a1 unique_commit a1 tree -p a0
on_committer_date "1971-08-16 00:00:06" save_tag b1 unique_commit b1 tree -p a0
on_committer_date "1971-08-16 00:00:07" save_tag c1 unique_commit c1 tree -p b1
on_committer_date "1971-08-16 00:00:08" as_author foobar@example.com save_tag b2 unique_commit b2 tree -p b1
on_committer_date "1971-08-16 00:00:09" save_tag b3 unique_commit b2 tree -p b2
on_committer_date "1971-08-16 00:00:09" save_tag b3 unique_commit b3 tree -p b2
on_committer_date "1971-08-16 00:00:10" save_tag c2 unique_commit c2 tree -p c1 -p b2
on_committer_date "1971-08-16 00:00:11" save_tag c3 unique_commit c3 tree -p c2
on_committer_date "1971-08-16 00:00:12" save_tag a2 unique_commit a2 tree -p a1
@ -116,15 +116,15 @@ g0
EOF
test_output_expect_success 'multiple heads' 'git-rev-list --topo-order a3 b3 c3' <<EOF
b3
c3
c2
b2
c1
b1
a3
a2
a1
c3
c2
c1
b3
b2
b1
a0
l2
l1
@ -133,26 +133,26 @@ root
EOF
test_output_expect_success 'multiple heads, prune at a1' 'git-rev-list --topo-order a3 b3 c3 ^a1' <<EOF
b3
c3
c2
b2
c1
b1
a3
a2
c3
c2
c1
b3
b2
b1
EOF
test_output_expect_success 'multiple heads, prune at l1' 'git-rev-list --topo-order a3 b3 c3 ^l1' <<EOF
b3
c3
c2
b2
c1
b1
a3
a2
a1
c3
c2
c1
b3
b2
b1
a0
l2
EOF

59
t/t6010-merge-base.sh Executable file
View File

@ -0,0 +1,59 @@
#!/bin/sh
#
# Copyright (c) 2005 Junio C Hamano
#
test_description='Merge base computation.
'
. ./test-lib.sh
T=$(git-write-tree)
M=1130000000
Z=+0000
export GIT_COMMITTER_EMAIL=git@comm.iter.xz
export GIT_COMMITTER_NAME='C O Mmiter'
export GIT_AUTHOR_NAME='A U Thor'
export GIT_AUTHOR_EMAIL=git@au.thor.xz
doit() {
OFFSET=$1; shift
NAME=$1; shift
PARENTS=
for P
do
PARENTS="${PARENTS}-p $P "
done
GIT_COMMITTER_DATE="$(($M + $OFFSET)) $Z"
GIT_AUTHOR_DATE=$GIT_COMMITTER_DATE
export GIT_COMMITTER_DATE GIT_AUTHOR_DATE
commit=$(echo $NAME | git-commit-tree $T $PARENTS)
echo $commit >.git/refs/tags/$NAME
echo $commit
}
# Setup...
E=$(doit 5 E)
D=$(doit 4 D $E)
F=$(doit 6 F $E)
C=$(doit 3 C $D)
B=$(doit 2 B $C)
A=$(doit 1 A $B)
G=$(doit 7 G $B $E)
H=$(doit 8 H $A $F)
test_expect_success 'compute merge-base (single)' \
'MB=$(git-merge-base G H) &&
expr "$(git-name-rev "$MB")" : "[0-9a-f]* B"'
test_expect_success 'compute merge-base (all)' \
'MB=$(git-merge-base --all G H) &&
expr "$(git-name-rev "$MB")" : "[0-9a-f]* B"'
test_expect_success 'compute merge-base with show-branch' \
'MB=$(git-show-branch --merge-base G H) &&
expr "$(git-name-rev "$MB")" : "[0-9a-f]* B"'
test_done

View File

@ -13,7 +13,6 @@ shq = $(subst ','\'',$(1))
shellquote = '$(call shq,$(1))'
all: boilerplates.made custom
find blt
# Put templates that can be copied straight from the source
# in a file direc--tory--file in the source. They will be

View File

@ -6,7 +6,7 @@
#include <sys/time.h>
static int dry_run, quiet;
static const char unpack_usage[] = "git-unpack-objects [-q] < pack-file";
static const char unpack_usage[] = "git-unpack-objects [-n] [-q] < pack-file";
/* We always read in 4kB chunks. */
static unsigned char buffer[4096];

View File

@ -19,7 +19,8 @@ static int re_verify(const char *path, unsigned char *oldsha1, unsigned char *cu
int main(int argc, char **argv)
{
char *hex;
const char *refname, *value, *oldval, *path, *lockpath;
const char *refname, *value, *oldval, *path;
char *lockpath;
unsigned char sha1[20], oldsha1[20], currsha1[20];
int fd, written;
@ -42,13 +43,15 @@ int main(int argc, char **argv)
if (oldval) {
if (memcmp(currsha1, oldsha1, 20))
die("Ref %s changed to %s", refname, sha1_to_hex(currsha1));
die("Ref %s is at %s but expected %s", refname, sha1_to_hex(currsha1), sha1_to_hex(oldsha1));
/* Nothing to do? */
if (!memcmp(oldsha1, sha1, 20))
exit(0);
}
path = strdup(path);
lockpath = mkpath("%s.lock", path);
if (safe_create_leading_directories(lockpath) < 0)
die("Unable to create all of %s", lockpath);
fd = open(lockpath, O_CREAT | O_EXCL | O_WRONLY, 0666);
if (fd < 0)