Compare commits
178 Commits
Author | SHA1 | Date | |
---|---|---|---|
c2f3bf071e | |||
41f93a2c90 | |||
a3431febfe | |||
4b3511b0f8 | |||
407c8eb0d0 | |||
29e4d36357 | |||
a5c21d6eb7 | |||
913419fcc6 | |||
47dd0d595d | |||
1c15afb934 | |||
1fdfd05db2 | |||
e32faa8adb | |||
ba922ccee7 | |||
d89056c258 | |||
3aadad1b32 | |||
ef1cc2cc21 | |||
42f4570c86 | |||
3af849a3da | |||
112d0bafd6 | |||
ea77e675e5 | |||
d808111ebd | |||
2247efb40b | |||
ad89721508 | |||
c054d64e87 | |||
f7087e2e7c | |||
8872f27b87 | |||
011fbc7f07 | |||
80248b2e48 | |||
01385e2758 | |||
69224716f7 | |||
68283999f8 | |||
3ae854c356 | |||
06bf6ac424 | |||
ee34518d62 | |||
06d900cf28 | |||
e5e3a9d8f9 | |||
1403959cc8 | |||
2a58a9a92e | |||
92811b5767 | |||
c6f60f991f | |||
6677c4665a | |||
8431c4eb09 | |||
988eece42a | |||
31ec6abf88 | |||
1ed91937e5 | |||
294c695d8c | |||
32d9954478 | |||
e0e3ba208d | |||
252fef7149 | |||
773b633943 | |||
9a26dbd120 | |||
2db8aaeca1 | |||
b0d3e9baaa | |||
a4adf54d38 | |||
5073eb04d6 | |||
9678faaaff | |||
3ae39ab232 | |||
7ab099d220 | |||
d20e2f161b | |||
87358b7a19 | |||
43a95cfbc9 | |||
6cf6193b45 | |||
cf1fe88ce1 | |||
4e7824b12e | |||
349701210d | |||
806f36d4d7 | |||
aa9dc7afd2 | |||
d025524d9d | |||
b3f041fb0f | |||
01f49e3453 | |||
f4f9adaea7 | |||
ed24928e12 | |||
9954f5b876 | |||
0a8b4def9a | |||
9755afbd94 | |||
803f498c03 | |||
76cead391f | |||
1e2ccd3abc | |||
180c474647 | |||
0532a5e46b | |||
86c9523305 | |||
c7a45bd20e | |||
44db136cad | |||
962537a3eb | |||
e726715a52 | |||
d28c8af623 | |||
a9572072f0 | |||
b825e6ff5d | |||
157dc07368 | |||
28e77a8164 | |||
7564577a6c | |||
eea420693b | |||
73ab46d6d0 | |||
024510c8d9 | |||
10945e006a | |||
6e33101abd | |||
3e525e6738 | |||
6df896b50a | |||
42f44b08bc | |||
1136fb5284 | |||
5744f27794 | |||
f88961a85f | |||
2777ef76be | |||
8b15e2fbc9 | |||
db9536c856 | |||
10b94e283a | |||
0f737464a6 | |||
2b86976bfd | |||
2dee581667 | |||
c82365dc6f | |||
8c667f4bb8 | |||
d839091d13 | |||
03f6c23c5e | |||
5dd7342142 | |||
31f232819f | |||
5e34c99d95 | |||
6f855371a5 | |||
d4ce5f7e50 | |||
674b28085e | |||
d972217457 | |||
56e5e9170e | |||
e293de3efb | |||
eaa54efc61 | |||
16cc50d12e | |||
68e37f8402 | |||
63ae26f87a | |||
bcaf60b25b | |||
9688a882e1 | |||
49ccb0877f | |||
128aed684d | |||
64224caf88 | |||
361c06d8f5 | |||
6bad1902f5 | |||
12bd7e78ee | |||
2fa090b6c1 | |||
5e80092f7e | |||
fd8ccbec4f | |||
d23748a6af | |||
b539c5e8fb | |||
3bd348aeea | |||
9754563ca9 | |||
e23eff8be9 | |||
a6da9395a5 | |||
be61db922a | |||
bb6d7b893e | |||
5f6da1d9d2 | |||
75a46f6b0e | |||
4a62eaed31 | |||
9c2e7c0ca2 | |||
61f693bd5a | |||
23c99d8460 | |||
8d69195124 | |||
4050c0df8e | |||
4dd5d0d9eb | |||
cd8c458947 | |||
53e7181cd9 | |||
9cebe90bc5 | |||
f13d7db4af | |||
dc5f9239f7 | |||
eb0362a467 | |||
dfa2f22f94 | |||
63d34b0b13 | |||
556cb4e583 | |||
3e15c67c90 | |||
d5eac49868 | |||
6f42f89c1f | |||
1494e03888 | |||
b270c634b7 | |||
18d1e701b7 | |||
f83df6d66e | |||
8bf14d6ef9 | |||
287f860054 | |||
7b9b4c452c | |||
9a79c5a8b4 | |||
3a2674337c | |||
4c353e890c | |||
38ad0910a0 | |||
b5c2f30689 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -60,7 +60,6 @@ git-merge-stupid
|
|||||||
git-mktag
|
git-mktag
|
||||||
git-name-rev
|
git-name-rev
|
||||||
git-mv
|
git-mv
|
||||||
git-octopus
|
|
||||||
git-pack-redundant
|
git-pack-redundant
|
||||||
git-pack-objects
|
git-pack-objects
|
||||||
git-parse-remote
|
git-parse-remote
|
||||||
|
@ -9,6 +9,7 @@ ARTICLES += diffcore
|
|||||||
ARTICLES += howto-index
|
ARTICLES += howto-index
|
||||||
ARTICLES += repository-layout
|
ARTICLES += repository-layout
|
||||||
ARTICLES += hooks
|
ARTICLES += hooks
|
||||||
|
ARTICLES += everyday
|
||||||
# with their own formatting rules.
|
# with their own formatting rules.
|
||||||
SP_ARTICLES = glossary howto/revert-branch-rebase
|
SP_ARTICLES = glossary howto/revert-branch-rebase
|
||||||
|
|
||||||
|
@ -187,7 +187,8 @@ you would use git-rev-list and git-diff-tree like this:
|
|||||||
|
|
||||||
We have already talked about the "\--stdin" form of git-diff-tree
|
We have already talked about the "\--stdin" form of git-diff-tree
|
||||||
command that reads the list of commits and compares each commit
|
command that reads the list of commits and compares each commit
|
||||||
with its parents. The git-whatchanged command internally runs
|
with its parents (otherwise you should go back and read the tutorial).
|
||||||
|
The git-whatchanged command internally runs
|
||||||
the equivalent of the above command, and can be used like this:
|
the equivalent of the above command, and can be used like this:
|
||||||
|
|
||||||
$ git-whatchanged -p -S'if (frotz) {
|
$ git-whatchanged -p -S'if (frotz) {
|
||||||
|
@ -18,6 +18,14 @@
|
|||||||
object name of pre- and post-image blob on the "index"
|
object name of pre- and post-image blob on the "index"
|
||||||
line when generating a patch format output.
|
line when generating a patch format output.
|
||||||
|
|
||||||
|
--abbrev[=<n>]::
|
||||||
|
Instead of showing the full 40-byte hexadecimal object
|
||||||
|
name in diff-raw format output and diff-tree header
|
||||||
|
lines, show only handful dhexigits prefix. This is
|
||||||
|
independent of --full-index option above, which controls
|
||||||
|
the diff-patch output format. Non default number of
|
||||||
|
digits can be specified with --abbrev=<n>.
|
||||||
|
|
||||||
-B::
|
-B::
|
||||||
Break complete rewrite changes into pairs of delete and create.
|
Break complete rewrite changes into pairs of delete and create.
|
||||||
|
|
||||||
|
441
Documentation/everyday.txt
Normal file
441
Documentation/everyday.txt
Normal file
@ -0,0 +1,441 @@
|
|||||||
|
Everyday GIT With 20 Commands Or So
|
||||||
|
===================================
|
||||||
|
|
||||||
|
GIT suite has over 100 commands, and the manual page for each of
|
||||||
|
them discusses what the command does and how it is used in
|
||||||
|
detail, but until you know what command should be used in order
|
||||||
|
to achieve what you want to do, you cannot tell which manual
|
||||||
|
page to look at, and if you know that already you do not need
|
||||||
|
the manual.
|
||||||
|
|
||||||
|
Does that mean you need to know all of them before you can use
|
||||||
|
git? Not at all. Depending on the role you play, the set of
|
||||||
|
commands you need to know is slightly different, but in any case
|
||||||
|
what you need to learn is far smaller than the full set of
|
||||||
|
commands to carry out your day-to-day work. This document is to
|
||||||
|
serve as a cheat-sheet and a set of pointers for people playing
|
||||||
|
various roles.
|
||||||
|
|
||||||
|
<<Basic Repository>> commands are needed by people who has a
|
||||||
|
repository --- that is everybody, because every working tree of
|
||||||
|
git is a repository.
|
||||||
|
|
||||||
|
In addition, <<Individual Developer (Standalone)>> commands are
|
||||||
|
essential for anybody who makes a commit, even for somebody who
|
||||||
|
works alone.
|
||||||
|
|
||||||
|
If you work with other people, you will need commands listed in
|
||||||
|
<<Individual Developer (Participant)>> section as well.
|
||||||
|
|
||||||
|
People who play <<Integrator>> role need to learn some more
|
||||||
|
commands in addition to the above.
|
||||||
|
|
||||||
|
<<Repository Administration>> commands are for system
|
||||||
|
administrators who are responsible to care and feed git
|
||||||
|
repositories to support developers.
|
||||||
|
|
||||||
|
|
||||||
|
Basic Repository[[Basic Repository]]
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
Everybody uses these commands to feed and care git repositories.
|
||||||
|
|
||||||
|
* gitlink:git-init-db[1] or gitlink:git-clone[1] to create a
|
||||||
|
new repository.
|
||||||
|
|
||||||
|
* gitlink:git-fsck-objects[1] to validate the repository.
|
||||||
|
|
||||||
|
* gitlink:git-prune[1] to garbage collect crufts in the
|
||||||
|
repository.
|
||||||
|
|
||||||
|
* gitlink:git-repack[1] to pack loose objects for efficiency.
|
||||||
|
|
||||||
|
Examples
|
||||||
|
~~~~~~~~
|
||||||
|
|
||||||
|
Check health and remove cruft.::
|
||||||
|
+
|
||||||
|
------------
|
||||||
|
$ git fsck-objects <1>
|
||||||
|
$ git prune
|
||||||
|
$ git count-objects <2>
|
||||||
|
$ git repack <3>
|
||||||
|
$ git prune <4>
|
||||||
|
|
||||||
|
<1> running without "--full" is usually cheap and assures the
|
||||||
|
repository health reasonably well.
|
||||||
|
<2> check how many loose objects there are and how much
|
||||||
|
diskspace is wasted by not repacking.
|
||||||
|
<3> without "-a" repacks incrementally. repacking every 4-5MB
|
||||||
|
of loose objects accumulation may be a good rule of thumb.
|
||||||
|
<4> after repack, prune removes the duplicate loose objects.
|
||||||
|
------------
|
||||||
|
|
||||||
|
Repack a small project into single pack.::
|
||||||
|
+
|
||||||
|
------------
|
||||||
|
$ git repack -a -d <1>
|
||||||
|
$ git prune
|
||||||
|
|
||||||
|
<1> pack all the objects reachable from the refs into one pack
|
||||||
|
and remove unneeded other packs
|
||||||
|
------------
|
||||||
|
|
||||||
|
|
||||||
|
Individual Developer (Standalone)[[Individual Developer (Standalone)]]
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
A standalone individual developer does not exchange patches with
|
||||||
|
other poeple, and works alone in a single repository, using the
|
||||||
|
following commands.
|
||||||
|
|
||||||
|
* gitlink:git-show-branch[1] to see where you are.
|
||||||
|
|
||||||
|
* gitlink:git-log[1] to see what happened.
|
||||||
|
|
||||||
|
* gitlink:git-whatchanged[1] to find out where things have
|
||||||
|
come from.
|
||||||
|
|
||||||
|
* gitlink:git-checkout[1] and gitlink:git-branch[1] to switch
|
||||||
|
branches.
|
||||||
|
|
||||||
|
* gitlink:git-add[1] and gitlink:git-update-index[1] to manage
|
||||||
|
the index file.
|
||||||
|
|
||||||
|
* gitlink:git-diff[1] and gitlink:git-status[1] to see what
|
||||||
|
you are in the middle of doing.
|
||||||
|
|
||||||
|
* gitlink:git-commit[1] to advance the current branch.
|
||||||
|
|
||||||
|
* gitlink:git-reset[1] and gitlink:git-checkout[1] (with
|
||||||
|
pathname parameters) to undo changes.
|
||||||
|
|
||||||
|
* gitlink:git-pull[1] with "." as the remote to merge between
|
||||||
|
local branches.
|
||||||
|
|
||||||
|
* gitlink:git-rebase[1] to maintain topic branches.
|
||||||
|
|
||||||
|
* gitlink:git-tag[1] to mark known point.
|
||||||
|
|
||||||
|
Examples
|
||||||
|
~~~~~~~~
|
||||||
|
|
||||||
|
Extract a tarball and create a working tree and a new repository to keep track of it.::
|
||||||
|
+
|
||||||
|
------------
|
||||||
|
$ tar zxf frotz.tar.gz
|
||||||
|
$ cd frotz
|
||||||
|
$ git-init-db
|
||||||
|
$ git add . <1>
|
||||||
|
$ git commit -m 'import of frotz source tree.'
|
||||||
|
$ git tag v2.43 <2>
|
||||||
|
|
||||||
|
<1> add everything under the current directory.
|
||||||
|
<2> make a lightweight, unannotated tag.
|
||||||
|
------------
|
||||||
|
|
||||||
|
Create a topic branch and develop.::
|
||||||
|
+
|
||||||
|
------------
|
||||||
|
$ git checkout -b alsa-audio <1>
|
||||||
|
$ edit/compile/test
|
||||||
|
$ git checkout -- curses/ux_audio_oss.c <2>
|
||||||
|
$ git add curses/ux_audio_alsa.c <3>
|
||||||
|
$ edit/compile/test
|
||||||
|
$ git diff <4>
|
||||||
|
$ git commit -a -s <5>
|
||||||
|
$ edit/compile/test
|
||||||
|
$ git reset --soft HEAD^ <6>
|
||||||
|
$ edit/compile/test
|
||||||
|
$ git diff ORIG_HEAD <7>
|
||||||
|
$ git commit -a -c ORIG_HEAD <8>
|
||||||
|
$ git checkout master <9>
|
||||||
|
$ git pull . alsa-audio <10>
|
||||||
|
$ git log --since='3 days ago' <11>
|
||||||
|
$ git log v2.43.. curses/ <12>
|
||||||
|
|
||||||
|
<1> create a new topic branch.
|
||||||
|
<2> revert your botched changes in "curses/ux_audio_oss.c".
|
||||||
|
<3> you need to tell git if you added a new file; removal and
|
||||||
|
modification will be caught if you do "commit -a" later.
|
||||||
|
<4> to see what changes you are committing.
|
||||||
|
<5> commit everything as you have tested, with your sign-off.
|
||||||
|
<6> take the last commit back, keeping what is in the working tree.
|
||||||
|
<7> look at the changes since the premature commit we took back.
|
||||||
|
<8> redo the commit undone in the previous step, using the message
|
||||||
|
you originally wrote.
|
||||||
|
<9> switch to the master branch.
|
||||||
|
<10> merge a topic branch into your master branch
|
||||||
|
<11> review commit logs; other forms to limit output can be
|
||||||
|
combined and include --max-count=10 (show 10 commits), --until='2005-12-10'.
|
||||||
|
<12> view only the changes that touch what's in curses/
|
||||||
|
directory, since v2.43 tag.
|
||||||
|
------------
|
||||||
|
|
||||||
|
|
||||||
|
Individual Developer (Participant)[[Individual Developer (Participant)]]
|
||||||
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
|
A developer working as a participant in a group project needs to
|
||||||
|
learn how to communicate with others, and uses these commands in
|
||||||
|
addition to the ones needed by a standalone developer.
|
||||||
|
|
||||||
|
* gitlink:git-clone[1] from the upstream to prime your local
|
||||||
|
repository.
|
||||||
|
|
||||||
|
* gitlink:git-pull[1] and gitlink:git-fetch[1] from "origin"
|
||||||
|
to keep up-to-date with the upstream.
|
||||||
|
|
||||||
|
* gitlink:git-push[1] to shared repository, if you adopt CVS
|
||||||
|
style shared repository workflow.
|
||||||
|
|
||||||
|
* gitlink:git-format-patch[1] to prepare e-mail submission, if
|
||||||
|
you adopt Linux kernel-style public forum workflow.
|
||||||
|
|
||||||
|
Examples
|
||||||
|
~~~~~~~~
|
||||||
|
|
||||||
|
Clone the upstream and work on it. Feed changes to upstream.::
|
||||||
|
+
|
||||||
|
------------
|
||||||
|
$ git clone git://git.kernel.org/pub/scm/.../torvalds/linux-2.6 my2.6
|
||||||
|
$ cd my2.6
|
||||||
|
$ edit/compile/test; git commit -a -s <1>
|
||||||
|
$ git format-patch origin <2>
|
||||||
|
$ git pull <3>
|
||||||
|
$ git whatchanged -p ORIG_HEAD.. arch/i386 include/asm-i386 <4>
|
||||||
|
$ git pull git://git.kernel.org/pub/.../jgarzik/libata-dev.git ALL <5>
|
||||||
|
$ git reset --hard ORIG_HEAD <6>
|
||||||
|
$ git prune <7>
|
||||||
|
$ git fetch --tags <8>
|
||||||
|
|
||||||
|
<1> repeat as needed.
|
||||||
|
<2> extract patches from your branch for e-mail submission.
|
||||||
|
<3> "pull" fetches from "origin" by default and merges into the
|
||||||
|
current branch.
|
||||||
|
<4> immediately after pulling, look at the changes done upstream
|
||||||
|
since last time we checked, only in the
|
||||||
|
area we are interested in.
|
||||||
|
<5> fetch from a specific branch from a specific repository and merge.
|
||||||
|
<6> revert the pull.
|
||||||
|
<7> garbage collect leftover objects from reverted pull.
|
||||||
|
<8> from time to time, obtain official tags from the "origin"
|
||||||
|
and store them under .git/refs/tags/.
|
||||||
|
------------
|
||||||
|
|
||||||
|
|
||||||
|
Push into another repository.::
|
||||||
|
+
|
||||||
|
------------
|
||||||
|
satellite$ git clone mothership:frotz/.git frotz <1>
|
||||||
|
satellite$ cd frotz
|
||||||
|
satellite$ cat .git/remotes/origin <2>
|
||||||
|
URL: mothership:frotz/.git
|
||||||
|
Pull: master:origin
|
||||||
|
satellite$ echo 'Push: master:satellite' >>.git/remotes/origin <3>
|
||||||
|
satellite$ edit/compile/test/commit
|
||||||
|
satellite$ git push origin <4>
|
||||||
|
|
||||||
|
mothership$ cd frotz
|
||||||
|
mothership$ git checkout master
|
||||||
|
mothership$ git pull . satellite <5>
|
||||||
|
|
||||||
|
<1> mothership machine has a frotz repository under your home
|
||||||
|
directory; clone from it to start a repository on the satellite
|
||||||
|
machine.
|
||||||
|
<2> clone creates this file by default. It arranges "git pull"
|
||||||
|
to fetch and store the master branch head of mothership machine
|
||||||
|
to local "origin" branch.
|
||||||
|
<3> arrange "git push" to push local "master" branch to
|
||||||
|
"satellite" branch of the mothership machine.
|
||||||
|
<4> push will stash our work away on "satellite" branch on the
|
||||||
|
mothership machine. You could use this as a back-up method.
|
||||||
|
<5> on mothership machine, merge the work done on the satellite
|
||||||
|
machine into the master branch.
|
||||||
|
------------
|
||||||
|
|
||||||
|
Branch off of a specific tag.::
|
||||||
|
+
|
||||||
|
------------
|
||||||
|
$ git checkout -b private2.6.14 v2.6.14 <1>
|
||||||
|
$ edit/compile/test; git commit -a
|
||||||
|
$ git checkout master
|
||||||
|
$ git format-patch -k -m --stdout v2.6.14..private2.6.14 |
|
||||||
|
git am -3 -k <2>
|
||||||
|
|
||||||
|
<1> create a private branch based on a well known (but somewhat behind)
|
||||||
|
tag.
|
||||||
|
<2> forward port all changes in private2.6.14 branch to master branch
|
||||||
|
without a formal "merging".
|
||||||
|
------------
|
||||||
|
|
||||||
|
|
||||||
|
Integrator[[Integrator]]
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
A fairly central person acting as the integrator in a group
|
||||||
|
project receives changes made by others, reviews and integrates
|
||||||
|
them and publishes the result for others to use, using these
|
||||||
|
commands in addition to the ones needed by participants.
|
||||||
|
|
||||||
|
* gitlink:git-am[1] to apply patches e-mailed in from your
|
||||||
|
contributors.
|
||||||
|
|
||||||
|
* gitlink:git-pull[1] to merge from your trusted lieutenants.
|
||||||
|
|
||||||
|
* gitlink:git-format-patch[1] to prepare and send suggested
|
||||||
|
alternative to contributors.
|
||||||
|
|
||||||
|
* gitlink:git-revert[1] to undo botched commits.
|
||||||
|
|
||||||
|
* gitlink:git-push[1] to publish the bleeding edge.
|
||||||
|
|
||||||
|
|
||||||
|
Examples
|
||||||
|
~~~~~~~~
|
||||||
|
|
||||||
|
My typical GIT day.::
|
||||||
|
+
|
||||||
|
------------
|
||||||
|
$ git status <1>
|
||||||
|
$ git show-branch <2>
|
||||||
|
$ mailx <3>
|
||||||
|
& s 2 3 4 5 ./+to-apply
|
||||||
|
& s 7 8 ./+hold-linus
|
||||||
|
& q
|
||||||
|
$ git checkout master
|
||||||
|
$ git am -3 -i -s -u ./+to-apply <4>
|
||||||
|
$ compile/test
|
||||||
|
$ git checkout -b hold/linus && git am -3 -i -s -u ./+hold-linus <5>
|
||||||
|
$ git checkout topic/one && git rebase master <6>
|
||||||
|
$ git checkout pu && git reset --hard master <7>
|
||||||
|
$ git pull . topic/one topic/two && git pull . hold/linus <8>
|
||||||
|
$ git checkout maint
|
||||||
|
$ git cherry-pick master~4 <9>
|
||||||
|
$ compile/test
|
||||||
|
$ git tag -s -m 'GIT 0.99.9x' v0.99.9x <10>
|
||||||
|
$ git fetch ko && git show-branch master maint 'tags/ko-*' <11>
|
||||||
|
$ git push ko <12>
|
||||||
|
$ git push ko v0.99.9x <13>
|
||||||
|
|
||||||
|
<1> see what I was in the middle of doing, if any.
|
||||||
|
<2> see what topic branches I have and think about how ready
|
||||||
|
they are.
|
||||||
|
<3> read mails, save ones that are applicable, and save others
|
||||||
|
that are not quite ready.
|
||||||
|
<4> apply them, interactively, with my sign-offs.
|
||||||
|
<5> create topic branch as needed and apply, again with my
|
||||||
|
sign-offs.
|
||||||
|
<6> rebase internal topic branch that has not been merged to the
|
||||||
|
master, nor exposed as a part of a stable branch.
|
||||||
|
<7> restart "pu" every time from the master.
|
||||||
|
<8> and bundle topic branches still cooking.
|
||||||
|
<9> backport a critical fix.
|
||||||
|
<10> create a signed tag.
|
||||||
|
<11> make sure I did not accidentally rewind master beyond what I
|
||||||
|
already pushed out. "ko" shorthand points at the repository I have
|
||||||
|
at kernel.org, and looks like this:
|
||||||
|
$ cat .git/remotes/ko
|
||||||
|
URL: kernel.org:/pub/scm/git/git.git
|
||||||
|
Pull: master:refs/tags/ko-master
|
||||||
|
Pull: maint:refs/tags/ko-maint
|
||||||
|
Push: master
|
||||||
|
Push: +pu
|
||||||
|
Push: maint
|
||||||
|
In the output from "git show-branch", "master" should have
|
||||||
|
everything "ko-master" has.
|
||||||
|
<12> push out the bleeding edge.
|
||||||
|
<13> push the tag out, too.
|
||||||
|
------------
|
||||||
|
|
||||||
|
|
||||||
|
Repository Administration[[Repository Administration]]
|
||||||
|
------------------------------------------------------
|
||||||
|
|
||||||
|
A repository administrator uses the following tools to set up
|
||||||
|
and maintain access to the repository by developers.
|
||||||
|
|
||||||
|
* gitlink:git-daemon[1] to allow anonymous download from
|
||||||
|
repository.
|
||||||
|
|
||||||
|
* gitlink:git-shell[1] can be used as a 'restricted login shell'
|
||||||
|
for shared central repository users.
|
||||||
|
|
||||||
|
link:howto/update-hook-example.txt[update hook howto] has a good
|
||||||
|
example of managing a shared central repository.
|
||||||
|
|
||||||
|
|
||||||
|
Examples
|
||||||
|
~~~~~~~~
|
||||||
|
|
||||||
|
Run git-daemon to serve /pub/scm from inetd.::
|
||||||
|
+
|
||||||
|
------------
|
||||||
|
$ grep git /etc/inet.conf
|
||||||
|
git stream tcp nowait nobody \
|
||||||
|
/usr/bin/git-daemon git-daemon --inetd --syslog --export-all /pub/scm
|
||||||
|
------------
|
||||||
|
+
|
||||||
|
The actual configuration line should be on one line.
|
||||||
|
|
||||||
|
Give push/pull only access to developers.::
|
||||||
|
+
|
||||||
|
------------
|
||||||
|
$ grep git /etc/passwd <1>
|
||||||
|
alice:x:1000:1000::/home/alice:/usr/bin/git-shell
|
||||||
|
bob:x:1001:1001::/home/bob:/usr/bin/git-shell
|
||||||
|
cindy:x:1002:1002::/home/cindy:/usr/bin/git-shell
|
||||||
|
david:x:1003:1003::/home/david:/usr/bin/git-shell
|
||||||
|
$ grep git /etc/shells <2>
|
||||||
|
/usr/bin/git-shell
|
||||||
|
|
||||||
|
<1> log-in shell is set to /usr/bin/git-shell, which does not
|
||||||
|
allow anything but "git push" and "git pull". The users should
|
||||||
|
get an ssh access to the machine.
|
||||||
|
<2> in many distributions /etc/shells needs to list what is used
|
||||||
|
as the login shell.
|
||||||
|
------------
|
||||||
|
|
||||||
|
CVS-style shared repository.::
|
||||||
|
+
|
||||||
|
------------
|
||||||
|
$ grep git /etc/group <1>
|
||||||
|
git:x:9418:alice,bob,cindy,david
|
||||||
|
$ cd /home/devo.git
|
||||||
|
$ ls -l <2>
|
||||||
|
lrwxrwxrwx 1 david git 17 Dec 4 22:40 HEAD -> refs/heads/master
|
||||||
|
drwxrwsr-x 2 david git 4096 Dec 4 22:40 branches
|
||||||
|
-rw-rw-r-- 1 david git 84 Dec 4 22:40 config
|
||||||
|
-rw-rw-r-- 1 david git 58 Dec 4 22:40 description
|
||||||
|
drwxrwsr-x 2 david git 4096 Dec 4 22:40 hooks
|
||||||
|
-rw-rw-r-- 1 david git 37504 Dec 4 22:40 index
|
||||||
|
drwxrwsr-x 2 david git 4096 Dec 4 22:40 info
|
||||||
|
drwxrwsr-x 4 david git 4096 Dec 4 22:40 objects
|
||||||
|
drwxrwsr-x 4 david git 4096 Nov 7 14:58 refs
|
||||||
|
drwxrwsr-x 2 david git 4096 Dec 4 22:40 remotes
|
||||||
|
$ ls -l hooks/update <3>
|
||||||
|
-r-xr-xr-x 1 david git 3536 Dec 4 22:40 update
|
||||||
|
$ cat info/allowed-users <4>
|
||||||
|
refs/heads/master alice\|cindy
|
||||||
|
refs/heads/doc-update bob
|
||||||
|
refs/tags/v[0-9]* david
|
||||||
|
|
||||||
|
<1> place the developers into the same git group.
|
||||||
|
<2> and make the shared repository writable by the group.
|
||||||
|
<3> use update-hook example by Carl from Documentation/howto/
|
||||||
|
for branch policy control.
|
||||||
|
<4> alice and cindy can push into master, only bob can push into doc-update.
|
||||||
|
david is the release manager and is the only person who can
|
||||||
|
create and push version tags.
|
||||||
|
------------
|
||||||
|
|
||||||
|
HTTP server to support dumb protocol transfer.::
|
||||||
|
+
|
||||||
|
------------
|
||||||
|
dev$ git update-server-info <1>
|
||||||
|
dev$ ftp user@isp.example.com <2>
|
||||||
|
ftp> cp -r .git /home/user/myproject.git
|
||||||
|
|
||||||
|
<1> make sure your info/refs and objects/info/packs are up-to-date
|
||||||
|
<2> upload to public HTTP server hosted by your ISP.
|
||||||
|
------------
|
@ -28,7 +28,7 @@ OPTIONS
|
|||||||
area to store extracted patches.
|
area to store extracted patches.
|
||||||
|
|
||||||
--utf8, --keep::
|
--utf8, --keep::
|
||||||
Pass `--utf8` and `--keep` flags to `git-mailinfo` (see
|
Pass `-u` and `-k` flags to `git-mailinfo` (see
|
||||||
gitlink:git-mailinfo[1]).
|
gitlink:git-mailinfo[1]).
|
||||||
|
|
||||||
--binary::
|
--binary::
|
||||||
@ -69,7 +69,7 @@ recover from this in one of two ways:
|
|||||||
|
|
||||||
. hand resolve the conflict in the working directory, and update
|
. hand resolve the conflict in the working directory, and update
|
||||||
the index file to bring it in a state that the patch should
|
the index file to bring it in a state that the patch should
|
||||||
have produced. Then run the command with '--resume' option.
|
have produced. Then run the command with '--resolved' option.
|
||||||
|
|
||||||
The command refuses to process new mailboxes while `.dotest`
|
The command refuses to process new mailboxes while `.dotest`
|
||||||
directory exists, so if you decide to start over from scratch,
|
directory exists, so if you decide to start over from scratch,
|
||||||
|
@ -8,7 +8,8 @@ git-archimport - Import an Arch repository into git
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
`git-archimport` [ -h ] [ -v ] [ -T ] [ -t tempdir ]
|
`git-archimport` [ -h ] [ -v ] [ -o ] [ -a ] [ -f ] [ -T ]
|
||||||
|
[ -D depth ] [ -t tempdir ]
|
||||||
<archive/branch> [ <archive/branch> ]
|
<archive/branch> [ <archive/branch> ]
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
@ -63,6 +64,26 @@ OPTIONS
|
|||||||
Many tags. Will create a tag for every commit, reflecting the commit
|
Many tags. Will create a tag for every commit, reflecting the commit
|
||||||
name in the Arch repository.
|
name in the Arch repository.
|
||||||
|
|
||||||
|
-f::
|
||||||
|
Use the fast patchset import strategy. This can be significantly
|
||||||
|
faster for large trees, but cannot handle directory renames or
|
||||||
|
permissions changes. The default strategy is slow and safe.
|
||||||
|
|
||||||
|
-o::
|
||||||
|
Use this for compatibility with old-style branch names used by
|
||||||
|
earlier versions of git-archimport. Old-style branch names
|
||||||
|
were category--branch, whereas new-style branch names are
|
||||||
|
archive,category--branch--version.
|
||||||
|
|
||||||
|
-D <depth>::
|
||||||
|
Follow merge ancestry and attempt to import trees that have been
|
||||||
|
merged from. Specify a depth greater than 1 if patch logs have been
|
||||||
|
pruned.
|
||||||
|
|
||||||
|
-a::
|
||||||
|
Attempt to auto-register archives at http://mirrors.sourcecontrol.net
|
||||||
|
This is particularly useful with the -D option.
|
||||||
|
|
||||||
-t <tmpdir>::
|
-t <tmpdir>::
|
||||||
Override the default tempdir.
|
Override the default tempdir.
|
||||||
|
|
||||||
|
@ -8,16 +8,21 @@ git-bisect - Find the change that introduced a bug
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
'git bisect' start
|
'git bisect' <subcommand> <options>
|
||||||
'git bisect' bad <rev>
|
|
||||||
'git bisect' good <rev>
|
|
||||||
'git bisect' reset [<branch>]
|
|
||||||
'git bisect' visualize
|
|
||||||
'git bisect' replay <logfile>
|
|
||||||
'git bisect' log
|
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
|
The command takes various subcommands, and different options
|
||||||
|
depending on the subcommand:
|
||||||
|
|
||||||
|
git bisect start [<paths>...]
|
||||||
|
git bisect bad <rev>
|
||||||
|
git bisect good <rev>
|
||||||
|
git bisect reset [<branch>]
|
||||||
|
git bisect visualize
|
||||||
|
git bisect replay <logfile>
|
||||||
|
git bisect log
|
||||||
|
|
||||||
This command uses 'git-rev-list --bisect' option to help drive
|
This command uses 'git-rev-list --bisect' option to help drive
|
||||||
the binary search process to find which change introduced a bug,
|
the binary search process to find which change introduced a bug,
|
||||||
given an old "good" commit object name and a later "bad" commit
|
given an old "good" commit object name and a later "bad" commit
|
||||||
@ -26,10 +31,10 @@ object name.
|
|||||||
The way you use it is:
|
The way you use it is:
|
||||||
|
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
git bisect start
|
$ git bisect start
|
||||||
git bisect bad # Current version is bad
|
$ git bisect bad # Current version is bad
|
||||||
git bisect good v2.6.13-rc2 # v2.6.13-rc2 was the last version
|
$ git bisect good v2.6.13-rc2 # v2.6.13-rc2 was the last version
|
||||||
# tested that was good
|
# tested that was good
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
|
|
||||||
When you give at least one bad and one good versions, it will
|
When you give at least one bad and one good versions, it will
|
||||||
@ -43,7 +48,7 @@ and check out the state in the middle. Now, compile that kernel, and boot
|
|||||||
it. Now, let's say that this booted kernel works fine, then just do
|
it. Now, let's say that this booted kernel works fine, then just do
|
||||||
|
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
git bisect good # this one is good
|
$ git bisect good # this one is good
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
|
|
||||||
which will now say
|
which will now say
|
||||||
@ -62,7 +67,7 @@ kernel rev in "refs/bisect/bad".
|
|||||||
Oh, and then after you want to reset to the original head, do a
|
Oh, and then after you want to reset to the original head, do a
|
||||||
|
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
git bisect reset
|
$ git bisect reset
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
|
|
||||||
to get back to the master branch, instead of being in one of the bisection
|
to get back to the master branch, instead of being in one of the bisection
|
||||||
@ -72,7 +77,9 @@ not using some old bisection branch).
|
|||||||
|
|
||||||
During the bisection process, you can say
|
During the bisection process, you can say
|
||||||
|
|
||||||
git bisect visualize
|
------------
|
||||||
|
$ git bisect visualize
|
||||||
|
------------
|
||||||
|
|
||||||
to see the currently remaining suspects in `gitk`.
|
to see the currently remaining suspects in `gitk`.
|
||||||
|
|
||||||
@ -80,11 +87,40 @@ The good/bad input is logged, and `git bisect
|
|||||||
log` shows what you have done so far. You can truncate its
|
log` shows what you have done so far. You can truncate its
|
||||||
output somewhere and save it in a file, and run
|
output somewhere and save it in a file, and run
|
||||||
|
|
||||||
git bisect replay that-file
|
------------
|
||||||
|
$ git bisect replay that-file
|
||||||
|
------------
|
||||||
|
|
||||||
if you find later you made a mistake telling good/bad about a
|
if you find later you made a mistake telling good/bad about a
|
||||||
revision.
|
revision.
|
||||||
|
|
||||||
|
If in a middle of bisect session, you know what the bisect
|
||||||
|
suggested to try next is not a good one to test (e.g. the change
|
||||||
|
the commit introduces is known not to work in your environment
|
||||||
|
and you know it does not have anything to do with the bug you
|
||||||
|
are chasing), you may want to find a near-by commit and try that
|
||||||
|
instead. It goes something like this:
|
||||||
|
|
||||||
|
------------
|
||||||
|
$ git bisect good/bad # previous round was good/bad.
|
||||||
|
Bisecting: 337 revisions left to test after this
|
||||||
|
$ git bisect visualize # oops, that is uninteresting.
|
||||||
|
$ git reset --hard HEAD~3 # try 3 revs before what
|
||||||
|
# was suggested
|
||||||
|
------------
|
||||||
|
|
||||||
|
Then compile and test the one you chose to try. After that,
|
||||||
|
tell bisect what the result was as usual.
|
||||||
|
|
||||||
|
You can further cut down the number of trials if you know what
|
||||||
|
part of the tree is involved in the problem you are tracking
|
||||||
|
down, by giving paths parameters when you say `bisect start`,
|
||||||
|
like this:
|
||||||
|
|
||||||
|
------------
|
||||||
|
$ git bisect start arch/i386 include/asm-i386
|
||||||
|
------------
|
||||||
|
|
||||||
|
|
||||||
Author
|
Author
|
||||||
------
|
------
|
||||||
|
@ -32,6 +32,32 @@ start-point::
|
|||||||
Where to create the branch; defaults to HEAD. This
|
Where to create the branch; defaults to HEAD. This
|
||||||
option has no meaning with -d and -D.
|
option has no meaning with -d and -D.
|
||||||
|
|
||||||
|
|
||||||
|
Examples
|
||||||
|
~~~~~~~~
|
||||||
|
|
||||||
|
Start development off of a know tag::
|
||||||
|
+
|
||||||
|
------------
|
||||||
|
$ git clone git://git.kernel.org/pub/scm/.../linux-2.6 my2.6
|
||||||
|
$ cd my2.6
|
||||||
|
$ git branch my2.6.14 v2.6.14 <1>
|
||||||
|
$ git checkout my2.6.14
|
||||||
|
|
||||||
|
<1> These two steps are the same as "checkout -b my2.6.14 v2.6.14".
|
||||||
|
------------
|
||||||
|
|
||||||
|
Delete unneeded branch::
|
||||||
|
+
|
||||||
|
------------
|
||||||
|
$ git clone git://git.kernel.org/.../git.git my.git
|
||||||
|
$ cd my.git
|
||||||
|
$ git branch -D todo <1>
|
||||||
|
|
||||||
|
<1> delete todo branch even if the "master" branch does not have all
|
||||||
|
commits from todo branch.
|
||||||
|
------------
|
||||||
|
|
||||||
Author
|
Author
|
||||||
------
|
------
|
||||||
Written by Linus Torvalds <torvalds@osdl.org> and Junio C Hamano <junkio@cox.net>
|
Written by Linus Torvalds <torvalds@osdl.org> and Junio C Hamano <junkio@cox.net>
|
||||||
|
@ -26,13 +26,15 @@ imposes the following rules on how refs are named:
|
|||||||
|
|
||||||
. It cannot have ASCII control character (i.e. bytes whose
|
. It cannot have ASCII control character (i.e. bytes whose
|
||||||
values are lower than \040, or \177 `DEL`), space, tilde `~`,
|
values are lower than \040, or \177 `DEL`), space, tilde `~`,
|
||||||
caret `{caret}`, or colon `:` anywhere;
|
caret `{caret}`, colon `:`, question-mark `?`, asterisk `*`,
|
||||||
|
or open bracket `[` anywhere;
|
||||||
|
|
||||||
. It cannot end with a slash `/`.
|
. It cannot end with a slash `/`.
|
||||||
|
|
||||||
These rules makes it easy for shell script based tools to parse
|
These rules makes it easy for shell script based tools to parse
|
||||||
refnames, and also avoids ambiguities in certain refname
|
refnames, pathname expansion by the shell when a refname is used
|
||||||
expressions (see gitlink:git-rev-parse[1]). Namely:
|
unquoted (by mistake), and also avoids ambiguities in certain
|
||||||
|
refname expressions (see gitlink:git-rev-parse[1]). Namely:
|
||||||
|
|
||||||
. double-dot `..` are often used as in `ref1..ref2`, and in some
|
. double-dot `..` are often used as in `ref1..ref2`, and in some
|
||||||
context this notation means `{caret}ref1 ref2` (i.e. not in
|
context this notation means `{caret}ref1 ref2` (i.e. not in
|
||||||
|
@ -9,7 +9,7 @@ git-checkout-index - Copy files from the index to the working directory
|
|||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
'git-checkout-index' [-u] [-q] [-a] [-f] [-n] [--prefix=<string>]
|
'git-checkout-index' [-u] [-q] [-a] [-f] [-n] [--prefix=<string>]
|
||||||
[--] <file>...
|
[--stage=<number>] [--] <file>...
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
@ -40,58 +40,80 @@ OPTIONS
|
|||||||
When creating files, prepend <string> (usually a directory
|
When creating files, prepend <string> (usually a directory
|
||||||
including a trailing /)
|
including a trailing /)
|
||||||
|
|
||||||
|
--stage=<number>::
|
||||||
|
Instead of checking out unmerged entries, copy out the
|
||||||
|
files from named stage. <number> must be between 1 and 3.
|
||||||
|
|
||||||
--::
|
--::
|
||||||
Do not interpret any more arguments as options.
|
Do not interpret any more arguments as options.
|
||||||
|
|
||||||
The order of the flags used to matter, but not anymore.
|
The order of the flags used to matter, but not anymore.
|
||||||
|
|
||||||
Just doing "git-checkout-index" does nothing. You probably meant
|
Just doing `git-checkout-index` does nothing. You probably meant
|
||||||
"git-checkout-index -a". And if you want to force it, you want
|
`git-checkout-index -a`. And if you want to force it, you want
|
||||||
"git-checkout-index -f -a".
|
`git-checkout-index -f -a`.
|
||||||
|
|
||||||
Intuitiveness is not the goal here. Repeatability is. The reason for
|
Intuitiveness is not the goal here. Repeatability is. The reason for
|
||||||
the "no arguments means no work" thing is that from scripts you are
|
the "no arguments means no work" behavior is that from scripts you are
|
||||||
supposed to be able to do things like:
|
supposed to be able to do:
|
||||||
|
|
||||||
find . -name '*.h' -print0 | xargs -0 git-checkout-index -f --
|
----------------
|
||||||
|
$ find . -name '*.h' -print0 | xargs -0 git-checkout-index -f --
|
||||||
|
----------------
|
||||||
|
|
||||||
which will force all existing `*.h` files to be replaced with their
|
which will force all existing `*.h` files to be replaced with their
|
||||||
cached copies. If an empty command line implied "all", then this would
|
cached copies. If an empty command line implied "all", then this would
|
||||||
force-refresh everything in the index, 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:
|
The `--` is just a good idea when you know the rest will be filenames;
|
||||||
|
it will prevent problems with a filename of, for example, `-a`.
|
||||||
|
Using `--` is probably a good policy in scripts.
|
||||||
|
|
||||||
git-checkout-index -n -f -a && git-update-index --ignore-missing --refresh
|
|
||||||
|
|
||||||
Oh, and the "--" is just a good idea when you know the rest will be
|
EXAMPLES
|
||||||
filenames. Just so that you wouldn't have a filename of "-a" causing
|
--------
|
||||||
problems (not possible in the above example, but get used to it in
|
To update and refresh only the files already checked out::
|
||||||
scripting!).
|
+
|
||||||
|
----------------
|
||||||
|
$ git-checkout-index -n -f -a && git-update-index --ignore-missing --refresh
|
||||||
|
----------------
|
||||||
|
|
||||||
The prefix ability basically makes it trivial to use
|
Using `git-checkout-index` to "export an entire tree"::
|
||||||
git-checkout-index as an "export as tree" function. Just read the
|
The prefix ability basically makes it trivial to use
|
||||||
desired tree into the index, and do a
|
`git-checkout-index` as an "export as tree" function.
|
||||||
|
Just read the desired tree into the index, and do:
|
||||||
git-checkout-index --prefix=git-export-dir/ -a
|
+
|
||||||
|
----------------
|
||||||
and git-checkout-index will "export" the index into the specified
|
$ git-checkout-index --prefix=git-export-dir/ -a
|
||||||
|
----------------
|
||||||
|
+
|
||||||
|
`git-checkout-index` will "export" the index into the specified
|
||||||
directory.
|
directory.
|
||||||
|
+
|
||||||
|
The final "/" is important. The exported name is literally just
|
||||||
|
prefixed with the specified string. Contrast this with the
|
||||||
|
following example.
|
||||||
|
|
||||||
NOTE The final "/" is important. The exported name is literally just
|
Export files with a prefix::
|
||||||
prefixed with the specified string, so you can also do something like
|
+
|
||||||
|
----------------
|
||||||
|
$ git-checkout-index --prefix=.merged- Makefile
|
||||||
|
----------------
|
||||||
|
+
|
||||||
|
This will check out the currently cached copy of `Makefile`
|
||||||
|
into the file `.merged-Makefile`.
|
||||||
|
|
||||||
git-checkout-index --prefix=.merged- Makefile
|
|
||||||
|
|
||||||
to check out the currently cached copy of `Makefile` into the file
|
|
||||||
`.merged-Makefile`
|
|
||||||
|
|
||||||
Author
|
Author
|
||||||
------
|
------
|
||||||
Written by Linus Torvalds <torvalds@osdl.org>
|
Written by Linus Torvalds <torvalds@osdl.org>
|
||||||
|
|
||||||
|
|
||||||
Documentation
|
Documentation
|
||||||
--------------
|
--------------
|
||||||
Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
|
Documentation by David Greaves,
|
||||||
|
Junio C Hamano and the git-list <git@vger.kernel.org>.
|
||||||
|
|
||||||
|
|
||||||
GIT
|
GIT
|
||||||
---
|
---
|
||||||
|
@ -50,10 +50,14 @@ the `Makefile` to two revisions back, deletes hello.c by
|
|||||||
mistake, and gets it back from the index.
|
mistake, and gets it back from the index.
|
||||||
|
|
||||||
------------
|
------------
|
||||||
$ git checkout master
|
$ git checkout master <1>
|
||||||
$ git checkout master~2 Makefile
|
$ git checkout master~2 Makefile <2>
|
||||||
$ rm -f hello.c
|
$ rm -f hello.c
|
||||||
$ git checkout hello.c
|
$ git checkout hello.c <3>
|
||||||
|
|
||||||
|
<1> switch branch
|
||||||
|
<2> take out a file out of other commit
|
||||||
|
<3> or "git checkout -- hello.c", as in the next example.
|
||||||
------------
|
------------
|
||||||
|
|
||||||
If you have an unfortunate branch that is named `hello.c`, the
|
If you have an unfortunate branch that is named `hello.c`, the
|
||||||
|
@ -7,7 +7,7 @@ git-cherry-pick - Apply the change introduced by an existing commit.
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
'git-cherry-pick' [-n] [-r] <commit>
|
'git-cherry-pick' [--edit] [-n] [-r] <commit>
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
@ -20,15 +20,19 @@ OPTIONS
|
|||||||
<commit>::
|
<commit>::
|
||||||
Commit to cherry-pick.
|
Commit to cherry-pick.
|
||||||
|
|
||||||
-r::
|
-e|--edit::
|
||||||
|
With this option, `git-cherry-pick` will let you edit the commit
|
||||||
|
message prior committing.
|
||||||
|
|
||||||
|
-r|--replay::
|
||||||
Usually the command appends which commit was
|
Usually the command appends which commit was
|
||||||
cherry-picked after the original commit message when
|
cherry-picked after the original commit message when
|
||||||
making a commit. This option, '--replay', causes it to
|
making a commit. This option, '--replay', causes it to
|
||||||
use the original commit message intact. This is useful
|
use the original commit message intact. This is useful
|
||||||
when you are reordering the patches in your private tree
|
when you are reordering the patches in your private tree
|
||||||
before publishing, and is used by 'git rebase'.
|
before publishing.
|
||||||
|
|
||||||
-n::
|
-n|--no-commit::
|
||||||
Usually the command automatically creates a commit with
|
Usually the command automatically creates a commit with
|
||||||
a commit log message stating which commit was
|
a commit log message stating which commit was
|
||||||
cherry-picked. This flag applies the change necessary
|
cherry-picked. This flag applies the change necessary
|
||||||
|
@ -43,7 +43,11 @@ OPTIONS
|
|||||||
The heads to update. This is relative to $GIT_DIR
|
The heads to update. This is relative to $GIT_DIR
|
||||||
(e.g. "HEAD", "refs/heads/master"). When unspecified,
|
(e.g. "HEAD", "refs/heads/master"). When unspecified,
|
||||||
all heads are updated to match the remote repository.
|
all heads are updated to match the remote repository.
|
||||||
|
+
|
||||||
|
Usually all the refs from existing repository are stored
|
||||||
|
under the same name in the new repository. Giving explicit
|
||||||
|
<head> arguments instead writes the object names and refs to
|
||||||
|
the standard output, just like get-fetch-pack does.
|
||||||
|
|
||||||
Author
|
Author
|
||||||
------
|
------
|
||||||
|
@ -74,10 +74,31 @@ OPTIONS
|
|||||||
for "host.xz:foo/.git"). Cloning into an existing directory
|
for "host.xz:foo/.git"). Cloning into an existing directory
|
||||||
is not allowed.
|
is not allowed.
|
||||||
|
|
||||||
|
Examples
|
||||||
|
~~~~~~~~
|
||||||
|
|
||||||
|
Clone from upstream::
|
||||||
|
+
|
||||||
|
------------
|
||||||
|
$ git clone git://git.kernel.org/pub/scm/.../linux-2.6 my2.6
|
||||||
|
$ cd my2.6
|
||||||
|
$ make
|
||||||
|
------------
|
||||||
|
|
||||||
|
|
||||||
|
Make a local clone that borrows from the current directory, without checking things out::
|
||||||
|
+
|
||||||
|
------------
|
||||||
|
$ git clone -l -s -n . ../copy
|
||||||
|
$ cd copy
|
||||||
|
$ git show-branch
|
||||||
|
------------
|
||||||
|
|
||||||
Author
|
Author
|
||||||
------
|
------
|
||||||
Written by Linus Torvalds <torvalds@osdl.org>
|
Written by Linus Torvalds <torvalds@osdl.org>
|
||||||
|
|
||||||
|
|
||||||
Documentation
|
Documentation
|
||||||
--------------
|
--------------
|
||||||
Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
|
Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
|
||||||
|
@ -7,7 +7,7 @@ git-commit - Record your changes
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
'git-commit' [-a] [-s] [-v] [(-c | -C) <commit> | -F <file> | -m <msg>] [-e] <file>...
|
'git-commit' [-a] [-s] [-v] [(-c | -C) <commit> | -F <file> | -m <msg>] [-e] [--] <file>...
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
@ -22,7 +22,7 @@ information.
|
|||||||
|
|
||||||
OPTIONS
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
-a::
|
-a|--all::
|
||||||
Update all paths in the index file.
|
Update all paths in the index file.
|
||||||
|
|
||||||
-c or -C <commit>::
|
-c or -C <commit>::
|
||||||
@ -39,27 +39,37 @@ OPTIONS
|
|||||||
-m <msg>::
|
-m <msg>::
|
||||||
Use the given <msg> as the commit message.
|
Use the given <msg> as the commit message.
|
||||||
|
|
||||||
-s::
|
-s|--signoff::
|
||||||
Add Signed-off-by line at the end of the commit message.
|
Add Signed-off-by line at the end of the commit message.
|
||||||
|
|
||||||
-v::
|
-v|--verify::
|
||||||
Look for suspicious lines the commit introduces, and
|
Look for suspicious lines the commit introduces, and
|
||||||
abort committing if there is one. The definition of
|
abort committing if there is one. The definition of
|
||||||
'suspicious lines' is currently the lines that has
|
'suspicious lines' is currently the lines that has
|
||||||
trailing whitespaces, and the lines whose indentation
|
trailing whitespaces, and the lines whose indentation
|
||||||
has a SP character immediately followed by a TAB
|
has a SP character immediately followed by a TAB
|
||||||
character.
|
character. This is the default.
|
||||||
|
|
||||||
-e::
|
-n|--no-verify::
|
||||||
|
The opposite of `--verify`.
|
||||||
|
|
||||||
|
-e|--edit::
|
||||||
The message taken from file with `-F`, command line with
|
The message taken from file with `-F`, command line with
|
||||||
`-m`, and from file with `-C` are usually used as the
|
`-m`, and from file with `-C` are usually used as the
|
||||||
commit log message unmodified. This option lets you
|
commit log message unmodified. This option lets you
|
||||||
further edit the message taken from these sources.
|
further edit the message taken from these sources.
|
||||||
|
|
||||||
|
--::
|
||||||
|
Do not interpret any more arguments as options.
|
||||||
|
|
||||||
<file>...::
|
<file>...::
|
||||||
Update specified paths in the index file before committing.
|
Update specified paths in the index file before committing.
|
||||||
|
|
||||||
|
|
||||||
|
If you make a commit and then found a mistake immediately after
|
||||||
|
that, you can recover from it with gitlink:git-reset[1].
|
||||||
|
|
||||||
|
|
||||||
Author
|
Author
|
||||||
------
|
------
|
||||||
Written by Linus Torvalds <torvalds@osdl.org> and
|
Written by Linus Torvalds <torvalds@osdl.org> and
|
||||||
|
@ -8,7 +8,7 @@ git-cvsexportcommit - Export a commit to a CVS checkout
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
git-cvsapplycommmit.perl
|
git-cvsexportcommmit.perl
|
||||||
[ -h ] [ -v ] [ -c ] [ -p ] [PARENTCOMMIT] COMMITID
|
[ -h ] [ -v ] [ -c ] [ -p ] [PARENTCOMMIT] COMMITID
|
||||||
|
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ the old cvs2git tool.
|
|||||||
+
|
+
|
||||||
If you need to pass multiple options, separate them with a comma.
|
If you need to pass multiple options, separate them with a comma.
|
||||||
|
|
||||||
-P:: <cvsps-output-file>
|
-P <cvsps-output-file>::
|
||||||
Instead of calling cvsps, read the provided cvsps output file. Useful
|
Instead of calling cvsps, read the provided cvsps output file. Useful
|
||||||
for debugging or when cvsps is being handled outside cvsimport.
|
for debugging or when cvsps is being handled outside cvsimport.
|
||||||
|
|
||||||
|
@ -17,14 +17,16 @@ ent and the index file, or the index file and the working tree.
|
|||||||
The combination of what is compared with what is determined by
|
The combination of what is compared with what is determined by
|
||||||
the number of ents given to the command.
|
the number of ents given to the command.
|
||||||
|
|
||||||
`----------------`--------`-----------------------------`------------------
|
* When no <ent> is given, the working tree and the index
|
||||||
Number of ents Options What's Compared Underlying command
|
file is compared, using `git-diff-files`.
|
||||||
---------------------------------------------------------------------------
|
|
||||||
0 - index file and working tree git-diff-files
|
* When one <ent> is given, the working tree and the named
|
||||||
1 --cached ent and index file git-diff-index
|
tree is compared, using `git-diff-index`. The option
|
||||||
1 - ent and working tree git-diff-index
|
`--cached` can be given to compare the index file and
|
||||||
2 - two ents git-diff-tree
|
the named tree.
|
||||||
---------------------------------------------------------------------------
|
|
||||||
|
* When two <ent>s are given, these two trees are compared
|
||||||
|
using `git-diff-tree`.
|
||||||
|
|
||||||
OPTIONS
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
@ -38,6 +40,68 @@ OPTIONS
|
|||||||
commands.
|
commands.
|
||||||
|
|
||||||
|
|
||||||
|
EXAMPLES
|
||||||
|
--------
|
||||||
|
|
||||||
|
Various ways to check your working tree::
|
||||||
|
+
|
||||||
|
------------
|
||||||
|
$ git diff <1>
|
||||||
|
$ git diff --cached <2>
|
||||||
|
$ git diff HEAD <3>
|
||||||
|
|
||||||
|
<1> changes in the working tree since your last git-update-index.
|
||||||
|
<2> changes between the index and your last commit; what you
|
||||||
|
would be committing if you run "git commit" without "-a" option.
|
||||||
|
<3> changes in the working tree since your last commit; what you
|
||||||
|
would be committing if you run "git commit -a"
|
||||||
|
------------
|
||||||
|
|
||||||
|
Comparing with arbitrary commits::
|
||||||
|
+
|
||||||
|
------------
|
||||||
|
$ git diff test <1>
|
||||||
|
$ git diff HEAD -- ./test <2>
|
||||||
|
$ git diff HEAD^ HEAD <3>
|
||||||
|
|
||||||
|
<1> instead of using the tip of the current branch, compare with the
|
||||||
|
tip of "test" branch.
|
||||||
|
<2> instead of comparing with the tip of "test" branch, compare with
|
||||||
|
the tip of the curren branch, but limit the comparison to the
|
||||||
|
file "test".
|
||||||
|
<3> compare the version before the last commit and the last commit.
|
||||||
|
------------
|
||||||
|
|
||||||
|
|
||||||
|
Limiting the diff output::
|
||||||
|
+
|
||||||
|
------------
|
||||||
|
$ git diff --diff-filter=MRC <1>
|
||||||
|
$ git diff --name-status -r <2>
|
||||||
|
$ git diff arch/i386 include/asm-i386 <3>
|
||||||
|
|
||||||
|
<1> show only modification, rename and copy, but not addition
|
||||||
|
nor deletion.
|
||||||
|
<2> show only names and the nature of change, but not actual
|
||||||
|
diff output. --name-status disables usual patch generation
|
||||||
|
which in turn also disables recursive behaviour, so without -r
|
||||||
|
you would only see the directory name if there is a change in a
|
||||||
|
file in a subdirectory.
|
||||||
|
<3> limit diff output to named subtrees.
|
||||||
|
------------
|
||||||
|
|
||||||
|
Munging the diff output::
|
||||||
|
+
|
||||||
|
------------
|
||||||
|
$ git diff --find-copies-harder -B -C <1>
|
||||||
|
$ git diff -R <2>
|
||||||
|
|
||||||
|
<1> spend extra cycles to find renames, copies and complete
|
||||||
|
rewrites (very expensive).
|
||||||
|
<2> output diff in reverse.
|
||||||
|
------------
|
||||||
|
|
||||||
|
|
||||||
Author
|
Author
|
||||||
------
|
------
|
||||||
Written by Linus Torvalds <torvalds@osdl.org>
|
Written by Linus Torvalds <torvalds@osdl.org>
|
||||||
|
@ -8,7 +8,7 @@ git-fetch-pack - Receive missing objects from another repository.
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
git-fetch-pack [-q] [--exec=<git-upload-pack>] [<host>:]<directory> [<refs>...]
|
git-fetch-pack [-q] [-k] [--exec=<git-upload-pack>] [<host>:]<directory> [<refs>...]
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
@ -29,6 +29,11 @@ OPTIONS
|
|||||||
Pass '-q' flag to 'git-unpack-objects'; this makes the
|
Pass '-q' flag to 'git-unpack-objects'; this makes the
|
||||||
cloning process less verbose.
|
cloning process less verbose.
|
||||||
|
|
||||||
|
-k::
|
||||||
|
Do not invoke 'git-unpack-objects' on received data, but
|
||||||
|
create a single packfile out of it instead, and store it
|
||||||
|
in the object database.
|
||||||
|
|
||||||
--exec=<git-upload-pack>::
|
--exec=<git-upload-pack>::
|
||||||
Use this to specify the path to 'git-upload-pack' on the
|
Use this to specify the path to 'git-upload-pack' on the
|
||||||
remote side, if is not found on your $PATH.
|
remote side, if is not found on your $PATH.
|
||||||
|
@ -18,7 +18,7 @@ the objects necessary to complete them.
|
|||||||
|
|
||||||
The ref names and their object names of fetched refs are stored
|
The ref names and their object names of fetched refs are stored
|
||||||
in `.git/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".
|
operation done by "git merge".
|
||||||
|
|
||||||
|
|
||||||
OPTIONS
|
OPTIONS
|
||||||
|
@ -8,7 +8,7 @@ git-format-patch - Prepare patches for e-mail submission.
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
'git-format-patch' [-n][-o <dir>|--stdout][-k][--mbox][--diff-options] <his> [<mine>]
|
'git-format-patch' [-n | -k] [-o <dir> | --stdout] [-s] [-c] [--mbox] [--diff-options] <his> [<mine>]
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
@ -32,23 +32,34 @@ processing with applymbox.
|
|||||||
|
|
||||||
OPTIONS
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
-o <dir>::
|
-o|--output-directory <dir>::
|
||||||
Use <dir> to store the resulting files, instead of the
|
Use <dir> to store the resulting files, instead of the
|
||||||
current working directory.
|
current working directory.
|
||||||
|
|
||||||
-n::
|
-n|--numbered::
|
||||||
Name output in '[PATCH n/m]' format.
|
Name output in '[PATCH n/m]' format.
|
||||||
|
|
||||||
-k::
|
-k|--keep-subject::
|
||||||
Do not strip/add '[PATCH]' from the first line of the
|
Do not strip/add '[PATCH]' from the first line of the
|
||||||
commit log message.
|
commit log message.
|
||||||
|
|
||||||
--author, --date::
|
-a|--author, -d|--date::
|
||||||
Output From: and Date: headers for commits made by
|
Output From: and Date: headers for commits made by
|
||||||
yourself as well. Usually these are output only for
|
yourself as well. Usually these are output only for
|
||||||
commits made by people other than yourself.
|
commits made by people other than yourself.
|
||||||
|
|
||||||
--mbox::
|
-s|--signoff::
|
||||||
|
Add `Signed-off-by:` line to the commit message, using
|
||||||
|
the committer identity of yourself.
|
||||||
|
|
||||||
|
-c|--check::
|
||||||
|
Display suspicious lines in the patch. The definition
|
||||||
|
of 'suspicious lines' is currently the lines that has
|
||||||
|
trailing whitespaces, and the lines whose indentation
|
||||||
|
has a SP character immediately followed by a TAB
|
||||||
|
character.
|
||||||
|
|
||||||
|
-m|--mbox::
|
||||||
Format the output files for closer to mbox format by
|
Format the output files for closer to mbox format by
|
||||||
adding a phony Unix "From " line, so they can be
|
adding a phony Unix "From " line, so they can be
|
||||||
concatenated together and fed to `git-applymbox`.
|
concatenated together and fed to `git-applymbox`.
|
||||||
@ -73,6 +84,15 @@ git-format-patch origin::
|
|||||||
pulled from origin the last time in a patch form for
|
pulled from origin the last time in a patch form for
|
||||||
e-mail submission.
|
e-mail submission.
|
||||||
|
|
||||||
|
git-format-patch -M -B origin::
|
||||||
|
The same as the previous one, except detect and handle
|
||||||
|
renames and complete rewrites intelligently to produce
|
||||||
|
renaming patch. A renaming patch reduces the amount of
|
||||||
|
text output, and generally makes it easier to review
|
||||||
|
it. Note that the "patch" program does not understand
|
||||||
|
renaming patch well, so use it only when you know the
|
||||||
|
recipient uses git to apply your patch.
|
||||||
|
|
||||||
|
|
||||||
See Also
|
See Also
|
||||||
--------
|
--------
|
||||||
|
@ -8,7 +8,7 @@ git-hash-object - Computes object ID and optionally creates a blob from a file.
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
'git-hash-object' [-t <type>] [-w] <any-file-on-the-filesystem>
|
'git-hash-object' [-t <type>] [-w] [--stdin] [--] <file>...
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
@ -29,6 +29,9 @@ OPTIONS
|
|||||||
-w::
|
-w::
|
||||||
Actually write the object into the object database.
|
Actually write the object into the object database.
|
||||||
|
|
||||||
|
--stdin::
|
||||||
|
Read the object from standard input instead of from a file.
|
||||||
|
|
||||||
Author
|
Author
|
||||||
------
|
------
|
||||||
Written by Junio C Hamano <junkio@cox.net>
|
Written by Junio C Hamano <junkio@cox.net>
|
||||||
|
@ -14,6 +14,12 @@ DESCRIPTION
|
|||||||
-----------
|
-----------
|
||||||
Downloads a remote git repository via HTTP.
|
Downloads a remote git repository via HTTP.
|
||||||
|
|
||||||
|
OPTIONS
|
||||||
|
-------
|
||||||
|
commit-id::
|
||||||
|
Either the hash or the filename under [URL]/refs/ to
|
||||||
|
pull.
|
||||||
|
|
||||||
-c::
|
-c::
|
||||||
Get the commit objects.
|
Get the commit objects.
|
||||||
-t::
|
-t::
|
||||||
|
@ -8,7 +8,14 @@ git-init-db - Creates an empty git repository
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
'git-init-db'
|
'git-init-db' [--template=<template_directory>]
|
||||||
|
|
||||||
|
|
||||||
|
OPTIONS
|
||||||
|
-------
|
||||||
|
--template=<template_directory>::
|
||||||
|
Provide the directory in from which templates will be used.
|
||||||
|
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
@ -16,14 +23,29 @@ This simply creates an empty git repository - basically a `.git` directory
|
|||||||
and `.git/object/??/`, `.git/refs/heads` and `.git/refs/tags` directories,
|
and `.git/object/??/`, `.git/refs/heads` and `.git/refs/tags` directories,
|
||||||
and links `.git/HEAD` symbolically to `.git/refs/heads/master`.
|
and links `.git/HEAD` symbolically to `.git/refs/heads/master`.
|
||||||
|
|
||||||
If the 'GIT_DIR' environment variable is set then it specifies a path
|
If the `$GIT_DIR` environment variable is set then it specifies a path
|
||||||
to use instead of `./.git` for the base of the repository.
|
to use instead of `./.git` for the base of the repository.
|
||||||
|
|
||||||
If the object storage directory is specified via the 'GIT_OBJECT_DIRECTORY'
|
If the object storage directory is specified via the `$GIT_OBJECT_DIRECTORY`
|
||||||
environment variable then the sha1 directories are created underneath -
|
environment variable then the sha1 directories are created underneath -
|
||||||
otherwise the default `$GIT_DIR/objects` directory is used.
|
otherwise the default `$GIT_DIR/objects` directory is used.
|
||||||
|
|
||||||
"git-init-db" won't hurt an existing repository.
|
`git-init-db` won't hurt an existing repository.
|
||||||
|
|
||||||
|
|
||||||
|
EXAMPLES
|
||||||
|
--------
|
||||||
|
|
||||||
|
Start a new git repository for an existing code base::
|
||||||
|
+
|
||||||
|
----------------
|
||||||
|
$ cd /path/to/my/codebase
|
||||||
|
$ git-init-db <1>
|
||||||
|
$ git-add . <2>
|
||||||
|
|
||||||
|
<1> prepare /path/to/my/codebase/.git directory
|
||||||
|
<2> add all existing file to the index
|
||||||
|
----------------
|
||||||
|
|
||||||
|
|
||||||
Author
|
Author
|
||||||
|
@ -17,7 +17,7 @@ Displays the references other repository has.
|
|||||||
|
|
||||||
OPTIONS
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
--heads --tags::
|
-h|--heads, -t|--tags::
|
||||||
Limit to only refs/heads and refs/tags, respectively.
|
Limit to only refs/heads and refs/tags, respectively.
|
||||||
These options are _not_ mutually exclusive; when given
|
These options are _not_ mutually exclusive; when given
|
||||||
both, references stored in refs/heads and refs/tags are
|
both, references stored in refs/heads and refs/tags are
|
||||||
|
@ -8,12 +8,15 @@ git-ls-tree - Lists the contents of a tree object.
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
'git-ls-tree' [-d] [-r] [-z] <tree-ish> [paths...]
|
'git-ls-tree' [-d] [-r] [-t] [-z] [--name-only] [--name-status] <tree-ish> [paths...]
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
Lists the contents of a tree object, like what "/bin/ls -a" does
|
Lists the contents of a given tree object, like what "/bin/ls -a" does
|
||||||
in the current working directory.
|
in the current working directory. Note that the usage is subtly different,
|
||||||
|
though - 'paths' denote just a list of patterns to match, e.g. so specifying
|
||||||
|
directory name (without '-r') will behave differently, and order of the
|
||||||
|
arguments does not matter.
|
||||||
|
|
||||||
OPTIONS
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
@ -21,36 +24,48 @@ OPTIONS
|
|||||||
Id of a tree-ish.
|
Id of a tree-ish.
|
||||||
|
|
||||||
-d::
|
-d::
|
||||||
show only the named tree entry itself, not its children
|
Show only the named tree entry itself, not its children.
|
||||||
|
|
||||||
-r::
|
-r::
|
||||||
recurse into sub-trees
|
Recurse into sub-trees.
|
||||||
|
|
||||||
|
-t::
|
||||||
|
Show tree entries even when going to recurse them. Has no effect
|
||||||
|
if '-r' was not passed. '-d' implies '-t'.
|
||||||
|
|
||||||
-z::
|
-z::
|
||||||
\0 line termination on output
|
\0 line termination on output.
|
||||||
|
|
||||||
|
--name-only::
|
||||||
|
--name-status::
|
||||||
|
List only filenames (instead of the "long" output), one per line.
|
||||||
|
|
||||||
paths::
|
paths::
|
||||||
When paths are given, show them. Otherwise implicitly
|
When paths are given, show them (note that this isn't really raw
|
||||||
uses the root level of the tree as the sole path argument.
|
pathnames, but rather a list of patterns to match). Otherwise
|
||||||
|
implicitly uses the root level of the tree as the sole path argument.
|
||||||
|
|
||||||
|
|
||||||
Output Format
|
Output Format
|
||||||
-------------
|
-------------
|
||||||
<mode> SP <type> SP <object> TAB <file>
|
<mode> SP <type> SP <object> TAB <file>
|
||||||
|
|
||||||
When `-z` option is not used, TAB, LF, and backslash characters
|
When the `-z` option is not used, TAB, LF, and backslash characters
|
||||||
in pathnames are represented as `\t`, `\n`, and `\\`,
|
in pathnames are represented as `\t`, `\n`, and `\\`, respectively.
|
||||||
respectively.
|
|
||||||
|
|
||||||
|
|
||||||
Author
|
Author
|
||||||
------
|
------
|
||||||
Written by Linus Torvalds <torvalds@osdl.org>
|
Written by Petr Baudis <pasky@suse.cz>
|
||||||
Completely rewritten from scratch by Junio C Hamano <junkio@cox.net>
|
Completely rewritten from scratch by Junio C Hamano <junkio@cox.net>,
|
||||||
|
another major rewrite by Linus Torvalds <torvalds@osdl.org>
|
||||||
|
|
||||||
Documentation
|
Documentation
|
||||||
--------------
|
--------------
|
||||||
Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
|
Documentation by David Greaves, Junio C Hamano and the git-list
|
||||||
|
<git@vger.kernel.org>.
|
||||||
|
|
||||||
|
This manual page is a stub. You can help the git documentation by expanding it.
|
||||||
|
|
||||||
GIT
|
GIT
|
||||||
---
|
---
|
||||||
|
@ -7,7 +7,7 @@ git-mailsplit - Totally braindamaged mbox splitter program.
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
'git-mailsplit' [-d<prec>] [<mbox>] <directory>
|
'git-mailsplit' [-b] [-f<nn>] [-d<prec>] -o<directory> [--] [<mbox>...]
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
@ -23,11 +23,18 @@ OPTIONS
|
|||||||
<directory>::
|
<directory>::
|
||||||
Directory in which to place the individual messages.
|
Directory in which to place the individual messages.
|
||||||
|
|
||||||
|
-b::
|
||||||
|
If any file doesn't begin with a From line, assume it is a
|
||||||
|
single mail message instead of signalling error.
|
||||||
|
|
||||||
-d<prec>::
|
-d<prec>::
|
||||||
Instead of the default 4 digits with leading zeros,
|
Instead of the default 4 digits with leading zeros,
|
||||||
different precision can be specified for the generated
|
different precision can be specified for the generated
|
||||||
filenames.
|
filenames.
|
||||||
|
|
||||||
|
-f<nn>::
|
||||||
|
Skip the first <nn> numbers, for example if -f3 is specified,
|
||||||
|
start the numbering with 0004.
|
||||||
|
|
||||||
Author
|
Author
|
||||||
------
|
------
|
||||||
|
@ -20,7 +20,7 @@ files are passed as arguments 5, 6 and 7.
|
|||||||
OPTIONS
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
--::
|
--::
|
||||||
Interpret all following arguments as filenames.
|
Do not interpret any more arguments as options.
|
||||||
|
|
||||||
-a::
|
-a::
|
||||||
Run merge against all files in the index that need merging.
|
Run merge against all files in the index that need merging.
|
||||||
|
@ -37,6 +37,11 @@ include::merge-options.txt[]
|
|||||||
include::merge-strategies.txt[]
|
include::merge-strategies.txt[]
|
||||||
|
|
||||||
|
|
||||||
|
If you tried a merge which resulted in a complex conflicts and
|
||||||
|
would want to start over, you can recover with
|
||||||
|
gitlink:git-reset[1].
|
||||||
|
|
||||||
|
|
||||||
HOW MERGE WORKS
|
HOW MERGE WORKS
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
@ -8,12 +8,15 @@ git-mv - Script used to move or rename a file, directory or symlink.
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
'git-mv' [-f] [-n] <source> <destination>
|
'git-mv' <options>... <args>...
|
||||||
'git-mv' [-f] [-n] [-k] <source> ... <destination directory>
|
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
This script is used to move or rename a file, directory or symlink.
|
This script is used to move or rename a file, directory or symlink.
|
||||||
|
|
||||||
|
git-mv [-f] [-n] <source> <destination>
|
||||||
|
git-mv [-f] [-n] [-k] <source> ... <destination directory>
|
||||||
|
|
||||||
In the first form, it renames <source>, which must exist and be either
|
In the first form, it renames <source>, which must exist and be either
|
||||||
a file, symlink or directory, to <destination>.
|
a file, symlink or directory, to <destination>.
|
||||||
In the second form, the last argument has to be an existing
|
In the second form, the last argument has to be an existing
|
||||||
|
@ -1,38 +0,0 @@
|
|||||||
git-octopus(1)
|
|
||||||
==============
|
|
||||||
|
|
||||||
NAME
|
|
||||||
----
|
|
||||||
git-octopus - Merge more than two commits.
|
|
||||||
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
--------
|
|
||||||
'git-octopus'
|
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
-----------
|
|
||||||
After running 'git fetch', $GIT_DIR/FETCH_HEAD contains the
|
|
||||||
following information, one line per remote ref:
|
|
||||||
|
|
||||||
------------------------------------------------
|
|
||||||
<object name> <ref name> from <repository>
|
|
||||||
------------------------------------------------
|
|
||||||
|
|
||||||
Using this information, create and commit an Octopus merge on
|
|
||||||
top of the current HEAD.
|
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
@ -8,7 +8,7 @@ git-pack-objects - Create a packed archive of objects.
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
'git-pack-objects' [--local] [--incremental] [--window=N] [--depth=N] {--stdout | base-name} < object-list
|
'git-pack-objects' [--non-empty] [--local] [--incremental] [--window=N] [--depth=N] {--stdout | base-name} < object-list
|
||||||
|
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
@ -70,6 +70,10 @@ base-name::
|
|||||||
that are packed and not in the local object store
|
that are packed and not in the local object store
|
||||||
(i.e. borrowed from an alternate).
|
(i.e. borrowed from an alternate).
|
||||||
|
|
||||||
|
--non-empty::
|
||||||
|
Only create a packed archive if it would contain at
|
||||||
|
least one object.
|
||||||
|
|
||||||
Author
|
Author
|
||||||
------
|
------
|
||||||
Written by Linus Torvalds <torvalds@osdl.org>
|
Written by Linus Torvalds <torvalds@osdl.org>
|
||||||
|
@ -9,19 +9,22 @@ residing in a pack file.
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
'git-prune-packed'
|
'git-prune-packed' [-n]
|
||||||
|
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
This program search the GIT_OBJECT_DIR for all objects that currently exist in
|
This program search the `$GIT_OBJECT_DIR` for all objects that currently
|
||||||
a pack file as well as the independent object directories.
|
exist in a pack file as well as the independent object directories.
|
||||||
|
|
||||||
All such extra objects are removed.
|
All such extra objects are removed.
|
||||||
|
|
||||||
A pack is a collection of objects, individually compressed, with delta
|
A pack is a collection of objects, individually compressed, with delta
|
||||||
compression applied, stored in a single file, with an associated index file.
|
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.
|
Packs are used to reduce the load on mirror systems, backup engines,
|
||||||
|
disk storage, etc.
|
||||||
|
|
||||||
|
|
||||||
OPTIONS
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
|
@ -8,15 +8,16 @@ git-prune - Prunes all unreachable objects from the object database
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
'git-prune' [-n]
|
'git-prune' [-n] [--] [<head>...]
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
This runs `git-fsck-objects --unreachable` using the heads
|
This runs `git-fsck-objects --unreachable` using all the refs
|
||||||
specified on the command line (or `$GIT_DIR/refs/heads/\*` and
|
available in `$GIT_DIR/refs`, optionally with additional set of
|
||||||
`$GIT_DIR/refs/tags/\*` if none is specified), and prunes all
|
objects specified on the command line, and prunes all
|
||||||
unreachable objects from the object database. In addition, it
|
objects unreachable from any of these head objects from the object database.
|
||||||
|
In addition, it
|
||||||
prunes the unpacked objects that are also found in packs by
|
prunes the unpacked objects that are also found in packs by
|
||||||
running `git prune-packed`.
|
running `git prune-packed`.
|
||||||
|
|
||||||
@ -27,6 +28,24 @@ OPTIONS
|
|||||||
Do not remove anything; just report what it would
|
Do not remove anything; just report what it would
|
||||||
remove.
|
remove.
|
||||||
|
|
||||||
|
--::
|
||||||
|
Do not interpret any more arguments as options.
|
||||||
|
|
||||||
|
<head>...::
|
||||||
|
In addition to objects
|
||||||
|
reachable from any of our references, keep objects
|
||||||
|
reachable from listed <head>s.
|
||||||
|
|
||||||
|
EXAMPLE
|
||||||
|
-------
|
||||||
|
|
||||||
|
To prune objects not used by your repository nor another that
|
||||||
|
borrows from your repository via its
|
||||||
|
`.git/objects/info/alternates`:
|
||||||
|
|
||||||
|
------------
|
||||||
|
$ git prune $(cd ../another && $(git-rev-parse --all))
|
||||||
|
------------
|
||||||
|
|
||||||
Author
|
Author
|
||||||
------
|
------
|
||||||
|
@ -104,6 +104,11 @@ merge the remote `origin` head into the current,
|
|||||||
local `master` branch.
|
local `master` branch.
|
||||||
|
|
||||||
|
|
||||||
|
If you tried a pull which resulted in a complex conflicts and
|
||||||
|
would want to start over, you can recover with
|
||||||
|
gitlink:git-reset[1].
|
||||||
|
|
||||||
|
|
||||||
SEE ALSO
|
SEE ALSO
|
||||||
--------
|
--------
|
||||||
gitlink:git-fetch[1], gitlink:git-merge[1]
|
gitlink:git-fetch[1], gitlink:git-merge[1]
|
||||||
|
@ -16,6 +16,10 @@ DESCRIPTION
|
|||||||
Updates remote refs using local refs, while sending objects
|
Updates remote refs using local refs, while sending objects
|
||||||
necessary to complete the given refs.
|
necessary to complete the given refs.
|
||||||
|
|
||||||
|
You can make "interesting" things to happen on the repository
|
||||||
|
every time you push into it, by setting up 'hooks' there. See
|
||||||
|
documentation for gitlink:git-receive-pack[1].
|
||||||
|
|
||||||
|
|
||||||
OPTIONS
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
@ -31,6 +35,7 @@ include::pull-fetch-param.txt[]
|
|||||||
This flag disables the check. What this means is that the
|
This flag disables the check. What this means is that the
|
||||||
local repository can lose commits; use it with care.
|
local repository can lose commits; use it with care.
|
||||||
|
|
||||||
|
|
||||||
Author
|
Author
|
||||||
------
|
------
|
||||||
Written by Junio C Hamano <junkio@cox.net>
|
Written by Junio C Hamano <junkio@cox.net>
|
||||||
|
@ -8,22 +8,22 @@ git-read-tree - Reads tree information into the index
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
'git-read-tree' (<tree-ish> | [-m [-u|-i]] <tree-ish1> [<tree-ish2> [<tree-ish3>]])
|
'git-read-tree' (<tree-ish> | [[-m | --reset] [-u | -i]] <tree-ish1> [<tree-ish2> [<tree-ish3>]])
|
||||||
|
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
Reads the tree information given by <tree-ish> into the index,
|
Reads the tree information given by <tree-ish> into the index,
|
||||||
but does not actually *update* any of the files it "caches". (see:
|
but does not actually *update* any of the files it "caches". (see:
|
||||||
git-checkout-index)
|
gitlink:git-checkout-index[1])
|
||||||
|
|
||||||
Optionally, it can merge a tree into the index, 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
|
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
|
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.
|
the files in the work tree with the result of the merge.
|
||||||
|
|
||||||
Trivial merges are done by "git-read-tree" itself. Only conflicting paths
|
Trivial merges are done by `git-read-tree` itself. Only conflicting paths
|
||||||
will be in unmerged state when "git-read-tree" returns.
|
will be in unmerged state when `git-read-tree` returns.
|
||||||
|
|
||||||
OPTIONS
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
@ -56,7 +56,7 @@ OPTIONS
|
|||||||
|
|
||||||
Merging
|
Merging
|
||||||
-------
|
-------
|
||||||
If '-m' is specified, "git-read-tree" can perform 3 kinds of
|
If `-m` is specified, `git-read-tree` can perform 3 kinds of
|
||||||
merge, a single tree merge if only 1 tree is given, a
|
merge, a single tree merge if only 1 tree is given, a
|
||||||
fast-forward merge with 2 trees, or a 3-way merge if 3 trees are
|
fast-forward merge with 2 trees, or a 3-way merge if 3 trees are
|
||||||
provided.
|
provided.
|
||||||
@ -65,23 +65,23 @@ provided.
|
|||||||
Single Tree Merge
|
Single Tree Merge
|
||||||
~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~
|
||||||
If only 1 tree is specified, git-read-tree operates as if the user did not
|
If only 1 tree is specified, git-read-tree operates as if the user did not
|
||||||
specify '-m', except that if the original index 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
|
given pathname, and the contents of the path matches with the tree
|
||||||
being read, the stat info from the index is used. (In other words, the
|
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).
|
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
|
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
|
`git-checkout-index -f -u -a`, the `git-checkout-index` only checks out
|
||||||
the stuff that really changed.
|
the stuff that really changed.
|
||||||
|
|
||||||
This is used to avoid unnecessary false hits when "git-diff-files" is
|
This is used to avoid unnecessary false hits when `git-diff-files` is
|
||||||
run after git-read-tree.
|
run after `git-read-tree`.
|
||||||
|
|
||||||
|
|
||||||
Two Tree Merge
|
Two Tree Merge
|
||||||
~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Typically, this is invoked as "git-read-tree -m $H $M", where $H
|
Typically, this is invoked as `git-read-tree -m $H $M`, where $H
|
||||||
is the head commit of the current repository, and $M is the head
|
is the head commit of the current repository, and $M is the head
|
||||||
of a foreign tree, which is simply ahead of $H (i.e. we are in a
|
of a foreign tree, which is simply ahead of $H (i.e. we are in a
|
||||||
fast forward situation).
|
fast forward situation).
|
||||||
@ -94,7 +94,7 @@ the following:
|
|||||||
|
|
||||||
2. The user wants to fast-forward to $M.
|
2. The user wants to fast-forward to $M.
|
||||||
|
|
||||||
In this case, the "git-read-tree -m $H $M" command makes sure
|
In this case, the `git-read-tree -m $H $M` command makes sure
|
||||||
that no local change is lost as the result of this "merge".
|
that no local change is lost as the result of this "merge".
|
||||||
Here are the "carry forward" rules:
|
Here are the "carry forward" rules:
|
||||||
|
|
||||||
@ -141,13 +141,13 @@ operating under the -u flag.
|
|||||||
|
|
||||||
When this form of git-read-tree returns successfully, you can
|
When this form of git-read-tree returns successfully, you can
|
||||||
see what "local changes" you made are carried forward by running
|
see what "local changes" you made are carried forward by running
|
||||||
"git-diff-index --cached $M". Note that this does not
|
`git-diff-index --cached $M`. Note that this does not
|
||||||
necessarily match "git-diff-index --cached $H" would have
|
necessarily match `git-diff-index --cached $H` would have
|
||||||
produced before such a two tree merge. This is because of cases
|
produced before such a two tree merge. This is because of cases
|
||||||
18 and 19 --- if you already had the changes in $M (e.g. maybe
|
18 and 19 --- if you already had the changes in $M (e.g. maybe
|
||||||
you picked it up via e-mail in a patch form), "git-diff-index
|
you picked it up via e-mail in a patch form), `git-diff-index
|
||||||
--cached $H" would have told you about the change before this
|
--cached $H` would have told you about the change before this
|
||||||
merge, but it would not show in "git-diff-index --cached $M"
|
merge, but it would not show in `git-diff-index --cached $M`
|
||||||
output after two-tree merge.
|
output after two-tree merge.
|
||||||
|
|
||||||
|
|
||||||
@ -156,31 +156,39 @@ output after two-tree merge.
|
|||||||
Each "index" entry has two bits worth of "stage" state. stage 0 is the
|
Each "index" entry has two bits worth of "stage" state. stage 0 is the
|
||||||
normal one, and is the only one you'd see in any kind of normal use.
|
normal one, and is the only one you'd see in any kind of normal use.
|
||||||
|
|
||||||
However, when you do "git-read-tree" with three trees, the "stage"
|
However, when you do `git-read-tree` with three trees, the "stage"
|
||||||
starts out at 1.
|
starts out at 1.
|
||||||
|
|
||||||
This means that you can do
|
This means that you can do
|
||||||
|
|
||||||
git-read-tree -m <tree1> <tree2> <tree3>
|
----------------
|
||||||
|
$ git-read-tree -m <tree1> <tree2> <tree3>
|
||||||
|
----------------
|
||||||
|
|
||||||
and you will end up with an index with all of the <tree1> entries in
|
and you will end up with an index with all of the <tree1> entries in
|
||||||
"stage1", all of the <tree2> entries in "stage2" and all of the
|
"stage1", all of the <tree2> entries in "stage2" and all of the
|
||||||
<tree3> entries in "stage3".
|
<tree3> entries in "stage3". When performing a merge of another
|
||||||
|
branch into the current branch, we use the common ancestor tree
|
||||||
|
as <tree1>, the current branch head as <tree2>, and the other
|
||||||
|
branch head as <tree3>.
|
||||||
|
|
||||||
Furthermore, "git-read-tree" has special-case logic that says: if you see
|
Furthermore, `git-read-tree` has special-case logic that says: if you see
|
||||||
a file that matches in all respects in the following states, it
|
a file that matches in all respects in the following states, it
|
||||||
"collapses" back to "stage0":
|
"collapses" back to "stage0":
|
||||||
|
|
||||||
- stage 2 and 3 are the same; take one or the other (it makes no
|
- stage 2 and 3 are the same; take one or the other (it makes no
|
||||||
difference - the same work has been done on stage 2 and 3)
|
difference - the same work has been done on our branch in
|
||||||
|
stage 2 and their branch in stage 3)
|
||||||
|
|
||||||
- stage 1 and stage 2 are the same and stage 3 is different; take
|
- stage 1 and stage 2 are the same and stage 3 is different; take
|
||||||
stage 3 (some work has been done on stage 3)
|
stage 3 (our branch in stage 2 did not do anything since the
|
||||||
|
ancestor in stage 1 while their branch in stage 3 worked on
|
||||||
|
it)
|
||||||
|
|
||||||
- stage 1 and stage 3 are the same and stage 2 is different take
|
- stage 1 and stage 3 are the same and stage 2 is different take
|
||||||
stage 2 (some work has been done on stage 2)
|
stage 2 (we did something while they did nothing)
|
||||||
|
|
||||||
The "git-write-tree" command refuses to write a nonsensical tree, and it
|
The `git-write-tree` command refuses to write a nonsensical tree, and it
|
||||||
will complain about unmerged entries if it sees a single entry that is not
|
will complain about unmerged entries if it sees a single entry that is not
|
||||||
stage 0.
|
stage 0.
|
||||||
|
|
||||||
@ -220,12 +228,10 @@ populated. Here is an outline of how the algorithm works:
|
|||||||
matching "stage1" entry if it exists too. .. all the normal
|
matching "stage1" entry if it exists too. .. all the normal
|
||||||
trivial rules ..
|
trivial rules ..
|
||||||
|
|
||||||
You would normally use "git-merge-index" with supplied
|
You would normally use `git-merge-index` with supplied
|
||||||
"git-merge-one-file" to do this last step. The script
|
`git-merge-one-file` to do this last step. The script updates
|
||||||
does not touch the files in the work tree, and the entire merge
|
the files in the working tree as it merges each path and at the
|
||||||
happens in the index file. In other words, there is no need to
|
end of a successful merge.
|
||||||
worry about what is in the working directory, since it is never
|
|
||||||
shown and never used.
|
|
||||||
|
|
||||||
When you start a 3-way merge with an index file that is already
|
When you start a 3-way merge with an index file that is already
|
||||||
populated, it is assumed that it represents the state of the
|
populated, it is assumed that it represents the state of the
|
||||||
@ -236,33 +242,54 @@ merge refuses to run if it finds an entry in the original index
|
|||||||
file that does not match stage 2.
|
file that does not match stage 2.
|
||||||
|
|
||||||
This is done to prevent you from losing your work-in-progress
|
This is done to prevent you from losing your work-in-progress
|
||||||
changes. To illustrate, suppose you start from what has been
|
changes, and mixing your random changes in an unrelated merge
|
||||||
|
commit. To illustrate, suppose you start from what has been
|
||||||
commited last to your repository:
|
commited last to your repository:
|
||||||
|
|
||||||
$ JC=`git-rev-parse --verify "HEAD^0"`
|
----------------
|
||||||
$ git-checkout-index -f -u -a $JC
|
$ JC=`git-rev-parse --verify "HEAD^0"`
|
||||||
|
$ git-checkout-index -f -u -a $JC
|
||||||
|
----------------
|
||||||
|
|
||||||
You do random edits, without running git-update-index. And then
|
You do random edits, without running git-update-index. And then
|
||||||
you notice that the tip of your "upstream" tree has advanced
|
you notice that the tip of your "upstream" tree has advanced
|
||||||
since you pulled from him:
|
since you pulled from him:
|
||||||
|
|
||||||
$ git-fetch rsync://.... linus
|
----------------
|
||||||
$ LT=`cat .git/MERGE_HEAD`
|
$ git-fetch git://.... linus
|
||||||
|
$ LT=`cat .git/FETCH_HEAD`
|
||||||
|
----------------
|
||||||
|
|
||||||
Your work tree is still based on your HEAD ($JC), but you have
|
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
|
some edits since. Three-way merge makes sure that you have not
|
||||||
added or modified index 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:
|
then does the right thing. So with the following sequence:
|
||||||
|
|
||||||
$ git-read-tree -m -u `git-merge-base $JC $LT` $JC $LT
|
----------------
|
||||||
$ git-merge-index git-merge-one-file -a
|
$ git-read-tree -m -u `git-merge-base $JC $LT` $JC $LT
|
||||||
$ echo "Merge with Linus" | \
|
$ git-merge-index git-merge-one-file -a
|
||||||
git-commit-tree `git-write-tree` -p $JC -p $LT
|
$ echo "Merge with Linus" | \
|
||||||
|
git-commit-tree `git-write-tree` -p $JC -p $LT
|
||||||
|
----------------
|
||||||
|
|
||||||
what you would commit is a pure merge between $JC and LT without
|
what you would commit is a pure merge between $JC and $LT without
|
||||||
your work-in-progress changes, and your work tree would be
|
your work-in-progress changes, and your work tree would be
|
||||||
updated to the result of the merge.
|
updated to the result of the merge.
|
||||||
|
|
||||||
|
However, if you have local changes in the working tree that
|
||||||
|
would be overwritten by this merge,`git-read-tree` will refuse
|
||||||
|
to run to prevent your changes from being lost.
|
||||||
|
|
||||||
|
In other words, there is no need to worry about what exists only
|
||||||
|
in the working tree. When you have local changes in a part of
|
||||||
|
the project that is not involved in the merge, your changes do
|
||||||
|
not interfere with the merge, and are kept intact. When they
|
||||||
|
*do* interfere, the merge does not even start (`git-read-tree`
|
||||||
|
complains loudly and fails without modifying anything). In such
|
||||||
|
a case, you can simply continue doing what you were in the
|
||||||
|
middle of doing, and when your working tree is ready (i.e. you
|
||||||
|
have finished your work-in-progress), attempt the merge again.
|
||||||
|
|
||||||
|
|
||||||
See Also
|
See Also
|
||||||
--------
|
--------
|
||||||
|
@ -71,6 +71,10 @@ packed and is served via a dumb transport.
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
exec git-update-server-info
|
exec git-update-server-info
|
||||||
|
|
||||||
|
There are other real-world examples of using update and
|
||||||
|
post-update hooks found in the Documentation/howto directory.
|
||||||
|
|
||||||
|
|
||||||
OPTIONS
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
<directory>::
|
<directory>::
|
||||||
|
@ -9,7 +9,7 @@ objects into pack files.
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
'git-repack' [-a] [-d]
|
'git-repack' [-a] [-d] [-l] [-n]
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
@ -39,6 +39,13 @@ OPTIONS
|
|||||||
After packing, if the newly created packs make some
|
After packing, if the newly created packs make some
|
||||||
existing packs redundant, remove the redundant packs.
|
existing packs redundant, remove the redundant packs.
|
||||||
|
|
||||||
|
-l::
|
||||||
|
Pass the `--local` option to `git pack-objects`, see
|
||||||
|
gitlink:git-pack-objects[1].
|
||||||
|
|
||||||
|
-n::
|
||||||
|
Do not update the server information with
|
||||||
|
`git update-server-info`.
|
||||||
|
|
||||||
Author
|
Author
|
||||||
------
|
------
|
||||||
|
@ -42,6 +42,109 @@ OPTIONS
|
|||||||
<commit-ish>::
|
<commit-ish>::
|
||||||
Commit to make the current HEAD.
|
Commit to make the current HEAD.
|
||||||
|
|
||||||
|
Examples
|
||||||
|
~~~~~~~~
|
||||||
|
|
||||||
|
Undo a commit and redo::
|
||||||
|
+
|
||||||
|
------------
|
||||||
|
$ git commit ...
|
||||||
|
$ git reset --soft HEAD^ <1>
|
||||||
|
$ edit <2>
|
||||||
|
$ git commit -a -c ORIG_HEAD <3>
|
||||||
|
|
||||||
|
<1> This is most often done when you remembered what you
|
||||||
|
just committed is incomplete, or you misspelled your commit
|
||||||
|
message, or both. Leaves working tree as it was before "reset".
|
||||||
|
<2> make corrections to working tree files.
|
||||||
|
<3> "reset" copies the old head to .git/ORIG_HEAD; redo the
|
||||||
|
commit by starting with its log message. If you do not need to
|
||||||
|
edit the message further, you can give -C option instead.
|
||||||
|
------------
|
||||||
|
|
||||||
|
Undo commits permanently::
|
||||||
|
+
|
||||||
|
------------
|
||||||
|
$ git commit ...
|
||||||
|
$ git reset --hard HEAD~3 <1>
|
||||||
|
|
||||||
|
<1> The last three commits (HEAD, HEAD^, and HEAD~2) were bad
|
||||||
|
and you do not want to ever see them again. Do *not* do this if
|
||||||
|
you have already given these commits to somebody else.
|
||||||
|
------------
|
||||||
|
|
||||||
|
Undo a commit, making it a topic branch::
|
||||||
|
+
|
||||||
|
------------
|
||||||
|
$ git branch topic/wip <1>
|
||||||
|
$ git reset --hard HEAD~3 <2>
|
||||||
|
$ git checkout topic/wip <3>
|
||||||
|
|
||||||
|
<1> You have made some commits, but realize they were premature
|
||||||
|
to be in the "master" branch. You want to continue polishing
|
||||||
|
them in a topic branch, so create "topic/wip" branch off of the
|
||||||
|
current HEAD.
|
||||||
|
<2> Rewind the master branch to get rid of those three commits.
|
||||||
|
<3> Switch to "topic/wip" branch and keep working.
|
||||||
|
------------
|
||||||
|
|
||||||
|
Undo update-index::
|
||||||
|
+
|
||||||
|
------------
|
||||||
|
$ edit <1>
|
||||||
|
$ git-update-index frotz.c filfre.c
|
||||||
|
$ mailx <2>
|
||||||
|
$ git reset <3>
|
||||||
|
$ git pull git://info.example.com/ nitfol <4>
|
||||||
|
|
||||||
|
<1> you are happily working on something, and find the changes
|
||||||
|
in these files are in good order. You do not want to see them
|
||||||
|
when you run "git diff", because you plan to work on other files
|
||||||
|
and changes with these files are distracting.
|
||||||
|
<2> somebody asks you to pull, and the changes sounds worthy of merging.
|
||||||
|
<3> however, you already dirtied the index (i.e. your index does
|
||||||
|
not match the HEAD commit). But you know the pull you are going
|
||||||
|
to make does not affect frotz.c nor filfre.c, so you revert the
|
||||||
|
index changes for these two files. Your changes in working tree
|
||||||
|
remain there.
|
||||||
|
<4> then you can pull and merge, leaving frotz.c and filfre.c
|
||||||
|
changes still in the working tree.
|
||||||
|
------------
|
||||||
|
|
||||||
|
Undo a merge or pull::
|
||||||
|
+
|
||||||
|
------------
|
||||||
|
$ git pull <1>
|
||||||
|
Trying really trivial in-index merge...
|
||||||
|
fatal: Merge requires file-level merging
|
||||||
|
Nope.
|
||||||
|
...
|
||||||
|
Auto-merging nitfol
|
||||||
|
CONFLICT (content): Merge conflict in nitfol
|
||||||
|
Automatic merge failed/prevented; fix up by hand
|
||||||
|
$ git reset --hard <2>
|
||||||
|
|
||||||
|
<1> try to update from the upstream resulted in a lot of
|
||||||
|
conflicts; you were not ready to spend a lot of time merging
|
||||||
|
right now, so you decide to do that later.
|
||||||
|
<2> "pull" has not made merge commit, so "git reset --hard"
|
||||||
|
which is a synonym for "git reset --hard HEAD" clears the mess
|
||||||
|
from the index file and the working tree.
|
||||||
|
|
||||||
|
$ git pull . topic/branch <3>
|
||||||
|
Updating from 41223... to 13134...
|
||||||
|
Fast forward
|
||||||
|
$ git reset --hard ORIG_HEAD <4>
|
||||||
|
|
||||||
|
<3> merge a topic branch into the current branch, which resulted
|
||||||
|
in a fast forward.
|
||||||
|
<4> but you decided that the topic branch is not ready for public
|
||||||
|
consumption yet. "pull" or "merge" always leaves the original
|
||||||
|
tip of the current branch in ORIG_HEAD, so resetting hard to it
|
||||||
|
brings your index file and the working tree back to that state,
|
||||||
|
and resets the tip of the branch to that commit.
|
||||||
|
------------
|
||||||
|
|
||||||
Author
|
Author
|
||||||
------
|
------
|
||||||
Written by Junio C Hamano <junkio@cox.net> and Linus Torvalds <torvalds@osdl.org>
|
Written by Junio C Hamano <junkio@cox.net> and Linus Torvalds <torvalds@osdl.org>
|
||||||
|
@ -7,7 +7,7 @@ git-revert - Revert an existing commit.
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
'git-revert' [-n] <commit>
|
'git-revert' [--edit | --no-edit] [-n] <commit>
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
@ -20,7 +20,16 @@ OPTIONS
|
|||||||
<commit>::
|
<commit>::
|
||||||
Commit to revert.
|
Commit to revert.
|
||||||
|
|
||||||
-n::
|
-e|--edit::
|
||||||
|
With this option, `git-revert` will let you edit the commit
|
||||||
|
message prior committing the revert. This is the default if
|
||||||
|
you run the command from a terminal.
|
||||||
|
|
||||||
|
--no-edit::
|
||||||
|
With this option, `git-revert` will not start the commit
|
||||||
|
message editor.
|
||||||
|
|
||||||
|
-n|--no-commit::
|
||||||
Usually the command automatically creates a commit with
|
Usually the command automatically creates a commit with
|
||||||
a commit log message stating which commit was reverted.
|
a commit log message stating which commit was reverted.
|
||||||
This flag applies the change necessary to revert the
|
This flag applies the change necessary to revert the
|
||||||
|
@ -7,23 +7,40 @@ git-show-branch - Show branches and their commits.
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
'git-show-branch [--all] [--heads] [--tags] [--more=<n> | --list | --independent | --merge-base] [--no-name | --sha1-name] <reference>...'
|
'git-show-branch [--all] [--heads] [--tags] [--topo-order] [--more=<n> | --list | --independent | --merge-base] [--no-name | --sha1-name] [<rev> | <glob>]...'
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
Shows the head commits from the named <reference> (or all refs under
|
|
||||||
$GIT_DIR/refs/heads), and displays concise list of commit logs
|
Shows the commit ancestry graph starting from the commits named
|
||||||
to show their relationship semi-visually.
|
with <rev>s or <globs>s (or all refs under $GIT_DIR/refs/heads
|
||||||
|
and/or $GIT_DIR/refs/tags) semi-visually.
|
||||||
|
|
||||||
|
It cannot show more than 29 branches and commits at a time.
|
||||||
|
|
||||||
|
|
||||||
OPTIONS
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
<reference>::
|
<rev>::
|
||||||
Name of the reference under $GIT_DIR/refs/.
|
Arbitrary extended SHA1 expression (see `git-rev-parse`)
|
||||||
|
that typically names a branch HEAD or a tag.
|
||||||
|
|
||||||
|
<glob>::
|
||||||
|
A glob pattern that matches branch or tag names under
|
||||||
|
$GIT_DIR/refs. For example, if you have many topic
|
||||||
|
branches under $GIT_DIR/refs/heads/topic, giving
|
||||||
|
`topic/*` would show all of them.
|
||||||
|
|
||||||
--all --heads --tags::
|
--all --heads --tags::
|
||||||
Show all refs under $GIT_DIR/refs, $GIT_DIR/refs/heads,
|
Show all refs under $GIT_DIR/refs, $GIT_DIR/refs/heads,
|
||||||
and $GIT_DIR/refs/tags, respectively.
|
and $GIT_DIR/refs/tags, respectively.
|
||||||
|
|
||||||
|
--topo-order::
|
||||||
|
By default, the branches and their commits are shown in
|
||||||
|
reverse chronological order. This option makes them
|
||||||
|
appear in topological order (i.e., descendant commits
|
||||||
|
are shown before their parents).
|
||||||
|
|
||||||
--more=<n>::
|
--more=<n>::
|
||||||
Usually the command stops output upon showing the commit
|
Usually the command stops output upon showing the commit
|
||||||
that is the common ancestor of all the branches. This
|
that is the common ancestor of all the branches. This
|
||||||
|
@ -10,26 +10,6 @@ SYNOPSIS
|
|||||||
--------
|
--------
|
||||||
'git-tag' [-a | -s | -u <key-id>] [-f | -d] [-m <msg>] <name> [<head>]
|
'git-tag' [-a | -s | -u <key-id>] [-f | -d] [-m <msg>] <name> [<head>]
|
||||||
|
|
||||||
OPTIONS
|
|
||||||
-------
|
|
||||||
-a::
|
|
||||||
Make an unsigned, annotated tag object
|
|
||||||
|
|
||||||
-s::
|
|
||||||
Make a GPG-signed tag, using the default e-mail address's key
|
|
||||||
|
|
||||||
-u <key-id>::
|
|
||||||
Make a GPG-signed tag, using the given key
|
|
||||||
|
|
||||||
-f::
|
|
||||||
Replace an existing tag with the given name (instead of failing)
|
|
||||||
|
|
||||||
-d::
|
|
||||||
Delete an existing tag with the given name
|
|
||||||
|
|
||||||
-m <msg>::
|
|
||||||
Use the given tag message (instead of prompting)
|
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
Adds a 'tag' reference in .git/refs/tags/
|
Adds a 'tag' reference in .git/refs/tags/
|
||||||
@ -52,6 +32,26 @@ GnuPG key for signing.
|
|||||||
|
|
||||||
`-d <tag>` deletes the tag.
|
`-d <tag>` deletes the tag.
|
||||||
|
|
||||||
|
OPTIONS
|
||||||
|
-------
|
||||||
|
-a::
|
||||||
|
Make an unsigned, annotated tag object
|
||||||
|
|
||||||
|
-s::
|
||||||
|
Make a GPG-signed tag, using the default e-mail address's key
|
||||||
|
|
||||||
|
-u <key-id>::
|
||||||
|
Make a GPG-signed tag, using the given key
|
||||||
|
|
||||||
|
-f::
|
||||||
|
Replace an existing tag with the given name (instead of failing)
|
||||||
|
|
||||||
|
-d::
|
||||||
|
Delete an existing tag with the given name
|
||||||
|
|
||||||
|
-m <msg>::
|
||||||
|
Use the given tag message (instead of prompting)
|
||||||
|
|
||||||
|
|
||||||
Author
|
Author
|
||||||
------
|
------
|
||||||
|
@ -123,7 +123,9 @@ merging.
|
|||||||
|
|
||||||
To pretend you have a file with mode and sha1 at path, say:
|
To pretend you have a file with mode and sha1 at path, say:
|
||||||
|
|
||||||
$ git-update-index --cacheinfo mode sha1 path
|
----------------
|
||||||
|
$ git-update-index --cacheinfo mode sha1 path
|
||||||
|
----------------
|
||||||
|
|
||||||
'--info-only' is used to register files without placing them in the object
|
'--info-only' is used to register files without placing them in the object
|
||||||
database. This is useful for status-only repositories.
|
database. This is useful for status-only repositories.
|
||||||
@ -134,11 +136,70 @@ in the database but the file isn't available locally. '--info-only' is
|
|||||||
useful when the file is available, but you do not wish to update the
|
useful when the file is available, but you do not wish to update the
|
||||||
object database.
|
object database.
|
||||||
|
|
||||||
|
|
||||||
|
Using --index-info
|
||||||
|
------------------
|
||||||
|
|
||||||
|
`--index-info` is a more powerful mechanism that lets you feed
|
||||||
|
multiple entry definitions from the standard input, and designed
|
||||||
|
specifically for scripts. It can take inputs of three formats:
|
||||||
|
|
||||||
|
. mode SP sha1 TAB path
|
||||||
|
+
|
||||||
|
The first format is what "git-apply --index-info"
|
||||||
|
reports, and used to reconstruct a partial tree
|
||||||
|
that is used for phony merge base tree when falling
|
||||||
|
back on 3-way merge.
|
||||||
|
|
||||||
|
. mode SP type SP sha1 TAB path
|
||||||
|
+
|
||||||
|
The second format is to stuff git-ls-tree output
|
||||||
|
into the index file.
|
||||||
|
|
||||||
|
. mode SP sha1 SP stage TAB path
|
||||||
|
+
|
||||||
|
This format is to put higher order stages into the
|
||||||
|
index file and matches git-ls-files --stage output.
|
||||||
|
|
||||||
|
To place a higher stage entry to the index, the path should
|
||||||
|
first be removed by feeding a mode=0 entry for the path, and
|
||||||
|
then feeding necessary input lines in the third format.
|
||||||
|
|
||||||
|
For example, starting with this index:
|
||||||
|
|
||||||
|
------------
|
||||||
|
$ git ls-files -s
|
||||||
|
100644 8a1218a1024a212bb3db30becd860315f9f3ac52 0 frotz
|
||||||
|
------------
|
||||||
|
|
||||||
|
you can feed the following input to `--index-info`:
|
||||||
|
|
||||||
|
------------
|
||||||
|
$ git update-index --index-info
|
||||||
|
0 0000000000000000000000000000000000000000 frotz
|
||||||
|
100644 8a1218a1024a212bb3db30becd860315f9f3ac52 1 frotz
|
||||||
|
100755 8a1218a1024a212bb3db30becd860315f9f3ac52 2 frotz
|
||||||
|
------------
|
||||||
|
|
||||||
|
The first line of the input feeds 0 as the mode to remove the
|
||||||
|
path; the SHA1 does not matter as long as it is well formatted.
|
||||||
|
Then the second and third line feeds stage 1 and stage 2 entries
|
||||||
|
for that path. After the above, we would end up with this:
|
||||||
|
|
||||||
|
------------
|
||||||
|
$ git ls-files -s
|
||||||
|
100644 8a1218a1024a212bb3db30becd860315f9f3ac52 1 frotz
|
||||||
|
100755 8a1218a1024a212bb3db30becd860315f9f3ac52 2 frotz
|
||||||
|
------------
|
||||||
|
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
--------
|
--------
|
||||||
To update and refresh only the files already checked out:
|
To update and refresh only the files already checked out:
|
||||||
|
|
||||||
git-checkout-index -n -f -a && git-update-index --ignore-missing --refresh
|
----------------
|
||||||
|
$ git-checkout-index -n -f -a && git-update-index --ignore-missing --refresh
|
||||||
|
----------------
|
||||||
|
|
||||||
|
|
||||||
Configuration
|
Configuration
|
||||||
@ -146,12 +207,18 @@ Configuration
|
|||||||
|
|
||||||
The command honors `core.filemode` configuration variable. If
|
The command honors `core.filemode` configuration variable. If
|
||||||
your repository is on an filesystem whose executable bits are
|
your repository is on an filesystem whose executable bits are
|
||||||
unreliable, this should be set to 'false'. This causes the
|
unreliable, this should be set to 'false' (see gitlink:git-repo-config[1]).
|
||||||
command to ignore differences in file modes recorded in the
|
This causes the command to ignore differences in file modes recorded
|
||||||
index and the file mode on the filesystem if they differ only on
|
in the index and the file mode on the filesystem if they differ only on
|
||||||
executable bit. On such an unfortunate filesystem, you may
|
executable bit. On such an unfortunate filesystem, you may
|
||||||
need to use `git-update-index --chmod=`.
|
need to use `git-update-index --chmod=`.
|
||||||
|
|
||||||
|
|
||||||
|
See Also
|
||||||
|
--------
|
||||||
|
gitlink:git-repo-config[1]
|
||||||
|
|
||||||
|
|
||||||
Author
|
Author
|
||||||
------
|
------
|
||||||
Written by Linus Torvalds <torvalds@osdl.org>
|
Written by Linus Torvalds <torvalds@osdl.org>
|
||||||
|
@ -12,17 +12,17 @@ SYNOPSIS
|
|||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
A dumb server that does not do on-the-fly pack generations can
|
A dumb server that does not do on-the-fly pack generations must
|
||||||
have some auxiliary information files in $GIT_DIR/info and
|
have some auxiliary information files in $GIT_DIR/info and
|
||||||
$GIT_OBJECT_DIRECTORY/info directories to help clients discover
|
$GIT_OBJECT_DIRECTORY/info directories to help clients discover
|
||||||
what references and packs the server has and make optimized
|
what references and packs the server has. This command
|
||||||
pull decisions. This command generates such auxiliary files.
|
generates such auxiliary files.
|
||||||
|
|
||||||
|
|
||||||
OPTIONS
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
|
|
||||||
--force::
|
-f|--force::
|
||||||
Update the info files from scratch.
|
Update the info files from scratch.
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ git-verify-pack - Validate packed git archive files.
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
'git-verify-pack' [-v] <pack>.idx ...
|
'git-verify-pack' [-v] [--] <pack>.idx ...
|
||||||
|
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
@ -25,6 +25,8 @@ OPTIONS
|
|||||||
-v::
|
-v::
|
||||||
After verifying the pack, show list of objects contained
|
After verifying the pack, show list of objects contained
|
||||||
in the pack.
|
in the pack.
|
||||||
|
--::
|
||||||
|
Do not interpret any more arguments as options.
|
||||||
|
|
||||||
OUTPUT FORMAT
|
OUTPUT FORMAT
|
||||||
-------------
|
-------------
|
||||||
|
@ -14,19 +14,21 @@ DESCRIPTION
|
|||||||
-----------
|
-----------
|
||||||
Creates a tree object using the current index.
|
Creates a tree object using the current index.
|
||||||
|
|
||||||
The index must be merged.
|
The index must be in a fully merged state.
|
||||||
|
|
||||||
Conceptually, "git-write-tree" sync()s the current index contents
|
Conceptually, `git-write-tree` sync()s the current index contents
|
||||||
into a set of tree files.
|
into a set of tree files.
|
||||||
In order to have that match what is actually in your directory right
|
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
|
now, you need to have done a `git-update-index` phase before you did the
|
||||||
"git-write-tree".
|
`git-write-tree`.
|
||||||
|
|
||||||
|
|
||||||
OPTIONS
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
--missing-ok::
|
--missing-ok::
|
||||||
Normally "git-write-tree" ensures that the objects referenced by the
|
Normally `git-write-tree` ensures that the objects referenced by the
|
||||||
directory exist in the object database. This option disables this check.
|
directory exist in the object database. This option disables this
|
||||||
|
check.
|
||||||
|
|
||||||
Author
|
Author
|
||||||
------
|
------
|
||||||
|
@ -33,34 +33,45 @@ OPTIONS
|
|||||||
environment variable. If no path is given 'git' will print
|
environment variable. If no path is given 'git' will print
|
||||||
the current setting and then exit.
|
the current setting and then exit.
|
||||||
|
|
||||||
CORE GIT COMMANDS
|
|
||||||
-----------------
|
|
||||||
Before reading this cover to cover, you may want to take a look
|
|
||||||
at the link:tutorial.html[tutorial] document.
|
|
||||||
|
|
||||||
The <<Discussion>> section below contains much useful definition and
|
NOT LEARNING CORE GIT COMMANDS
|
||||||
clarification info - read that first. And of the commands, I suggest
|
------------------------------
|
||||||
reading gitlink:git-update-index[1] and
|
|
||||||
gitlink:git-read-tree[1] first - I wish I had!
|
|
||||||
|
|
||||||
If you are migrating from CVS, link:cvs-migration.html[cvs migration]
|
This manual is intended to give complete background information
|
||||||
document may be helpful after you finish the tutorial.
|
and internal workings of git, which may be too much for most
|
||||||
|
people. The <<Discussion>> section below contains much useful
|
||||||
|
definition and clarification - read that first.
|
||||||
|
|
||||||
|
If you are interested in using git to manage (version control)
|
||||||
|
projects, use link:everyday.html[Everyday GIT] as a guide to the
|
||||||
|
minimum set of commands you need to know for day-to-day work.
|
||||||
|
Most likely, that will get you started, and you can go a long
|
||||||
|
way without knowing the low level details too much.
|
||||||
|
|
||||||
|
The link:tutorial.html[tutorial] document covers how things
|
||||||
|
internally work.
|
||||||
|
|
||||||
|
If you are migrating from CVS, link:cvs-migration.html[cvs
|
||||||
|
migration] document may be helpful after you finish the
|
||||||
|
tutorial.
|
||||||
|
|
||||||
After you get the general feel from the tutorial and this
|
After you get the general feel from the tutorial and this
|
||||||
overview page, you may want to take a look at the
|
overview page, you may want to take a look at the
|
||||||
link:howto-index.html[howto] documents.
|
link:howto-index.html[howto] documents.
|
||||||
|
|
||||||
|
|
||||||
David Greaves <david@dgreaves.com>
|
CORE GIT COMMANDS
|
||||||
08/05/05
|
-----------------
|
||||||
|
|
||||||
|
If you are writing your own Porcelain, you need to be familiar
|
||||||
|
with most of the low level commands --- I suggest starting from
|
||||||
|
gitlink:git-update-index[1] and gitlink:git-read-tree[1].
|
||||||
|
|
||||||
Updated by Junio C Hamano <junkio@cox.net> on 2005-05-05 to
|
|
||||||
reflect recent changes.
|
|
||||||
|
|
||||||
Commands Overview
|
Commands Overview
|
||||||
-----------------
|
-----------------
|
||||||
The git commands can helpfully be split into those that manipulate
|
The git commands can helpfully be split into those that manipulate
|
||||||
the repository, the index and the working fileset, those that
|
the repository, the index and the files in the working tree, those that
|
||||||
interrogate and compare them, and those that moves objects and
|
interrogate and compare them, and those that moves objects and
|
||||||
references between repositories.
|
references between repositories.
|
||||||
|
|
||||||
@ -79,25 +90,26 @@ gitlink:git-apply[1]::
|
|||||||
applies it to the working tree.
|
applies it to the working tree.
|
||||||
|
|
||||||
gitlink:git-checkout-index[1]::
|
gitlink:git-checkout-index[1]::
|
||||||
Copy files from the index to the working directory
|
Copy files from the index to the working tree.
|
||||||
|
|
||||||
gitlink:git-commit-tree[1]::
|
gitlink:git-commit-tree[1]::
|
||||||
Creates a new commit object
|
Creates a new commit object.
|
||||||
|
|
||||||
gitlink:git-hash-object[1]::
|
gitlink:git-hash-object[1]::
|
||||||
Computes the object ID from a file.
|
Computes the object ID from a file.
|
||||||
|
|
||||||
gitlink:git-index-pack[1]::
|
gitlink:git-index-pack[1]::
|
||||||
Build pack index file for an existing packed archive.
|
Build pack idx file for an existing packed archive.
|
||||||
|
|
||||||
gitlink:git-init-db[1]::
|
gitlink:git-init-db[1]::
|
||||||
Creates an empty git object database
|
Creates an empty git object database, or reinitialize an
|
||||||
|
existing one.
|
||||||
|
|
||||||
gitlink:git-merge-index[1]::
|
gitlink:git-merge-index[1]::
|
||||||
Runs a merge for files needing merging
|
Runs a merge for files needing merging.
|
||||||
|
|
||||||
gitlink:git-mktag[1]::
|
gitlink:git-mktag[1]::
|
||||||
Creates a tag object
|
Creates a tag object.
|
||||||
|
|
||||||
gitlink:git-pack-objects[1]::
|
gitlink:git-pack-objects[1]::
|
||||||
Creates a packed archive of objects.
|
Creates a packed archive of objects.
|
||||||
@ -106,7 +118,7 @@ gitlink:git-prune-packed[1]::
|
|||||||
Remove extra objects that are already in pack files.
|
Remove extra objects that are already in pack files.
|
||||||
|
|
||||||
gitlink:git-read-tree[1]::
|
gitlink:git-read-tree[1]::
|
||||||
Reads tree information into the directory index
|
Reads tree information into the index.
|
||||||
|
|
||||||
gitlink:git-repo-config[1]::
|
gitlink:git-repo-config[1]::
|
||||||
Get and set options in .git/config.
|
Get and set options in .git/config.
|
||||||
@ -115,65 +127,68 @@ gitlink:git-unpack-objects[1]::
|
|||||||
Unpacks objects out of a packed archive.
|
Unpacks objects out of a packed archive.
|
||||||
|
|
||||||
gitlink:git-update-index[1]::
|
gitlink:git-update-index[1]::
|
||||||
Modifies the index or directory cache
|
Registers files in the working tree to the index.
|
||||||
|
|
||||||
gitlink:git-write-tree[1]::
|
gitlink:git-write-tree[1]::
|
||||||
Creates a tree from the current index
|
Creates a tree from the index.
|
||||||
|
|
||||||
|
|
||||||
Interrogation commands
|
Interrogation commands
|
||||||
~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
gitlink:git-cat-file[1]::
|
gitlink:git-cat-file[1]::
|
||||||
Provide content or type information for repository objects
|
Provide content or type/size information for repository objects.
|
||||||
|
|
||||||
gitlink:git-diff-index[1]::
|
gitlink:git-diff-index[1]::
|
||||||
Compares content and mode of blobs between the index and repository
|
Compares content and mode of blobs between the index and repository.
|
||||||
|
|
||||||
gitlink:git-diff-files[1]::
|
gitlink:git-diff-files[1]::
|
||||||
Compares files in the working tree and the index
|
Compares files in the working tree and the index.
|
||||||
|
|
||||||
gitlink:git-diff-stages[1]::
|
gitlink:git-diff-stages[1]::
|
||||||
Compares two "merge stages" in the index file.
|
Compares two "merge stages" in the index.
|
||||||
|
|
||||||
gitlink:git-diff-tree[1]::
|
gitlink:git-diff-tree[1]::
|
||||||
Compares the content and mode of blobs found via two tree objects
|
Compares the content and mode of blobs found via two tree objects.
|
||||||
|
|
||||||
gitlink:git-fsck-objects[1]::
|
gitlink:git-fsck-objects[1]::
|
||||||
Verifies the connectivity and validity of the objects in the database
|
Verifies the connectivity and validity of the objects in the database.
|
||||||
|
|
||||||
gitlink:git-ls-files[1]::
|
gitlink:git-ls-files[1]::
|
||||||
Information about files in the index/working directory
|
Information about files in the index and the working tree.
|
||||||
|
|
||||||
gitlink:git-ls-tree[1]::
|
gitlink:git-ls-tree[1]::
|
||||||
Displays a tree object in human readable form
|
Displays a tree object in human readable form.
|
||||||
|
|
||||||
gitlink:git-merge-base[1]::
|
gitlink:git-merge-base[1]::
|
||||||
Finds as good a common ancestor as possible for a merge
|
Finds as good common ancestors as possible for a merge.
|
||||||
|
|
||||||
gitlink:git-name-rev[1]::
|
gitlink:git-name-rev[1]::
|
||||||
Find symbolic names for given revs
|
Find symbolic names for given revs.
|
||||||
|
|
||||||
|
gitlink:git-pack-redundant[1]::
|
||||||
|
Find redundant pack files.
|
||||||
|
|
||||||
gitlink:git-rev-list[1]::
|
gitlink:git-rev-list[1]::
|
||||||
Lists commit objects in reverse chronological order
|
Lists commit objects in reverse chronological order.
|
||||||
|
|
||||||
gitlink:git-show-index[1]::
|
gitlink:git-show-index[1]::
|
||||||
Displays contents of a pack idx file.
|
Displays contents of a pack idx file.
|
||||||
|
|
||||||
gitlink:git-tar-tree[1]::
|
gitlink:git-tar-tree[1]::
|
||||||
Creates a tar archive of the files in the named tree
|
Creates a tar archive of the files in the named tree object.
|
||||||
|
|
||||||
gitlink:git-unpack-file[1]::
|
gitlink:git-unpack-file[1]::
|
||||||
Creates a temporary file with a blob's contents
|
Creates a temporary file with a blob's contents.
|
||||||
|
|
||||||
gitlink:git-var[1]::
|
gitlink:git-var[1]::
|
||||||
Displays a git logical variable
|
Displays a git logical variable.
|
||||||
|
|
||||||
gitlink:git-verify-pack[1]::
|
gitlink:git-verify-pack[1]::
|
||||||
Validates packed git archive files
|
Validates packed git archive files.
|
||||||
|
|
||||||
The interrogate commands may create files - and you can force them to
|
In general, the interrogate commands do not touch the files in
|
||||||
touch the working file set - but in general they don't
|
the working tree.
|
||||||
|
|
||||||
|
|
||||||
Synching repositories
|
Synching repositories
|
||||||
@ -181,19 +196,24 @@ Synching repositories
|
|||||||
|
|
||||||
gitlink:git-clone-pack[1]::
|
gitlink:git-clone-pack[1]::
|
||||||
Clones a repository into the current repository (engine
|
Clones a repository into the current repository (engine
|
||||||
for ssh and local transport)
|
for ssh and local transport).
|
||||||
|
|
||||||
gitlink:git-fetch-pack[1]::
|
gitlink:git-fetch-pack[1]::
|
||||||
Updates from a remote repository.
|
Updates from a remote repository (engine for ssh and
|
||||||
|
local transport).
|
||||||
|
|
||||||
gitlink:git-http-fetch[1]::
|
gitlink:git-http-fetch[1]::
|
||||||
Downloads a remote git repository via HTTP
|
Downloads a remote git repository via HTTP by walking
|
||||||
|
commit chain.
|
||||||
|
|
||||||
gitlink:git-local-fetch[1]::
|
gitlink:git-local-fetch[1]::
|
||||||
Duplicates another git repository on a local system
|
Duplicates another git repository on a local system by
|
||||||
|
walking commit chain.
|
||||||
|
|
||||||
gitlink:git-peek-remote[1]::
|
gitlink:git-peek-remote[1]::
|
||||||
Lists references on a remote repository using upload-pack protocol.
|
Lists references on a remote repository using
|
||||||
|
upload-pack protocol (engine for ssh and local
|
||||||
|
transport).
|
||||||
|
|
||||||
gitlink:git-receive-pack[1]::
|
gitlink:git-receive-pack[1]::
|
||||||
Invoked by 'git-send-pack' to receive what is pushed to it.
|
Invoked by 'git-send-pack' to receive what is pushed to it.
|
||||||
@ -201,14 +221,18 @@ gitlink:git-receive-pack[1]::
|
|||||||
gitlink:git-send-pack[1]::
|
gitlink:git-send-pack[1]::
|
||||||
Pushes to a remote repository, intelligently.
|
Pushes to a remote repository, intelligently.
|
||||||
|
|
||||||
|
gitlink:git-http-push[1]::
|
||||||
|
Push missing objects using HTTP/DAV.
|
||||||
|
|
||||||
gitlink:git-shell[1]::
|
gitlink:git-shell[1]::
|
||||||
Restricted shell for GIT-only SSH access.
|
Restricted shell for GIT-only SSH access.
|
||||||
|
|
||||||
gitlink:git-ssh-fetch[1]::
|
gitlink:git-ssh-fetch[1]::
|
||||||
Pulls from a remote repository over ssh connection
|
Pulls from a remote repository over ssh connection by
|
||||||
|
walking commit chain.
|
||||||
|
|
||||||
gitlink:git-ssh-upload[1]::
|
gitlink:git-ssh-upload[1]::
|
||||||
Helper "server-side" program used by git-ssh-fetch
|
Helper "server-side" program used by git-ssh-fetch.
|
||||||
|
|
||||||
gitlink:git-update-server-info[1]::
|
gitlink:git-update-server-info[1]::
|
||||||
Updates auxiliary information on a dumb server to help
|
Updates auxiliary information on a dumb server to help
|
||||||
@ -223,16 +247,16 @@ Porcelain-ish Commands
|
|||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
gitlink:git-add[1]::
|
gitlink:git-add[1]::
|
||||||
Add paths to the index file.
|
Add paths to the index.
|
||||||
|
|
||||||
gitlink:git-am[1]::
|
gitlink:git-am[1]::
|
||||||
Apply patches from a mailbox, but cooler.
|
Apply patches from a mailbox, but cooler.
|
||||||
|
|
||||||
gitlink:git-applymbox[1]::
|
gitlink:git-applymbox[1]::
|
||||||
Apply patches from a mailbox.
|
Apply patches from a mailbox, original version by Linus.
|
||||||
|
|
||||||
gitlink:git-bisect[1]::
|
gitlink:git-bisect[1]::
|
||||||
Find the change that introduced a bug.
|
Find the change that introduced a bug by binary search.
|
||||||
|
|
||||||
gitlink:git-branch[1]::
|
gitlink:git-branch[1]::
|
||||||
Create and Show branches.
|
Create and Show branches.
|
||||||
@ -259,7 +283,7 @@ gitlink:git-format-patch[1]::
|
|||||||
Prepare patches for e-mail submission.
|
Prepare patches for e-mail submission.
|
||||||
|
|
||||||
gitlink:git-grep[1]::
|
gitlink:git-grep[1]::
|
||||||
Print lines matching a pattern
|
Print lines matching a pattern.
|
||||||
|
|
||||||
gitlink:git-log[1]::
|
gitlink:git-log[1]::
|
||||||
Shows commit logs.
|
Shows commit logs.
|
||||||
@ -273,9 +297,6 @@ gitlink:git-merge[1]::
|
|||||||
gitlink:git-mv[1]::
|
gitlink:git-mv[1]::
|
||||||
Move or rename a file, a directory, or a symlink.
|
Move or rename a file, a directory, or a symlink.
|
||||||
|
|
||||||
gitlink:git-octopus[1]::
|
|
||||||
Merge more than two commits.
|
|
||||||
|
|
||||||
gitlink:git-pull[1]::
|
gitlink:git-pull[1]::
|
||||||
Fetch from and merge with a remote repository.
|
Fetch from and merge with a remote repository.
|
||||||
|
|
||||||
@ -283,7 +304,7 @@ gitlink:git-push[1]::
|
|||||||
Update remote refs along with associated objects.
|
Update remote refs along with associated objects.
|
||||||
|
|
||||||
gitlink:git-rebase[1]::
|
gitlink:git-rebase[1]::
|
||||||
Rebase local commits to new upstream head.
|
Rebase local commits to the updated upstream head.
|
||||||
|
|
||||||
gitlink:git-repack[1]::
|
gitlink:git-repack[1]::
|
||||||
Pack unpacked objects in a repository.
|
Pack unpacked objects in a repository.
|
||||||
@ -324,19 +345,22 @@ gitlink:git-archimport[1]::
|
|||||||
Import an arch repository into git.
|
Import an arch repository into git.
|
||||||
|
|
||||||
gitlink:git-convert-objects[1]::
|
gitlink:git-convert-objects[1]::
|
||||||
Converts old-style git repository
|
Converts old-style git repository.
|
||||||
|
|
||||||
gitlink:git-cvsimport[1]::
|
gitlink:git-cvsimport[1]::
|
||||||
Salvage your data out of another SCM people love to hate.
|
Salvage your data out of another SCM people love to hate.
|
||||||
|
|
||||||
|
gitlink:git-cvsexportcommit[1]::
|
||||||
|
Export a single commit to a CVS checkout.
|
||||||
|
|
||||||
gitlink:git-lost-found[1]::
|
gitlink:git-lost-found[1]::
|
||||||
Recover lost refs that luckily have not yet been pruned.
|
Recover lost refs that luckily have not yet been pruned.
|
||||||
|
|
||||||
gitlink:git-merge-one-file[1]::
|
gitlink:git-merge-one-file[1]::
|
||||||
The standard helper program to use with "git-merge-index"
|
The standard helper program to use with `git-merge-index`.
|
||||||
|
|
||||||
gitlink:git-prune[1]::
|
gitlink:git-prune[1]::
|
||||||
Prunes all unreachable objects from the object database
|
Prunes all unreachable objects from the object database.
|
||||||
|
|
||||||
gitlink:git-relink[1]::
|
gitlink:git-relink[1]::
|
||||||
Hardlink common objects in local repositories.
|
Hardlink common objects in local repositories.
|
||||||
@ -348,10 +372,10 @@ gitlink:git-sh-setup[1]::
|
|||||||
Common git shell script setup code.
|
Common git shell script setup code.
|
||||||
|
|
||||||
gitlink:git-symbolic-ref[1]::
|
gitlink:git-symbolic-ref[1]::
|
||||||
Read and modify symbolic refs
|
Read and modify symbolic refs.
|
||||||
|
|
||||||
gitlink:git-tag[1]::
|
gitlink:git-tag[1]::
|
||||||
An example script to create a tag object signed with GPG
|
An example script to create a tag object signed with GPG.
|
||||||
|
|
||||||
gitlink:git-update-ref[1]::
|
gitlink:git-update-ref[1]::
|
||||||
Update the object name stored in a ref safely.
|
Update the object name stored in a ref safely.
|
||||||
@ -375,16 +399,19 @@ gitlink:git-get-tar-commit-id[1]::
|
|||||||
Extract commit ID from an archive created using git-tar-tree.
|
Extract commit ID from an archive created using git-tar-tree.
|
||||||
|
|
||||||
gitlink:git-mailinfo[1]::
|
gitlink:git-mailinfo[1]::
|
||||||
Extracts patch from a single e-mail message.
|
Extracts patch and authorship information from a single
|
||||||
|
e-mail message, optionally transliterating the commit
|
||||||
|
message into utf-8.
|
||||||
|
|
||||||
gitlink:git-mailsplit[1]::
|
gitlink:git-mailsplit[1]::
|
||||||
git-mailsplit.
|
A stupid program to split UNIX mbox format mailbox into
|
||||||
|
individual pieces of e-mail.
|
||||||
|
|
||||||
gitlink:git-patch-id[1]::
|
gitlink:git-patch-id[1]::
|
||||||
Compute unique ID for a patch.
|
Compute unique ID for a patch.
|
||||||
|
|
||||||
gitlink:git-parse-remote[1]::
|
gitlink:git-parse-remote[1]::
|
||||||
Routines to help parsing $GIT_DIR/remotes/
|
Routines to help parsing `$GIT_DIR/remotes/` files.
|
||||||
|
|
||||||
gitlink:git-request-pull[1]::
|
gitlink:git-request-pull[1]::
|
||||||
git-request-pull.
|
git-request-pull.
|
||||||
@ -406,22 +433,20 @@ Commands not yet documented
|
|||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
gitlink:gitk[1]::
|
gitlink:gitk[1]::
|
||||||
gitk.
|
The gitk repository browser.
|
||||||
|
|
||||||
|
|
||||||
Configuration Mechanism
|
Configuration Mechanism
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
Starting from 0.99.9 (actually mid 0.99.8.GIT), .git/config file
|
Starting from 0.99.9 (actually mid 0.99.8.GIT), `.git/config` file
|
||||||
is used to hold per-repository configuration options. It is a
|
is used to hold per-repository configuration options. It is a
|
||||||
simple text file modelled after `.ini` format familiar to some
|
simple text file modelled after `.ini` format familiar to some
|
||||||
people. Here is an example:
|
people. Here is an example:
|
||||||
|
|
||||||
------------
|
------------
|
||||||
#
|
#
|
||||||
# This is the config file, and
|
# A '#' or ';' character indicates a comment.
|
||||||
# a '#' or ';' character indicates
|
|
||||||
# a comment
|
|
||||||
#
|
#
|
||||||
|
|
||||||
; core variables
|
; core variables
|
||||||
@ -443,30 +468,30 @@ their operation accordingly.
|
|||||||
Identifier Terminology
|
Identifier Terminology
|
||||||
----------------------
|
----------------------
|
||||||
<object>::
|
<object>::
|
||||||
Indicates the sha1 identifier for any type of object
|
Indicates the object name for any type of object.
|
||||||
|
|
||||||
<blob>::
|
<blob>::
|
||||||
Indicates a blob object sha1 identifier
|
Indicates a blob object name.
|
||||||
|
|
||||||
<tree>::
|
<tree>::
|
||||||
Indicates a tree object sha1 identifier
|
Indicates a tree object name.
|
||||||
|
|
||||||
<commit>::
|
<commit>::
|
||||||
Indicates a commit object sha1 identifier
|
Indicates a commit object name.
|
||||||
|
|
||||||
<tree-ish>::
|
<tree-ish>::
|
||||||
Indicates a tree, commit or tag object sha1 identifier. A
|
Indicates a tree, commit or tag object name. A
|
||||||
command that takes a <tree-ish> argument ultimately wants to
|
command that takes a <tree-ish> argument ultimately wants to
|
||||||
operate on a <tree> object but automatically dereferences
|
operate on a <tree> object but automatically dereferences
|
||||||
<commit> and <tag> objects that point at a <tree>.
|
<commit> and <tag> objects that point at a <tree>.
|
||||||
|
|
||||||
<type>::
|
<type>::
|
||||||
Indicates that an object type is required.
|
Indicates that an object type is required.
|
||||||
Currently one of: blob/tree/commit/tag
|
Currently one of: `blob`, `tree`, `commit`, or `tag`.
|
||||||
|
|
||||||
<file>::
|
<file>::
|
||||||
Indicates a filename - always relative to the root of
|
Indicates a filename - almost always relative to the
|
||||||
the tree structure GIT_INDEX_FILE describes.
|
root of the tree structure `GIT_INDEX_FILE` describes.
|
||||||
|
|
||||||
Symbolic Identifiers
|
Symbolic Identifiers
|
||||||
--------------------
|
--------------------
|
||||||
@ -474,17 +499,20 @@ Any git command accepting any <object> can also use the following
|
|||||||
symbolic notation:
|
symbolic notation:
|
||||||
|
|
||||||
HEAD::
|
HEAD::
|
||||||
indicates the head of the repository (ie the contents of
|
indicates the head of the current branch (i.e. the
|
||||||
`$GIT_DIR/HEAD`)
|
contents of `$GIT_DIR/HEAD`).
|
||||||
|
|
||||||
<tag>::
|
<tag>::
|
||||||
a valid tag 'name'+
|
a valid tag 'name'
|
||||||
(ie the contents of `$GIT_DIR/refs/tags/<tag>`)
|
(i.e. the contents of `$GIT_DIR/refs/tags/<tag>`).
|
||||||
|
|
||||||
<head>::
|
<head>::
|
||||||
a valid head 'name'+
|
a valid head 'name'
|
||||||
(ie the contents of `$GIT_DIR/refs/heads/<head>`)
|
(i.e. the contents of `$GIT_DIR/refs/heads/<head>`).
|
||||||
|
|
||||||
<snap>::
|
<snap>::
|
||||||
a valid snapshot 'name'+
|
a valid snapshot 'name'
|
||||||
(ie the contents of `$GIT_DIR/refs/snap/<snap>`)
|
(i.e. the contents of `$GIT_DIR/refs/snap/<snap>`).
|
||||||
|
|
||||||
|
|
||||||
File/Directory Structure
|
File/Directory Structure
|
||||||
@ -493,7 +521,7 @@ File/Directory Structure
|
|||||||
Please see link:repository-layout.html[repository layout] document.
|
Please see link:repository-layout.html[repository layout] document.
|
||||||
|
|
||||||
Higher level SCMs may provide and manage additional information in the
|
Higher level SCMs may provide and manage additional information in the
|
||||||
GIT_DIR.
|
`$GIT_DIR`.
|
||||||
|
|
||||||
|
|
||||||
Terminology
|
Terminology
|
||||||
@ -509,7 +537,7 @@ The git Repository
|
|||||||
~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~
|
||||||
These environment variables apply to 'all' core git commands. Nb: it
|
These environment variables apply to 'all' core git commands. Nb: it
|
||||||
is worth noting that they may be used/overridden by SCMS sitting above
|
is worth noting that they may be used/overridden by SCMS sitting above
|
||||||
git so take care if using Cogito etc
|
git so take care if using Cogito etc.
|
||||||
|
|
||||||
'GIT_INDEX_FILE'::
|
'GIT_INDEX_FILE'::
|
||||||
This environment allows the specification of an alternate
|
This environment allows the specification of an alternate
|
||||||
@ -530,9 +558,9 @@ git so take care if using Cogito etc
|
|||||||
written to these directories.
|
written to these directories.
|
||||||
|
|
||||||
'GIT_DIR'::
|
'GIT_DIR'::
|
||||||
If the 'GIT_DIR' environment variable is set then it specifies
|
If the 'GIT_DIR' environment variable is set then it
|
||||||
a path to use instead of `./.git` for the base of the
|
specifies a path to use instead of the default `.git`
|
||||||
repository.
|
for the base of the repository.
|
||||||
|
|
||||||
git Commits
|
git Commits
|
||||||
~~~~~~~~~~~
|
~~~~~~~~~~~
|
||||||
@ -558,14 +586,16 @@ include::../README[]
|
|||||||
|
|
||||||
Authors
|
Authors
|
||||||
-------
|
-------
|
||||||
git's founding father is Linus Torvalds <torvalds@osdl.org>.
|
* git's founding father is Linus Torvalds <torvalds@osdl.org>.
|
||||||
The current git nurse is Junio C. Hamano <junkio@cox.net>.
|
* The current git nurse is Junio C Hamano <junkio@cox.net>.
|
||||||
The git potty was written by Andres Ericsson <ae@op5.se>.
|
* The git potty was written by Andres Ericsson <ae@op5.se>.
|
||||||
General upbringing is handled by the git-list <git@vger.kernel.org>.
|
* General upbringing is handled by the git-list <git@vger.kernel.org>.
|
||||||
|
|
||||||
Documentation
|
Documentation
|
||||||
--------------
|
--------------
|
||||||
Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
|
The documentation for git suite was started by David Greaves
|
||||||
|
<david@dgreaves.com>, and later enhanced greatly by the
|
||||||
|
contributors on the git-list <git@vger.kernel.org>.
|
||||||
|
|
||||||
GIT
|
GIT
|
||||||
---
|
---
|
||||||
|
@ -20,7 +20,7 @@ hash::
|
|||||||
|
|
||||||
object database::
|
object database::
|
||||||
Stores a set of "objects", and an individial object is identified
|
Stores a set of "objects", and an individial object is identified
|
||||||
by its object name. The object usually live in $GIT_DIR/objects/.
|
by its object name. The objects usually live in `$GIT_DIR/objects/`.
|
||||||
|
|
||||||
blob object::
|
blob object::
|
||||||
Untyped object, e.g. the contents of a file.
|
Untyped object, e.g. the contents of a file.
|
||||||
@ -109,15 +109,15 @@ head::
|
|||||||
branch::
|
branch::
|
||||||
A non-cyclical graph of revisions, i.e. the complete history of
|
A non-cyclical graph of revisions, i.e. the complete history of
|
||||||
a particular revision, which is called the branch head. The
|
a particular revision, which is called the branch head. The
|
||||||
branch heads are stored in $GIT_DIR/refs/heads/.
|
branch heads are stored in `$GIT_DIR/refs/heads/`.
|
||||||
|
|
||||||
ref::
|
ref::
|
||||||
A 40-byte hex representation of a SHA1 pointing to a particular
|
A 40-byte hex representation of a SHA1 pointing to a particular
|
||||||
object. These may be stored in $GIT_DIR/refs/.
|
object. These may be stored in `$GIT_DIR/refs/`.
|
||||||
|
|
||||||
head ref::
|
head ref::
|
||||||
A ref pointing to a head. Often, this is abbreviated to "head".
|
A ref pointing to a head. Often, this is abbreviated to "head".
|
||||||
Head refs are stored in $GIT_DIR/refs/heads/.
|
Head refs are stored in `$GIT_DIR/refs/heads/`.
|
||||||
|
|
||||||
tree-ish::
|
tree-ish::
|
||||||
A ref pointing to either a commit object, a tree object, or a
|
A ref pointing to either a commit object, a tree object, or a
|
||||||
@ -125,7 +125,7 @@ tree-ish::
|
|||||||
|
|
||||||
ent::
|
ent::
|
||||||
Favorite synonym to "tree-ish" by some total geeks. See
|
Favorite synonym to "tree-ish" by some total geeks. See
|
||||||
http://en.wikipedia.org/wiki/Ent_(Middle-earth) for an in-depth
|
`http://en.wikipedia.org/wiki/Ent_(Middle-earth)` for an in-depth
|
||||||
explanation.
|
explanation.
|
||||||
|
|
||||||
tag object::
|
tag object::
|
||||||
@ -137,7 +137,7 @@ tag object::
|
|||||||
tag::
|
tag::
|
||||||
A ref pointing to a tag or commit object. In contrast to a head,
|
A ref pointing to a tag or commit object. In contrast to a head,
|
||||||
a tag is not changed by a commit. Tags (not tag objects) are
|
a tag is not changed by a commit. Tags (not tag objects) are
|
||||||
stored in $GIT_DIR/refs/tags/. A git tag has nothing to do with
|
stored in `$GIT_DIR/refs/tags/`. A git tag has nothing to do with
|
||||||
a Lisp tag (which is called object type in git's context).
|
a Lisp tag (which is called object type in git's context).
|
||||||
A tag is most typically used to mark a particular point in the
|
A tag is most typically used to mark a particular point in the
|
||||||
commit ancestry chain.
|
commit ancestry chain.
|
||||||
|
@ -111,6 +111,10 @@ Another use suggested on the mailing list is to use this hook to
|
|||||||
implement access control which is finer grained than the one
|
implement access control which is finer grained than the one
|
||||||
based on filesystem group.
|
based on filesystem group.
|
||||||
|
|
||||||
|
The standard output of this hook is sent to /dev/null; if you
|
||||||
|
want to report something to the git-send-pack on the other end,
|
||||||
|
you can redirect your output to your stderr.
|
||||||
|
|
||||||
post-update
|
post-update
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
@ -125,3 +129,7 @@ the outcome of `git-receive-pack`.
|
|||||||
The default post-update hook, when enabled, runs
|
The default post-update hook, when enabled, runs
|
||||||
`git-update-server-info` to keep the information used by dumb
|
`git-update-server-info` to keep the information used by dumb
|
||||||
transport up-to-date.
|
transport up-to-date.
|
||||||
|
|
||||||
|
The standard output of this hook is sent to /dev/null; if you
|
||||||
|
want to report something to the git-send-pack on the other end,
|
||||||
|
you can redirect your output to your stderr.
|
||||||
|
@ -10,7 +10,7 @@ The pages under http://www.kernel.org/pub/software/scm/git/docs/
|
|||||||
are built from Documentation/ directory of the git.git project
|
are built from Documentation/ directory of the git.git project
|
||||||
and needed to be kept up-to-date. The www.kernel.org/ servers
|
and needed to be kept up-to-date. The www.kernel.org/ servers
|
||||||
are mirrored and I was told that the origin of the mirror is on
|
are mirrored and I was told that the origin of the mirror is on
|
||||||
the machine master.kernel.org, on which I was given an account
|
the machine $some.kernel.org, on which I was given an account
|
||||||
when I took over git maintainership from Linus.
|
when I took over git maintainership from Linus.
|
||||||
|
|
||||||
The directories relevant to this how-to are these two:
|
The directories relevant to this how-to are these two:
|
||||||
@ -63,7 +63,7 @@ like this:
|
|||||||
EOF
|
EOF
|
||||||
$ chmod +x /pub/scm/git/git.git/hooks/post-update
|
$ chmod +x /pub/scm/git/git.git/hooks/post-update
|
||||||
|
|
||||||
There are three things worth mentioning:
|
There are four things worth mentioning:
|
||||||
|
|
||||||
- The update-hook is run after the repository accepts a "git
|
- The update-hook is run after the repository accepts a "git
|
||||||
push", under my user privilege. It is given the full names
|
push", under my user privilege. It is given the full names
|
||||||
@ -77,6 +77,10 @@ There are three things worth mentioning:
|
|||||||
pull" it does into $HOME/doc-git/docgen/ repository would not
|
pull" it does into $HOME/doc-git/docgen/ repository would not
|
||||||
work correctly.
|
work correctly.
|
||||||
|
|
||||||
|
- The stdout of update hook script is not connected to git
|
||||||
|
push; I run the heavy part of the command inside "at", to
|
||||||
|
receive the execution report via e-mail.
|
||||||
|
|
||||||
- This is still crude and does not protect against simultaneous
|
- This is still crude and does not protect against simultaneous
|
||||||
make invocations stomping on each other. I would need to add
|
make invocations stomping on each other. I would need to add
|
||||||
some locking mechanism for this.
|
some locking mechanism for this.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
From: Junio C Hamano <junkio@cox.net>
|
From: Junio C Hamano <junkio@cox.net> and Carl Baldwin <cnb@fc.hp.com>
|
||||||
Subject: control access to branches.
|
Subject: control access to branches.
|
||||||
Date: Thu, 17 Nov 2005 23:55:32 -0800
|
Date: Thu, 17 Nov 2005 23:55:32 -0800
|
||||||
Message-ID: <7vfypumlu3.fsf@assigned-by-dhcp.cox.net>
|
Message-ID: <7vfypumlu3.fsf@assigned-by-dhcp.cox.net>
|
||||||
@ -26,63 +26,137 @@ section of the documentation:
|
|||||||
So if your policy is (1) always require fast-forward push
|
So if your policy is (1) always require fast-forward push
|
||||||
(i.e. never allow "git-push repo +branch:branch"), (2) you
|
(i.e. never allow "git-push repo +branch:branch"), (2) you
|
||||||
have a list of users allowed to update each branch, and (3) you
|
have a list of users allowed to update each branch, and (3) you
|
||||||
do not let tags to be overwritten, then:
|
do not let tags to be overwritten, then you can use something
|
||||||
|
like this as your hooks/update script.
|
||||||
|
|
||||||
#!/bin/sh
|
[jc: editorial note. This is a much improved version by Carl
|
||||||
# This is a sample hooks/update script, written by JC
|
since I posted the original outline]
|
||||||
# in his e-mail buffer, so naturally it is not tested
|
|
||||||
# but hopefully would convey the idea.
|
|
||||||
|
|
||||||
umask 002
|
-- >8 -- beginning of script -- >8 --
|
||||||
case "$1" in
|
|
||||||
refs/tags/*)
|
|
||||||
# No overwriting an existing tag
|
|
||||||
if test -f "$GIT_DIR/$1"
|
|
||||||
then
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
refs/heads/*)
|
|
||||||
# No rebasing or rewinding
|
|
||||||
if expr "$2" : '0*$' >/dev/null
|
|
||||||
then
|
|
||||||
# creating a new branch
|
|
||||||
;
|
|
||||||
else
|
|
||||||
# updating -- make sure it is a fast forward
|
|
||||||
mb=`git-merge-base "$2" "$3"`
|
|
||||||
case "$mb,$2" in
|
|
||||||
"$2,$mb")
|
|
||||||
;; # fast forward -- happy
|
|
||||||
*)
|
|
||||||
exit 1 ;; # unhappy
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
# No funny refs allowed
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# Is the user allowed to update it?
|
#!/bin/bash
|
||||||
me=`id -u -n` ;# e.g. "junio"
|
|
||||||
while read head_pattern users
|
|
||||||
do
|
|
||||||
if expr "$1" : "$head_pattern" >/dev/null
|
|
||||||
then
|
|
||||||
case " $users " in
|
|
||||||
*" $me "*)
|
|
||||||
exit 0 ;; # happy
|
|
||||||
' * ')
|
|
||||||
exit 0 ;; # anybody
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
exit 1
|
|
||||||
|
|
||||||
For the sake of simplicity, I assumed that you keep something
|
umask 002
|
||||||
like this in $GIT_DIR/info/allowed-pushers file:
|
|
||||||
|
# If you are having trouble with this access control hook script
|
||||||
|
# you can try setting this to true. It will tell you exactly
|
||||||
|
# why a user is being allowed/denied access.
|
||||||
|
|
||||||
|
verbose=false
|
||||||
|
|
||||||
|
# Default shell globbing messes things up downstream
|
||||||
|
GLOBIGNORE=*
|
||||||
|
|
||||||
|
function grant {
|
||||||
|
$verbose && echo >&2 "-Grant- $1"
|
||||||
|
echo grant
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function deny {
|
||||||
|
$verbose && echo >&2 "-Deny- $1"
|
||||||
|
echo deny
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function info {
|
||||||
|
$verbose && echo >&2 "-Info- $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Implement generic branch and tag policies.
|
||||||
|
# - Tags should not be updated once created.
|
||||||
|
# - Branches should only be fast-forwarded.
|
||||||
|
case "$1" in
|
||||||
|
refs/tags/*)
|
||||||
|
[ -f "$GIT_DIR/$1" ] &&
|
||||||
|
deny >/dev/null "You can't overwrite an existing tag"
|
||||||
|
;;
|
||||||
|
refs/heads/*)
|
||||||
|
# No rebasing or rewinding
|
||||||
|
if expr "$2" : '0*$' >/dev/null; then
|
||||||
|
info "The branch '$1' is new..."
|
||||||
|
else
|
||||||
|
# updating -- make sure it is a fast forward
|
||||||
|
mb=$(git-merge-base "$2" "$3")
|
||||||
|
case "$mb,$2" in
|
||||||
|
"$2,$mb") info "Update is fast-forward" ;;
|
||||||
|
*) deny >/dev/null "This is not a fast-forward update." ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
deny >/dev/null \
|
||||||
|
"Branch is not under refs/heads or refs/tags. What are you trying to do?"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Implement per-branch controls based on username
|
||||||
|
allowed_users_file=$GIT_DIR/info/allowed-users
|
||||||
|
username=$(id -u -n)
|
||||||
|
info "The user is: '$username'"
|
||||||
|
|
||||||
|
if [ -f "$allowed_users_file" ]; then
|
||||||
|
rc=$(cat $allowed_users_file | grep -v '^#' | grep -v '^$' |
|
||||||
|
while read head_pattern user_patterns; do
|
||||||
|
matchlen=$(expr "$1" : "$head_pattern")
|
||||||
|
if [ "$matchlen" == "${#1}" ]; then
|
||||||
|
info "Found matching head pattern: '$head_pattern'"
|
||||||
|
for user_pattern in $user_patterns; do
|
||||||
|
info "Checking user: '$username' against pattern: '$user_pattern'"
|
||||||
|
matchlen=$(expr "$username" : "$user_pattern")
|
||||||
|
if [ "$matchlen" == "${#username}" ]; then
|
||||||
|
grant "Allowing user: '$username' with pattern: '$user_pattern'"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
deny "The user is not in the access list for this branch"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
)
|
||||||
|
case "$rc" in
|
||||||
|
grant) grant >/dev/null "Granting access based on $allowed_users_file" ;;
|
||||||
|
deny) deny >/dev/null "Denying access based on $allowed_users_file" ;;
|
||||||
|
*) ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
allowed_groups_file=$GIT_DIR/info/allowed-groups
|
||||||
|
groups=$(id -G -n)
|
||||||
|
info "The user belongs to the following groups:"
|
||||||
|
info "'$groups'"
|
||||||
|
|
||||||
|
if [ -f "$allowed_groups_file" ]; then
|
||||||
|
rc=$(cat $allowed_groups_file | grep -v '^#' | grep -v '^$' |
|
||||||
|
while read head_pattern group_patterns; do
|
||||||
|
matchlen=$(expr "$1" : "$head_pattern")
|
||||||
|
if [ "$matchlen" == "${#1}" ]; then
|
||||||
|
info "Found matching head pattern: '$head_pattern'"
|
||||||
|
for group_pattern in $group_patterns; do
|
||||||
|
for groupname in $groups; do
|
||||||
|
info "Checking group: '$groupname' against pattern: '$group_pattern'"
|
||||||
|
matchlen=$(expr "$groupname" : "$group_pattern")
|
||||||
|
if [ "$matchlen" == "${#groupname}" ]; then
|
||||||
|
grant "Allowing group: '$groupname' with pattern: '$group_pattern'"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
done
|
||||||
|
deny "None of the user's groups are in the access list for this branch"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
)
|
||||||
|
case "$rc" in
|
||||||
|
grant) grant >/dev/null "Granting access based on $allowed_groups_file" ;;
|
||||||
|
deny) deny >/dev/null "Denying access based on $allowed_groups_file" ;;
|
||||||
|
*) ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
deny >/dev/null "There are no more rules to check. Denying access"
|
||||||
|
|
||||||
|
-- >8 -- end of script -- >8 --
|
||||||
|
|
||||||
|
This uses two files, $GIT_DIR/info/allowed-users and
|
||||||
|
allowed-groups, to describe which heads can be pushed into by
|
||||||
|
whom. The format of each file would look like this:
|
||||||
|
|
||||||
refs/heads/master junio
|
refs/heads/master junio
|
||||||
refs/heads/cogito$ pasky
|
refs/heads/cogito$ pasky
|
||||||
@ -91,15 +165,8 @@ like this in $GIT_DIR/info/allowed-pushers file:
|
|||||||
refs/tags/v[0-9]* junio
|
refs/tags/v[0-9]* junio
|
||||||
|
|
||||||
With this, Linus can push or create "bw/penguin" or "bw/zebra"
|
With this, Linus can push or create "bw/penguin" or "bw/zebra"
|
||||||
or "bw/panda" branches, Pasky can do only "cogito", and I can do
|
or "bw/panda" branches, Pasky can do only "cogito", and JC can
|
||||||
master branch and make versioned tags. And anybody can do
|
do master branch and make versioned tags. And anybody can do
|
||||||
tmp/blah branches. This assumes all the users are in a single
|
tmp/blah branches.
|
||||||
group that can write into $GIT_DIR/ and underneath.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
------------
|
||||||
|
@ -31,7 +31,7 @@ test tree and then pull to the release tree as that would leave trivial
|
|||||||
patches blocked in the test tree waiting for complex changes to accumulate
|
patches blocked in the test tree waiting for complex changes to accumulate
|
||||||
enough test time to graduate.
|
enough test time to graduate.
|
||||||
|
|
||||||
Back in the BitKeeper days I achieved this my creating small forests of
|
Back in the BitKeeper days I achieved this by creating small forests of
|
||||||
temporary trees, one tree for each logical grouping of patches, and then
|
temporary trees, one tree for each logical grouping of patches, and then
|
||||||
pulling changes from these trees first to the test tree, and then to the
|
pulling changes from these trees first to the test tree, and then to the
|
||||||
release tree. At first I replicated this in GIT, but then I realised
|
release tree. At first I replicated this in GIT, but then I realised
|
||||||
@ -42,7 +42,7 @@ So here is the step-by-step guide how this all works for me.
|
|||||||
|
|
||||||
First create your work tree by cloning Linus's public tree:
|
First create your work tree by cloning Linus's public tree:
|
||||||
|
|
||||||
$ git clone rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git work
|
$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git work
|
||||||
|
|
||||||
Change directory into the cloned tree you just created
|
Change directory into the cloned tree you just created
|
||||||
|
|
||||||
@ -52,7 +52,7 @@ Set up a remotes file so that you can fetch the latest from Linus' master
|
|||||||
branch into a local branch named "linus":
|
branch into a local branch named "linus":
|
||||||
|
|
||||||
$ cat > .git/remotes/linus
|
$ cat > .git/remotes/linus
|
||||||
URL: rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
|
URL: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
|
||||||
Pull: master:linus
|
Pull: master:linus
|
||||||
^D
|
^D
|
||||||
|
|
||||||
|
@ -11,6 +11,6 @@
|
|||||||
Use the given merge strategy; can be supplied more than
|
Use the given merge strategy; can be supplied more than
|
||||||
once to specify them in the order they should be tried.
|
once to specify them in the order they should be tried.
|
||||||
If there is no `-s` option, a built-in list of strategies
|
If there is no `-s` option, a built-in list of strategies
|
||||||
is used instead (`git-merge-resolve` when merging a single
|
is used instead (`git-merge-recursive` when merging a single
|
||||||
head, `git-merge-octopus` otherwise).
|
head, `git-merge-octopus` otherwise).
|
||||||
|
|
||||||
|
@ -6,27 +6,27 @@ resolve::
|
|||||||
and another branch you pulled from) using 3-way merge
|
and another branch you pulled from) using 3-way merge
|
||||||
algorithm. It tries to carefully detect criss-cross
|
algorithm. It tries to carefully detect criss-cross
|
||||||
merge ambiguities and is considered generally safe and
|
merge ambiguities and is considered generally safe and
|
||||||
fast. This is the default merge strategy when pulling
|
fast.
|
||||||
one branch.
|
|
||||||
|
|
||||||
recursive::
|
recursive::
|
||||||
This can only resolve two heads using 3-way merge
|
This can only resolve two heads using 3-way merge
|
||||||
algorithm. When there are more than one common
|
algorithm. When there are more than one common
|
||||||
ancestors that can be used for 3-way merge, it creates a
|
ancestors that can be used for 3-way merge, it creates a
|
||||||
merged tree of the common ancestores and uses that as
|
merged tree of the common ancestors and uses that as
|
||||||
the reference tree for the 3-way merge. This has been
|
the reference tree for the 3-way merge. This has been
|
||||||
reported to result in fewer merge conflicts without
|
reported to result in fewer merge conflicts without
|
||||||
causing mis-merges by tests done on actual merge commits
|
causing mis-merges by tests done on actual merge commits
|
||||||
taken from Linux 2.6 kernel development history.
|
taken from Linux 2.6 kernel development history.
|
||||||
Additionally this can detect and handle merges involving
|
Additionally this can detect and handle merges involving
|
||||||
renames.
|
renames. This is the default merge strategy when
|
||||||
|
pulling or merging one branch.
|
||||||
|
|
||||||
octopus::
|
octopus::
|
||||||
This resolves more than two-head case, but refuses to do
|
This resolves more than two-head case, but refuses to do
|
||||||
complex merge that needs manual resolution. It is
|
complex merge that needs manual resolution. It is
|
||||||
primarily meant to be used for bundling topic branch
|
primarily meant to be used for bundling topic branch
|
||||||
heads together. This is the default merge strategy when
|
heads together. This is the default merge strategy when
|
||||||
pulling more than one branch.
|
pulling or merging more than one branches.
|
||||||
|
|
||||||
ours::
|
ours::
|
||||||
This resolves any number of heads, but the result of the
|
This resolves any number of heads, but the result of the
|
||||||
|
@ -42,7 +42,6 @@ sub no_spaces ($) {
|
|||||||
|
|
||||||
print 'GIT Glossary
|
print 'GIT Glossary
|
||||||
============
|
============
|
||||||
Aug 2005
|
|
||||||
|
|
||||||
This list is sorted alphabetically:
|
This list is sorted alphabetically:
|
||||||
|
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
Pack transfer protocols
|
||||||
|
=======================
|
||||||
|
|
||||||
There are two Pack push-pull protocols.
|
There are two Pack push-pull protocols.
|
||||||
|
|
||||||
upload-pack (S) | fetch/clone-pack (C) protocol:
|
upload-pack (S) | fetch/clone-pack (C) protocol:
|
@ -18,7 +18,20 @@ doing.
|
|||||||
The core git is often called "plumbing", with the prettier user
|
The core git is often called "plumbing", with the prettier user
|
||||||
interfaces on top of it called "porcelain". You may not want to use the
|
interfaces on top of it called "porcelain". You may not want to use the
|
||||||
plumbing directly very often, but it can be good to know what the
|
plumbing directly very often, but it can be good to know what the
|
||||||
plumbing does for when the porcelain isn't flushing...
|
plumbing does for when the porcelain isn't flushing.
|
||||||
|
|
||||||
|
The material presented here often goes deep describing how things
|
||||||
|
work internally. If you are mostly interested in using git as a
|
||||||
|
SCM, you can skip them during your first pass.
|
||||||
|
|
||||||
|
[NOTE]
|
||||||
|
And those "too deep" descriptions are often marked as Note.
|
||||||
|
|
||||||
|
[NOTE]
|
||||||
|
If you are already familiar with another version control system,
|
||||||
|
like CVS, you may want to take a look at
|
||||||
|
link:everyday.html[Everyday GIT in 20 commands or so] first
|
||||||
|
before reading this.
|
||||||
|
|
||||||
|
|
||||||
Creating a git repository
|
Creating a git repository
|
||||||
@ -252,6 +265,17 @@ tree. That's very useful.
|
|||||||
A common shorthand for `git-diff-files -p` is to just write `git
|
A common shorthand for `git-diff-files -p` is to just write `git
|
||||||
diff`, which will do the same thing.
|
diff`, which will do the same thing.
|
||||||
|
|
||||||
|
------------
|
||||||
|
$ git diff
|
||||||
|
diff --git a/hello b/hello
|
||||||
|
index 557db03..263414f 100644
|
||||||
|
--- a/hello
|
||||||
|
+++ b/hello
|
||||||
|
@@ -1 +1,2 @@
|
||||||
|
Hello World
|
||||||
|
+It's a new day for git
|
||||||
|
------------
|
||||||
|
|
||||||
|
|
||||||
Committing git state
|
Committing git state
|
||||||
--------------------
|
--------------------
|
||||||
@ -1067,9 +1091,10 @@ lacks and transfers (close to) minimum set of objects.
|
|||||||
HTTP(S)::
|
HTTP(S)::
|
||||||
`http://remote.machine/path/to/repo.git/`
|
`http://remote.machine/path/to/repo.git/`
|
||||||
+
|
+
|
||||||
HTTP and HTTPS transport are used only for downloading. They
|
Downloader from http and https URL
|
||||||
first obtain the topmost commit object name from the remote site
|
first obtains the topmost commit object name from the remote site
|
||||||
by looking at `repo.git/info/refs` file, tries to obtain the
|
by looking at the specified refname under `repo.git/refs/` directory,
|
||||||
|
and then tries to obtain the
|
||||||
commit object by downloading from `repo.git/objects/xx/xxx\...`
|
commit object by downloading from `repo.git/objects/xx/xxx\...`
|
||||||
using the object name of that commit object. Then it reads the
|
using the object name of that commit object. Then it reads the
|
||||||
commit object to find out its parent commits and the associate
|
commit object to find out its parent commits and the associate
|
||||||
@ -1080,7 +1105,9 @@ sometimes also called 'commit walkers'.
|
|||||||
The 'commit walkers' are sometimes also called 'dumb
|
The 'commit walkers' are sometimes also called 'dumb
|
||||||
transports', because they do not require any git aware smart
|
transports', because they do not require any git aware smart
|
||||||
server like git Native transport does. Any stock HTTP server
|
server like git Native transport does. Any stock HTTP server
|
||||||
would suffice.
|
that does not even support directory index would suffice. But
|
||||||
|
you must prepare your repository with `git-update-server-info`
|
||||||
|
to help dumb transport downloaders.
|
||||||
+
|
+
|
||||||
There are (confusingly enough) `git-ssh-fetch` and `git-ssh-upload`
|
There are (confusingly enough) `git-ssh-fetch` and `git-ssh-upload`
|
||||||
programs, which are 'commit walkers'; they outlived their
|
programs, which are 'commit walkers'; they outlived their
|
||||||
@ -1282,26 +1309,27 @@ fatal: merge program failed
|
|||||||
|
|
||||||
`git-merge-one-file` script is called with parameters to
|
`git-merge-one-file` script is called with parameters to
|
||||||
describe those three versions, and is responsible to leave the
|
describe those three versions, and is responsible to leave the
|
||||||
merge results in the working tree and register it in the index
|
merge results in the working tree.
|
||||||
file. It is a fairly straightforward shell script, and
|
It is a fairly straightforward shell script, and
|
||||||
eventually calls `merge` program from RCS suite to perform the
|
eventually calls `merge` program from RCS suite to perform a
|
||||||
file-level 3-way merge. In this case, `merge` detects
|
file-level 3-way merge. In this case, `merge` detects
|
||||||
conflicts, and the merge result with conflict marks is left in
|
conflicts, and the merge result with conflict marks is left in
|
||||||
the working tree, while the index file is updated with the
|
the working tree.. This can be seen if you run `ls-files
|
||||||
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:
|
--stage` again at this point:
|
||||||
|
|
||||||
------------
|
------------
|
||||||
$ git-ls-files --stage
|
$ git-ls-files --stage
|
||||||
100644 7f8b141b65fdcee47321e399a2598a235a032422 0 example
|
100644 7f8b141b65fdcee47321e399a2598a235a032422 0 example
|
||||||
100644 06fa6a24256dc7e560efa5687fa84b51f0263c3a 0 hello
|
100644 263414f423d0e4d70dae8fe53fa34614ff3e2860 1 hello
|
||||||
|
100644 06fa6a24256dc7e560efa5687fa84b51f0263c3a 2 hello
|
||||||
|
100644 cc44c73eb783565da5831b4d820c962954019b69 3 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
|
This is the state of the index file and the working file after
|
||||||
`git merge` returns control back to you, leaving the conflicting
|
`git merge` returns control back to you, leaving the conflicting
|
||||||
merge for you to resolve.
|
merge for you to resolve. Notice that the path `hello` is still
|
||||||
|
unmerged, and what you see with `git diff` at this point is
|
||||||
|
differences since stage 2 (i.e. your version).
|
||||||
|
|
||||||
|
|
||||||
Publishing your work
|
Publishing your work
|
||||||
@ -1492,12 +1520,13 @@ A recommended workflow for a "project lead" goes like this:
|
|||||||
2. Prepare a public repository accessible to others.
|
2. Prepare a public repository accessible to others.
|
||||||
+
|
+
|
||||||
If other people are pulling from your repository over dumb
|
If other people are pulling from your repository over dumb
|
||||||
transport protocols, you need to keep this repository 'dumb
|
transport protocols (HTTP), you need to keep this repository
|
||||||
transport friendly'. After `git init-db`,
|
'dumb transport friendly'. After `git init-db`,
|
||||||
`$GIT_DIR/hooks/post-update` copied from the standard templates
|
`$GIT_DIR/hooks/post-update` copied from the standard templates
|
||||||
would contain a call to `git-update-server-info` but the
|
would contain a call to `git-update-server-info` but the
|
||||||
`post-update` hook itself is disabled by default -- enable it
|
`post-update` hook itself is disabled by default -- enable it
|
||||||
with `chmod +x post-update`.
|
with `chmod +x post-update`. This makes sure `git-update-server-info`
|
||||||
|
keeps the necessary files up-to-date.
|
||||||
|
|
||||||
3. Push into the public repository from your primary
|
3. Push into the public repository from your primary
|
||||||
repository.
|
repository.
|
||||||
@ -1596,7 +1625,9 @@ cooperation you are probably more familiar with as well.
|
|||||||
For this, set up a public repository on a machine that is
|
For this, set up a public repository on a machine that is
|
||||||
reachable via SSH by people with "commit privileges". Put the
|
reachable via SSH by people with "commit privileges". Put the
|
||||||
committers in the same user group and make the repository
|
committers in the same user group and make the repository
|
||||||
writable by that group.
|
writable by that group. Make sure their umasks are set up to
|
||||||
|
allow group members to write into directories other members
|
||||||
|
have created.
|
||||||
|
|
||||||
You, as an individual committer, then:
|
You, as an individual committer, then:
|
||||||
|
|
||||||
@ -1636,14 +1667,49 @@ fast forward. You need to pull and merge those other changes
|
|||||||
back before you push your work when it happens.
|
back before you push your work when it happens.
|
||||||
|
|
||||||
|
|
||||||
|
Advanced Shared Repository Management
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
Being able to push into a shared repository means being able to
|
||||||
|
write into it. If your developers are coming over the network,
|
||||||
|
this means you, as the repository administrator, need to give
|
||||||
|
each of them an SSH access to the shared repository machine.
|
||||||
|
|
||||||
|
In some cases, though, you may not want to give a normal shell
|
||||||
|
account to them, but want to restrict them to be able to only
|
||||||
|
do `git push` into the repository and nothing else.
|
||||||
|
|
||||||
|
You can achieve this by setting the login shell of your
|
||||||
|
developers on the shared repository host to `git-shell` program.
|
||||||
|
|
||||||
|
[NOTE]
|
||||||
|
Most likely you would also need to list `git-shell` program in
|
||||||
|
`/etc/shells` file.
|
||||||
|
|
||||||
|
This restricts the set of commands that can be run from incoming
|
||||||
|
SSH connection for these users to only `receive-pack` and
|
||||||
|
`upload-pack`, so the only thing they can do are `git fetch` and
|
||||||
|
`git push`.
|
||||||
|
|
||||||
|
You still need to create UNIX user accounts for each developer,
|
||||||
|
and put them in the same group. Make sure that the repository
|
||||||
|
shared among these developers is writable by that group.
|
||||||
|
|
||||||
|
You can implement finer grained branch policies using update
|
||||||
|
hooks. There is a document ("control access to branches") in
|
||||||
|
Documentation/howto by Carl Baldwin and JC outlining how to (1)
|
||||||
|
limit access to branch per user, (2) forbid overwriting existing
|
||||||
|
tags.
|
||||||
|
|
||||||
|
|
||||||
Bundling your work together
|
Bundling your work together
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
It is likely that you will be working on more than one thing at
|
It is likely that you will be working on more than one thing at
|
||||||
a time. It is easy to use those more-or-less independent tasks
|
a time. It is easy to manage those more-or-less independent tasks
|
||||||
using branches with git.
|
using branches with git.
|
||||||
|
|
||||||
We have already seen how branches work in a previous example,
|
We have already seen how branches work previously,
|
||||||
with "fun and work" example using two branches. The idea is the
|
with "fun and work" example using two branches. The idea is the
|
||||||
same if there are more than two branches. Let's say you started
|
same if there are more than two branches. Let's say you started
|
||||||
out from "master" head, and have some new code in the "master"
|
out from "master" head, and have some new code in the "master"
|
||||||
|
3
INSTALL
3
INSTALL
@ -87,3 +87,6 @@ Issues of note:
|
|||||||
have all the libraries/tools needed, or you may have
|
have all the libraries/tools needed, or you may have
|
||||||
necessary libraries at unusual locations. Please look at the
|
necessary libraries at unusual locations. Please look at the
|
||||||
top of the Makefile to see what can be adjusted for your needs.
|
top of the Makefile to see what can be adjusted for your needs.
|
||||||
|
You can place local settings in config.mak and the Makefile
|
||||||
|
will include them. Note that config.mak is not distributed;
|
||||||
|
the name is reserved for local settings.
|
||||||
|
26
Makefile
26
Makefile
@ -55,7 +55,7 @@ all:
|
|||||||
# Define USE_STDEV below if you want git to care about the underlying device
|
# 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.
|
# change being considered an inode change from the update-cache perspective.
|
||||||
|
|
||||||
GIT_VERSION = 0.99.9l
|
GIT_VERSION = 1.0.0
|
||||||
|
|
||||||
# CFLAGS and LDFLAGS are for the users to override from the command line.
|
# CFLAGS and LDFLAGS are for the users to override from the command line.
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ SCRIPT_SH = \
|
|||||||
git-cherry.sh git-clone.sh git-commit.sh \
|
git-cherry.sh git-clone.sh git-commit.sh \
|
||||||
git-count-objects.sh git-diff.sh git-fetch.sh \
|
git-count-objects.sh git-diff.sh git-fetch.sh \
|
||||||
git-format-patch.sh git-log.sh git-ls-remote.sh \
|
git-format-patch.sh git-log.sh git-ls-remote.sh \
|
||||||
git-merge-one-file.sh git-octopus.sh git-parse-remote.sh \
|
git-merge-one-file.sh git-parse-remote.sh \
|
||||||
git-prune.sh git-pull.sh git-push.sh git-rebase.sh \
|
git-prune.sh git-pull.sh git-push.sh git-rebase.sh \
|
||||||
git-repack.sh git-request-pull.sh git-reset.sh \
|
git-repack.sh git-request-pull.sh git-reset.sh \
|
||||||
git-resolve.sh git-revert.sh git-sh-setup.sh git-status.sh \
|
git-resolve.sh git-revert.sh git-sh-setup.sh git-status.sh \
|
||||||
@ -162,7 +162,7 @@ LIB_FILE=libgit.a
|
|||||||
LIB_H = \
|
LIB_H = \
|
||||||
blob.h cache.h commit.h count-delta.h csum-file.h delta.h \
|
blob.h cache.h commit.h count-delta.h csum-file.h delta.h \
|
||||||
diff.h epoch.h object.h pack.h pkt-line.h quote.h refs.h \
|
diff.h epoch.h object.h pack.h pkt-line.h quote.h refs.h \
|
||||||
run-command.h strbuf.h tag.h tree.h
|
run-command.h strbuf.h tag.h tree.h git-compat-util.h
|
||||||
|
|
||||||
DIFF_OBJS = \
|
DIFF_OBJS = \
|
||||||
diff.o diffcore-break.o diffcore-order.o diffcore-pathspec.o \
|
diff.o diffcore-break.o diffcore-order.o diffcore-pathspec.o \
|
||||||
@ -175,6 +175,7 @@ LIB_OBJS = \
|
|||||||
quote.o read-cache.o refs.o run-command.o \
|
quote.o read-cache.o refs.o run-command.o \
|
||||||
server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
|
server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
|
||||||
tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
|
tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
|
||||||
|
fetch-clone.o \
|
||||||
$(DIFF_OBJS)
|
$(DIFF_OBJS)
|
||||||
|
|
||||||
LIBS = $(LIB_FILE)
|
LIBS = $(LIB_FILE)
|
||||||
@ -243,6 +244,10 @@ ifeq ($(uname_S),NetBSD)
|
|||||||
ALL_CFLAGS += -I/usr/pkg/include
|
ALL_CFLAGS += -I/usr/pkg/include
|
||||||
ALL_LDFLAGS += -L/usr/pkg/lib -Wl,-rpath,/usr/pkg/lib
|
ALL_LDFLAGS += -L/usr/pkg/lib -Wl,-rpath,/usr/pkg/lib
|
||||||
endif
|
endif
|
||||||
|
ifeq ($(uname_S),AIX)
|
||||||
|
NO_STRCASESTR=YesPlease
|
||||||
|
NEEDS_LIBICONV=YesPlease
|
||||||
|
endif
|
||||||
ifneq (,$(findstring arm,$(uname_M)))
|
ifneq (,$(findstring arm,$(uname_M)))
|
||||||
ARM_SHA1 = YesPlease
|
ARM_SHA1 = YesPlease
|
||||||
endif
|
endif
|
||||||
@ -320,15 +325,15 @@ ifdef NEEDS_NSL
|
|||||||
SIMPLE_LIB += -lnsl
|
SIMPLE_LIB += -lnsl
|
||||||
endif
|
endif
|
||||||
ifdef NO_STRCASESTR
|
ifdef NO_STRCASESTR
|
||||||
COMPAT_CFLAGS += -Dstrcasestr=gitstrcasestr -DNO_STRCASESTR=1
|
COMPAT_CFLAGS += -DNO_STRCASESTR
|
||||||
COMPAT_OBJS += compat/strcasestr.o
|
COMPAT_OBJS += compat/strcasestr.o
|
||||||
endif
|
endif
|
||||||
ifdef NO_SETENV
|
ifdef NO_SETENV
|
||||||
COMPAT_CFLAGS += -Dsetenv=gitsetenv -DNO_SETENV=1
|
COMPAT_CFLAGS += -DNO_SETENV
|
||||||
COMPAT_OBJS += compat/setenv.o
|
COMPAT_OBJS += compat/setenv.o
|
||||||
endif
|
endif
|
||||||
ifdef NO_MMAP
|
ifdef NO_MMAP
|
||||||
COMPAT_CFLAGS += -Dmmap=gitfakemmap -Dmunmap=gitfakemunmap -DNO_MMAP
|
COMPAT_CFLAGS += -DNO_MMAP
|
||||||
COMPAT_OBJS += compat/mmap.o
|
COMPAT_OBJS += compat/mmap.o
|
||||||
endif
|
endif
|
||||||
ifdef NO_IPV6
|
ifdef NO_IPV6
|
||||||
@ -363,9 +368,9 @@ all: $(ALL_PROGRAMS)
|
|||||||
all:
|
all:
|
||||||
$(MAKE) -C templates
|
$(MAKE) -C templates
|
||||||
|
|
||||||
git$(X): git.c $(COMPAT_OBJS) Makefile
|
git$X: git.c $(LIB_FILE) Makefile
|
||||||
$(CC) -DGIT_EXEC_PATH='"$(bindir)"' -DGIT_VERSION='"$(GIT_VERSION)"' \
|
$(CC) -DGIT_EXEC_PATH='"$(bindir)"' -DGIT_VERSION='"$(GIT_VERSION)"' \
|
||||||
$(CFLAGS) $(COMPAT_CFLAGS) -o $@ $(filter %.c,$^) $(filter %.o,$^)
|
$(CFLAGS) $(COMPAT_CFLAGS) -o $@ $(filter %.c,$^) $(LIB_FILE)
|
||||||
|
|
||||||
$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
|
$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
|
||||||
rm -f $@
|
rm -f $@
|
||||||
@ -445,7 +450,7 @@ test-delta$X: test-delta.c diff-delta.o patch-delta.o
|
|||||||
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $^
|
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $^
|
||||||
|
|
||||||
check:
|
check:
|
||||||
for i in *.c; do sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i; done
|
for i in *.c; do sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i || exit; done
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -493,7 +498,7 @@ clean:
|
|||||||
rm -f *.o mozilla-sha1/*.o arm/*.o ppc/*.o compat/*.o $(LIB_FILE)
|
rm -f *.o mozilla-sha1/*.o arm/*.o ppc/*.o compat/*.o $(LIB_FILE)
|
||||||
rm -f $(PROGRAMS) $(SIMPLE_PROGRAMS) git$X
|
rm -f $(PROGRAMS) $(SIMPLE_PROGRAMS) git$X
|
||||||
rm -f $(filter-out gitk,$(SCRIPTS))
|
rm -f $(filter-out gitk,$(SCRIPTS))
|
||||||
rm -f *.spec *.pyc *.pyo
|
rm -f *.spec *.pyc *.pyo */*.pyc */*.pyo
|
||||||
rm -rf $(GIT_TARNAME)
|
rm -rf $(GIT_TARNAME)
|
||||||
rm -f $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz
|
rm -f $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz
|
||||||
rm -f git-core_$(GIT_VERSION)-*.dsc
|
rm -f git-core_$(GIT_VERSION)-*.dsc
|
||||||
@ -501,3 +506,4 @@ clean:
|
|||||||
$(MAKE) -C Documentation/ clean
|
$(MAKE) -C Documentation/ clean
|
||||||
$(MAKE) -C templates clean
|
$(MAKE) -C templates clean
|
||||||
$(MAKE) -C t/ clean
|
$(MAKE) -C t/ clean
|
||||||
|
|
||||||
|
17
README
17
README
@ -35,7 +35,7 @@ the object (i.e. how it is used, and how it can refer to other
|
|||||||
objects). There are currently four different object types: "blob",
|
objects). There are currently four different object types: "blob",
|
||||||
"tree", "commit" and "tag".
|
"tree", "commit" and "tag".
|
||||||
|
|
||||||
A "blob" object cannot refer to any other object, and is, like the tag
|
A "blob" object cannot refer to any other object, and is, like the type
|
||||||
implies, a pure storage object containing some user data. It is used to
|
implies, a pure storage object containing some user data. It is used to
|
||||||
actually store the file data, i.e. a blob object is associated with some
|
actually store the file data, i.e. a blob object is associated with some
|
||||||
particular version of some file.
|
particular version of some file.
|
||||||
@ -64,7 +64,7 @@ symbolic name (of course!) and, optionally, a signature.
|
|||||||
|
|
||||||
Regardless of object type, all objects share the following
|
Regardless of object type, all objects share the following
|
||||||
characteristics: they are all deflated with zlib, and have a header
|
characteristics: they are all deflated with zlib, and have a header
|
||||||
that not only specifies their tag, but also provides size information
|
that not only specifies their type, but also provides size information
|
||||||
about the data in the object. It's worth noting that the SHA1 hash
|
about the data in the object. It's worth noting that the SHA1 hash
|
||||||
that is used to name the object is the hash of the original data
|
that is used to name the object is the hash of the original data
|
||||||
plus this header, so `sha1sum` 'file' does not match the object name
|
plus this header, so `sha1sum` 'file' does not match the object name
|
||||||
@ -76,7 +76,7 @@ As a result, the general consistency of an object can always be tested
|
|||||||
independently of the contents or the type of the object: all objects can
|
independently of the contents or the type of the object: all objects can
|
||||||
be validated by verifying that (a) their hashes match the content of the
|
be validated by verifying that (a) their hashes match the content of the
|
||||||
file and (b) the object successfully inflates to a stream of bytes that
|
file and (b) the object successfully inflates to a stream of bytes that
|
||||||
forms a sequence of <ascii tag without space> + <space> + <ascii decimal
|
forms a sequence of <ascii type without space> + <space> + <ascii decimal
|
||||||
size> + <byte\0> + <binary object data>.
|
size> + <byte\0> + <binary object data>.
|
||||||
|
|
||||||
The structured objects can further have their structure and
|
The structured objects can further have their structure and
|
||||||
@ -297,7 +297,7 @@ will not normally add totally new entries or remove old entries,
|
|||||||
i.e. it will normally just update existing cache entries.
|
i.e. it will normally just update existing cache entries.
|
||||||
|
|
||||||
To tell git that yes, you really do realize that certain files no
|
To tell git that yes, you really do realize that certain files no
|
||||||
longer exist in the archive, or that new files should be added, you
|
longer exist, or that new files should be added, you
|
||||||
should use the `--remove` and `--add` flags respectively.
|
should use the `--remove` and `--add` flags respectively.
|
||||||
|
|
||||||
NOTE! A `--remove` flag does 'not' mean that subsequent filenames will
|
NOTE! A `--remove` flag does 'not' mean that subsequent filenames will
|
||||||
@ -515,8 +515,11 @@ index file, and you can just write the result out with
|
|||||||
Historical note. We did not have `-u` facility when this
|
Historical note. We did not have `-u` facility when this
|
||||||
section was first written, so we used to warn that
|
section was first written, so we used to warn that
|
||||||
the merge is done in the index file, not in your
|
the merge is done in the index file, not in your
|
||||||
working directory, and your working directory will no longer match your
|
working tree, and your working tree will not match your
|
||||||
index.
|
index after this step.
|
||||||
|
This is no longer true. The above command, thanks to `-u`
|
||||||
|
option, updates your working tree with the merge results for
|
||||||
|
paths that have been trivially merged.
|
||||||
|
|
||||||
|
|
||||||
8) Merging multiple trees, continued
|
8) Merging multiple trees, continued
|
||||||
@ -579,7 +582,7 @@ The above is the description of a git merge at the lowest level,
|
|||||||
to help you understand what conceptually happens under the hood.
|
to help you understand what conceptually happens under the hood.
|
||||||
In practice, nobody, not even git itself, uses three `git-cat-file`
|
In practice, nobody, not even git itself, uses three `git-cat-file`
|
||||||
for this. There is `git-merge-index` program that extracts the
|
for this. There is `git-merge-index` program that extracts the
|
||||||
stages to temporary files and calls a `merge` script on it
|
stages to temporary files and calls a "merge" script on it:
|
||||||
|
|
||||||
git-merge-index git-merge-one-file hello.c
|
git-merge-index git-merge-one-file hello.c
|
||||||
|
|
||||||
|
23
apply.c
23
apply.c
@ -84,14 +84,11 @@ static void *read_patch_file(int fd, unsigned long *sizep)
|
|||||||
buffer = xrealloc(buffer, alloc);
|
buffer = xrealloc(buffer, alloc);
|
||||||
nr = alloc - size;
|
nr = alloc - size;
|
||||||
}
|
}
|
||||||
nr = read(fd, buffer + size, nr);
|
nr = xread(fd, buffer + size, nr);
|
||||||
if (!nr)
|
if (!nr)
|
||||||
break;
|
break;
|
||||||
if (nr < 0) {
|
if (nr < 0)
|
||||||
if (errno == EAGAIN)
|
|
||||||
continue;
|
|
||||||
die("git-apply: read returned %s", strerror(errno));
|
die("git-apply: read returned %s", strerror(errno));
|
||||||
}
|
|
||||||
size += nr;
|
size += nr;
|
||||||
}
|
}
|
||||||
*sizep = size;
|
*sizep = size;
|
||||||
@ -1006,13 +1003,8 @@ static int read_old_data(struct stat *st, const char *path, void *buf, unsigned
|
|||||||
return error("unable to open %s", path);
|
return error("unable to open %s", path);
|
||||||
got = 0;
|
got = 0;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int ret = read(fd, buf + got, size - got);
|
int ret = xread(fd, buf + got, size - got);
|
||||||
if (ret < 0) {
|
if (ret <= 0)
|
||||||
if (errno == EAGAIN)
|
|
||||||
continue;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!ret)
|
|
||||||
break;
|
break;
|
||||||
got += ret;
|
got += ret;
|
||||||
}
|
}
|
||||||
@ -1600,12 +1592,9 @@ static int try_create_file(const char *path, unsigned int mode, const char *buf,
|
|||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return -1;
|
return -1;
|
||||||
while (size) {
|
while (size) {
|
||||||
int written = write(fd, buf, size);
|
int written = xwrite(fd, buf, size);
|
||||||
if (written < 0) {
|
if (written < 0)
|
||||||
if (errno == EINTR || errno == EAGAIN)
|
|
||||||
continue;
|
|
||||||
die("writing file %s: %s", path, strerror(errno));
|
die("writing file %s: %s", path, strerror(errno));
|
||||||
}
|
|
||||||
if (!written)
|
if (!written)
|
||||||
die("out of space writing file %s", path);
|
die("out of space writing file %s", path);
|
||||||
buf += written;
|
buf += written;
|
||||||
|
102
cache.h
102
cache.h
@ -1,23 +1,7 @@
|
|||||||
#ifndef CACHE_H
|
#ifndef CACHE_H
|
||||||
#define CACHE_H
|
#define CACHE_H
|
||||||
|
|
||||||
#include <unistd.h>
|
#include "git-compat-util.h"
|
||||||
#include <stdio.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#ifndef NO_MMAP
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#endif
|
|
||||||
#include <sys/param.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
|
|
||||||
#include SHA1_HEADER
|
#include SHA1_HEADER
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
@ -36,15 +20,6 @@
|
|||||||
#define DTYPE(de) DT_UNKNOWN
|
#define DTYPE(de) DT_UNKNOWN
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __GNUC__
|
|
||||||
#define NORETURN __attribute__((__noreturn__))
|
|
||||||
#else
|
|
||||||
#define NORETURN
|
|
||||||
#ifndef __attribute__
|
|
||||||
#define __attribute__(x)
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Intensive research over the course of many years has shown that
|
* Intensive research over the course of many years has shown that
|
||||||
* port 9418 is totally unused by anything else. Or
|
* port 9418 is totally unused by anything else. Or
|
||||||
@ -169,6 +144,7 @@ extern int ce_match_stat(struct cache_entry *ce, struct stat *st);
|
|||||||
extern int ce_modified(struct cache_entry *ce, struct stat *st);
|
extern int ce_modified(struct cache_entry *ce, struct stat *st);
|
||||||
extern int ce_path_match(const struct cache_entry *ce, const char **pathspec);
|
extern int ce_path_match(const struct cache_entry *ce, const char **pathspec);
|
||||||
extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, const char *type);
|
extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, const char *type);
|
||||||
|
extern int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object);
|
||||||
extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object);
|
extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object);
|
||||||
extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
|
extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
|
||||||
|
|
||||||
@ -250,11 +226,6 @@ extern const char *resolve_ref(const char *path, unsigned char *sha1, int);
|
|||||||
extern int create_symref(const char *git_HEAD, const char *refs_heads_master);
|
extern int create_symref(const char *git_HEAD, const char *refs_heads_master);
|
||||||
extern int validate_symref(const char *git_HEAD);
|
extern int validate_symref(const char *git_HEAD);
|
||||||
|
|
||||||
/* General helper functions */
|
|
||||||
extern void usage(const char *err) NORETURN;
|
|
||||||
extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2)));
|
|
||||||
extern int error(const char *err, ...) __attribute__((format (printf, 1, 2)));
|
|
||||||
|
|
||||||
extern int base_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
|
extern int base_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
|
||||||
extern int cache_name_compare(const char *name1, int len1, const char *name2, int len2);
|
extern int cache_name_compare(const char *name1, int len1, const char *name2, int len2);
|
||||||
|
|
||||||
@ -272,30 +243,6 @@ extern int setup_ident(void);
|
|||||||
extern const char *git_author_info(void);
|
extern const char *git_author_info(void);
|
||||||
extern const char *git_committer_info(void);
|
extern const char *git_committer_info(void);
|
||||||
|
|
||||||
static inline void *xmalloc(size_t size)
|
|
||||||
{
|
|
||||||
void *ret = malloc(size);
|
|
||||||
if (!ret)
|
|
||||||
die("Out of memory, malloc failed");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void *xrealloc(void *ptr, size_t size)
|
|
||||||
{
|
|
||||||
void *ret = realloc(ptr, size);
|
|
||||||
if (!ret)
|
|
||||||
die("Out of memory, realloc failed");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void *xcalloc(size_t nmemb, size_t size)
|
|
||||||
{
|
|
||||||
void *ret = calloc(nmemb, size);
|
|
||||||
if (!ret)
|
|
||||||
die("Out of memory, calloc failed");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct checkout {
|
struct checkout {
|
||||||
const char *base_dir;
|
const char *base_dir;
|
||||||
int base_dir_len;
|
int base_dir_len;
|
||||||
@ -373,20 +320,6 @@ extern void packed_object_info_detail(struct pack_entry *, char *, unsigned long
|
|||||||
/* Dumb servers support */
|
/* Dumb servers support */
|
||||||
extern int update_server_info(int);
|
extern int update_server_info(int);
|
||||||
|
|
||||||
#ifdef NO_MMAP
|
|
||||||
|
|
||||||
#ifndef PROT_READ
|
|
||||||
#define PROT_READ 1
|
|
||||||
#define PROT_WRITE 2
|
|
||||||
#define MAP_PRIVATE 1
|
|
||||||
#define MAP_FAILED ((void*)-1)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern void *gitfakemmap(void *start, size_t length, int prot , int flags, int fd, off_t offset);
|
|
||||||
extern int gitfakemunmap(void *start, size_t length);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef int (*config_fn_t)(const char *, const char *);
|
typedef int (*config_fn_t)(const char *, const char *);
|
||||||
extern int git_default_config(const char *, const char *);
|
extern int git_default_config(const char *, const char *);
|
||||||
extern int git_config_from_file(config_fn_t fn, const char *);
|
extern int git_config_from_file(config_fn_t fn, const char *);
|
||||||
@ -404,31 +337,10 @@ extern char git_default_name[MAX_GITNAME];
|
|||||||
#define MAX_ENCODING_LENGTH 64
|
#define MAX_ENCODING_LENGTH 64
|
||||||
extern char git_commit_encoding[MAX_ENCODING_LENGTH];
|
extern char git_commit_encoding[MAX_ENCODING_LENGTH];
|
||||||
|
|
||||||
/* Sane ctype - no locale, and works with signed chars */
|
|
||||||
#undef isspace
|
|
||||||
#undef isdigit
|
|
||||||
#undef isalpha
|
|
||||||
#undef isalnum
|
|
||||||
#undef tolower
|
|
||||||
#undef toupper
|
|
||||||
extern unsigned char sane_ctype[256];
|
|
||||||
#define GIT_SPACE 0x01
|
|
||||||
#define GIT_DIGIT 0x02
|
|
||||||
#define GIT_ALPHA 0x04
|
|
||||||
#define sane_istest(x,mask) ((sane_ctype[(unsigned char)(x)] & (mask)) != 0)
|
|
||||||
#define isspace(x) sane_istest(x,GIT_SPACE)
|
|
||||||
#define isdigit(x) sane_istest(x,GIT_DIGIT)
|
|
||||||
#define isalpha(x) sane_istest(x,GIT_ALPHA)
|
|
||||||
#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
|
|
||||||
#define tolower(x) sane_case((unsigned char)(x), 0x20)
|
|
||||||
#define toupper(x) sane_case((unsigned char)(x), 0)
|
|
||||||
|
|
||||||
static inline int sane_case(int x, int high)
|
|
||||||
{
|
|
||||||
if (sane_istest(x, GIT_ALPHA))
|
|
||||||
x = (x & ~0x20) | high;
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern int copy_fd(int ifd, int ofd);
|
extern int copy_fd(int ifd, int ofd);
|
||||||
|
|
||||||
|
/* Finish off pack transfer receiving end */
|
||||||
|
extern int receive_unpack_pack(int fd[2], const char *me, int quiet);
|
||||||
|
extern int receive_keep_pack(int fd[2], const char *me);
|
||||||
|
|
||||||
#endif /* CACHE_H */
|
#endif /* CACHE_H */
|
||||||
|
@ -55,10 +55,8 @@ int main(int argc, char **argv)
|
|||||||
die("git-cat-file %s: bad file", argv[2]);
|
die("git-cat-file %s: bad file", argv[2]);
|
||||||
|
|
||||||
while (size > 0) {
|
while (size > 0) {
|
||||||
long ret = write(1, buf, size);
|
long ret = xwrite(1, buf, size);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
if (errno == EAGAIN)
|
|
||||||
continue;
|
|
||||||
/* Ignore epipe */
|
/* Ignore epipe */
|
||||||
if (errno == EPIPE)
|
if (errno == EPIPE)
|
||||||
break;
|
break;
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
|
|
||||||
static const char *prefix;
|
static const char *prefix;
|
||||||
static int prefix_length;
|
static int prefix_length;
|
||||||
|
static int checkout_stage; /* default to checkout stage0 */
|
||||||
|
|
||||||
static struct checkout state = {
|
static struct checkout state = {
|
||||||
.base_dir = "",
|
.base_dir = "",
|
||||||
@ -48,20 +49,36 @@ static struct checkout state = {
|
|||||||
|
|
||||||
static int checkout_file(const char *name)
|
static int checkout_file(const char *name)
|
||||||
{
|
{
|
||||||
int pos = cache_name_pos(name, strlen(name));
|
int namelen = strlen(name);
|
||||||
if (pos < 0) {
|
int pos = cache_name_pos(name, namelen);
|
||||||
if (!state.quiet) {
|
int has_same_name = 0;
|
||||||
pos = -pos - 1;
|
|
||||||
fprintf(stderr,
|
if (pos < 0)
|
||||||
"git-checkout-index: %s is %s.\n",
|
pos = -pos - 1;
|
||||||
name,
|
|
||||||
(pos < active_nr &&
|
while (pos < active_nr) {
|
||||||
!strcmp(active_cache[pos]->name, name)) ?
|
struct cache_entry *ce = active_cache[pos];
|
||||||
"unmerged" : "not in the cache");
|
if (ce_namelen(ce) != namelen ||
|
||||||
}
|
memcmp(ce->name, name, namelen))
|
||||||
return -1;
|
break;
|
||||||
|
has_same_name = 1;
|
||||||
|
if (checkout_stage == ce_stage(ce))
|
||||||
|
return checkout_entry(ce, &state);
|
||||||
|
pos++;
|
||||||
}
|
}
|
||||||
return checkout_entry(active_cache[pos], &state);
|
|
||||||
|
if (!state.quiet) {
|
||||||
|
fprintf(stderr, "git-checkout-index: %s ", name);
|
||||||
|
if (!has_same_name)
|
||||||
|
fprintf(stderr, "is not in the cache");
|
||||||
|
else if (checkout_stage)
|
||||||
|
fprintf(stderr, "does not exist at stage %d",
|
||||||
|
checkout_stage);
|
||||||
|
else
|
||||||
|
fprintf(stderr, "is unmerged");
|
||||||
|
fputc('\n', stderr);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int checkout_all(void)
|
static int checkout_all(void)
|
||||||
@ -70,11 +87,11 @@ static int checkout_all(void)
|
|||||||
|
|
||||||
for (i = 0; i < active_nr ; i++) {
|
for (i = 0; i < active_nr ; i++) {
|
||||||
struct cache_entry *ce = active_cache[i];
|
struct cache_entry *ce = active_cache[i];
|
||||||
if (ce_stage(ce))
|
if (ce_stage(ce) != checkout_stage)
|
||||||
continue;
|
continue;
|
||||||
if (prefix && *prefix &&
|
if (prefix && *prefix &&
|
||||||
( ce_namelen(ce) <= prefix_length ||
|
(ce_namelen(ce) <= prefix_length ||
|
||||||
memcmp(prefix, ce->name, prefix_length) ))
|
memcmp(prefix, ce->name, prefix_length)))
|
||||||
continue;
|
continue;
|
||||||
if (checkout_entry(ce, &state) < 0)
|
if (checkout_entry(ce, &state) < 0)
|
||||||
errs++;
|
errs++;
|
||||||
@ -88,7 +105,7 @@ static int checkout_all(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const char checkout_cache_usage[] =
|
static const char checkout_cache_usage[] =
|
||||||
"git-checkout-index [-u] [-q] [-a] [-f] [-n] [--prefix=<string>] [--] <file>...";
|
"git-checkout-index [-u] [-q] [-a] [-f] [-n] [--stage=[123]] [--prefix=<string>] [--] <file>...";
|
||||||
|
|
||||||
static struct cache_file cache_file;
|
static struct cache_file cache_file;
|
||||||
|
|
||||||
@ -138,11 +155,19 @@ int main(int argc, char **argv)
|
|||||||
die("cannot open index.lock file.");
|
die("cannot open index.lock file.");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!memcmp(arg, "--prefix=", 9)) {
|
if (!strncmp(arg, "--prefix=", 9)) {
|
||||||
state.base_dir = arg+9;
|
state.base_dir = arg+9;
|
||||||
state.base_dir_len = strlen(state.base_dir);
|
state.base_dir_len = strlen(state.base_dir);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (!strncmp(arg, "--stage=", 8)) {
|
||||||
|
int ch = arg[8];
|
||||||
|
if ('1' <= ch && ch <= '3')
|
||||||
|
checkout_stage = arg[8] - '0';
|
||||||
|
else
|
||||||
|
die("stage should be between 1 and 3");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (arg[0] == '-')
|
if (arg[0] == '-')
|
||||||
usage(checkout_cache_usage);
|
usage(checkout_cache_usage);
|
||||||
break;
|
break;
|
||||||
|
151
clone-pack.c
151
clone-pack.c
@ -1,7 +1,6 @@
|
|||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
#include "refs.h"
|
#include "refs.h"
|
||||||
#include "pkt-line.h"
|
#include "pkt-line.h"
|
||||||
#include <sys/wait.h>
|
|
||||||
|
|
||||||
static const char clone_pack_usage[] =
|
static const char clone_pack_usage[] =
|
||||||
"git-clone-pack [--exec=<git-upload-pack>] [<host>:]<directory> [<heads>]*";
|
"git-clone-pack [--exec=<git-upload-pack>] [<host>:]<directory> [<heads>]*";
|
||||||
@ -112,139 +111,6 @@ static void write_refs(struct ref *ref)
|
|||||||
free(head_path);
|
free(head_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int finish_pack(const char *pack_tmp_name)
|
|
||||||
{
|
|
||||||
int pipe_fd[2];
|
|
||||||
pid_t pid;
|
|
||||||
char idx[PATH_MAX];
|
|
||||||
char final[PATH_MAX];
|
|
||||||
char hash[41];
|
|
||||||
unsigned char sha1[20];
|
|
||||||
char *cp;
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
if (pipe(pipe_fd) < 0)
|
|
||||||
die("git-clone-pack: unable to set up pipe");
|
|
||||||
|
|
||||||
strcpy(idx, pack_tmp_name); /* ".git/objects/pack-XXXXXX" */
|
|
||||||
cp = strrchr(idx, '/');
|
|
||||||
memcpy(cp, "/pidx", 5);
|
|
||||||
|
|
||||||
pid = fork();
|
|
||||||
if (pid < 0)
|
|
||||||
die("git-clone-pack: unable to fork off git-index-pack");
|
|
||||||
if (!pid) {
|
|
||||||
close(0);
|
|
||||||
dup2(pipe_fd[1], 1);
|
|
||||||
close(pipe_fd[0]);
|
|
||||||
close(pipe_fd[1]);
|
|
||||||
execlp("git-index-pack","git-index-pack",
|
|
||||||
"-o", idx, pack_tmp_name, NULL);
|
|
||||||
error("cannot exec git-index-pack <%s> <%s>",
|
|
||||||
idx, pack_tmp_name);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
close(pipe_fd[1]);
|
|
||||||
if (read(pipe_fd[0], hash, 40) != 40) {
|
|
||||||
error("git-clone-pack: unable to read from git-index-pack");
|
|
||||||
err = 1;
|
|
||||||
}
|
|
||||||
close(pipe_fd[0]);
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
int status, code;
|
|
||||||
int retval = waitpid(pid, &status, 0);
|
|
||||||
|
|
||||||
if (retval < 0) {
|
|
||||||
if (errno == EINTR)
|
|
||||||
continue;
|
|
||||||
error("waitpid failed (%s)", strerror(retval));
|
|
||||||
goto error_die;
|
|
||||||
}
|
|
||||||
if (WIFSIGNALED(status)) {
|
|
||||||
int sig = WTERMSIG(status);
|
|
||||||
error("git-index-pack died of signal %d", sig);
|
|
||||||
goto error_die;
|
|
||||||
}
|
|
||||||
if (!WIFEXITED(status)) {
|
|
||||||
error("git-index-pack died of unnatural causes %d",
|
|
||||||
status);
|
|
||||||
goto error_die;
|
|
||||||
}
|
|
||||||
code = WEXITSTATUS(status);
|
|
||||||
if (code) {
|
|
||||||
error("git-index-pack died with error code %d", code);
|
|
||||||
goto error_die;
|
|
||||||
}
|
|
||||||
if (err)
|
|
||||||
goto error_die;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
hash[40] = 0;
|
|
||||||
if (get_sha1_hex(hash, sha1)) {
|
|
||||||
error("git-index-pack reported nonsense '%s'", hash);
|
|
||||||
goto error_die;
|
|
||||||
}
|
|
||||||
/* Now we have pack in pack_tmp_name[], and
|
|
||||||
* idx in idx[]; rename them to their final names.
|
|
||||||
*/
|
|
||||||
snprintf(final, sizeof(final),
|
|
||||||
"%s/pack/pack-%s.pack", get_object_directory(), hash);
|
|
||||||
move_temp_to_file(pack_tmp_name, final);
|
|
||||||
chmod(final, 0444);
|
|
||||||
snprintf(final, sizeof(final),
|
|
||||||
"%s/pack/pack-%s.idx", get_object_directory(), hash);
|
|
||||||
move_temp_to_file(idx, final);
|
|
||||||
chmod(final, 0444);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
error_die:
|
|
||||||
unlink(idx);
|
|
||||||
unlink(pack_tmp_name);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int clone_without_unpack(int fd[2])
|
|
||||||
{
|
|
||||||
char tmpfile[PATH_MAX];
|
|
||||||
int ofd, ifd;
|
|
||||||
|
|
||||||
ifd = fd[0];
|
|
||||||
snprintf(tmpfile, sizeof(tmpfile),
|
|
||||||
"%s/pack/tmp-XXXXXX", get_object_directory());
|
|
||||||
ofd = mkstemp(tmpfile);
|
|
||||||
if (ofd < 0)
|
|
||||||
return error("unable to create temporary file %s", tmpfile);
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
char buf[8192];
|
|
||||||
ssize_t sz, wsz, pos;
|
|
||||||
sz = read(ifd, buf, sizeof(buf));
|
|
||||||
if (sz == 0)
|
|
||||||
break;
|
|
||||||
if (sz < 0) {
|
|
||||||
error("error reading pack (%s)", strerror(errno));
|
|
||||||
close(ofd);
|
|
||||||
unlink(tmpfile);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
pos = 0;
|
|
||||||
while (pos < sz) {
|
|
||||||
wsz = write(ofd, buf + pos, sz - pos);
|
|
||||||
if (wsz < 0) {
|
|
||||||
error("error writing pack (%s)",
|
|
||||||
strerror(errno));
|
|
||||||
close(ofd);
|
|
||||||
unlink(tmpfile);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
pos += wsz;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(ofd);
|
|
||||||
return finish_pack(tmpfile);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int clone_pack(int fd[2], int nr_match, char **match)
|
static int clone_pack(int fd[2], int nr_match, char **match)
|
||||||
{
|
{
|
||||||
struct ref *refs;
|
struct ref *refs;
|
||||||
@ -257,10 +123,19 @@ static int clone_pack(int fd[2], int nr_match, char **match)
|
|||||||
}
|
}
|
||||||
clone_handshake(fd, refs);
|
clone_handshake(fd, refs);
|
||||||
|
|
||||||
status = clone_without_unpack(fd);
|
status = receive_keep_pack(fd, "git-clone-pack");
|
||||||
|
|
||||||
if (!status)
|
if (!status) {
|
||||||
write_refs(refs);
|
if (nr_match == 0)
|
||||||
|
write_refs(refs);
|
||||||
|
else
|
||||||
|
while (refs) {
|
||||||
|
printf("%s %s\n",
|
||||||
|
sha1_to_hex(refs->old_sha1),
|
||||||
|
refs->name);
|
||||||
|
refs = refs->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,8 +160,6 @@ int main(int argc, char **argv)
|
|||||||
exec = arg + 7;
|
exec = arg + 7;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!strcmp("--keep", arg))
|
|
||||||
continue;
|
|
||||||
usage(clone_pack_usage);
|
usage(clone_pack_usage);
|
||||||
}
|
}
|
||||||
dest = arg;
|
dest = arg;
|
||||||
|
@ -1,62 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
#
|
|
||||||
# If you installed git by hand previously, you may find this
|
|
||||||
# script useful to remove the symbolic links that we shipped
|
|
||||||
# for backward compatibility.
|
|
||||||
#
|
|
||||||
# Running this script with the previous installation directory
|
|
||||||
# like this:
|
|
||||||
#
|
|
||||||
# $ cmd-rename.sh /usr/local/bin/
|
|
||||||
#
|
|
||||||
# would clean them.
|
|
||||||
|
|
||||||
d="$1"
|
|
||||||
test -d "$d" || exit
|
|
||||||
while read old new
|
|
||||||
do
|
|
||||||
rm -f "$d/$old"
|
|
||||||
done <<\EOF
|
|
||||||
git-add-script git-add
|
|
||||||
git-archimport-script git-archimport
|
|
||||||
git-bisect-script git-bisect
|
|
||||||
git-branch-script git-branch
|
|
||||||
git-checkout-script git-checkout
|
|
||||||
git-cherry-pick-script git-cherry-pick
|
|
||||||
git-clone-script git-clone
|
|
||||||
git-commit-script git-commit
|
|
||||||
git-count-objects-script git-count-objects
|
|
||||||
git-cvsimport-script git-cvsimport
|
|
||||||
git-diff-script git-diff
|
|
||||||
git-send-email-script git-send-email
|
|
||||||
git-fetch-script git-fetch
|
|
||||||
git-format-patch-script git-format-patch
|
|
||||||
git-log-script git-log
|
|
||||||
git-ls-remote-script git-ls-remote
|
|
||||||
git-merge-one-file-script git-merge-one-file
|
|
||||||
git-octopus-script git-octopus
|
|
||||||
git-parse-remote-script git-parse-remote
|
|
||||||
git-prune-script git-prune
|
|
||||||
git-pull-script git-pull
|
|
||||||
git-push-script git-push
|
|
||||||
git-rebase-script git-rebase
|
|
||||||
git-relink-script git-relink
|
|
||||||
git-rename-script git-rename
|
|
||||||
git-repack-script git-repack
|
|
||||||
git-request-pull-script git-request-pull
|
|
||||||
git-reset-script git-reset
|
|
||||||
git-resolve-script git-resolve
|
|
||||||
git-revert-script git-revert
|
|
||||||
git-sh-setup-script git-sh-setup
|
|
||||||
git-status-script git-status
|
|
||||||
git-tag-script git-tag
|
|
||||||
git-verify-tag-script git-verify-tag
|
|
||||||
git-http-pull git-http-fetch
|
|
||||||
git-local-pull git-local-fetch
|
|
||||||
git-checkout-cache git-checkout-index
|
|
||||||
git-diff-cache git-diff-index
|
|
||||||
git-merge-cache git-merge-index
|
|
||||||
git-update-cache git-update-index
|
|
||||||
git-convert-cache git-convert-objects
|
|
||||||
git-fsck-cache git-fsck-objects
|
|
||||||
EOF
|
|
@ -2,7 +2,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include "../cache.h"
|
#include "../git-compat-util.h"
|
||||||
|
|
||||||
void *gitfakemmap(void *start, size_t length, int prot , int flags, int fd, off_t offset)
|
void *gitfakemmap(void *start, size_t length, int prot , int flags, int fd, off_t offset)
|
||||||
{
|
{
|
||||||
|
@ -16,7 +16,7 @@ int gitsetenv(const char *name, const char *value, int replace)
|
|||||||
|
|
||||||
namelen = strlen(name);
|
namelen = strlen(name);
|
||||||
valuelen = strlen(value);
|
valuelen = strlen(value);
|
||||||
envstr = malloc((namelen + valuelen + 2) * sizeof(char));
|
envstr = malloc((namelen + valuelen + 2));
|
||||||
if (!envstr) return -1;
|
if (!envstr) return -1;
|
||||||
|
|
||||||
memcpy(envstr, name, namelen);
|
memcpy(envstr, name, namelen);
|
||||||
@ -25,7 +25,11 @@ int gitsetenv(const char *name, const char *value, int replace)
|
|||||||
envstr[namelen + valuelen + 1] = 0;
|
envstr[namelen + valuelen + 1] = 0;
|
||||||
|
|
||||||
out = putenv(envstr);
|
out = putenv(envstr);
|
||||||
|
/* putenv(3) makes the argument string part of the environment,
|
||||||
|
* and changing that string modifies the environment --- which
|
||||||
|
* means we do not own that storage anymore. Do not free
|
||||||
|
* envstr.
|
||||||
|
*/
|
||||||
|
|
||||||
free(envstr);
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#include <string.h>
|
#include "../git-compat-util.h"
|
||||||
#include <ctype.h>
|
|
||||||
|
|
||||||
char *gitstrcasestr(const char *haystack, const char *needle)
|
char *gitstrcasestr(const char *haystack, const char *needle)
|
||||||
{
|
{
|
||||||
|
8
config.c
8
config.c
@ -458,12 +458,6 @@ int git_config_set_multivar(const char* key, const char* value,
|
|||||||
* If .git/config does not exist yet, write a minimal version.
|
* If .git/config does not exist yet, write a minimal version.
|
||||||
*/
|
*/
|
||||||
if (stat(config_filename, &st)) {
|
if (stat(config_filename, &st)) {
|
||||||
static const char contents[] =
|
|
||||||
"#\n"
|
|
||||||
"# This is the config file\n"
|
|
||||||
"#\n"
|
|
||||||
"\n";
|
|
||||||
|
|
||||||
free(store.key);
|
free(store.key);
|
||||||
|
|
||||||
/* if nothing to unset, error out */
|
/* if nothing to unset, error out */
|
||||||
@ -474,8 +468,6 @@ int git_config_set_multivar(const char* key, const char* value,
|
|||||||
}
|
}
|
||||||
|
|
||||||
store.key = (char*)key;
|
store.key = (char*)key;
|
||||||
|
|
||||||
write(fd, contents, sizeof(contents)-1);
|
|
||||||
store_write_section(fd, key);
|
store_write_section(fd, key);
|
||||||
store_write_pair(fd, key, value);
|
store_write_pair(fd, key, value);
|
||||||
} else{
|
} else{
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#define _XOPEN_SOURCE /* glibc2 needs this */
|
#define _XOPEN_SOURCE 500 /* glibc2 and AIX 5.3L need this */
|
||||||
|
#define _XOPEN_SOURCE_EXTENDED 1 /* AIX 5.3L needs this */
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
|
|
||||||
|
19
copy.c
19
copy.c
@ -6,32 +6,27 @@ int copy_fd(int ifd, int ofd)
|
|||||||
int len;
|
int len;
|
||||||
char buffer[8192];
|
char buffer[8192];
|
||||||
char *buf = buffer;
|
char *buf = buffer;
|
||||||
len = read(ifd, buffer, sizeof(buffer));
|
len = xread(ifd, buffer, sizeof(buffer));
|
||||||
if (!len)
|
if (!len)
|
||||||
break;
|
break;
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
int read_error;
|
int read_error;
|
||||||
if (errno == EAGAIN)
|
|
||||||
continue;
|
|
||||||
read_error = errno;
|
read_error = errno;
|
||||||
close(ifd);
|
close(ifd);
|
||||||
return error("copy-fd: read returned %s",
|
return error("copy-fd: read returned %s",
|
||||||
strerror(read_error));
|
strerror(read_error));
|
||||||
}
|
}
|
||||||
while (1) {
|
while (len) {
|
||||||
int written = write(ofd, buf, len);
|
int written = xwrite(ofd, buf, len);
|
||||||
if (written > 0) {
|
if (written > 0) {
|
||||||
buf += written;
|
buf += written;
|
||||||
len -= written;
|
len -= written;
|
||||||
if (!len)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
if (!written)
|
else if (!written)
|
||||||
return error("copy-fd: write returned 0");
|
return error("copy-fd: write returned 0");
|
||||||
if (errno == EAGAIN || errno == EINTR)
|
else
|
||||||
continue;
|
return error("copy-fd: write returned %s",
|
||||||
return error("copy-fd: write returned %s",
|
strerror(errno));
|
||||||
strerror(errno));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
close(ifd);
|
close(ifd);
|
||||||
|
@ -15,7 +15,7 @@ static int sha1flush(struct sha1file *f, unsigned int count)
|
|||||||
void *buf = f->buffer;
|
void *buf = f->buffer;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int ret = write(f->fd, buf, count);
|
int ret = xwrite(f->fd, buf, count);
|
||||||
if (ret > 0) {
|
if (ret > 0) {
|
||||||
buf += ret;
|
buf += ret;
|
||||||
count -= ret;
|
count -= ret;
|
||||||
@ -25,8 +25,6 @@ static int sha1flush(struct sha1file *f, unsigned int count)
|
|||||||
}
|
}
|
||||||
if (!ret)
|
if (!ret)
|
||||||
die("sha1 file '%s' write error. Out of diskspace", f->name);
|
die("sha1 file '%s' write error. Out of diskspace", f->name);
|
||||||
if (errno == EAGAIN || errno == EINTR)
|
|
||||||
continue;
|
|
||||||
die("sha1 file '%s' write error (%s)", f->name, strerror(errno));
|
die("sha1 file '%s' write error (%s)", f->name, strerror(errno));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
18
debian/changelog
vendored
18
debian/changelog
vendored
@ -1,3 +1,21 @@
|
|||||||
|
git-core (1.0.0-0) unstable; urgency=low
|
||||||
|
|
||||||
|
* GIT 1.0.0
|
||||||
|
|
||||||
|
-- Junio C Hamano <junkio@cox.net> Wed, 21 Dec 2005 00:01:00 -0800
|
||||||
|
|
||||||
|
git-core (0.99.9n-0) unstable; urgency=low
|
||||||
|
|
||||||
|
* GIT 0.99.9n aka 1.0rc6
|
||||||
|
|
||||||
|
-- Junio C Hamano <junkio@cox.net> Wed, 14 Dec 2005 17:27:08 -0800
|
||||||
|
|
||||||
|
git-core (0.99.9m-0) unstable; urgency=low
|
||||||
|
|
||||||
|
* GIT 0.99.9m aka 1.0rc5
|
||||||
|
|
||||||
|
-- Junio C Hamano <junkio@cox.net> Sun, 11 Dec 2005 16:48:06 -0800
|
||||||
|
|
||||||
git-core (0.99.9l-0) unstable; urgency=low
|
git-core (0.99.9l-0) unstable; urgency=low
|
||||||
|
|
||||||
* GIT 0.99.9l aka 1.0rc4
|
* GIT 0.99.9l aka 1.0rc4
|
||||||
|
34
diff-delta.c
34
diff-delta.c
@ -84,20 +84,15 @@ typedef struct s_chanode {
|
|||||||
} chanode_t;
|
} chanode_t;
|
||||||
|
|
||||||
typedef struct s_chastore {
|
typedef struct s_chastore {
|
||||||
chanode_t *head, *tail;
|
|
||||||
int isize, nsize;
|
int isize, nsize;
|
||||||
chanode_t *ancur;
|
chanode_t *ancur;
|
||||||
chanode_t *sncur;
|
|
||||||
int scurr;
|
|
||||||
} chastore_t;
|
} chastore_t;
|
||||||
|
|
||||||
static void cha_init(chastore_t *cha, int isize, int icount)
|
static void cha_init(chastore_t *cha, int isize, int icount)
|
||||||
{
|
{
|
||||||
cha->head = cha->tail = NULL;
|
|
||||||
cha->isize = isize;
|
cha->isize = isize;
|
||||||
cha->nsize = icount * isize;
|
cha->nsize = icount * isize;
|
||||||
cha->ancur = cha->sncur = NULL;
|
cha->ancur = NULL;
|
||||||
cha->scurr = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *cha_alloc(chastore_t *cha)
|
static void *cha_alloc(chastore_t *cha)
|
||||||
@ -111,12 +106,7 @@ static void *cha_alloc(chastore_t *cha)
|
|||||||
if (!ancur)
|
if (!ancur)
|
||||||
return NULL;
|
return NULL;
|
||||||
ancur->icurr = 0;
|
ancur->icurr = 0;
|
||||||
ancur->next = NULL;
|
ancur->next = cha->ancur;
|
||||||
if (cha->tail)
|
|
||||||
cha->tail->next = ancur;
|
|
||||||
if (!cha->head)
|
|
||||||
cha->head = ancur;
|
|
||||||
cha->tail = ancur;
|
|
||||||
cha->ancur = ancur;
|
cha->ancur = ancur;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,7 +117,7 @@ static void *cha_alloc(chastore_t *cha)
|
|||||||
|
|
||||||
static void cha_free(chastore_t *cha)
|
static void cha_free(chastore_t *cha)
|
||||||
{
|
{
|
||||||
chanode_t *cur = cha->head;
|
chanode_t *cur = cha->ancur;
|
||||||
while (cur) {
|
while (cur) {
|
||||||
chanode_t *tmp = cur;
|
chanode_t *tmp = cur;
|
||||||
cur = cur->next;
|
cur = cur->next;
|
||||||
@ -142,7 +132,6 @@ typedef struct s_bdrecord {
|
|||||||
} bdrecord_t;
|
} bdrecord_t;
|
||||||
|
|
||||||
typedef struct s_bdfile {
|
typedef struct s_bdfile {
|
||||||
const unsigned char *data, *top;
|
|
||||||
chastore_t cha;
|
chastore_t cha;
|
||||||
unsigned int fphbits;
|
unsigned int fphbits;
|
||||||
bdrecord_t **fphash;
|
bdrecord_t **fphash;
|
||||||
@ -152,7 +141,7 @@ static int delta_prepare(const unsigned char *buf, int bufsize, bdfile_t *bdf)
|
|||||||
{
|
{
|
||||||
unsigned int fphbits;
|
unsigned int fphbits;
|
||||||
int i, hsize;
|
int i, hsize;
|
||||||
const unsigned char *base, *data, *top;
|
const unsigned char *data, *top;
|
||||||
bdrecord_t *brec;
|
bdrecord_t *brec;
|
||||||
bdrecord_t **fphash;
|
bdrecord_t **fphash;
|
||||||
|
|
||||||
@ -165,13 +154,12 @@ static int delta_prepare(const unsigned char *buf, int bufsize, bdfile_t *bdf)
|
|||||||
fphash[i] = NULL;
|
fphash[i] = NULL;
|
||||||
cha_init(&bdf->cha, sizeof(bdrecord_t), hsize / 4 + 1);
|
cha_init(&bdf->cha, sizeof(bdrecord_t), hsize / 4 + 1);
|
||||||
|
|
||||||
bdf->data = data = base = buf;
|
top = buf + bufsize;
|
||||||
bdf->top = top = buf + bufsize;
|
data = buf + (bufsize / BLK_SIZE) * BLK_SIZE;
|
||||||
data += (bufsize / BLK_SIZE) * BLK_SIZE;
|
|
||||||
if (data == top)
|
if (data == top)
|
||||||
data -= BLK_SIZE;
|
data -= BLK_SIZE;
|
||||||
|
|
||||||
for ( ; data >= base; data -= BLK_SIZE) {
|
for ( ; data >= buf; data -= BLK_SIZE) {
|
||||||
brec = cha_alloc(&bdf->cha);
|
brec = cha_alloc(&bdf->cha);
|
||||||
if (!brec) {
|
if (!brec) {
|
||||||
cha_free(&bdf->cha);
|
cha_free(&bdf->cha);
|
||||||
@ -208,7 +196,7 @@ void *diff_delta(void *from_buf, unsigned long from_size,
|
|||||||
{
|
{
|
||||||
int i, outpos, outsize, inscnt, csize, msize, moff;
|
int i, outpos, outsize, inscnt, csize, msize, moff;
|
||||||
unsigned int fp;
|
unsigned int fp;
|
||||||
const unsigned char *data, *top, *ptr1, *ptr2;
|
const unsigned char *ref_data, *ref_top, *data, *top, *ptr1, *ptr2;
|
||||||
unsigned char *out, *orig;
|
unsigned char *out, *orig;
|
||||||
bdrecord_t *brec;
|
bdrecord_t *brec;
|
||||||
bdfile_t bdf;
|
bdfile_t bdf;
|
||||||
@ -224,6 +212,8 @@ void *diff_delta(void *from_buf, unsigned long from_size,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ref_data = from_buf;
|
||||||
|
ref_top = from_buf + from_size;
|
||||||
data = to_buf;
|
data = to_buf;
|
||||||
top = to_buf + to_size;
|
top = to_buf + to_size;
|
||||||
|
|
||||||
@ -253,7 +243,7 @@ void *diff_delta(void *from_buf, unsigned long from_size,
|
|||||||
i = HASH(fp, bdf.fphbits);
|
i = HASH(fp, bdf.fphbits);
|
||||||
for (brec = bdf.fphash[i]; brec; brec = brec->next) {
|
for (brec = bdf.fphash[i]; brec; brec = brec->next) {
|
||||||
if (brec->fp == fp) {
|
if (brec->fp == fp) {
|
||||||
csize = bdf.top - brec->ptr;
|
csize = ref_top - brec->ptr;
|
||||||
if (csize > top - data)
|
if (csize > top - data)
|
||||||
csize = top - data;
|
csize = top - data;
|
||||||
for (ptr1 = brec->ptr, ptr2 = data;
|
for (ptr1 = brec->ptr, ptr2 = data;
|
||||||
@ -262,7 +252,7 @@ void *diff_delta(void *from_buf, unsigned long from_size,
|
|||||||
|
|
||||||
csize = ptr1 - brec->ptr;
|
csize = ptr1 - brec->ptr;
|
||||||
if (csize > msize) {
|
if (csize > msize) {
|
||||||
moff = brec->ptr - bdf.data;
|
moff = brec->ptr - ref_data;
|
||||||
msize = csize;
|
msize = csize;
|
||||||
if (msize >= 0x10000) {
|
if (msize >= 0x10000) {
|
||||||
msize = 0x10000;
|
msize = 0x10000;
|
||||||
|
40
diff-tree.c
40
diff-tree.c
@ -14,11 +14,6 @@ static enum cmit_fmt commit_format = CMIT_FMT_RAW;
|
|||||||
|
|
||||||
static struct diff_options diff_options;
|
static struct diff_options diff_options;
|
||||||
|
|
||||||
static void call_diff_setup_done(void)
|
|
||||||
{
|
|
||||||
diff_setup_done(&diff_options);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int call_diff_flush(void)
|
static int call_diff_flush(void)
|
||||||
{
|
{
|
||||||
diffcore_std(&diff_options);
|
diffcore_std(&diff_options);
|
||||||
@ -43,7 +38,6 @@ static int diff_tree_sha1_top(const unsigned char *old,
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
call_diff_setup_done();
|
|
||||||
ret = diff_tree_sha1(old, new, base, &diff_options);
|
ret = diff_tree_sha1(old, new, base, &diff_options);
|
||||||
call_diff_flush();
|
call_diff_flush();
|
||||||
return ret;
|
return ret;
|
||||||
@ -55,7 +49,6 @@ static int diff_root_tree(const unsigned char *new, const char *base)
|
|||||||
void *tree;
|
void *tree;
|
||||||
struct tree_desc empty, real;
|
struct tree_desc empty, real;
|
||||||
|
|
||||||
call_diff_setup_done();
|
|
||||||
tree = read_object_with_reference(new, "tree", &real.size, NULL);
|
tree = read_object_with_reference(new, "tree", &real.size, NULL);
|
||||||
if (!tree)
|
if (!tree)
|
||||||
die("unable to read root tree (%s)", sha1_to_hex(new));
|
die("unable to read root tree (%s)", sha1_to_hex(new));
|
||||||
@ -69,18 +62,29 @@ static int diff_root_tree(const unsigned char *new, const char *base)
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *generate_header(const char *commit, const char *parent, const char *msg)
|
static const char *generate_header(const unsigned char *commit_sha1,
|
||||||
|
const unsigned char *parent_sha1,
|
||||||
|
const char *msg)
|
||||||
{
|
{
|
||||||
static char this_header[16384];
|
static char this_header[16384];
|
||||||
int offset;
|
int offset;
|
||||||
unsigned long len;
|
unsigned long len;
|
||||||
|
int abbrev = diff_options.abbrev;
|
||||||
|
|
||||||
if (!verbose_header)
|
if (!verbose_header)
|
||||||
return commit;
|
return sha1_to_hex(commit_sha1);
|
||||||
|
|
||||||
len = strlen(msg);
|
len = strlen(msg);
|
||||||
offset = sprintf(this_header, "%s%s (from %s)\n", header_prefix, commit, parent);
|
|
||||||
offset += pretty_print_commit(commit_format, msg, len, this_header + offset, sizeof(this_header) - offset);
|
offset = sprintf(this_header, "%s%s ",
|
||||||
|
header_prefix,
|
||||||
|
diff_unique_abbrev(commit_sha1, abbrev));
|
||||||
|
offset += sprintf(this_header + offset, "(from %s)\n",
|
||||||
|
parent_sha1 ?
|
||||||
|
diff_unique_abbrev(parent_sha1, abbrev) : "root");
|
||||||
|
offset += pretty_print_commit(commit_format, msg, len,
|
||||||
|
this_header + offset,
|
||||||
|
sizeof(this_header) - offset);
|
||||||
return this_header;
|
return this_header;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,18 +103,18 @@ static int diff_tree_commit(const unsigned char *commit_sha1)
|
|||||||
|
|
||||||
/* Root commit? */
|
/* Root commit? */
|
||||||
if (show_root_diff && !commit->parents) {
|
if (show_root_diff && !commit->parents) {
|
||||||
header = generate_header(name, "root", commit->buffer);
|
header = generate_header(sha1, NULL, commit->buffer);
|
||||||
diff_root_tree(commit_sha1, "");
|
diff_root_tree(commit_sha1, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* More than one parent? */
|
/* More than one parent? */
|
||||||
if (ignore_merges && commit->parents && commit->parents->next)
|
if (ignore_merges && commit->parents && commit->parents->next)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for (parents = commit->parents; parents; parents = parents->next) {
|
for (parents = commit->parents; parents; parents = parents->next) {
|
||||||
struct commit *parent = parents->item;
|
struct commit *parent = parents->item;
|
||||||
header = generate_header(name,
|
header = generate_header(sha1,
|
||||||
sha1_to_hex(parent->object.sha1),
|
parent->object.sha1,
|
||||||
commit->buffer);
|
commit->buffer);
|
||||||
diff_tree_sha1_top(parent->object.sha1, commit_sha1, "");
|
diff_tree_sha1_top(parent->object.sha1, commit_sha1, "");
|
||||||
if (!header && verbose_header) {
|
if (!header && verbose_header) {
|
||||||
@ -129,6 +133,7 @@ static int diff_tree_stdin(char *line)
|
|||||||
int len = strlen(line);
|
int len = strlen(line);
|
||||||
unsigned char commit[20], parent[20];
|
unsigned char commit[20], parent[20];
|
||||||
static char this_header[1000];
|
static char this_header[1000];
|
||||||
|
int abbrev = diff_options.abbrev;
|
||||||
|
|
||||||
if (!len || line[len-1] != '\n')
|
if (!len || line[len-1] != '\n')
|
||||||
return -1;
|
return -1;
|
||||||
@ -138,7 +143,9 @@ static int diff_tree_stdin(char *line)
|
|||||||
if (isspace(line[40]) && !get_sha1_hex(line+41, parent)) {
|
if (isspace(line[40]) && !get_sha1_hex(line+41, parent)) {
|
||||||
line[40] = 0;
|
line[40] = 0;
|
||||||
line[81] = 0;
|
line[81] = 0;
|
||||||
sprintf(this_header, "%s (from %s)\n", line, line+41);
|
sprintf(this_header, "%s (from %s)\n",
|
||||||
|
diff_unique_abbrev(commit, abbrev),
|
||||||
|
diff_unique_abbrev(parent, abbrev));
|
||||||
header = this_header;
|
header = this_header;
|
||||||
return diff_tree_sha1_top(parent, commit, "");
|
return diff_tree_sha1_top(parent, commit, "");
|
||||||
}
|
}
|
||||||
@ -239,6 +246,7 @@ int main(int argc, const char **argv)
|
|||||||
diff_options.recursive = 1;
|
diff_options.recursive = 1;
|
||||||
|
|
||||||
diff_tree_setup_paths(get_pathspec(prefix, argv));
|
diff_tree_setup_paths(get_pathspec(prefix, argv));
|
||||||
|
diff_setup_done(&diff_options);
|
||||||
|
|
||||||
switch (nr_sha1) {
|
switch (nr_sha1) {
|
||||||
case 0:
|
case 0:
|
||||||
|
57
diff.c
57
diff.c
@ -723,11 +723,13 @@ static void run_diff(struct diff_filepair *p, struct diff_options *o)
|
|||||||
|
|
||||||
if (memcmp(one->sha1, two->sha1, 20)) {
|
if (memcmp(one->sha1, two->sha1, 20)) {
|
||||||
char one_sha1[41];
|
char one_sha1[41];
|
||||||
const char *index_fmt = o->full_index ? "index %s..%s" : "index %.7s..%.7s";
|
int abbrev = o->full_index ? 40 : DIFF_DEFAULT_INDEX_ABBREV;
|
||||||
memcpy(one_sha1, sha1_to_hex(one->sha1), 41);
|
memcpy(one_sha1, sha1_to_hex(one->sha1), 41);
|
||||||
|
|
||||||
len += snprintf(msg + len, sizeof(msg) - len,
|
len += snprintf(msg + len, sizeof(msg) - len,
|
||||||
index_fmt, one_sha1, sha1_to_hex(two->sha1));
|
"index %.*s..%.*s",
|
||||||
|
abbrev, one_sha1, abbrev,
|
||||||
|
sha1_to_hex(two->sha1));
|
||||||
if (one->mode == two->mode)
|
if (one->mode == two->mode)
|
||||||
len += snprintf(msg + len, sizeof(msg) - len,
|
len += snprintf(msg + len, sizeof(msg) - len,
|
||||||
" %06o", one->mode);
|
" %06o", one->mode);
|
||||||
@ -791,6 +793,8 @@ int diff_setup_done(struct diff_options *options)
|
|||||||
}
|
}
|
||||||
if (options->setup & DIFF_SETUP_USE_SIZE_CACHE)
|
if (options->setup & DIFF_SETUP_USE_SIZE_CACHE)
|
||||||
use_size_cache = 1;
|
use_size_cache = 1;
|
||||||
|
if (options->abbrev <= 0 || 40 < options->abbrev)
|
||||||
|
options->abbrev = 40; /* full */
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -841,6 +845,10 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
|
|||||||
}
|
}
|
||||||
else if (!strcmp(arg, "--find-copies-harder"))
|
else if (!strcmp(arg, "--find-copies-harder"))
|
||||||
options->find_copies_harder = 1;
|
options->find_copies_harder = 1;
|
||||||
|
else if (!strcmp(arg, "--abbrev"))
|
||||||
|
options->abbrev = DIFF_DEFAULT_ABBREV;
|
||||||
|
else if (!strncmp(arg, "--abbrev=", 9))
|
||||||
|
options->abbrev = strtoul(arg + 9, NULL, 10);
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
return 1;
|
return 1;
|
||||||
@ -947,14 +955,49 @@ void diff_free_filepair(struct diff_filepair *p)
|
|||||||
free(p);
|
free(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This is different from find_unique_abbrev() in that
|
||||||
|
* it needs to deal with 0{40} SHA1.
|
||||||
|
*/
|
||||||
|
const char *diff_unique_abbrev(const unsigned char *sha1, int len)
|
||||||
|
{
|
||||||
|
int abblen;
|
||||||
|
const char *abbrev;
|
||||||
|
if (len == 40)
|
||||||
|
return sha1_to_hex(sha1);
|
||||||
|
|
||||||
|
abbrev = find_unique_abbrev(sha1, len);
|
||||||
|
if (!abbrev) {
|
||||||
|
if (!memcmp(sha1, null_sha1, 20)) {
|
||||||
|
char *buf = sha1_to_hex(null_sha1);
|
||||||
|
if (len < 37)
|
||||||
|
strcpy(buf + len, "...");
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return sha1_to_hex(sha1);
|
||||||
|
}
|
||||||
|
abblen = strlen(abbrev);
|
||||||
|
if (abblen < 37) {
|
||||||
|
static char hex[41];
|
||||||
|
if (len < abblen && abblen <= len + 2)
|
||||||
|
sprintf(hex, "%s%.*s", abbrev, len+3-abblen, "..");
|
||||||
|
else
|
||||||
|
sprintf(hex, "%s...", abbrev);
|
||||||
|
return hex;
|
||||||
|
}
|
||||||
|
return sha1_to_hex(sha1);
|
||||||
|
}
|
||||||
|
|
||||||
static void diff_flush_raw(struct diff_filepair *p,
|
static void diff_flush_raw(struct diff_filepair *p,
|
||||||
int line_termination,
|
int line_termination,
|
||||||
int inter_name_termination,
|
int inter_name_termination,
|
||||||
int output_format)
|
struct diff_options *options)
|
||||||
{
|
{
|
||||||
int two_paths;
|
int two_paths;
|
||||||
char status[10];
|
char status[10];
|
||||||
|
int abbrev = options->abbrev;
|
||||||
const char *path_one, *path_two;
|
const char *path_one, *path_two;
|
||||||
|
int output_format = options->output_format;
|
||||||
|
|
||||||
path_one = p->one->path;
|
path_one = p->one->path;
|
||||||
path_two = p->two->path;
|
path_two = p->two->path;
|
||||||
@ -985,8 +1028,10 @@ static void diff_flush_raw(struct diff_filepair *p,
|
|||||||
}
|
}
|
||||||
if (output_format != DIFF_FORMAT_NAME_STATUS) {
|
if (output_format != DIFF_FORMAT_NAME_STATUS) {
|
||||||
printf(":%06o %06o %s ",
|
printf(":%06o %06o %s ",
|
||||||
p->one->mode, p->two->mode, sha1_to_hex(p->one->sha1));
|
p->one->mode, p->two->mode,
|
||||||
printf("%s ", sha1_to_hex(p->two->sha1));
|
diff_unique_abbrev(p->one->sha1, abbrev));
|
||||||
|
printf("%s ",
|
||||||
|
diff_unique_abbrev(p->two->sha1, abbrev));
|
||||||
}
|
}
|
||||||
printf("%s%c%s", status, inter_name_termination, path_one);
|
printf("%s%c%s", status, inter_name_termination, path_one);
|
||||||
if (two_paths)
|
if (two_paths)
|
||||||
@ -1194,7 +1239,7 @@ void diff_flush(struct diff_options *options)
|
|||||||
case DIFF_FORMAT_NAME_STATUS:
|
case DIFF_FORMAT_NAME_STATUS:
|
||||||
diff_flush_raw(p, line_termination,
|
diff_flush_raw(p, line_termination,
|
||||||
inter_name_termination,
|
inter_name_termination,
|
||||||
diff_output_format);
|
options);
|
||||||
break;
|
break;
|
||||||
case DIFF_FORMAT_NAME:
|
case DIFF_FORMAT_NAME:
|
||||||
diff_flush_name(p,
|
diff_flush_name(p,
|
||||||
|
9
diff.h
9
diff.h
@ -44,6 +44,7 @@ struct diff_options {
|
|||||||
int reverse_diff;
|
int reverse_diff;
|
||||||
int rename_limit;
|
int rename_limit;
|
||||||
int setup;
|
int setup;
|
||||||
|
int abbrev;
|
||||||
|
|
||||||
change_fn_t change;
|
change_fn_t change;
|
||||||
add_remove_fn_t add_remove;
|
add_remove_fn_t add_remove;
|
||||||
@ -87,6 +88,9 @@ extern int diff_setup_done(struct diff_options *);
|
|||||||
|
|
||||||
#define DIFF_PICKAXE_ALL 1
|
#define DIFF_PICKAXE_ALL 1
|
||||||
|
|
||||||
|
#define DIFF_DEFAULT_INDEX_ABBREV 7 /* hex digits */
|
||||||
|
#define DIFF_DEFAULT_ABBREV 7 /* hex digits */
|
||||||
|
|
||||||
extern void diffcore_std(struct diff_options *);
|
extern void diffcore_std(struct diff_options *);
|
||||||
|
|
||||||
extern void diffcore_std_no_resolve(struct diff_options *);
|
extern void diffcore_std_no_resolve(struct diff_options *);
|
||||||
@ -98,7 +102,8 @@ extern void diffcore_std_no_resolve(struct diff_options *);
|
|||||||
" -u synonym for -p.\n" \
|
" -u synonym for -p.\n" \
|
||||||
" --name-only show only names of changed files.\n" \
|
" --name-only show only names of changed files.\n" \
|
||||||
" --name-status show names and status of changed files.\n" \
|
" --name-status show names and status of changed files.\n" \
|
||||||
" --full-index show full object name on index ines.\n" \
|
" --full-index show full object name on index lines.\n" \
|
||||||
|
" --abbrev=<n> abbreviate object names in diff-tree header and diff-raw.\n" \
|
||||||
" -R swap input file pairs.\n" \
|
" -R swap input file pairs.\n" \
|
||||||
" -B detect complete rewrites.\n" \
|
" -B detect complete rewrites.\n" \
|
||||||
" -M detect renames.\n" \
|
" -M detect renames.\n" \
|
||||||
@ -137,4 +142,6 @@ extern void diff_flush(struct diff_options*);
|
|||||||
#define DIFF_STATUS_FILTER_AON '*'
|
#define DIFF_STATUS_FILTER_AON '*'
|
||||||
#define DIFF_STATUS_FILTER_BROKEN 'B'
|
#define DIFF_STATUS_FILTER_BROKEN 'B'
|
||||||
|
|
||||||
|
extern const char *diff_unique_abbrev(const unsigned char *, int);
|
||||||
|
|
||||||
#endif /* DIFF_H */
|
#endif /* DIFF_H */
|
||||||
|
@ -62,10 +62,14 @@ static int should_break(struct diff_filespec *src,
|
|||||||
return 0; /* error but caught downstream */
|
return 0; /* error but caught downstream */
|
||||||
|
|
||||||
base_size = ((src->size < dst->size) ? src->size : dst->size);
|
base_size = ((src->size < dst->size) ? src->size : dst->size);
|
||||||
|
if (base_size < MINIMUM_BREAK_SIZE)
|
||||||
|
return 0; /* we do not break too small filepair */
|
||||||
|
|
||||||
delta = diff_delta(src->data, src->size,
|
delta = diff_delta(src->data, src->size,
|
||||||
dst->data, dst->size,
|
dst->data, dst->size,
|
||||||
&delta_size, 0);
|
&delta_size, 0);
|
||||||
|
if (!delta)
|
||||||
|
return 0; /* error but caught downstream */
|
||||||
|
|
||||||
/* Estimate the edit size by interpreting delta. */
|
/* Estimate the edit size by interpreting delta. */
|
||||||
if (count_delta(delta, delta_size,
|
if (count_delta(delta, delta_size,
|
||||||
@ -168,8 +172,7 @@ void diffcore_break(int break_score)
|
|||||||
!S_ISDIR(p->one->mode) && !S_ISDIR(p->two->mode) &&
|
!S_ISDIR(p->one->mode) && !S_ISDIR(p->two->mode) &&
|
||||||
!strcmp(p->one->path, p->two->path)) {
|
!strcmp(p->one->path, p->two->path)) {
|
||||||
if (should_break(p->one, p->two,
|
if (should_break(p->one, p->two,
|
||||||
break_score, &score) &&
|
break_score, &score)) {
|
||||||
MINIMUM_BREAK_SIZE <= p->one->size) {
|
|
||||||
/* Split this into delete and create */
|
/* Split this into delete and create */
|
||||||
struct diff_filespec *null_one, *null_two;
|
struct diff_filespec *null_one, *null_two;
|
||||||
struct diff_filepair *dp;
|
struct diff_filepair *dp;
|
||||||
|
172
fetch-clone.c
Normal file
172
fetch-clone.c
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
#include "cache.h"
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
static int finish_pack(const char *pack_tmp_name, const char *me)
|
||||||
|
{
|
||||||
|
int pipe_fd[2];
|
||||||
|
pid_t pid;
|
||||||
|
char idx[PATH_MAX];
|
||||||
|
char final[PATH_MAX];
|
||||||
|
char hash[41];
|
||||||
|
unsigned char sha1[20];
|
||||||
|
char *cp;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
if (pipe(pipe_fd) < 0)
|
||||||
|
die("%s: unable to set up pipe", me);
|
||||||
|
|
||||||
|
strcpy(idx, pack_tmp_name); /* ".git/objects/pack-XXXXXX" */
|
||||||
|
cp = strrchr(idx, '/');
|
||||||
|
memcpy(cp, "/pidx", 5);
|
||||||
|
|
||||||
|
pid = fork();
|
||||||
|
if (pid < 0)
|
||||||
|
die("git-clone-pack: unable to fork off git-index-pack");
|
||||||
|
if (!pid) {
|
||||||
|
close(0);
|
||||||
|
dup2(pipe_fd[1], 1);
|
||||||
|
close(pipe_fd[0]);
|
||||||
|
close(pipe_fd[1]);
|
||||||
|
execlp("git-index-pack","git-index-pack",
|
||||||
|
"-o", idx, pack_tmp_name, NULL);
|
||||||
|
error("cannot exec git-index-pack <%s> <%s>",
|
||||||
|
idx, pack_tmp_name);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
close(pipe_fd[1]);
|
||||||
|
if (read(pipe_fd[0], hash, 40) != 40) {
|
||||||
|
error("%s: unable to read from git-index-pack", me);
|
||||||
|
err = 1;
|
||||||
|
}
|
||||||
|
close(pipe_fd[0]);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
int status, code;
|
||||||
|
int retval = waitpid(pid, &status, 0);
|
||||||
|
|
||||||
|
if (retval < 0) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
error("waitpid failed (%s)", strerror(retval));
|
||||||
|
goto error_die;
|
||||||
|
}
|
||||||
|
if (WIFSIGNALED(status)) {
|
||||||
|
int sig = WTERMSIG(status);
|
||||||
|
error("git-index-pack died of signal %d", sig);
|
||||||
|
goto error_die;
|
||||||
|
}
|
||||||
|
if (!WIFEXITED(status)) {
|
||||||
|
error("git-index-pack died of unnatural causes %d",
|
||||||
|
status);
|
||||||
|
goto error_die;
|
||||||
|
}
|
||||||
|
code = WEXITSTATUS(status);
|
||||||
|
if (code) {
|
||||||
|
error("git-index-pack died with error code %d", code);
|
||||||
|
goto error_die;
|
||||||
|
}
|
||||||
|
if (err)
|
||||||
|
goto error_die;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
hash[40] = 0;
|
||||||
|
if (get_sha1_hex(hash, sha1)) {
|
||||||
|
error("git-index-pack reported nonsense '%s'", hash);
|
||||||
|
goto error_die;
|
||||||
|
}
|
||||||
|
/* Now we have pack in pack_tmp_name[], and
|
||||||
|
* idx in idx[]; rename them to their final names.
|
||||||
|
*/
|
||||||
|
snprintf(final, sizeof(final),
|
||||||
|
"%s/pack/pack-%s.pack", get_object_directory(), hash);
|
||||||
|
move_temp_to_file(pack_tmp_name, final);
|
||||||
|
chmod(final, 0444);
|
||||||
|
snprintf(final, sizeof(final),
|
||||||
|
"%s/pack/pack-%s.idx", get_object_directory(), hash);
|
||||||
|
move_temp_to_file(idx, final);
|
||||||
|
chmod(final, 0444);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error_die:
|
||||||
|
unlink(idx);
|
||||||
|
unlink(pack_tmp_name);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int receive_unpack_pack(int fd[2], const char *me, int quiet)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
|
pid = fork();
|
||||||
|
if (pid < 0)
|
||||||
|
die("%s: unable to fork off git-unpack-objects", me);
|
||||||
|
if (!pid) {
|
||||||
|
dup2(fd[0], 0);
|
||||||
|
close(fd[0]);
|
||||||
|
close(fd[1]);
|
||||||
|
execlp("git-unpack-objects", "git-unpack-objects",
|
||||||
|
quiet ? "-q" : NULL, NULL);
|
||||||
|
die("git-unpack-objects exec failed");
|
||||||
|
}
|
||||||
|
close(fd[0]);
|
||||||
|
close(fd[1]);
|
||||||
|
while (waitpid(pid, &status, 0) < 0) {
|
||||||
|
if (errno != EINTR)
|
||||||
|
die("waiting for git-unpack-objects: %s",
|
||||||
|
strerror(errno));
|
||||||
|
}
|
||||||
|
if (WIFEXITED(status)) {
|
||||||
|
int code = WEXITSTATUS(status);
|
||||||
|
if (code)
|
||||||
|
die("git-unpack-objects died with error code %d",
|
||||||
|
code);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (WIFSIGNALED(status)) {
|
||||||
|
int sig = WTERMSIG(status);
|
||||||
|
die("git-unpack-objects died of signal %d", sig);
|
||||||
|
}
|
||||||
|
die("git-unpack-objects died of unnatural causes %d", status);
|
||||||
|
}
|
||||||
|
|
||||||
|
int receive_keep_pack(int fd[2], const char *me)
|
||||||
|
{
|
||||||
|
char tmpfile[PATH_MAX];
|
||||||
|
int ofd, ifd;
|
||||||
|
|
||||||
|
ifd = fd[0];
|
||||||
|
snprintf(tmpfile, sizeof(tmpfile),
|
||||||
|
"%s/pack/tmp-XXXXXX", get_object_directory());
|
||||||
|
ofd = mkstemp(tmpfile);
|
||||||
|
if (ofd < 0)
|
||||||
|
return error("unable to create temporary file %s", tmpfile);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
char buf[8192];
|
||||||
|
ssize_t sz, wsz, pos;
|
||||||
|
sz = read(ifd, buf, sizeof(buf));
|
||||||
|
if (sz == 0)
|
||||||
|
break;
|
||||||
|
if (sz < 0) {
|
||||||
|
error("error reading pack (%s)", strerror(errno));
|
||||||
|
close(ofd);
|
||||||
|
unlink(tmpfile);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
pos = 0;
|
||||||
|
while (pos < sz) {
|
||||||
|
wsz = write(ofd, buf + pos, sz - pos);
|
||||||
|
if (wsz < 0) {
|
||||||
|
error("error writing pack (%s)",
|
||||||
|
strerror(errno));
|
||||||
|
close(ofd);
|
||||||
|
unlink(tmpfile);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
pos += wsz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(ofd);
|
||||||
|
return finish_pack(tmpfile, me);
|
||||||
|
}
|
60
fetch-pack.c
60
fetch-pack.c
@ -3,13 +3,12 @@
|
|||||||
#include "pkt-line.h"
|
#include "pkt-line.h"
|
||||||
#include "commit.h"
|
#include "commit.h"
|
||||||
#include "tag.h"
|
#include "tag.h"
|
||||||
#include <time.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
|
|
||||||
|
static int keep_pack;
|
||||||
static int quiet;
|
static int quiet;
|
||||||
static int verbose;
|
static int verbose;
|
||||||
static const char fetch_pack_usage[] =
|
static const char fetch_pack_usage[] =
|
||||||
"git-fetch-pack [-q] [-v] [--exec=upload-pack] [host:]directory <refs>...";
|
"git-fetch-pack [-q] [-v] [-k] [--exec=upload-pack] [host:]directory <refs>...";
|
||||||
static const char *exec = "git-upload-pack";
|
static const char *exec = "git-upload-pack";
|
||||||
|
|
||||||
#define COMPLETE (1U << 0)
|
#define COMPLETE (1U << 0)
|
||||||
@ -363,7 +362,6 @@ static int fetch_pack(int fd[2], int nr_match, char **match)
|
|||||||
struct ref *ref;
|
struct ref *ref;
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
int status;
|
int status;
|
||||||
pid_t pid;
|
|
||||||
|
|
||||||
get_remote_heads(fd[0], &ref, 0, NULL, 0);
|
get_remote_heads(fd[0], &ref, 0, NULL, 0);
|
||||||
if (server_supports("multi_ack")) {
|
if (server_supports("multi_ack")) {
|
||||||
@ -381,40 +379,22 @@ static int fetch_pack(int fd[2], int nr_match, char **match)
|
|||||||
}
|
}
|
||||||
if (find_common(fd, sha1, ref) < 0)
|
if (find_common(fd, sha1, ref) < 0)
|
||||||
fprintf(stderr, "warning: no common commits\n");
|
fprintf(stderr, "warning: no common commits\n");
|
||||||
pid = fork();
|
|
||||||
if (pid < 0)
|
if (keep_pack)
|
||||||
die("git-fetch-pack: unable to fork off git-unpack-objects");
|
status = receive_keep_pack(fd, "git-fetch-pack");
|
||||||
if (!pid) {
|
else
|
||||||
dup2(fd[0], 0);
|
status = receive_unpack_pack(fd, "git-fetch-pack", quiet);
|
||||||
close(fd[0]);
|
|
||||||
close(fd[1]);
|
if (status)
|
||||||
execlp("git-unpack-objects", "git-unpack-objects",
|
die("git-fetch-pack: fetch failed.");
|
||||||
quiet ? "-q" : NULL, NULL);
|
|
||||||
die("git-unpack-objects exec failed");
|
all_done:
|
||||||
|
while (ref) {
|
||||||
|
printf("%s %s\n",
|
||||||
|
sha1_to_hex(ref->old_sha1), ref->name);
|
||||||
|
ref = ref->next;
|
||||||
}
|
}
|
||||||
close(fd[0]);
|
return 0;
|
||||||
close(fd[1]);
|
|
||||||
while (waitpid(pid, &status, 0) < 0) {
|
|
||||||
if (errno != EINTR)
|
|
||||||
die("waiting for git-unpack-objects: %s", strerror(errno));
|
|
||||||
}
|
|
||||||
if (WIFEXITED(status)) {
|
|
||||||
int code = WEXITSTATUS(status);
|
|
||||||
if (code)
|
|
||||||
die("git-unpack-objects died with error code %d", code);
|
|
||||||
all_done:
|
|
||||||
while (ref) {
|
|
||||||
printf("%s %s\n",
|
|
||||||
sha1_to_hex(ref->old_sha1), ref->name);
|
|
||||||
ref = ref->next;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (WIFSIGNALED(status)) {
|
|
||||||
int sig = WTERMSIG(status);
|
|
||||||
die("git-unpack-objects died of signal %d", sig);
|
|
||||||
}
|
|
||||||
die("Sherlock Holmes! git-unpack-objects died of unnatural causes %d!", status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
@ -436,10 +416,14 @@ int main(int argc, char **argv)
|
|||||||
exec = arg + 7;
|
exec = arg + 7;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!strcmp("-q", arg)) {
|
if (!strcmp("--quiet", arg) || !strcmp("-q", arg)) {
|
||||||
quiet = 1;
|
quiet = 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (!strcmp("--keep", arg) || !strcmp("-k", arg)) {
|
||||||
|
keep_pack = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (!strcmp("-v", arg)) {
|
if (!strcmp("-v", arg)) {
|
||||||
verbose = 1;
|
verbose = 1;
|
||||||
continue;
|
continue;
|
||||||
|
13
git-add.sh
13
git-add.sh
@ -1,13 +1,8 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
die () {
|
USAGE='[-n] [-v] <file>...'
|
||||||
echo >&2 "$*"
|
SUBDIRECTORY_OK='Yes'
|
||||||
exit 1
|
. git-sh-setup
|
||||||
}
|
|
||||||
|
|
||||||
usage() {
|
|
||||||
die "usage: git add [-n] [-v] <file>..."
|
|
||||||
}
|
|
||||||
|
|
||||||
show_only=
|
show_only=
|
||||||
verbose=
|
verbose=
|
||||||
@ -29,8 +24,6 @@ while : ; do
|
|||||||
shift
|
shift
|
||||||
done
|
done
|
||||||
|
|
||||||
GIT_DIR=$(git-rev-parse --git-dir) || exit
|
|
||||||
|
|
||||||
if test -f "$GIT_DIR/info/exclude"
|
if test -f "$GIT_DIR/info/exclude"
|
||||||
then
|
then
|
||||||
git-ls-files -z \
|
git-ls-files -z \
|
||||||
|
26
git-am.sh
26
git-am.sh
@ -1,14 +1,10 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
. git-sh-setup
|
|
||||||
|
|
||||||
usage () {
|
USAGE='[--signoff] [--dotest=<dir>] [--utf8] [--binary] [--3way] <mbox>
|
||||||
echo >&2 "usage: $0 [--signoff] [--dotest=<dir>] [--utf8] [--binary] [--3way] <mbox>"
|
or, when resuming [--skip | --resolved]'
|
||||||
echo >&2 " or, when resuming"
|
. git-sh-setup
|
||||||
echo >&2 " $0 [--skip | --resolved]"
|
|
||||||
exit 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
stop_here () {
|
stop_here () {
|
||||||
echo "$1" >"$dotest/next"
|
echo "$1" >"$dotest/next"
|
||||||
@ -164,10 +160,7 @@ else
|
|||||||
# Start afresh.
|
# Start afresh.
|
||||||
mkdir -p "$dotest" || exit
|
mkdir -p "$dotest" || exit
|
||||||
|
|
||||||
# cat does the right thing for us, including '-' to mean
|
git-mailsplit -d"$prec" -o"$dotest" -b -- "$@" > "$dotest/last" || {
|
||||||
# standard input.
|
|
||||||
cat "$@" |
|
|
||||||
git-mailsplit -d$prec "$dotest/" >"$dotest/last" || {
|
|
||||||
rm -fr "$dotest"
|
rm -fr "$dotest"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
@ -218,6 +211,7 @@ this=`cat "$dotest/next"`
|
|||||||
if test "$skip" = t
|
if test "$skip" = t
|
||||||
then
|
then
|
||||||
this=`expr "$this" + 1`
|
this=`expr "$this" + 1`
|
||||||
|
resume=
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test "$this" -gt "$last"
|
if test "$this" -gt "$last"
|
||||||
@ -232,6 +226,7 @@ do
|
|||||||
msgnum=`printf "%0${prec}d" $this`
|
msgnum=`printf "%0${prec}d" $this`
|
||||||
next=`expr "$this" + 1`
|
next=`expr "$this" + 1`
|
||||||
test -f "$dotest/$msgnum" || {
|
test -f "$dotest/$msgnum" || {
|
||||||
|
resume=
|
||||||
go_next
|
go_next
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -256,6 +251,13 @@ do
|
|||||||
GIT_AUTHOR_NAME="$(sed -n '/^Author/ s/Author: //p' "$dotest/info")"
|
GIT_AUTHOR_NAME="$(sed -n '/^Author/ s/Author: //p' "$dotest/info")"
|
||||||
GIT_AUTHOR_EMAIL="$(sed -n '/^Email/ s/Email: //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")"
|
GIT_AUTHOR_DATE="$(sed -n '/^Date/ s/Date: //p' "$dotest/info")"
|
||||||
|
|
||||||
|
if test -z "$GIT_AUTHOR_EMAIL"
|
||||||
|
then
|
||||||
|
echo "Patch does not have a valid e-mail address."
|
||||||
|
stop_here $this
|
||||||
|
fi
|
||||||
|
|
||||||
export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE
|
export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE
|
||||||
|
|
||||||
SUBJECT="$(sed -n '/^Subject/ s/Subject: //p' "$dotest/info")"
|
SUBJECT="$(sed -n '/^Subject/ s/Subject: //p' "$dotest/info")"
|
||||||
@ -312,7 +314,7 @@ do
|
|||||||
echo "--------------------------"
|
echo "--------------------------"
|
||||||
cat "$dotest/final-commit"
|
cat "$dotest/final-commit"
|
||||||
echo "--------------------------"
|
echo "--------------------------"
|
||||||
echo -n "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all "
|
printf "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all "
|
||||||
read reply
|
read reply
|
||||||
case "$reply" in
|
case "$reply" in
|
||||||
[yY]*) action=yes ;;
|
[yY]*) action=yes ;;
|
||||||
|
@ -18,13 +18,9 @@
|
|||||||
##
|
##
|
||||||
## git-am is supposed to be the newer and better tool for this job.
|
## git-am is supposed to be the newer and better tool for this job.
|
||||||
|
|
||||||
|
USAGE='[-u] [-k] [-q] [-m] (-c .dotest/<num> | mbox) [signoff]'
|
||||||
. git-sh-setup
|
. git-sh-setup
|
||||||
|
|
||||||
usage () {
|
|
||||||
echo >&2 "applymbox [-u] [-k] [-q] [-m] (-c .dotest/<num> | mbox) [signoff]"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
keep_subject= query_apply= continue= utf8= resume=t
|
keep_subject= query_apply= continue= utf8= resume=t
|
||||||
while case "$#" in 0) break ;; esac
|
while case "$#" in 0) break ;; esac
|
||||||
do
|
do
|
||||||
|
@ -10,8 +10,12 @@
|
|||||||
## $3 - "info" file with Author, email and subject
|
## $3 - "info" file with Author, email and subject
|
||||||
## $4 - optional file containing signoff to add
|
## $4 - optional file containing signoff to add
|
||||||
##
|
##
|
||||||
|
|
||||||
|
USAGE='<msg> <patch> <info> [<signoff>]'
|
||||||
. git-sh-setup
|
. git-sh-setup
|
||||||
|
|
||||||
|
case "$#" in 3|4) ;; *) usage ;; esac
|
||||||
|
|
||||||
final=.dotest/final-commit
|
final=.dotest/final-commit
|
||||||
##
|
##
|
||||||
## If this file exists, we ask before applying
|
## If this file exists, we ask before applying
|
||||||
@ -83,7 +87,7 @@ while [ "$interactive" = yes ]; do
|
|||||||
echo "--------------------------"
|
echo "--------------------------"
|
||||||
cat "$final"
|
cat "$final"
|
||||||
echo "--------------------------"
|
echo "--------------------------"
|
||||||
echo -n "Apply? [y]es/[n]o/[e]dit/[a]ccept all "
|
printf "Apply? [y]es/[n]o/[e]dit/[a]ccept all "
|
||||||
read reply
|
read reply
|
||||||
case "$reply" in
|
case "$reply" in
|
||||||
y|Y) interactive=no;;
|
y|Y) interactive=no;;
|
||||||
|
@ -9,7 +9,8 @@
|
|||||||
|
|
||||||
=head1 Invocation
|
=head1 Invocation
|
||||||
|
|
||||||
git-archimport [ -h ] [ -v ] [ -T ] [ -t tempdir ] <archive>/<branch> [ <archive>/<branch> ]
|
git-archimport [ -h ] [ -v ] [ -o ] [ -a ] [ -f ] [ -T ]
|
||||||
|
[ -D depth] [ -t tempdir ] <archive>/<branch> [ <archive>/<branch> ]
|
||||||
|
|
||||||
Imports a project from one or more Arch repositories. It will follow branches
|
Imports a project from one or more Arch repositories. It will follow branches
|
||||||
and repositories within the namespaces defined by the <archive/branch>
|
and repositories within the namespaces defined by the <archive/branch>
|
||||||
@ -25,6 +26,9 @@ See man (1) git-archimport for more details.
|
|||||||
- audit shell-escaping of filenames
|
- audit shell-escaping of filenames
|
||||||
- hide our private tags somewhere smarter
|
- hide our private tags somewhere smarter
|
||||||
- find a way to make "cat *patches | patch" safe even when patchfiles are missing newlines
|
- find a way to make "cat *patches | patch" safe even when patchfiles are missing newlines
|
||||||
|
- sort and apply patches by graphing ancestry relations instead of just
|
||||||
|
relying in dates supplied in the changeset itself.
|
||||||
|
tla ancestry-graph -m could be helpful here...
|
||||||
|
|
||||||
=head1 Devel tricks
|
=head1 Devel tricks
|
||||||
|
|
||||||
@ -53,15 +57,9 @@ and can contain multiple, unrelated branches.
|
|||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use Getopt::Std;
|
use Getopt::Std;
|
||||||
use File::Spec;
|
use File::Temp qw(tempdir);
|
||||||
use File::Temp qw(tempfile tempdir);
|
use File::Path qw(mkpath rmtree);
|
||||||
use File::Path qw(mkpath);
|
|
||||||
use File::Basename qw(basename dirname);
|
use File::Basename qw(basename dirname);
|
||||||
use String::ShellQuote;
|
|
||||||
use Time::Local;
|
|
||||||
use IO::Socket;
|
|
||||||
use IO::Pipe;
|
|
||||||
use POSIX qw(strftime dup2);
|
|
||||||
use Data::Dumper qw/ Dumper /;
|
use Data::Dumper qw/ Dumper /;
|
||||||
use IPC::Open2;
|
use IPC::Open2;
|
||||||
|
|
||||||
@ -72,124 +70,150 @@ my $git_dir = $ENV{"GIT_DIR"} || ".git";
|
|||||||
$ENV{"GIT_DIR"} = $git_dir;
|
$ENV{"GIT_DIR"} = $git_dir;
|
||||||
my $ptag_dir = "$git_dir/archimport/tags";
|
my $ptag_dir = "$git_dir/archimport/tags";
|
||||||
|
|
||||||
our($opt_h,$opt_v, $opt_T,$opt_t,$opt_o);
|
our($opt_h,$opt_f,$opt_v,$opt_T,$opt_t,$opt_D,$opt_a,$opt_o);
|
||||||
|
|
||||||
sub usage() {
|
sub usage() {
|
||||||
print STDERR <<END;
|
print STDERR <<END;
|
||||||
Usage: ${\basename $0} # fetch/update GIT from Arch
|
Usage: ${\basename $0} # fetch/update GIT from Arch
|
||||||
[ -o ] [ -h ] [ -v ] [ -T ] [ -t tempdir ]
|
[ -h ] [ -v ] [ -o ] [ -a ] [ -f ] [ -T ] [ -D depth ] [ -t tempdir ]
|
||||||
repository/arch-branch [ repository/arch-branch] ...
|
repository/arch-branch [ repository/arch-branch] ...
|
||||||
END
|
END
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
getopts("Thvt:") or usage();
|
getopts("fThvat:D:") or usage();
|
||||||
usage if $opt_h;
|
usage if $opt_h;
|
||||||
|
|
||||||
@ARGV >= 1 or usage();
|
@ARGV >= 1 or usage();
|
||||||
my @arch_roots = @ARGV;
|
# $arch_branches:
|
||||||
|
# values associated with keys:
|
||||||
|
# =1 - Arch version / git 'branch' detected via abrowse on a limit
|
||||||
|
# >1 - Arch version / git 'branch' of an auxilliary branch we've merged
|
||||||
|
my %arch_branches = map { $_ => 1 } @ARGV;
|
||||||
|
|
||||||
my ($tmpdir, $tmpdirname) = tempdir('git-archimport-XXXXXX', TMPDIR => 1, CLEANUP => 1);
|
$ENV{'TMPDIR'} = $opt_t if $opt_t; # $ENV{TMPDIR} will affect tempdir() calls:
|
||||||
my $tmp = $opt_t || 1;
|
my $tmp = tempdir('git-archimport-XXXXXX', TMPDIR => 1, CLEANUP => 1);
|
||||||
$tmp = tempdir('git-archimport-XXXXXX', TMPDIR => 1, CLEANUP => 1);
|
|
||||||
$opt_v && print "+ Using $tmp as temporary directory\n";
|
$opt_v && print "+ Using $tmp as temporary directory\n";
|
||||||
|
|
||||||
|
my %reachable = (); # Arch repositories we can access
|
||||||
|
my %unreachable = (); # Arch repositories we can't access :<
|
||||||
my @psets = (); # the collection
|
my @psets = (); # the collection
|
||||||
my %psets = (); # the collection, by name
|
my %psets = (); # the collection, by name
|
||||||
|
my %stats = ( # Track which strategy we used to import:
|
||||||
|
get_tag => 0, replay => 0, get_new => 0, get_delta => 0,
|
||||||
|
simple_changeset => 0, import_or_tag => 0
|
||||||
|
);
|
||||||
|
|
||||||
my %rptags = (); # my reverse private tags
|
my %rptags = (); # my reverse private tags
|
||||||
# to map a SHA1 to a commitid
|
# to map a SHA1 to a commitid
|
||||||
|
my $TLA = $ENV{'ARCH_CLIENT'} || 'tla';
|
||||||
|
|
||||||
foreach my $root (@arch_roots) {
|
sub do_abrowse {
|
||||||
my ($arepo, $abranch) = split(m!/!, $root);
|
my $stage = shift;
|
||||||
open ABROWSE, "tla abrowse -f -A $arepo --desc --merges $abranch |"
|
while (my ($limit, $level) = each %arch_branches) {
|
||||||
or die "Problems with tla abrowse: $!";
|
next unless $level == $stage;
|
||||||
|
|
||||||
my %ps = (); # the current one
|
|
||||||
my $mode = '';
|
|
||||||
my $lastseen = '';
|
|
||||||
|
|
||||||
while (<ABROWSE>) {
|
|
||||||
chomp;
|
|
||||||
|
|
||||||
# first record padded w 8 spaces
|
open ABROWSE, "$TLA abrowse -fkD --merges $limit |"
|
||||||
if (s/^\s{8}\b//) {
|
or die "Problems with tla abrowse: $!";
|
||||||
|
|
||||||
|
my %ps = (); # the current one
|
||||||
|
my $lastseen = '';
|
||||||
|
|
||||||
|
while (<ABROWSE>) {
|
||||||
|
chomp;
|
||||||
|
|
||||||
# store the record we just captured
|
# first record padded w 8 spaces
|
||||||
if (%ps) {
|
if (s/^\s{8}\b//) {
|
||||||
my %temp = %ps; # break references
|
my ($id, $type) = split(m/\s+/, $_, 2);
|
||||||
push (@psets, \%temp);
|
|
||||||
$psets{$temp{id}} = \%temp;
|
|
||||||
%ps = ();
|
|
||||||
}
|
|
||||||
|
|
||||||
my ($id, $type) = split(m/\s{3}/, $_);
|
|
||||||
$ps{id} = $id;
|
|
||||||
$ps{repo} = $arepo;
|
|
||||||
|
|
||||||
# deal with types
|
my %last_ps;
|
||||||
if ($type =~ m/^\(simple changeset\)/) {
|
# store the record we just captured
|
||||||
$ps{type} = 's';
|
if (%ps && !exists $psets{ $ps{id} }) {
|
||||||
} elsif ($type eq '(initial import)') {
|
%last_ps = %ps; # break references
|
||||||
$ps{type} = 'i';
|
push (@psets, \%last_ps);
|
||||||
} elsif ($type =~ m/^\(tag revision of (.+)\)/) {
|
$psets{ $last_ps{id} } = \%last_ps;
|
||||||
$ps{type} = 't';
|
|
||||||
$ps{tag} = $1;
|
|
||||||
} else {
|
|
||||||
warn "Unknown type $type";
|
|
||||||
}
|
|
||||||
$lastseen = 'id';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s/^\s{10}//) {
|
|
||||||
# 10 leading spaces or more
|
|
||||||
# indicate commit metadata
|
|
||||||
|
|
||||||
# date & author
|
|
||||||
if ($lastseen eq 'id' && m/^\d{4}-\d{2}-\d{2}/) {
|
|
||||||
|
|
||||||
my ($date, $authoremail) = split(m/\s{2,}/, $_);
|
|
||||||
$ps{date} = $date;
|
|
||||||
$ps{date} =~ s/\bGMT$//; # strip off trailign GMT
|
|
||||||
if ($ps{date} =~ m/\b\w+$/) {
|
|
||||||
warn 'Arch dates not in GMT?! - imported dates will be wrong';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$authoremail =~ m/^(.+)\s(\S+)$/;
|
my $branch = extract_versionname($id);
|
||||||
$ps{author} = $1;
|
%ps = ( id => $id, branch => $branch );
|
||||||
$ps{email} = $2;
|
if (%last_ps && ($last_ps{branch} eq $branch)) {
|
||||||
|
$ps{parent_id} = $last_ps{id};
|
||||||
$lastseen = 'date';
|
}
|
||||||
|
|
||||||
} elsif ($lastseen eq 'date') {
|
$arch_branches{$branch} = 1;
|
||||||
# the only hint is position
|
$lastseen = 'id';
|
||||||
# subject is after date
|
|
||||||
$ps{subj} = $_;
|
|
||||||
$lastseen = 'subj';
|
|
||||||
|
|
||||||
} elsif ($lastseen eq 'subj' && $_ eq 'merges in:') {
|
|
||||||
$ps{merges} = [];
|
|
||||||
$lastseen = 'merges';
|
|
||||||
|
|
||||||
} elsif ($lastseen eq 'merges' && s/^\s{2}//) {
|
|
||||||
push (@{$ps{merges}}, $_);
|
|
||||||
} else {
|
|
||||||
warn 'more metadata after merges!?';
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (%ps) {
|
# deal with types (should work with baz or tla):
|
||||||
my %temp = %ps; # break references
|
if ($type =~ m/\(.*changeset\)/) {
|
||||||
push (@psets, \%temp);
|
$ps{type} = 's';
|
||||||
$psets{ $temp{id} } = \%temp;
|
} elsif ($type =~ /\(.*import\)/) {
|
||||||
%ps = ();
|
$ps{type} = 'i';
|
||||||
}
|
} elsif ($type =~ m/\(tag.*?(\S+\@\S+).*?\)/) {
|
||||||
close ABROWSE;
|
$ps{type} = 't';
|
||||||
|
# read which revision we've tagged when we parse the log
|
||||||
|
$ps{tag} = $1;
|
||||||
|
} else {
|
||||||
|
warn "Unknown type $type";
|
||||||
|
}
|
||||||
|
|
||||||
|
$arch_branches{$branch} = 1;
|
||||||
|
$lastseen = 'id';
|
||||||
|
} elsif (s/^\s{10}//) {
|
||||||
|
# 10 leading spaces or more
|
||||||
|
# indicate commit metadata
|
||||||
|
|
||||||
|
# date
|
||||||
|
if ($lastseen eq 'id' && m/^(\d{4}-\d\d-\d\d \d\d:\d\d:\d\d)/){
|
||||||
|
$ps{date} = $1;
|
||||||
|
$lastseen = 'date';
|
||||||
|
} elsif ($_ eq 'merges in:') {
|
||||||
|
$ps{merges} = [];
|
||||||
|
$lastseen = 'merges';
|
||||||
|
} elsif ($lastseen eq 'merges' && s/^\s{2}//) {
|
||||||
|
my $id = $_;
|
||||||
|
push (@{$ps{merges}}, $id);
|
||||||
|
|
||||||
|
# aggressive branch finding:
|
||||||
|
if ($opt_D) {
|
||||||
|
my $branch = extract_versionname($id);
|
||||||
|
my $repo = extract_reponame($branch);
|
||||||
|
|
||||||
|
if (archive_reachable($repo) &&
|
||||||
|
!defined $arch_branches{$branch}) {
|
||||||
|
$arch_branches{$branch} = $stage + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
warn "more metadata after merges!?: $_\n" unless /^\s*$/;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (%ps && !exists $psets{ $ps{id} }) {
|
||||||
|
my %temp = %ps; # break references
|
||||||
|
if (@psets && $psets[$#psets]{branch} eq $ps{branch}) {
|
||||||
|
$temp{parent_id} = $psets[$#psets]{id};
|
||||||
|
}
|
||||||
|
push (@psets, \%temp);
|
||||||
|
$psets{ $temp{id} } = \%temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
close ABROWSE or die "$TLA abrowse failed on $limit\n";
|
||||||
|
}
|
||||||
} # end foreach $root
|
} # end foreach $root
|
||||||
|
|
||||||
|
do_abrowse(1);
|
||||||
|
my $depth = 2;
|
||||||
|
$opt_D ||= 0;
|
||||||
|
while ($depth <= $opt_D) {
|
||||||
|
do_abrowse($depth);
|
||||||
|
$depth++;
|
||||||
|
}
|
||||||
|
|
||||||
## Order patches by time
|
## Order patches by time
|
||||||
|
# FIXME see if we can find a more optimal way to do this by graphing
|
||||||
|
# the ancestry data and walking it, that way we won't have to rely on
|
||||||
|
# client-supplied dates
|
||||||
@psets = sort {$a->{date}.$b->{id} cmp $b->{date}.$b->{id}} @psets;
|
@psets = sort {$a->{date}.$b->{id} cmp $b->{date}.$b->{id}} @psets;
|
||||||
|
|
||||||
#print Dumper \@psets;
|
#print Dumper \@psets;
|
||||||
@ -210,7 +234,7 @@ unless (-d $git_dir) { # initial import
|
|||||||
}
|
}
|
||||||
} else { # progressing an import
|
} else { # progressing an import
|
||||||
# load the rptags
|
# load the rptags
|
||||||
opendir(DIR, "$git_dir/archimport/tags")
|
opendir(DIR, $ptag_dir)
|
||||||
|| die "can't opendir: $!";
|
|| die "can't opendir: $!";
|
||||||
while (my $file = readdir(DIR)) {
|
while (my $file = readdir(DIR)) {
|
||||||
# skip non-interesting-files
|
# skip non-interesting-files
|
||||||
@ -272,29 +296,69 @@ sub old_style_branchname {
|
|||||||
|
|
||||||
*git_branchname = $opt_o ? *old_style_branchname : *tree_dirname;
|
*git_branchname = $opt_o ? *old_style_branchname : *tree_dirname;
|
||||||
|
|
||||||
# process patchsets
|
sub process_patchset_accurate {
|
||||||
foreach my $ps (@psets) {
|
my $ps = shift;
|
||||||
$ps->{branch} = git_branchname($ps->{id});
|
|
||||||
|
# switch to that branch if we're not already in that branch:
|
||||||
|
if (-e "$git_dir/refs/heads/$ps->{branch}") {
|
||||||
|
system('git-checkout','-f',$ps->{branch}) == 0 or die "$! $?\n";
|
||||||
|
|
||||||
#
|
# remove any old stuff that got leftover:
|
||||||
# ensure we have a clean state
|
my $rm = safe_pipe_capture('git-ls-files','--others','-z');
|
||||||
#
|
rmtree(split(/\0/,$rm)) if $rm;
|
||||||
if (`git diff-files`) {
|
|
||||||
die "Unclean tree when about to process $ps->{id} " .
|
|
||||||
" - did we fail to commit cleanly before?";
|
|
||||||
}
|
}
|
||||||
die $! if $?;
|
|
||||||
|
# Apply the import/changeset/merge into the working tree
|
||||||
|
my $dir = sync_to_ps($ps);
|
||||||
|
# read the new log entry:
|
||||||
|
my @commitlog = safe_pipe_capture($TLA,'cat-log','-d',$dir,$ps->{id});
|
||||||
|
die "Error in cat-log: $!" if $?;
|
||||||
|
chomp @commitlog;
|
||||||
|
|
||||||
#
|
# grab variables we want from the log, new fields get added to $ps:
|
||||||
# skip commits already in repo
|
# (author, date, email, summary, message body ...)
|
||||||
#
|
parselog($ps, \@commitlog);
|
||||||
if (ptag($ps->{id})) {
|
|
||||||
$opt_v && print " * Skipping already imported: $ps->{id}\n";
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
|
|
||||||
print " * Starting to work on $ps->{id}\n";
|
if ($ps->{id} =~ /--base-0$/ && $ps->{id} ne $psets[0]{id}) {
|
||||||
|
# this should work when importing continuations
|
||||||
|
if ($ps->{tag} && (my $branchpoint = eval { ptag($ps->{tag}) })) {
|
||||||
|
|
||||||
|
# find where we are supposed to branch from
|
||||||
|
system('git-checkout','-f','-b',$ps->{branch},
|
||||||
|
$branchpoint) == 0 or die "$! $?\n";
|
||||||
|
|
||||||
|
# remove any old stuff that got leftover:
|
||||||
|
my $rm = safe_pipe_capture('git-ls-files','--others','-z');
|
||||||
|
rmtree(split(/\0/,$rm)) if $rm;
|
||||||
|
|
||||||
|
# If we trust Arch with the fact that this is just
|
||||||
|
# a tag, and it does not affect the state of the tree
|
||||||
|
# then we just tag and move on
|
||||||
|
tag($ps->{id}, $branchpoint);
|
||||||
|
ptag($ps->{id}, $branchpoint);
|
||||||
|
print " * Tagged $ps->{id} at $branchpoint\n";
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
warn "Tagging from unknown id unsupported\n" if $ps->{tag};
|
||||||
|
}
|
||||||
|
# allow multiple bases/imports here since Arch supports cherry-picks
|
||||||
|
# from unrelated trees
|
||||||
|
}
|
||||||
|
|
||||||
|
# update the index with all the changes we got
|
||||||
|
system('git-ls-files --others -z | '.
|
||||||
|
'git-update-index --add -z --stdin') == 0 or die "$! $?\n";
|
||||||
|
system('git-ls-files --deleted -z | '.
|
||||||
|
'git-update-index --remove -z --stdin') == 0 or die "$! $?\n";
|
||||||
|
system('git-ls-files -z | '.
|
||||||
|
'git-update-index -z --stdin') == 0 or die "$! $?\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
# the native changeset processing strategy. This is very fast, but
|
||||||
|
# does not handle permissions or any renames involving directories
|
||||||
|
sub process_patchset_fast {
|
||||||
|
my $ps = shift;
|
||||||
#
|
#
|
||||||
# create the branch if needed
|
# create the branch if needed
|
||||||
#
|
#
|
||||||
@ -305,7 +369,7 @@ foreach my $ps (@psets) {
|
|||||||
unless ($import) { # skip for import
|
unless ($import) { # skip for import
|
||||||
if ( -e "$git_dir/refs/heads/$ps->{branch}") {
|
if ( -e "$git_dir/refs/heads/$ps->{branch}") {
|
||||||
# we know about this branch
|
# we know about this branch
|
||||||
`git checkout $ps->{branch}`;
|
system('git-checkout',$ps->{branch});
|
||||||
} else {
|
} else {
|
||||||
# new branch! we need to verify a few things
|
# new branch! we need to verify a few things
|
||||||
die "Branch on a non-tag!" unless $ps->{type} eq 't';
|
die "Branch on a non-tag!" unless $ps->{type} eq 't';
|
||||||
@ -314,7 +378,7 @@ foreach my $ps (@psets) {
|
|||||||
unless $branchpoint;
|
unless $branchpoint;
|
||||||
|
|
||||||
# find where we are supposed to branch from
|
# find where we are supposed to branch from
|
||||||
`git checkout -b $ps->{branch} $branchpoint`;
|
system('git-checkout','-b',$ps->{branch},$branchpoint);
|
||||||
|
|
||||||
# If we trust Arch with the fact that this is just
|
# If we trust Arch with the fact that this is just
|
||||||
# a tag, and it does not affect the state of the tree
|
# a tag, and it does not affect the state of the tree
|
||||||
@ -322,7 +386,7 @@ foreach my $ps (@psets) {
|
|||||||
tag($ps->{id}, $branchpoint);
|
tag($ps->{id}, $branchpoint);
|
||||||
ptag($ps->{id}, $branchpoint);
|
ptag($ps->{id}, $branchpoint);
|
||||||
print " * Tagged $ps->{id} at $branchpoint\n";
|
print " * Tagged $ps->{id} at $branchpoint\n";
|
||||||
next;
|
return 0;
|
||||||
}
|
}
|
||||||
die $! if $?;
|
die $! if $?;
|
||||||
}
|
}
|
||||||
@ -332,96 +396,128 @@ foreach my $ps (@psets) {
|
|||||||
#
|
#
|
||||||
if ($ps->{type} eq 'i' || $ps->{type} eq 't') {
|
if ($ps->{type} eq 'i' || $ps->{type} eq 't') {
|
||||||
apply_import($ps) or die $!;
|
apply_import($ps) or die $!;
|
||||||
|
$stats{import_or_tag}++;
|
||||||
$import=0;
|
$import=0;
|
||||||
} elsif ($ps->{type} eq 's') {
|
} elsif ($ps->{type} eq 's') {
|
||||||
apply_cset($ps);
|
apply_cset($ps);
|
||||||
|
$stats{simple_changeset}++;
|
||||||
}
|
}
|
||||||
|
|
||||||
#
|
#
|
||||||
# prepare update git's index, based on what arch knows
|
# prepare update git's index, based on what arch knows
|
||||||
# about the pset, resolve parents, etc
|
# about the pset, resolve parents, etc
|
||||||
#
|
#
|
||||||
my $tree;
|
|
||||||
|
|
||||||
my $commitlog = `tla cat-archive-log -A $ps->{repo} $ps->{id}`;
|
my @commitlog = safe_pipe_capture($TLA,'cat-archive-log',$ps->{id});
|
||||||
die "Error in cat-archive-log: $!" if $?;
|
die "Error in cat-archive-log: $!" if $?;
|
||||||
|
|
||||||
# parselog will git-add/rm files
|
parselog($ps,\@commitlog);
|
||||||
# and generally prepare things for the commit
|
|
||||||
# NOTE: parselog will shell-quote filenames!
|
|
||||||
my ($sum, $msg, $add, $del, $mod, $ren) = parselog($commitlog);
|
|
||||||
my $logmessage = "$sum\n$msg";
|
|
||||||
|
|
||||||
|
|
||||||
# imports don't give us good info
|
# imports don't give us good info
|
||||||
# on added files. Shame on them
|
# on added files. Shame on them
|
||||||
if ($ps->{type} eq 'i' || $ps->{type} eq 't') {
|
if ($ps->{type} eq 'i' || $ps->{type} eq 't') {
|
||||||
`find . -type f -print0 | grep -zv '^./$git_dir' | xargs -0 -l100 git-update-index --add`;
|
system('git-ls-files --others -z | '.
|
||||||
`git-ls-files --deleted -z | xargs --no-run-if-empty -0 -l100 git-update-index --remove`;
|
'git-update-index --add -z --stdin') == 0 or die "$! $?\n";
|
||||||
|
system('git-ls-files --deleted -z | '.
|
||||||
|
'git-update-index --remove -z --stdin') == 0 or die "$! $?\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (@$add) {
|
# TODO: handle removed_directories and renamed_directories:
|
||||||
|
|
||||||
|
if (my $add = $ps->{new_files}) {
|
||||||
while (@$add) {
|
while (@$add) {
|
||||||
my @slice = splice(@$add, 0, 100);
|
my @slice = splice(@$add, 0, 100);
|
||||||
my $slice = join(' ', @slice);
|
system('git-update-index','--add','--',@slice) == 0 or
|
||||||
`git-update-index --add $slice`;
|
die "Error in git-update-index --add: $! $?\n";
|
||||||
die "Error in git-update-index --add: $!" if $?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (@$del) {
|
|
||||||
foreach my $file (@$del) {
|
if (my $del = $ps->{removed_files}) {
|
||||||
unlink $file or die "Problems deleting $file : $!";
|
unlink @$del;
|
||||||
}
|
|
||||||
while (@$del) {
|
while (@$del) {
|
||||||
my @slice = splice(@$del, 0, 100);
|
my @slice = splice(@$del, 0, 100);
|
||||||
my $slice = join(' ', @slice);
|
system('git-update-index','--remove','--',@slice) == 0 or
|
||||||
`git-update-index --remove $slice`;
|
die "Error in git-update-index --remove: $! $?\n";
|
||||||
die "Error in git-update-index --remove: $!" if $?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (@$ren) { # renamed
|
|
||||||
|
if (my $ren = $ps->{renamed_files}) { # renamed
|
||||||
if (@$ren % 2) {
|
if (@$ren % 2) {
|
||||||
die "Odd number of entries in rename!?";
|
die "Odd number of entries in rename!?";
|
||||||
}
|
}
|
||||||
;
|
|
||||||
while (@$ren) {
|
while (@$ren) {
|
||||||
my $from = pop @$ren;
|
my $from = shift @$ren;
|
||||||
my $to = pop @$ren;
|
my $to = shift @$ren;
|
||||||
|
|
||||||
unless (-d dirname($to)) {
|
unless (-d dirname($to)) {
|
||||||
mkpath(dirname($to)); # will die on err
|
mkpath(dirname($to)); # will die on err
|
||||||
}
|
}
|
||||||
#print "moving $from $to";
|
# print "moving $from $to";
|
||||||
`mv $from $to`;
|
rename($from, $to) or die "Error renaming '$from' '$to': $!\n";
|
||||||
die "Error renaming $from $to : $!" if $?;
|
system('git-update-index','--remove','--',$from) == 0 or
|
||||||
`git-update-index --remove $from`;
|
die "Error in git-update-index --remove: $! $?\n";
|
||||||
die "Error in git-update-index --remove: $!" if $?;
|
system('git-update-index','--add','--',$to) == 0 or
|
||||||
`git-update-index --add $to`;
|
die "Error in git-update-index --add: $! $?\n";
|
||||||
die "Error in git-update-index --add: $!" if $?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (@$mod) { # must be _after_ renames
|
|
||||||
|
if (my $mod = $ps->{modified_files}) {
|
||||||
while (@$mod) {
|
while (@$mod) {
|
||||||
my @slice = splice(@$mod, 0, 100);
|
my @slice = splice(@$mod, 0, 100);
|
||||||
my $slice = join(' ', @slice);
|
system('git-update-index','--',@slice) == 0 or
|
||||||
`git-update-index $slice`;
|
die "Error in git-update-index: $! $?\n";
|
||||||
die "Error in git-update-index: $!" if $?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return 1; # we successfully applied the changeset
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($opt_f) {
|
||||||
|
print "Will import patchsets using the fast strategy\n",
|
||||||
|
"Renamed directories and permission changes will be missed\n";
|
||||||
|
*process_patchset = *process_patchset_fast;
|
||||||
|
} else {
|
||||||
|
print "Using the default (accurate) import strategy.\n",
|
||||||
|
"Things may be a bit slow\n";
|
||||||
|
*process_patchset = *process_patchset_accurate;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach my $ps (@psets) {
|
||||||
|
# process patchsets
|
||||||
|
$ps->{branch} = git_branchname($ps->{id});
|
||||||
|
|
||||||
|
#
|
||||||
|
# ensure we have a clean state
|
||||||
|
#
|
||||||
|
if (my $dirty = `git-diff-files`) {
|
||||||
|
die "Unclean tree when about to process $ps->{id} " .
|
||||||
|
" - did we fail to commit cleanly before?\n$dirty";
|
||||||
|
}
|
||||||
|
die $! if $?;
|
||||||
|
|
||||||
|
#
|
||||||
|
# skip commits already in repo
|
||||||
|
#
|
||||||
|
if (ptag($ps->{id})) {
|
||||||
|
$opt_v && print " * Skipping already imported: $ps->{id}\n";
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
print " * Starting to work on $ps->{id}\n";
|
||||||
|
|
||||||
|
process_patchset($ps) or next;
|
||||||
|
|
||||||
# warn "errors when running git-update-index! $!";
|
# warn "errors when running git-update-index! $!";
|
||||||
$tree = `git-write-tree`;
|
my $tree = `git-write-tree`;
|
||||||
die "cannot write tree $!" if $?;
|
die "cannot write tree $!" if $?;
|
||||||
chomp $tree;
|
chomp $tree;
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Who's your daddy?
|
# Who's your daddy?
|
||||||
#
|
#
|
||||||
my @par;
|
my @par;
|
||||||
if ( -e "$git_dir/refs/heads/$ps->{branch}") {
|
if ( -e "$git_dir/refs/heads/$ps->{branch}") {
|
||||||
if (open HEAD, "<$git_dir/refs/heads/$ps->{branch}") {
|
if (open HEAD, "<","$git_dir/refs/heads/$ps->{branch}") {
|
||||||
my $p = <HEAD>;
|
my $p = <HEAD>;
|
||||||
close HEAD;
|
close HEAD;
|
||||||
chomp $p;
|
chomp $p;
|
||||||
@ -436,7 +532,6 @@ foreach my $ps (@psets) {
|
|||||||
if ($ps->{merges}) {
|
if ($ps->{merges}) {
|
||||||
push @par, find_parents($ps);
|
push @par, find_parents($ps);
|
||||||
}
|
}
|
||||||
my $par = join (' ', @par);
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Commit, tag and clean state
|
# Commit, tag and clean state
|
||||||
@ -449,13 +544,14 @@ foreach my $ps (@psets) {
|
|||||||
$ENV{GIT_COMMITTER_EMAIL} = $ps->{email};
|
$ENV{GIT_COMMITTER_EMAIL} = $ps->{email};
|
||||||
$ENV{GIT_COMMITTER_DATE} = $ps->{date};
|
$ENV{GIT_COMMITTER_DATE} = $ps->{date};
|
||||||
|
|
||||||
my ($pid, $commit_rh, $commit_wh);
|
my $pid = open2(*READER, *WRITER,'git-commit-tree',$tree,@par)
|
||||||
$commit_rh = 'commit_rh';
|
|
||||||
$commit_wh = 'commit_wh';
|
|
||||||
|
|
||||||
$pid = open2(*READER, *WRITER, "git-commit-tree $tree $par")
|
|
||||||
or die $!;
|
or die $!;
|
||||||
print WRITER $logmessage; # write
|
print WRITER $ps->{summary},"\n";
|
||||||
|
print WRITER $ps->{message},"\n";
|
||||||
|
|
||||||
|
# make it easy to backtrack and figure out which Arch revision this was:
|
||||||
|
print WRITER 'git-archimport-id: ',$ps->{id},"\n";
|
||||||
|
|
||||||
close WRITER;
|
close WRITER;
|
||||||
my $commitid = <READER>; # read
|
my $commitid = <READER>; # read
|
||||||
chomp $commitid;
|
chomp $commitid;
|
||||||
@ -468,7 +564,7 @@ foreach my $ps (@psets) {
|
|||||||
#
|
#
|
||||||
# Update the branch
|
# Update the branch
|
||||||
#
|
#
|
||||||
open HEAD, ">$git_dir/refs/heads/$ps->{branch}";
|
open HEAD, ">","$git_dir/refs/heads/$ps->{branch}";
|
||||||
print HEAD $commitid;
|
print HEAD $commitid;
|
||||||
close HEAD;
|
close HEAD;
|
||||||
system('git-update-ref', 'HEAD', "$ps->{branch}");
|
system('git-update-ref', 'HEAD', "$ps->{branch}");
|
||||||
@ -482,21 +578,78 @@ foreach my $ps (@psets) {
|
|||||||
print " + tree $tree\n";
|
print " + tree $tree\n";
|
||||||
print " + commit $commitid\n";
|
print " + commit $commitid\n";
|
||||||
$opt_v && print " + commit date is $ps->{date} \n";
|
$opt_v && print " + commit date is $ps->{date} \n";
|
||||||
$opt_v && print " + parents: $par \n";
|
$opt_v && print " + parents: ",join(' ',@par),"\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($opt_v) {
|
||||||
|
foreach (sort keys %stats) {
|
||||||
|
print" $_: $stats{$_}\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exit 0;
|
||||||
|
|
||||||
|
# used by the accurate strategy:
|
||||||
|
sub sync_to_ps {
|
||||||
|
my $ps = shift;
|
||||||
|
my $tree_dir = $tmp.'/'.tree_dirname($ps->{id});
|
||||||
|
|
||||||
|
$opt_v && print "sync_to_ps($ps->{id}) method: ";
|
||||||
|
|
||||||
|
if (-d $tree_dir) {
|
||||||
|
if ($ps->{type} eq 't') {
|
||||||
|
$opt_v && print "get (tag)\n";
|
||||||
|
# looks like a tag-only or (worse,) a mixed tags/changeset branch,
|
||||||
|
# can't rely on replay to work correctly on these
|
||||||
|
rmtree($tree_dir);
|
||||||
|
safe_pipe_capture($TLA,'get','--no-pristine',$ps->{id},$tree_dir);
|
||||||
|
$stats{get_tag}++;
|
||||||
|
} else {
|
||||||
|
my $tree_id = arch_tree_id($tree_dir);
|
||||||
|
if ($ps->{parent_id} && ($ps->{parent_id} eq $tree_id)) {
|
||||||
|
# the common case (hopefully)
|
||||||
|
$opt_v && print "replay\n";
|
||||||
|
safe_pipe_capture($TLA,'replay','-d',$tree_dir,$ps->{id});
|
||||||
|
$stats{replay}++;
|
||||||
|
} else {
|
||||||
|
# getting one tree is usually faster than getting two trees
|
||||||
|
# and applying the delta ...
|
||||||
|
rmtree($tree_dir);
|
||||||
|
$opt_v && print "apply-delta\n";
|
||||||
|
safe_pipe_capture($TLA,'get','--no-pristine',
|
||||||
|
$ps->{id},$tree_dir);
|
||||||
|
$stats{get_delta}++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
# new branch work
|
||||||
|
$opt_v && print "get (new tree)\n";
|
||||||
|
safe_pipe_capture($TLA,'get','--no-pristine',$ps->{id},$tree_dir);
|
||||||
|
$stats{get_new}++;
|
||||||
|
}
|
||||||
|
|
||||||
|
# added -I flag to rsync since we're going to fast! AIEEEEE!!!!
|
||||||
|
system('rsync','-aI','--delete','--exclude',$git_dir,
|
||||||
|
# '--exclude','.arch-inventory',
|
||||||
|
'--exclude','.arch-ids','--exclude','{arch}',
|
||||||
|
'--exclude','+*','--exclude',',*',
|
||||||
|
"$tree_dir/",'./') == 0 or die "Cannot rsync $tree_dir: $! $?";
|
||||||
|
return $tree_dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub apply_import {
|
sub apply_import {
|
||||||
my $ps = shift;
|
my $ps = shift;
|
||||||
my $bname = git_branchname($ps->{id});
|
my $bname = git_branchname($ps->{id});
|
||||||
|
|
||||||
`mkdir -p $tmp`;
|
mkpath($tmp);
|
||||||
|
|
||||||
`tla get -s --no-pristine -A $ps->{repo} $ps->{id} $tmp/import`;
|
safe_pipe_capture($TLA,'get','-s','--no-pristine',$ps->{id},"$tmp/import");
|
||||||
die "Cannot get import: $!" if $?;
|
die "Cannot get import: $!" if $?;
|
||||||
`rsync -v --archive --delete --exclude '$git_dir' --exclude '.arch-ids' --exclude '{arch}' $tmp/import/* ./`;
|
system('rsync','-aI','--delete', '--exclude',$git_dir,
|
||||||
|
'--exclude','.arch-ids','--exclude','{arch}',
|
||||||
|
"$tmp/import/", './');
|
||||||
die "Cannot rsync import:$!" if $?;
|
die "Cannot rsync import:$!" if $?;
|
||||||
|
|
||||||
`rm -fr $tmp/import`;
|
rmtree("$tmp/import");
|
||||||
die "Cannot remove tempdir: $!" if $?;
|
die "Cannot remove tempdir: $!" if $?;
|
||||||
|
|
||||||
|
|
||||||
@ -506,10 +659,10 @@ sub apply_import {
|
|||||||
sub apply_cset {
|
sub apply_cset {
|
||||||
my $ps = shift;
|
my $ps = shift;
|
||||||
|
|
||||||
`mkdir -p $tmp`;
|
mkpath($tmp);
|
||||||
|
|
||||||
# get the changeset
|
# get the changeset
|
||||||
`tla get-changeset -A $ps->{repo} $ps->{id} $tmp/changeset`;
|
safe_pipe_capture($TLA,'get-changeset',$ps->{id},"$tmp/changeset");
|
||||||
die "Cannot get changeset: $!" if $?;
|
die "Cannot get changeset: $!" if $?;
|
||||||
|
|
||||||
# apply patches
|
# apply patches
|
||||||
@ -533,22 +686,27 @@ sub apply_cset {
|
|||||||
$orig =~ s/\.modified$//; # lazy
|
$orig =~ s/\.modified$//; # lazy
|
||||||
$orig =~ s!^\Q$tmp\E/changeset/patches/!!;
|
$orig =~ s!^\Q$tmp\E/changeset/patches/!!;
|
||||||
#print "rsync -p '$mod' '$orig'";
|
#print "rsync -p '$mod' '$orig'";
|
||||||
`rsync -p $mod ./$orig`;
|
system('rsync','-p',$mod,"./$orig");
|
||||||
die "Problem applying binary changes! $!" if $?;
|
die "Problem applying binary changes! $!" if $?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# bring in new files
|
# bring in new files
|
||||||
`rsync --archive --exclude '$git_dir' --exclude '.arch-ids' --exclude '{arch}' $tmp/changeset/new-files-archive/* ./`;
|
system('rsync','-aI','--exclude',$git_dir,
|
||||||
|
'--exclude','.arch-ids',
|
||||||
|
'--exclude', '{arch}',
|
||||||
|
"$tmp/changeset/new-files-archive/",'./');
|
||||||
|
|
||||||
# deleted files are hinted from the commitlog processing
|
# deleted files are hinted from the commitlog processing
|
||||||
|
|
||||||
`rm -fr $tmp/changeset`;
|
rmtree("$tmp/changeset");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# =for reference
|
# =for reference
|
||||||
# A log entry looks like
|
# notes: *-files/-directories keys cannot have spaces, they're always
|
||||||
|
# pika-escaped. Everything after the first newline
|
||||||
|
# A log entry looks like:
|
||||||
# Revision: moodle-org--moodle--1.3.3--patch-15
|
# Revision: moodle-org--moodle--1.3.3--patch-15
|
||||||
# Archive: arch-eduforge@catalyst.net.nz--2004
|
# Archive: arch-eduforge@catalyst.net.nz--2004
|
||||||
# Creator: Penny Leach <penny@catalyst.net.nz>
|
# Creator: Penny Leach <penny@catalyst.net.nz>
|
||||||
@ -566,70 +724,85 @@ sub apply_cset {
|
|||||||
# admin/editor.html backup/lib.php backup/restore.php
|
# admin/editor.html backup/lib.php backup/restore.php
|
||||||
# New-patches: arch-eduforge@catalyst.net.nz--2004/moodle-org--moodle--1.3.3--patch-15
|
# New-patches: arch-eduforge@catalyst.net.nz--2004/moodle-org--moodle--1.3.3--patch-15
|
||||||
# Summary: Updating to latest from MOODLE_14_STABLE (1.4.5+)
|
# Summary: Updating to latest from MOODLE_14_STABLE (1.4.5+)
|
||||||
|
# summary can be multiline with a leading space just like the above fields
|
||||||
# Keywords:
|
# Keywords:
|
||||||
#
|
#
|
||||||
# Updating yadda tadda tadda madda
|
# Updating yadda tadda tadda madda
|
||||||
sub parselog {
|
sub parselog {
|
||||||
my $log = shift;
|
my ($ps, $log) = @_;
|
||||||
#print $log;
|
my $key = undef;
|
||||||
|
|
||||||
my (@add, @del, @mod, @ren, @kw, $sum, $msg );
|
# headers we want that contain filenames:
|
||||||
|
my %want_headers = (
|
||||||
if ($log =~ m/(?:\n|^)New-files:(.*?)(?=\n\w)/s ) {
|
new_files => 1,
|
||||||
my $files = $1;
|
modified_files => 1,
|
||||||
@add = split(m/\s+/s, $files);
|
renamed_files => 1,
|
||||||
}
|
renamed_directories => 1,
|
||||||
|
removed_files => 1,
|
||||||
if ($log =~ m/(?:\n|^)Removed-files:(.*?)(?=\n\w)/s ) {
|
removed_directories => 1,
|
||||||
my $files = $1;
|
);
|
||||||
@del = split(m/\s+/s, $files);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($log =~ m/(?:\n|^)Modified-files:(.*?)(?=\n\w)/s ) {
|
chomp (@$log);
|
||||||
my $files = $1;
|
while ($_ = shift @$log) {
|
||||||
@mod = split(m/\s+/s, $files);
|
if (/^Continuation-of:\s*(.*)/) {
|
||||||
|
$ps->{tag} = $1;
|
||||||
|
$key = undef;
|
||||||
|
} elsif (/^Summary:\s*(.*)$/ ) {
|
||||||
|
# summary can be multiline as long as it has a leading space
|
||||||
|
$ps->{summary} = [ $1 ];
|
||||||
|
$key = 'summary';
|
||||||
|
} elsif (/^Creator: (.*)\s*<([^\>]+)>/) {
|
||||||
|
$ps->{author} = $1;
|
||||||
|
$ps->{email} = $2;
|
||||||
|
$key = undef;
|
||||||
|
# any *-files or *-directories can be read here:
|
||||||
|
} elsif (/^([A-Z][a-z\-]+):\s*(.*)$/) {
|
||||||
|
my $val = $2;
|
||||||
|
$key = lc $1;
|
||||||
|
$key =~ tr/-/_/; # too lazy to quote :P
|
||||||
|
if ($want_headers{$key}) {
|
||||||
|
push @{$ps->{$key}}, split(/\s+/, $val);
|
||||||
|
} else {
|
||||||
|
$key = undef;
|
||||||
|
}
|
||||||
|
} elsif (/^$/) {
|
||||||
|
last; # remainder of @$log that didn't get shifted off is message
|
||||||
|
} elsif ($key) {
|
||||||
|
if (/^\s+(.*)$/) {
|
||||||
|
if ($key eq 'summary') {
|
||||||
|
push @{$ps->{$key}}, $1;
|
||||||
|
} else { # files/directories:
|
||||||
|
push @{$ps->{$key}}, split(/\s+/, $1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$key = undef;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# post-processing:
|
||||||
|
$ps->{summary} = join("\n",@{$ps->{summary}})."\n";
|
||||||
|
$ps->{message} = join("\n",@$log);
|
||||||
|
|
||||||
if ($log =~ m/(?:\n|^)Renamed-files:(.*?)(?=\n\w)/s ) {
|
# skip Arch control files, unescape pika-escaped files
|
||||||
my $files = $1;
|
foreach my $k (keys %want_headers) {
|
||||||
@ren = split(m/\s+/s, $files);
|
next unless (defined $ps->{$k});
|
||||||
}
|
|
||||||
|
|
||||||
$sum ='';
|
|
||||||
if ($log =~ m/^Summary:(.+?)$/m ) {
|
|
||||||
$sum = $1;
|
|
||||||
$sum =~ s/^\s+//;
|
|
||||||
$sum =~ s/\s+$//;
|
|
||||||
}
|
|
||||||
|
|
||||||
$msg = '';
|
|
||||||
if ($log =~ m/\n\n(.+)$/s) {
|
|
||||||
$msg = $1;
|
|
||||||
$msg =~ s/^\s+//;
|
|
||||||
$msg =~ s/\s+$//;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# cleanup the arrays
|
|
||||||
foreach my $ref ( (\@add, \@del, \@mod, \@ren) ) {
|
|
||||||
my @tmp = ();
|
my @tmp = ();
|
||||||
while (my $t = pop @$ref) {
|
foreach my $t (@{$ps->{$k}}) {
|
||||||
next unless length ($t);
|
next unless length ($t);
|
||||||
next if $t =~ m!\{arch\}/!;
|
next if $t =~ m!\{arch\}/!;
|
||||||
next if $t =~ m!\.arch-ids/!;
|
next if $t =~ m!\.arch-ids/!;
|
||||||
next if $t =~ m!\.arch-inventory$!;
|
# should we skip this?
|
||||||
|
next if $t =~ m!\.arch-inventory$!;
|
||||||
# tla cat-archive-log will give us filenames with spaces as file\(sp)name - why?
|
# 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.
|
# we can assume that any filename with \ indicates some pika escaping that we want to get rid of.
|
||||||
if ($t =~ /\\/ ){
|
if ($t =~ /\\/ ){
|
||||||
$t = `tla escape --unescaped '$t'`;
|
$t = (safe_pipe_capture($TLA,'escape','--unescaped',$t))[0];
|
||||||
}
|
}
|
||||||
push (@tmp, shell_quote($t));
|
push @tmp, $t;
|
||||||
}
|
}
|
||||||
@$ref = @tmp;
|
$ps->{$k} = \@tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
#print Dumper [$sum, $msg, \@add, \@del, \@mod, \@ren];
|
|
||||||
return ($sum, $msg, \@add, \@del, \@mod, \@ren);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# write/read a tag
|
# write/read a tag
|
||||||
@ -826,8 +999,11 @@ sub find_parents {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@parents = keys %parents;
|
|
||||||
@parents = map { " -p " . ptag($_) } @parents;
|
@parents = ();
|
||||||
|
foreach (keys %parents) {
|
||||||
|
push @parents, '-p', ptag($_);
|
||||||
|
}
|
||||||
return @parents;
|
return @parents;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -850,3 +1026,45 @@ sub commitid2pset {
|
|||||||
|| (print Dumper(sort keys %psets)) && die "Cannot find patchset for $name";
|
|| (print Dumper(sort keys %psets)) && die "Cannot find patchset for $name";
|
||||||
return $ps;
|
return $ps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# an alterative to `command` that allows input to be passed as an array
|
||||||
|
# to work around shell problems with weird characters in arguments
|
||||||
|
sub safe_pipe_capture {
|
||||||
|
my @output;
|
||||||
|
if (my $pid = open my $child, '-|') {
|
||||||
|
@output = (<$child>);
|
||||||
|
close $child or die join(' ',@_).": $! $?";
|
||||||
|
} else {
|
||||||
|
exec(@_) or die "$! $?"; # exec() can fail the executable can't be found
|
||||||
|
}
|
||||||
|
return wantarray ? @output : join('',@output);
|
||||||
|
}
|
||||||
|
|
||||||
|
# `tla logs -rf -d <dir> | head -n1` or `baz tree-id <dir>`
|
||||||
|
sub arch_tree_id {
|
||||||
|
my $dir = shift;
|
||||||
|
chomp( my $ret = (safe_pipe_capture($TLA,'logs','-rf','-d',$dir))[0] );
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub archive_reachable {
|
||||||
|
my $archive = shift;
|
||||||
|
return 1 if $reachable{$archive};
|
||||||
|
return 0 if $unreachable{$archive};
|
||||||
|
|
||||||
|
if (system "$TLA whereis-archive $archive >/dev/null") {
|
||||||
|
if ($opt_a && (system($TLA,'register-archive',
|
||||||
|
"http://mirrors.sourcecontrol.net/$archive") == 0)) {
|
||||||
|
$reachable{$archive} = 1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
print STDERR "Archive is unreachable: $archive\n";
|
||||||
|
$unreachable{$archive} = 1;
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
$reachable{$archive} = 1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,15 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
|
USAGE='[start|bad|good|next|reset|visualize]'
|
||||||
|
LONG_USAGE='git bisect start [<pathspec>] reset bisect state and start bisection.
|
||||||
|
git bisect bad [<rev>] mark <rev> a known-bad revision.
|
||||||
|
git bisect good [<rev>...] mark <rev>... known-good revisions.
|
||||||
|
git bisect next find next bisection to test and check it out.
|
||||||
|
git bisect reset [<branch>] finish bisection search and go back to branch.
|
||||||
|
git bisect visualize show bisect status in gitk.
|
||||||
|
git bisect replay <logfile> replay bisection log
|
||||||
|
git bisect log show bisect log.'
|
||||||
|
|
||||||
. git-sh-setup
|
. git-sh-setup
|
||||||
|
|
||||||
sq() {
|
sq() {
|
||||||
@ -11,19 +22,6 @@ sq() {
|
|||||||
' "$@"
|
' "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
usage() {
|
|
||||||
echo >&2 'usage: git bisect [start|bad|good|next|reset|visualize]
|
|
||||||
git bisect start [<pathspec>] reset bisect state and start bisection.
|
|
||||||
git bisect bad [<rev>] mark <rev> a known-bad revision.
|
|
||||||
git bisect good [<rev>...] mark <rev>... known-good revisions.
|
|
||||||
git bisect next find next bisection to test and check it out.
|
|
||||||
git bisect reset [<branch>] finish bisection search and go back to branch.
|
|
||||||
git bisect visualize show bisect status in gitk.
|
|
||||||
git bisect replay <logfile> replay bisection log
|
|
||||||
git bisect log show bisect log.'
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
bisect_autostart() {
|
bisect_autostart() {
|
||||||
test -d "$GIT_DIR/refs/bisect" || {
|
test -d "$GIT_DIR/refs/bisect" || {
|
||||||
echo >&2 'You need to start by "git bisect start"'
|
echo >&2 'You need to start by "git bisect start"'
|
||||||
@ -67,7 +65,7 @@ bisect_start() {
|
|||||||
rm -rf "$GIT_DIR/refs/bisect/"
|
rm -rf "$GIT_DIR/refs/bisect/"
|
||||||
mkdir "$GIT_DIR/refs/bisect"
|
mkdir "$GIT_DIR/refs/bisect"
|
||||||
{
|
{
|
||||||
echo -n "git-bisect start"
|
printf "git-bisect start"
|
||||||
sq "$@"
|
sq "$@"
|
||||||
} >"$GIT_DIR/BISECT_LOG"
|
} >"$GIT_DIR/BISECT_LOG"
|
||||||
sq "$@" >"$GIT_DIR/BISECT_NAMES"
|
sq "$@" >"$GIT_DIR/BISECT_NAMES"
|
||||||
|
@ -1,21 +1,12 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
GIT_DIR=`git-rev-parse --git-dir` || exit $?
|
USAGE='[-d <branch>] | [[-f] <branch> [start-point]]'
|
||||||
|
LONG_USAGE='If no arguments, show available branches and mark current branch with a star.
|
||||||
die () {
|
|
||||||
echo >&2 "$*"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
usage () {
|
|
||||||
echo >&2 "usage: $(basename $0)"' [-d <branch>] | [[-f] <branch> [start-point]]
|
|
||||||
|
|
||||||
If no arguments, show available branches and mark current branch with a star.
|
|
||||||
If one argument, create a new branch <branchname> based off of current HEAD.
|
If one argument, create a new branch <branchname> based off of current HEAD.
|
||||||
If two arguments, create a new branch <branchname> based off of <start-point>.
|
If two arguments, create a new branch <branchname> based off of <start-point>.'
|
||||||
'
|
|
||||||
exit 1
|
SUBDIRECTORY_OK='Yes'
|
||||||
}
|
. git-sh-setup
|
||||||
|
|
||||||
headref=$(git-symbolic-ref HEAD | sed -e 's|^refs/heads/||')
|
headref=$(git-symbolic-ref HEAD | sed -e 's|^refs/heads/||')
|
||||||
|
|
||||||
@ -41,11 +32,11 @@ delete_branch () {
|
|||||||
case " $mbs " in
|
case " $mbs " in
|
||||||
*' '$branch' '*)
|
*' '$branch' '*)
|
||||||
# the merge base of branch and HEAD contains branch --
|
# the merge base of branch and HEAD contains branch --
|
||||||
# which means that the HEAD contains everything in the HEAD.
|
# which means that the HEAD contains everything in both.
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo >&2 "The branch '$branch_name' is not a strict subset of your current HEAD.
|
echo >&2 "The branch '$branch_name' is not a strict subset of your current HEAD.
|
||||||
If you are sure you want to delete it, run 'git branch -D $branch_name'."
|
If you are sure you want to delete it, run 'git branch -D $branch_name'."
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
. git-sh-setup
|
|
||||||
|
|
||||||
usage () {
|
USAGE='[-f] [-b <new_branch>] [<branch>] [<paths>...]'
|
||||||
die "usage: git checkout [-f] [-b <new_branch>] [<branch>] [<paths>...]"
|
. git-sh-setup
|
||||||
}
|
|
||||||
|
|
||||||
old=$(git-rev-parse HEAD)
|
old=$(git-rev-parse HEAD)
|
||||||
new=
|
new=
|
||||||
@ -118,7 +116,7 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
#
|
#
|
||||||
# Switch the HEAD pointer to the new branch if it we
|
# Switch the HEAD pointer to the new branch if we
|
||||||
# checked out a branch head, and remove any potential
|
# checked out a branch head, and remove any potential
|
||||||
# old MERGE_HEAD's (subsequent commits will clearly not
|
# old MERGE_HEAD's (subsequent commits will clearly not
|
||||||
# be based on them, since we re-set the index)
|
# be based on them, since we re-set the index)
|
||||||
|
@ -3,11 +3,8 @@
|
|||||||
# Copyright (c) 2005 Junio C Hamano.
|
# Copyright (c) 2005 Junio C Hamano.
|
||||||
#
|
#
|
||||||
|
|
||||||
. git-sh-setup
|
USAGE='[-v] <upstream> [<head>]'
|
||||||
|
LONG_USAGE=' __*__*__*__*__> <upstream>
|
||||||
usage="usage: $0 "'[-v] <upstream> [<head>]
|
|
||||||
|
|
||||||
__*__*__*__*__> <upstream>
|
|
||||||
/
|
/
|
||||||
fork-point
|
fork-point
|
||||||
\__+__+__+__+__+__+__+__> <head>
|
\__+__+__+__+__+__+__+__> <head>
|
||||||
@ -16,8 +13,8 @@ Each commit between the fork-point and <head> is examined, and
|
|||||||
compared against the change each commit between the fork-point and
|
compared against the change each commit between the fork-point and
|
||||||
<upstream> introduces. If the change seems to be in the upstream,
|
<upstream> introduces. If the change seems to be in the upstream,
|
||||||
it is shown on the standard output with prefix "+". Otherwise
|
it is shown on the standard output with prefix "+". Otherwise
|
||||||
it is shown with prefix "-".
|
it is shown with prefix "-".'
|
||||||
'
|
. git-sh-setup
|
||||||
|
|
||||||
case "$1" in -v) verbose=t; shift ;; esac
|
case "$1" in -v) verbose=t; shift ;; esac
|
||||||
|
|
||||||
@ -35,7 +32,7 @@ case "$#" in
|
|||||||
2) upstream=`git-rev-parse --verify "$1"` &&
|
2) upstream=`git-rev-parse --verify "$1"` &&
|
||||||
ours=`git-rev-parse --verify "$2"` || exit
|
ours=`git-rev-parse --verify "$2"` || exit
|
||||||
;;
|
;;
|
||||||
*) echo >&2 "$usage"; exit 1 ;;
|
*) usage ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
# Note that these list commits in reverse order;
|
# Note that these list commits in reverse order;
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
unset CDPATH
|
unset CDPATH
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
echo >&2 "* git clone [-l [-s]] [-q] [-u <upload-pack>] [-n] <repo> [<dir>]"
|
echo >&2 "Usage: $0 [-l [-s]] [-q] [-u <upload-pack>] [-n] <repo> [<dir>]"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,7 +188,10 @@ yes,yes)
|
|||||||
cd "$D" && case "$upload_pack" in
|
cd "$D" && case "$upload_pack" in
|
||||||
'') git-clone-pack $quiet "$repo" ;;
|
'') git-clone-pack $quiet "$repo" ;;
|
||||||
*) git-clone-pack $quiet "$upload_pack" "$repo" ;;
|
*) git-clone-pack $quiet "$upload_pack" "$repo" ;;
|
||||||
esac
|
esac || {
|
||||||
|
echo >&2 "clone-pack from '$repo' failed."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
;;
|
;;
|
||||||
|
@ -3,12 +3,9 @@
|
|||||||
# Copyright (c) 2005 Linus Torvalds
|
# Copyright (c) 2005 Linus Torvalds
|
||||||
#
|
#
|
||||||
|
|
||||||
|
USAGE='[-a] [-s] [-v | --no-verify] [-m <message> | -F <logfile> | (-C|-c) <commit>] [-e] [<path>...]'
|
||||||
. git-sh-setup
|
. git-sh-setup
|
||||||
|
|
||||||
usage () {
|
|
||||||
die 'git commit [-a] [-s] [-v | --no-verify] [-m <message> | -F <logfile> | (-C|-c) <commit>] [-e] [<path>...]'
|
|
||||||
}
|
|
||||||
|
|
||||||
all= logfile= use_commit= no_edit= log_given= log_message= verify=t signoff=
|
all= logfile= use_commit= no_edit= log_given= log_message= verify=t signoff=
|
||||||
while case "$#" in 0) break;; esac
|
while case "$#" in 0) break;; esac
|
||||||
do
|
do
|
||||||
|
138
git-compat-util.h
Normal file
138
git-compat-util.h
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
#ifndef GIT_COMPAT_UTIL_H
|
||||||
|
#define GIT_COMPAT_UTIL_H
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define NORETURN __attribute__((__noreturn__))
|
||||||
|
#else
|
||||||
|
#define NORETURN
|
||||||
|
#ifndef __attribute__
|
||||||
|
#define __attribute__(x)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* General helper functions */
|
||||||
|
extern void usage(const char *err) NORETURN;
|
||||||
|
extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2)));
|
||||||
|
extern int error(const char *err, ...) __attribute__((format (printf, 1, 2)));
|
||||||
|
|
||||||
|
#ifdef NO_MMAP
|
||||||
|
|
||||||
|
#ifndef PROT_READ
|
||||||
|
#define PROT_READ 1
|
||||||
|
#define PROT_WRITE 2
|
||||||
|
#define MAP_PRIVATE 1
|
||||||
|
#define MAP_FAILED ((void*)-1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define mmap gitfakemmap
|
||||||
|
#define munmap gitfakemunmap
|
||||||
|
extern void *gitfakemmap(void *start, size_t length, int prot , int flags, int fd, off_t offset);
|
||||||
|
extern int gitfakemunmap(void *start, size_t length);
|
||||||
|
|
||||||
|
#else /* NO_MMAP */
|
||||||
|
|
||||||
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
#endif /* NO_MMAP */
|
||||||
|
|
||||||
|
#ifdef NO_SETENV
|
||||||
|
#define setenv gitsetenv
|
||||||
|
extern int gitsetenv(const char *, const char *, int);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef NO_STRCASESTR
|
||||||
|
#define strcasestr gitstrcasestr
|
||||||
|
extern char *gitstrcasestr(const char *haystack, const char *needle);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline void *xmalloc(size_t size)
|
||||||
|
{
|
||||||
|
void *ret = malloc(size);
|
||||||
|
if (!ret)
|
||||||
|
die("Out of memory, malloc failed");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void *xrealloc(void *ptr, size_t size)
|
||||||
|
{
|
||||||
|
void *ret = realloc(ptr, size);
|
||||||
|
if (!ret)
|
||||||
|
die("Out of memory, realloc failed");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void *xcalloc(size_t nmemb, size_t size)
|
||||||
|
{
|
||||||
|
void *ret = calloc(nmemb, size);
|
||||||
|
if (!ret)
|
||||||
|
die("Out of memory, calloc failed");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline ssize_t xread(int fd, void *buf, size_t len)
|
||||||
|
{
|
||||||
|
ssize_t nr;
|
||||||
|
while (1) {
|
||||||
|
nr = read(fd, buf, len);
|
||||||
|
if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
|
||||||
|
continue;
|
||||||
|
return nr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline ssize_t xwrite(int fd, const void *buf, size_t len)
|
||||||
|
{
|
||||||
|
ssize_t nr;
|
||||||
|
while (1) {
|
||||||
|
nr = write(fd, buf, len);
|
||||||
|
if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
|
||||||
|
continue;
|
||||||
|
return nr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sane ctype - no locale, and works with signed chars */
|
||||||
|
#undef isspace
|
||||||
|
#undef isdigit
|
||||||
|
#undef isalpha
|
||||||
|
#undef isalnum
|
||||||
|
#undef tolower
|
||||||
|
#undef toupper
|
||||||
|
extern unsigned char sane_ctype[256];
|
||||||
|
#define GIT_SPACE 0x01
|
||||||
|
#define GIT_DIGIT 0x02
|
||||||
|
#define GIT_ALPHA 0x04
|
||||||
|
#define sane_istest(x,mask) ((sane_ctype[(unsigned char)(x)] & (mask)) != 0)
|
||||||
|
#define isspace(x) sane_istest(x,GIT_SPACE)
|
||||||
|
#define isdigit(x) sane_istest(x,GIT_DIGIT)
|
||||||
|
#define isalpha(x) sane_istest(x,GIT_ALPHA)
|
||||||
|
#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
|
||||||
|
#define tolower(x) sane_case((unsigned char)(x), 0x20)
|
||||||
|
#define toupper(x) sane_case((unsigned char)(x), 0)
|
||||||
|
|
||||||
|
static inline int sane_case(int x, int high)
|
||||||
|
{
|
||||||
|
if (sane_istest(x, GIT_ALPHA))
|
||||||
|
x = (x & ~0x20) | high;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef MAXPATHLEN
|
||||||
|
#define MAXPATHLEN 256
|
||||||
|
#endif
|
||||||
|
#endif
|
14
git-diff.sh
14
git-diff.sh
@ -3,15 +3,14 @@
|
|||||||
# Copyright (c) 2005 Linus Torvalds
|
# Copyright (c) 2005 Linus Torvalds
|
||||||
# Copyright (c) 2005 Junio C Hamano
|
# Copyright (c) 2005 Junio C Hamano
|
||||||
|
|
||||||
|
USAGE='[ --diff-options ] <ent>{0,2} [<path>...]'
|
||||||
|
SUBDIRECTORY_OK='Yes'
|
||||||
|
. git-sh-setup
|
||||||
|
|
||||||
rev=$(git-rev-parse --revs-only --no-flags --sq "$@") || exit
|
rev=$(git-rev-parse --revs-only --no-flags --sq "$@") || exit
|
||||||
flags=$(git-rev-parse --no-revs --flags --sq "$@")
|
flags=$(git-rev-parse --no-revs --flags --sq "$@")
|
||||||
files=$(git-rev-parse --no-revs --no-flags --sq "$@")
|
files=$(git-rev-parse --no-revs --no-flags --sq "$@")
|
||||||
|
|
||||||
die () {
|
|
||||||
echo >&2 "$*"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# I often say 'git diff --cached -p' and get scolded by git-diff-files, but
|
# I often say 'git diff --cached -p' and get scolded by git-diff-files, but
|
||||||
# obviously I mean 'git diff --cached -p HEAD' in that case.
|
# obviously I mean 'git diff --cached -p HEAD' in that case.
|
||||||
case "$rev" in
|
case "$rev" in
|
||||||
@ -40,8 +39,7 @@ esac
|
|||||||
|
|
||||||
case "$rev" in
|
case "$rev" in
|
||||||
?*' '?*' '?*)
|
?*' '?*' '?*)
|
||||||
echo >&2 "I don't understand"
|
usage
|
||||||
exit 1
|
|
||||||
;;
|
;;
|
||||||
?*' '^?*)
|
?*' '^?*)
|
||||||
begin=$(expr "$rev" : '.*^.\([0-9a-f]*\).*') &&
|
begin=$(expr "$rev" : '.*^.\([0-9a-f]*\).*') &&
|
||||||
@ -58,7 +56,7 @@ case "$rev" in
|
|||||||
cmd="git-diff-files $flags -- $files"
|
cmd="git-diff-files $flags -- $files"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
die "I don't understand $*"
|
usage
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
#
|
#
|
||||||
|
|
||||||
|
USAGE='<fetch-options> <repository> <refspec>...'
|
||||||
. git-sh-setup
|
. git-sh-setup
|
||||||
. git-parse-remote
|
. git-parse-remote
|
||||||
_x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
|
_x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
|
||||||
@ -34,6 +36,9 @@ do
|
|||||||
-v|--verbose)
|
-v|--verbose)
|
||||||
verbose=Yes
|
verbose=Yes
|
||||||
;;
|
;;
|
||||||
|
-*)
|
||||||
|
usage
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
break
|
break
|
||||||
;;
|
;;
|
||||||
|
@ -3,19 +3,8 @@
|
|||||||
# Copyright (c) 2005 Junio C Hamano
|
# Copyright (c) 2005 Junio C Hamano
|
||||||
#
|
#
|
||||||
|
|
||||||
. git-sh-setup
|
USAGE='[-n | -k] [-o <dir> | --stdout] [--signoff] [--check] [--mbox] [--diff-options] <upstream> [<our-head>]'
|
||||||
|
LONG_USAGE='Prepare each commit with its patch since our-head forked from upstream,
|
||||||
# Force diff to run in C locale.
|
|
||||||
LANG=C LC_ALL=C
|
|
||||||
export LANG LC_ALL
|
|
||||||
|
|
||||||
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,
|
|
||||||
one file per patch, for e-mail submission. Each output file is
|
one file per patch, for e-mail submission. Each output file is
|
||||||
numbered sequentially from 1, and uses the first line of the commit
|
numbered sequentially from 1, and uses the first line of the commit
|
||||||
message (massaged for pathname safety) as the filename.
|
message (massaged for pathname safety) as the filename.
|
||||||
@ -28,10 +17,12 @@ as "[PATCH N/M] Subject", unless you have only one patch.
|
|||||||
|
|
||||||
When --mbox is specified, the output is formatted to resemble
|
When --mbox is specified, the output is formatted to resemble
|
||||||
UNIX mailbox format, and can be concatenated together for processing
|
UNIX mailbox format, and can be concatenated together for processing
|
||||||
with applymbox.
|
with applymbox.'
|
||||||
'
|
. git-sh-setup
|
||||||
exit 1
|
|
||||||
}
|
# Force diff to run in C locale.
|
||||||
|
LANG=C LC_ALL=C
|
||||||
|
export LANG LC_ALL
|
||||||
|
|
||||||
diff_opts=
|
diff_opts=
|
||||||
LF='
|
LF='
|
||||||
@ -219,6 +210,8 @@ Date: '"$ad"
|
|||||||
}
|
}
|
||||||
|
|
||||||
mailScript="$mailScript"'
|
mailScript="$mailScript"'
|
||||||
|
a\
|
||||||
|
|
||||||
: body
|
: body
|
||||||
p
|
p
|
||||||
n
|
n
|
||||||
@ -254,6 +247,15 @@ Date: '"$ad"
|
|||||||
}
|
}
|
||||||
|
|
||||||
total=`wc -l <$series | tr -dc "[0-9]"`
|
total=`wc -l <$series | tr -dc "[0-9]"`
|
||||||
|
case "$total,$numbered" in
|
||||||
|
1,*)
|
||||||
|
numfmt='' ;;
|
||||||
|
*,t)
|
||||||
|
numfmt=`echo "$total" | wc -c`
|
||||||
|
numfmt=$(($numfmt-1))
|
||||||
|
numfmt=" %0${numfmt}d/$total"
|
||||||
|
esac
|
||||||
|
|
||||||
i=1
|
i=1
|
||||||
while read commit
|
while read commit
|
||||||
do
|
do
|
||||||
@ -262,10 +264,7 @@ do
|
|||||||
case "$numbered" in
|
case "$numbered" in
|
||||||
'') num= ;;
|
'') num= ;;
|
||||||
*)
|
*)
|
||||||
case $total in
|
num=`printf "$numfmt" $i` ;;
|
||||||
1) num= ;;
|
|
||||||
*) num=' '`printf "%d/%d" $i $total` ;;
|
|
||||||
esac
|
|
||||||
esac
|
esac
|
||||||
|
|
||||||
file=`printf '%04d-%stxt' $i "$title"`
|
file=`printf '%04d-%stxt' $i "$title"`
|
||||||
|
@ -3,6 +3,10 @@
|
|||||||
# Copyright (c) Linus Torvalds, 2005
|
# Copyright (c) Linus Torvalds, 2005
|
||||||
#
|
#
|
||||||
|
|
||||||
|
USAGE='<option>... <pattern> <path>...'
|
||||||
|
SUBDIRECTORY_OK='Yes'
|
||||||
|
. git-sh-setup
|
||||||
|
|
||||||
pattern=
|
pattern=
|
||||||
flags=()
|
flags=()
|
||||||
git_flags=()
|
git_flags=()
|
||||||
@ -40,8 +44,7 @@ while : ; do
|
|||||||
shift
|
shift
|
||||||
done
|
done
|
||||||
[ "$pattern" ] || {
|
[ "$pattern" ] || {
|
||||||
echo >&2 "usage: 'git grep <pattern> [pathspec*]'"
|
usage
|
||||||
exit 1
|
|
||||||
}
|
}
|
||||||
git-ls-files -z "${git_flags[@]}" "$@" |
|
git-ls-files -z "${git_flags[@]}" "$@" |
|
||||||
xargs -0 grep "${flags[@]}" -e "$pattern"
|
xargs -0 grep "${flags[@]}" -e "$pattern"
|
||||||
|
@ -3,13 +3,13 @@
|
|||||||
# Copyright (c) 2005 Linus Torvalds
|
# Copyright (c) 2005 Linus Torvalds
|
||||||
#
|
#
|
||||||
|
|
||||||
# This one uses only subdirectory-aware commands, so no need to
|
USAGE='[--max-count=<n>] [<since>..<limit>] [--pretty=<format>] [git-rev-list options]'
|
||||||
# include sh-setup-script.
|
SUBDIRECTORY_OK='Yes'
|
||||||
|
. git-sh-setup
|
||||||
|
|
||||||
revs=$(git-rev-parse --revs-only --no-flags --default HEAD "$@") || exit
|
revs=$(git-rev-parse --revs-only --no-flags --default HEAD "$@") || exit
|
||||||
[ "$revs" ] || {
|
[ "$revs" ] || {
|
||||||
echo >&2 "No HEAD ref"
|
die "No HEAD ref"
|
||||||
exit 1
|
|
||||||
}
|
}
|
||||||
git-rev-list --pretty $(git-rev-parse --default HEAD "$@") |
|
git-rev-list --pretty $(git-rev-parse --default HEAD "$@") |
|
||||||
LESS=-S ${PAGER:-less}
|
LESS=-S ${PAGER:-less}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user