Merge branch 'master' of git://repo.or.cz/alt-git

This commit is contained in:
Johannes Sixt
2009-08-18 10:31:05 +02:00
160 changed files with 4666 additions and 638 deletions

View File

@@ -0,0 +1,51 @@
GIT v1.6.5 Release Notes
========================
In git 1.7.0, which is planned to be the release after 1.6.5, "git push"
into a branch that is currently checked out will be refused by default.
You can choose what should happen upon such a push by setting the
configuration variable receive.denyCurrentBranch in the receiving
repository.
Also, "git push $there :$killed" to delete the branch $killed in a remote
repository $there, when $killed branch is the current branch pointed at by
its HEAD, will be refused by default.
You can choose what should happen upon such a push by setting the
configuration variable receive.denyDeleteCurrent in the receiving
repository.
To ease the transition plan, the receiving repository of such a
push running this release will issue a big warning when the
configuration variable is missing. Please refer to:
http://git.or.cz/gitwiki/GitFaq#non-bare
http://thread.gmane.org/gmane.comp.version-control.git/107758/focus=108007
for more details on the reason why this change is needed and the
transition plan.
Updates since v1.6.4
--------------------
(subsystems)
(portability)
(performance)
(usability, bells and whistles)
(developers)
Fixes since v1.6.4
------------------
# All of the fixes in v1.6.4.X maintenance series are included in this
# release, unless otherwise noted.
# Here are fixes that this release has, but have not been backported to
# v1.6.4.X series.

View File

@@ -605,7 +605,7 @@ color.interactive.<slot>::
Use customized color for 'git-add --interactive'
output. `<slot>` may be `prompt`, `header`, `help` or `error`, for
four distinct types of normal output from interactive
programs. The values of these variables may be specified as
commands. The values of these variables may be specified as
in color.branch.<slot>.
color.pager::
@@ -1113,7 +1113,7 @@ instaweb.port::
linkgit:git-instaweb[1].
interactive.singlekey::
In interactive programs, allow the user to provide one-letter
In interactive commands, allow the user to provide one-letter
input with a single key (i.e., without hitting enter).
Currently this is used only by the `\--patch` mode of
linkgit:git-add[1]. Note that this setting is silently
@@ -1218,12 +1218,20 @@ pack.compression::
pack.deltaCacheSize::
The maximum memory in bytes used for caching deltas in
linkgit:git-pack-objects[1].
A value of 0 means no limit. Defaults to 0.
linkgit:git-pack-objects[1] before writing them out to a pack.
This cache is used to speed up the writing object phase by not
having to recompute the final delta result once the best match
for all objects is found. Repacking large repositories on machines
which are tight with memory might be badly impacted by this though,
especially if this cache pushes the system into swapping.
A value of 0 means no limit. The smallest size of 1 byte may be
used to virtually disable this cache. Defaults to 256 MiB.
pack.deltaCacheLimit::
The maximum size of a delta, that is cached in
linkgit:git-pack-objects[1]. Defaults to 1000.
linkgit:git-pack-objects[1]. This cache is used to speed up the
writing object phase by not having to recompute the final delta
result once the best match for all objects is found. Defaults to 1000.
pack.threads::
Specifies the number of threads to spawn when searching for best

View File

@@ -1,7 +1,7 @@
-q::
--quiet::
Pass --quiet to git-fetch-pack and silence any other internally
used programs.
used git commands.
-v::
--verbose::

View File

@@ -10,7 +10,7 @@ SYNOPSIS
[verse]
'git add' [-n] [-v] [--force | -f] [--interactive | -i] [--patch | -p]
[--edit | -e] [--all | [--update | -u]] [--intent-to-add | -N]
[--refresh] [--ignore-errors] [--] <filepattern>...
[--refresh] [--ignore-errors] [--] [<filepattern>...]
DESCRIPTION
-----------

View File

@@ -27,6 +27,9 @@ OPTIONS
-------
-d::
Remove untracked directories in addition to untracked files.
If an untracked directory is managed by a different git
repository, it is not removed by default. Use -f option twice
if you really want to remove such a directory.
-f::
If the git configuration specifies clean.requireForce as true,

View File

@@ -82,6 +82,14 @@ marks the same across runs.
allow that. So fake a tagger to be able to fast-import the
output.
--no-data::
Skip output of blob objects and instead refer to blobs via
their original SHA-1 hash. This is useful when rewriting the
directory structure or history of a repository without
touching the contents of individual files. Note that the
resulting stream can only be used by a repository which
already contains the necessary objects.
[git-rev-list-args...]::
A list of arguments, acceptable to 'git-rev-parse' and
'git-rev-list', that specifies the specific objects and references

View File

@@ -17,6 +17,7 @@ SYNOPSIS
[-l | --files-with-matches] [-L | --files-without-match]
[-z | --null]
[-c | --count] [--all-match]
[--max-depth <depth>]
[--color | --no-color]
[-A <post-context>] [-B <pre-context>] [-C <context>]
[-f <file>] [-e] <pattern>
@@ -47,6 +48,10 @@ OPTIONS
-I::
Don't match the pattern in binary files.
--max-depth <depth>::
For each pathspec given on command line, descend at most <depth>
levels of directories. A negative value means no limit.
-w::
--word-regexp::
Match the pattern only at word boundary (either begin at the

View File

@@ -8,7 +8,7 @@ git-init-db - Creates an empty git repository
SYNOPSIS
--------
'git init-db' [-q | --quiet] [--template=<template_directory>] [--shared[=<permissions>]]
'git init-db' [-q | --quiet] [--bare] [--template=<template_directory>] [--shared[=<permissions>]]
DESCRIPTION

View File

@@ -8,7 +8,7 @@ git-init - Create an empty git repository or reinitialize an existing one
SYNOPSIS
--------
'git init' [-q | --quiet] [--bare] [--template=<template_directory>] [--shared[=<permissions>]]
'git init' [-q | --quiet] [--bare] [--template=<template_directory>] [--shared[=<permissions>]] [directory]
OPTIONS
@@ -74,6 +74,9 @@ By default, the configuration flag receive.denyNonFastForwards is enabled
in shared repositories, so that you cannot force a non fast-forwarding push
into it.
If you name a (possibly non-existent) directory at the end of the command
line, the command is run inside the directory (possibly after creating it).
--

View File

@@ -44,7 +44,7 @@ OPTIONS
-o::
--others::
Show other files in the output
Show other (i.e. untracked) files in the output
-i::
--ignored::

View File

@@ -8,12 +8,12 @@ git-merge-base - Find as good common ancestors as possible for a merge
SYNOPSIS
--------
'git merge-base' [--all] <commit> <commit>...
'git merge-base' [-a|--all] <commit> <commit>...
DESCRIPTION
-----------
'git-merge-base' finds best common ancestor(s) between two commits to use
'git merge-base' finds best common ancestor(s) between two commits to use
in a three-way merge. One common ancestor is 'better' than another common
ancestor if the latter is an ancestor of the former. A common ancestor
that does not have any better common ancestor is a 'best common
@@ -27,8 +27,13 @@ commits on the command line. As the most common special case, specifying only
two commits on the command line means computing the merge base between
the given two commits.
As a consequence, the 'merge base' is not necessarily contained in each of the
commit arguments if more than two commits are specified. This is different
from linkgit:git-show-branch[1] when used with the `--merge-base` option.
OPTIONS
-------
-a::
--all::
Output all merge bases for the commits, instead of just one.

View File

@@ -10,7 +10,7 @@ SYNOPSIS
--------
[verse]
'git merge' [-n] [--stat] [--no-commit] [--squash] [-s <strategy>]...
[-m <msg>] <remote> <remote>...
[-m <msg>] <remote>...
'git merge' <msg> HEAD <remote>...
DESCRIPTION

View File

@@ -8,7 +8,7 @@ git-prune-packed - Remove extra objects that are already in pack files
SYNOPSIS
--------
'git prune-packed' [-n] [-q]
'git prune-packed' [-n|--dry-run] [-q|--quiet]
DESCRIPTION
@@ -28,10 +28,12 @@ disk storage, etc.
OPTIONS
-------
-n::
--dry-run::
Don't actually remove any objects, only show those that would have been
removed.
-q::
--quiet::
Squelch the progress indicator.
Author

View File

@@ -195,6 +195,92 @@ reason::
refs, no explanation is needed. For a failed ref, the reason for
failure is described.
Note about fast-forwards
------------------------
When an update changes a branch (or more in general, a ref) that used to
point at commit A to point at another commit B, it is called a
fast-forward update if and only if B is a descendant of A.
In a fast-forward update from A to B, the set of commits that the original
commit A built on top of is a subset of the commits the new commit B
builds on top of. Hence, it does not lose any history.
In contrast, a non-fast-forward update will lose history. For example,
suppose you and somebody else started at the same commit X, and you built
a history leading to commit B while the other person built a history
leading to commit A. The history looks like this:
----------------
B
/
---X---A
----------------
Further suppose that the other person already pushed changes leading to A
back to the original repository you two obtained the original commit X.
The push done by the other person updated the branch that used to point at
commit X to point at commit A. It is a fast-forward.
But if you try to push, you will attempt to update the branch (that
now points at A) with commit B. This does _not_ fast-forward. If you did
so, the changes introduced by commit A will be lost, because everybody
will now start building on top of B.
The command by default does not allow an update that is not a fast-forward
to prevent such loss of history.
If you do not want to lose your work (history from X to B) nor the work by
the other person (history from X to A), you would need to first fetch the
history from the repository, create a history that contains changes done
by both parties, and push the result back.
You can perform "git pull", resolve potential conflicts, and "git push"
the result. A "git pull" will create a merge commit C between commits A
and B.
----------------
B---C
/ /
---X---A
----------------
Updating A with the resulting merge commit will fast-forward and your
push will be accepted.
Alternatively, you can rebase your change between X and B on top of A,
with "git pull --rebase", and push the result back. The rebase will
create a new commit D that builds the change between X and B on top of
A.
----------------
B D
/ /
---X---A
----------------
Again, updating A with this commit will fast-forward and your push will be
accepted.
There is another common situation where you may encounter non-fast-forward
rejection when you try to push, and it is possible even when you are
pushing into a repository nobody else pushes into. After you push commit
A yourself (in the first picture in this section), replace it with "git
commit --amend" to produce commit B, and you try to push it out, because
forgot that you have pushed A out already. In such a case, and only if
you are certain that nobody in the meantime fetched your earlier commit A
(and started building on top of it), you can run "git push --force" to
overwrite it. In other words, "git push --force" is a method reserved for
a case where you do mean to lose history.
Examples
--------

View File

@@ -8,7 +8,10 @@ git-read-tree - Reads tree information into the index
SYNOPSIS
--------
'git read-tree' (<tree-ish> | [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] [--exclude-per-directory=<gitignore>] [--index-output=<file>] <tree-ish1> [<tree-ish2> [<tree-ish3>]])
'git read-tree' [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>]
[-u [--exclude-per-directory=<gitignore>] | -i]]
[--index-output=<file>]
<tree-ish1> [<tree-ish2> [<tree-ish3>]]
DESCRIPTION

View File

@@ -114,14 +114,14 @@ These stale branches have already been removed from the remote repository
referenced by <name>, but are still locally available in
"remotes/<name>".
+
With `--dry-run` option, report what branches will be pruned, but do no
With `--dry-run` option, report what branches will be pruned, but do not
actually prune them.
'update'::
Fetch updates for a named set of remotes in the repository as defined by
remotes.<group>. If a named group is not specified on the command line,
the configuration parameter remotes.default will get used; if
the configuration parameter remotes.default will be used; if
remotes.default is not defined, all remotes which do not have the
configuration parameter remote.<name>.skipDefaultUpdate set to true will
be updated. (See linkgit:git-config[1]).

View File

@@ -51,20 +51,26 @@ SYNOPSIS
DESCRIPTION
-----------
Lists commit objects in reverse chronological order starting at the
given commit(s), taking ancestry relationship into account. This is
useful to produce human-readable log output.
List commits that are reachable by following the `parent` links from the
given commit(s), but exclude commits that are reachable from the one(s)
given with a '{caret}' in front of them. The output is given in reverse
chronological order by default.
Commits which are stated with a preceding '{caret}' cause listing to
stop at that point. Their parents are implied. Thus the following
command:
You can think of this as a set operation. Commits given on the command
line form a set of commits that are reachable from any of them, and then
commits reachable from any of the ones given with '{caret}' in front are
subtracted from that set. The remaining commits are what comes out in the
command's output. Various other options and paths parameters can be used
to further limit the result.
Thus, the following command:
-----------------------------------------------------------------------
$ git rev-list foo bar ^baz
-----------------------------------------------------------------------
means "list all the commits which are included in 'foo' and 'bar', but
not in 'baz'".
means "list all the commits which are reachable from 'foo' or 'bar', but
not from 'baz'".
A special notation "'<commit1>'..'<commit2>'" can be used as a
short-hand for "{caret}'<commit1>' '<commit2>'". For example, either of
@@ -84,7 +90,7 @@ between the two operands. The following two commands are equivalent:
$ git rev-list A...B
-----------------------------------------------------------------------
'git-rev-list' is a very essential git program, since it
'rev-list' is a very essential git command, since it
provides the ability to build and traverse commit ancestry graphs. For
this reason, it has a lot of different options that enables it to be
used by commands as different as 'git-bisect' and

View File

@@ -142,8 +142,9 @@ user is prompted for a password while the input is masked for privacy.
--smtp-server-port=<port>::
Specifies a port different from the default port (SMTP
servers typically listen to smtp port 25 and ssmtp port
465); symbolic port names (e.g. "submission" instead of 465)
servers typically listen to smtp port 25, but may also listen to
submission port 587, or the common SSL smtp port 465);
symbolic port names (e.g. "submission" instead of 587)
are also accepted. The port can also be set with the
'sendemail.smtpserverport' configuration variable.

View File

@@ -8,11 +8,12 @@ git-show-branch - Show branches and their commits
SYNOPSIS
--------
[verse]
'git show-branch' [--all] [--remotes] [--topo-order | --date-order]
[--current] [--color | --no-color]
'git show-branch' [-a|--all] [-r|--remotes] [--topo-order | --date-order]
[--current] [--color | --no-color] [--sparse]
[--more=<n> | --list | --independent | --merge-base]
[--no-name | --sha1-name] [--topics]
[<rev> | <glob>]...
'git show-branch' (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]
DESCRIPTION
@@ -81,9 +82,11 @@ OPTIONS
Synonym to `--more=-1`
--merge-base::
Instead of showing the commit list, just act like the
'git-merge-base -a' command, except that it can accept
more than two heads.
Instead of showing the commit list, determine possible
merge bases for the specified commits. All merge bases
will be contained in all specified commits. This is
different from how linkgit:git-merge-base[1] handles
the case of three or more commits.
--independent::
Among the <reference>s given, display only the ones that

View File

@@ -114,7 +114,8 @@ no conflicts.
clear::
Remove all the stashed states. Note that those states will then
be subject to pruning, and may be difficult or impossible to recover.
be subject to pruning, and may be impossible to recover (see
'Examples' below for a possible strategy).
drop [-q|--quiet] [<stash>]::
@@ -217,6 +218,20 @@ $ edit/build/test remaining parts
$ git commit foo -m 'Remaining parts'
----------------------------------------------------------------
Recovering stashes that were cleared/dropped erroneously::
If you mistakenly drop or clear stashes, they cannot be recovered
through the normal safety mechanisms. However, you can try the
following incantation to get a list of stashes that are still in your
repository, but not reachable any more:
+
----------------------------------------------------------------
git fsck --unreachable |
grep commit | cut -d\ -f3 |
xargs git log --merges --no-walk --grep=WIP
----------------------------------------------------------------
SEE ALSO
--------
linkgit:git-checkout[1],

View File

@@ -14,8 +14,8 @@ SYNOPSIS
'git submodule' [--quiet] status [--cached] [--] [<path>...]
'git submodule' [--quiet] init [--] [<path>...]
'git submodule' [--quiet] update [--init] [-N|--no-fetch] [--rebase]
[--reference <repository>] [--] [<path>...]
'git submodule' [--quiet] summary [--summary-limit <n>] [commit] [--] [<path>...]
[--reference <repository>] [--merge] [--] [<path>...]
'git submodule' [--quiet] summary [--cached] [--summary-limit <n>] [commit] [--] [<path>...]
'git submodule' [--quiet] foreach <command>
'git submodule' [--quiet] sync [--] [<path>...]

View File

@@ -14,9 +14,9 @@ DESCRIPTION
Given one argument, reads which branch head the given symbolic
ref refers to and outputs its path, relative to the `.git/`
directory. Typically you would give `HEAD` as the <name>
argument to see on which branch your working tree is on.
argument to see which branch your working tree is on.
Give two arguments, create or update a symbolic ref <name> to
Given two arguments, creates or updates a symbolic ref <name> to
point at the given branch <ref>.
A symbolic ref is a regular file that stores a string that

View File

@@ -17,7 +17,10 @@ SYNOPSIS
DESCRIPTION
-----------
Adds a 'tag' reference in `.git/refs/tags/`
Adds a 'tag' reference in `.git/refs/tags/`. The tag <name> must pass
linkgit:git-check-ref-format[1] which basicly means that control characters,
space, ~, ^, :, ?, *, [ and \ are prohibited.
Unless `-f` is given, the tag must not yet exist in
`.git/refs/tags/` directory.

View File

@@ -8,7 +8,7 @@ git-verify-pack - Validate packed git archive files
SYNOPSIS
--------
'git verify-pack' [-v] [--] <pack>.idx ...
'git verify-pack' [-v|--verbose] [--] <pack>.idx ...
DESCRIPTION
@@ -23,6 +23,7 @@ OPTIONS
The idx files to verify.
-v::
--verbose::
After verifying the pack, show list of objects contained
in the pack.
\--::

View File

@@ -327,7 +327,7 @@ Synching repositories
include::cmds-synchingrepositories.txt[]
The following are helper programs used by the above; end users
The following are helper commands used by the above; end users
typically do not use them directly.
include::cmds-synchelpers.txt[]

View File

@@ -404,7 +404,7 @@ Performing a three-way merge
The attribute `merge` affects how three versions of a file is
merged when a file-level merge is necessary during `git merge`,
and other programs such as `git revert` and `git cherry-pick`.
and other commands such as `git revert` and `git cherry-pick`.
Set::

View File

@@ -12,7 +12,7 @@ git *
DESCRIPTION
-----------
This tutorial explains how to use the "core" git programs to set up and
This tutorial explains how to use the "core" git commands to set up and
work with a git repository.
If you just need to use git as a revision control system you may prefer
@@ -1328,7 +1328,7 @@ into it later. Obviously, this repository creation needs to be
done only once.
[NOTE]
'git-push' uses a pair of programs,
'git-push' uses a pair of commands,
'git-send-pack' on your local machine, and 'git-receive-pack'
on the remote machine. The communication between the two over
the network internally uses an SSH connection.

View File

@@ -0,0 +1,675 @@
gittutorial(7)
==============
NAME
----
gittutorial - Um tutorial de introdução ao git (para versão 1.5.1 ou mais nova)
SYNOPSIS
--------
git *
DESCRIPTION
-----------
Este tutorial explica como importar um novo projeto para o git,
adicionar mudanças a ele, e compartilhar mudanças com outros
desenvolvedores.
Se, ao invés disso, você está interessado primariamente em usar git para
obter um projeto, por exemplo, para testar a última versão, você pode
preferir começar com os primeiros dois capítulos de
link:user-manual.html[O Manual do Usuário Git].
Primeiro, note que você pode obter documentação para um comando como
`git log --graph` com:
------------------------------------------------
$ man git-log
------------------------------------------------
ou:
------------------------------------------------
$ git help log
------------------------------------------------
Com a última forma, você pode usar o visualizador de manual de sua
escolha; veja linkgit:git-help[1] para maior informação.
É uma boa idéia informar ao git seu nome e endereço público de email
antes de fazer qualquer operação. A maneira mais fácil de fazê-lo é:
------------------------------------------------
$ git config --global user.name "Seu Nome Vem Aqui"
$ git config --global user.email voce@seudominio.exemplo.com
------------------------------------------------
Importando um novo projeto
-----------------------
Assuma que você tem um tarball project.tar.gz com seu trabalho inicial.
Você pode colocá-lo sob controle de revisão git da seguinte forma:
------------------------------------------------
$ tar xzf project.tar.gz
$ cd project
$ git init
------------------------------------------------
Git irá responder
------------------------------------------------
Initialized empty Git repository in .git/
------------------------------------------------
Você agora iniciou seu diretório de trabalho--você deve ter notado um
novo diretório criado, com o nome de ".git".
A seguir, diga ao git para gravar um instantâneo do conteúdo de todos os
arquivos sob o diretório corrente (note o '.'), com 'git-add':
------------------------------------------------
$ git add .
------------------------------------------------
Este instantâneo está agora armazenado em uma área temporária que o git
chama de "index" ou índice. Você pode armazenar permanentemente o
conteúdo do índice no repositório com 'git-commit':
------------------------------------------------
$ git commit
------------------------------------------------
Isto vai te pedir por uma mensagem de commit. Você agora gravou sua
primeira versão de seu projeto no git.
Fazendo mudanças
--------------
Modifique alguns arquivos, e, então, adicione seu conteúdo atualizado ao
índice:
------------------------------------------------
$ git add file1 file2 file3
------------------------------------------------
Você está agora pronto para fazer o commit. Você pode ver o que está
para ser gravado usando 'git-diff' com a opção --cached:
------------------------------------------------
$ git diff --cached
------------------------------------------------
(Sem --cached, o comando 'git-diff' irá te mostrar quaisquer mudanças
que você tenha feito mas ainda não adicionou ao índice.) Você também
pode obter um breve sumário da situação com 'git-status':
------------------------------------------------
$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: file1
# modified: file2
# modified: file3
#
------------------------------------------------
Se você precisar fazer qualquer outro ajuste, faça-o agora, e, então,
adicione qualquer conteúdo modificado ao índice. Finalmente, grave suas
mudanças com:
------------------------------------------------
$ git commit
------------------------------------------------
Isto irá novamente te pedir por uma mensagem descrevendo a mudança, e,
então, gravar a nova versão do projeto.
Alternativamente, ao invés de executar 'git-add' antes, você pode usar
------------------------------------------------
$ git commit -a
------------------------------------------------
o que irá automaticamente notar quaisquer arquivos modificados (mas não
novos), adicioná-los ao índices, e gravar, tudo em um único passo.
Uma nota em mensagens de commit: Apesar de não ser exigido, é uma boa
idéia começar a mensagem com uma simples e curta (menos de 50
caracteres) linha sumarizando a mudança, seguida de uma linha em branco
e, então, uma descrição mais detalhada. Ferramentas que transformam
commits em email, por exemplo, usam a primeira linha no campo de
cabeçalho Subject: e o resto no corpo.
Git rastreia conteúdo, não arquivos
----------------------------
Muitos sistemas de controle de revisão provêem um comando `add` que diz
ao sistema para começar a rastrear mudanças em um novo arquivo. O
comando `add` do git faz algo mais simples e mais poderoso: 'git-add' é
usado tanto para arquivos novos e arquivos recentemente modificados, e
em ambos os casos, ele tira o instantâneo dos arquivos dados e armazena
o conteúdo no índice, pronto para inclusão do próximo commit.
Visualizando história do projeto
-----------------------
Em qualquer ponto você pode visualizar a história das suas mudanças
usando
------------------------------------------------
$ git log
------------------------------------------------
Se você também quer ver a diferença completa a cada passo, use
------------------------------------------------
$ git log -p
------------------------------------------------
Geralmente, uma visão geral da mudança é útil para ter a sensação de
cada passo
------------------------------------------------
$ git log --stat --summary
------------------------------------------------
Gerenciando "branches"/ramos
-----------------
Um simples repositório git pode manter múltiplos ramos de
desenvolvimento. Para criar um novo ramo chamado "experimental", use
------------------------------------------------
$ git branch experimental
------------------------------------------------
Se você executar agora
------------------------------------------------
$ git branch
------------------------------------------------
você vai obter uma lista de todos os ramos existentes:
------------------------------------------------
experimental
* master
------------------------------------------------
O ramo "experimental" é o que você acaba de criar, e o ramo "master" é o
ramo padrão que foi criado pra você automaticamente. O asterisco marca
o ramo em que você está atualmente; digite
------------------------------------------------
$ git checkout experimental
------------------------------------------------
para mudar para o ramo experimental. Agora edite um arquivo, grave a
mudança, e mude de volta para o ramo master:
------------------------------------------------
(edita arquivo)
$ git commit -a
$ git checkout master
------------------------------------------------
Verifique que a mudança que você fez não está mais visível, já que ela
foi feita no ramo experimental e você está de volta ao ramo master.
Você pode fazer uma mudança diferente no ramo master:
------------------------------------------------
(edit file)
$ git commit -a
------------------------------------------------
neste ponto, os dois ramos divergiram, com diferentes mudanças feitas em
cada um. Para unificar as mudanças feitas no experimental para o
master, execute
------------------------------------------------
$ git merge experimental
------------------------------------------------
Se as mudanças não conflitarem, estará pronto. Se existirem conflitos,
marcadores serão deixados nos arquivos problemáticos exibindo o
conflito;
------------------------------------------------
$ git diff
------------------------------------------------
vai exibir isto. Após você editar os arquivos para resolver os
conflitos,
------------------------------------------------
$ git commit -a
------------------------------------------------
irá gravar o resultado da unificação. Finalmente,
------------------------------------------------
$ gitk
------------------------------------------------
vai mostrar uma bela representação gráfica da história resultante.
Neste ponto você pode remover seu ramo experimental com
------------------------------------------------
$ git branch -d experimental
------------------------------------------------
Este comando garante que as mudanças no ramo experimental já estão no
ramo atual.
Se você desenvolve em um ramo ideia-louca, e se arrepende, você pode
sempre remover o ramo com
-------------------------------------
$ git branch -D ideia-louca
-------------------------------------
Ramos são baratos e fáceis, então isto é uma boa maneira de experimentar
alguma coisa.
Usando git para colaboração
---------------------------
Suponha que Alice começou um novo projeto com um repositório git em
/home/alice/project, e que Bob, que tem um diretório home na mesma
máquina, quer contribuir.
Bob começa com:
------------------------------------------------
bob$ git clone /home/alice/project myrepo
------------------------------------------------
Isso cria um novo diretório "myrepo" contendo um clone do repositório de
Alice. O clone está no mesmo pé que o projeto original, possuindo sua
própria cópia da história do projeto original.
Bob então faz algumas mudanças e as grava:
------------------------------------------------
(editar arquivos)
bob$ git commit -a
(repetir conforme necessário)
------------------------------------------------
Quanto está pronto, ele diz a Alice para puxar as mudanças do
repositório em /home/bob/myrepo. Ela o faz com:
------------------------------------------------
alice$ cd /home/alice/project
alice$ git pull /home/bob/myrepo master
------------------------------------------------
Isto unifica as mudanças do ramo "master" do Bob ao ramo atual de Alice.
Se Alice fez suas próprias mudanças no intervalo, ela, então, pode
precisar corrigir manualmente quaisquer conflitos. (Note que o argumento
"master" no comando acima é, de fato, desnecessário, já que é o padrão.)
O comando "pull" executa, então, duas operações: ele obtém mudanças de
um ramo remoto, e, então, as unifica no ramo atual.
Note que, em geral, Alice gostaria que suas mudanças locais fossem
gravadas antes de iniciar este "pull". Se o trabalho de Bob conflita
com o que Alice fez desde que suas histórias se ramificaram, Alice irá
usar seu diretório de trabalho e o índice para resolver conflitos, e
mudanças locais existentes irão interferir com o processo de resolução
de conflitos (git ainda irá realizar a obtenção mas irá se recusar a
unificar --- Alice terá que se livrar de suas mudanças locais de alguma
forma e puxar de novo quando isso acontecer).
Alice pode espiar o que Bob fez sem unificar primeiro, usando o comando
"fetch"; isto permite Alice inspecionar o que Bob fez, usando um símbolo
especial "FETCH_HEAD", com o fim de determinar se ele tem alguma coisa
que vale puxar, assim:
------------------------------------------------
alice$ git fetch /home/bob/myrepo master
alice$ git log -p HEAD..FETCH_HEAD
------------------------------------------------
Esta operação é segura mesmo se Alice tem mudanças locais não gravadas.
A notação de intervalo "HEAD..FETCH_HEAD" significa mostrar tudo que é
alcançável de FETCH_HEAD mas exclua tudo o que é alcançável de HEAD.
Alice já sabe tudo que leva a seu estado atual (HEAD), e revisa o que Bob
tem em seu estado (FETCH_HEAD) que ela ainda não viu com esse comando.
Se Alice quer visualizar o que Bob fez desde que suas histórias se
ramificaram, ela pode disparar o seguinte comando:
------------------------------------------------
$ gitk HEAD..FETCH_HEAD
------------------------------------------------
Isto usa a mesma notação de intervalo que vimos antes com 'git log'.
Alice pode querer ver o que ambos fizeram desde que ramificaram. Ela
pode usar a forma com três pontos ao invés da forma com dois pontos:
------------------------------------------------
$ gitk HEAD...FETCH_HEAD
------------------------------------------------
Isto significa "mostre tudo que é alcançável de qualquer um deles, mas
exclua tudo que é alcançável a partir de ambos".
Por favor, note que essas notações de intervalo podem ser usadas tanto
com gitk quanto com "git log".
Após inspecionar o que Bob fez, se não há nada urgente, Alice pode
decidir continuar trabalhando sem puxar de Bob. Se a história de Bob
tem alguma coisa que Alice precisa imediatamente, Alice pode optar por
separar seu trabalho em progresso primeiro, fazer um "pull", e, então,
finalmente, retomar seu trabalho em progresso em cima da história
resultante.
Quando você está trabalhando em um pequeno grupo unido, não é incomum
interagir com o mesmo repositório várias e várias vezes. Definindo um
repositório remoto antes de tudo, você pode fazê-lo mais facilmente:
------------------------------------------------
alice$ git remote add bob /home/bob/myrepo
------------------------------------------------
Com isso, Alice pode executar a primeira parte da operação "pull" usando
o comando 'git-fetch' sem unificar suas mudanças com seu próprio ramo,
usando:
-------------------------------------
alice$ git fetch bob
-------------------------------------
Diferente da forma longa, quando Alice obteve de Bob usando um
repositório remoto antes definido com 'git-remote', o que foi obtido é
armazenado em um ramo remoto, neste caso `bob/master`. Então, após isso:
-------------------------------------
alice$ git log -p master..bob/master
-------------------------------------
mostra uma lista de todas as mudanças que Bob fez desde que ramificou do
ramo master de Alice.
Após examinar essas mudanças, Alice pode unificá-las em seu ramo master:
-------------------------------------
alice$ git merge bob/master
-------------------------------------
Esse `merge` pode também ser feito puxando de seu próprio ramo remoto,
assim:
-------------------------------------
alice$ git pull . remotes/bob/master
-------------------------------------
Note que 'git pull' sempre unifica ao ramo atual, independente do que
mais foi passado na linha de comando.
Depois, Bob pode atualizar seu repositório com as últimas mudanças de
Alice, usando
-------------------------------------
bob$ git pull
-------------------------------------
Note que ele não precisa dar o caminho do repositório de Alice; quando
Bob clonou seu repositório, o git armazenou a localização de seu
repositório na configuração do mesmo, e essa localização é usada
para puxar:
-------------------------------------
bob$ git config --get remote.origin.url
/home/alice/project
-------------------------------------
(A configuração completa criada por 'git-clone' é visível usando `git
config -l`, e a página de manual linkgit:git-config[1] explica o
significado de cada opção.)
Git também mantém uma cópia limpa do ramo master de Alice sob o nome
"origin/master":
-------------------------------------
bob$ git branch -r
origin/master
-------------------------------------
Se Bob decidir depois em trabalhar em um host diferente, ele ainda pode
executar clones e puxar usando o protocolo ssh:
-------------------------------------
bob$ git clone alice.org:/home/alice/project myrepo
-------------------------------------
Alternativamente, o git tem um protocolo nativo, ou pode usar rsync ou
http; veja linkgit:git-pull[1] para detalhes.
Git pode também ser usado em um modo parecido com CVS, com um
repositório central para o qual vários usuários empurram modificações;
veja linkgit:git-push[1] e linkgit:gitcvs-migration[7].
Explorando história
-----------------
A história no git é representada como uma série de commits
interrelacionados. Nós já vimos que o comando 'git-log' pode listar
esses commits. Note que a primeira linha de cada entrada no log também
dá o nome para o commit:
-------------------------------------
$ git log
commit c82a22c39cbc32576f64f5c6b3f24b99ea8149c7
Author: Junio C Hamano <junkio@cox.net>
Date: Tue May 16 17:18:22 2006 -0700
merge-base: Clarify the comments on post processing.
-------------------------------------
Nós podemos dar este nome ao 'git-show' para ver os detalhes sobre este
commit.
-------------------------------------
$ git show c82a22c39cbc32576f64f5c6b3f24b99ea8149c7
-------------------------------------
Mas há outras formas de se referir aos commits. Você pode usar qualquer
parte inicial do nome que seja longo o bastante para identificar
unicamente o commit:
-------------------------------------
$ git show c82a22c39c # os primeiros caracteres do nome são o bastante
# usualmente
$ git show HEAD # a ponta do ramo atual
$ git show experimental # a ponta do ramo "experimental"
-------------------------------------
Todo commit normalmente tem um commit "pai" que aponta para o estado
anterior do projeto:
-------------------------------------
$ git show HEAD^ # para ver o pai de HEAD
$ git show HEAD^^ # para ver o avô de HEAD
$ git show HEAD~4 # para ver o trisavô de HEAD
-------------------------------------
Note que commits de unificação podem ter mais de um pai:
-------------------------------------
$ git show HEAD^1 # mostra o primeiro pai de HEAD (o mesmo que HEAD^)
$ git show HEAD^2 # mostra o segundo pai de HEAD
-------------------------------------
Você também pode dar aos commits nomes à sua escolha; após executar
-------------------------------------
$ git tag v2.5 1b2e1d63ff
-------------------------------------
você pode se referir a 1b2e1d63ff pelo nome "v2.5". Se você pretende
compartilhar esse nome com outras pessoas (por exemplo, para identificar
uma versão de lançamento), você deveria criar um objeto "tag", e talvez
assiná-lo; veja linkgit:git-tag[1] para detalhes.
Qualquer comando git que precise conhecer um commit pode receber
quaisquer desses nomes. Por exemplo:
-------------------------------------
$ git diff v2.5 HEAD # compara o HEAD atual com v2.5
$ git branch stable v2.5 # inicia um novo ramo chamado "stable" baseado
# em v2.5
$ git reset --hard HEAD^ # reseta seu ramo atual e seu diretório de
# trabalho a seu estado em HEAD^
-------------------------------------
Seja cuidadoso com o último comando: além de perder quaisquer mudanças
em seu diretório de trabalho, ele também remove todos os commits
posteriores desse ramo. Se esse ramo é o único ramo contendo esses
commits, eles serão perdidos. Também, não use 'git-reset' num ramo
publicamente visível de onde outros desenvolvedores puxam, já que vai
forçar unificações desnecessárias para que outros desenvolvedores limpem
a história. Se você precisa desfazer mudanças que você empurrou, use
'git-revert' no lugar.
O comando 'git-grep' pode buscar strings em qualquer versão de seu
projeto, então
-------------------------------------
$ git grep "hello" v2.5
-------------------------------------
procura por todas as ocorrências de "hello" em v2.5.
Se você deixar de fora o nome do commit, 'git-grep' irá procurar
quaisquer dos arquivos que ele gerencia no diretório corrente. Então
-------------------------------------
$ git grep "hello"
-------------------------------------
é uma forma rápida de buscar somente os arquivos que são rastreados pelo
git.
Muitos comandos git também recebem um conjunto de commits, o que pode
ser especificado de várias formas. Aqui estão alguns exemplos com 'git-log':
-------------------------------------
$ git log v2.5..v2.6 # commits entre v2.5 e v2.6
$ git log v2.5.. # commits desde v2.5
$ git log --since="2 weeks ago" # commits das últimas 2 semanas
$ git log v2.5.. Makefile # commits desde v2.5 que modificam
# Makefile
-------------------------------------
Você também pode dar ao 'git-log' um "intervalo" de commits onde o
primeiro não é necessariamente um ancestral do segundo; por exemplo, se
as pontas dos ramos "stable" e "master" divergiram de um commit
comum algum tempo atrás, então
-------------------------------------
$ git log stable..master
-------------------------------------
irá listar os commits feitos no ramo "master" mas não no ramo
"stable", enquanto
-------------------------------------
$ git log master..stable
-------------------------------------
irá listar a lista de commits feitos no ramo "stable" mas não no ramo
"master".
O comando 'git-log' tem uma fraqueza: ele precisa mostrar os commits em
uma lista. Quando a história tem linhas de desenvolvimento que
divergiram e então foram unificadas novamente, a ordem em que 'git-log'
apresenta essas mudanças é irrelevante.
A maioria dos projetos com múltiplos contribuidores (como o kernel
Linux, ou o próprio git) tem unificações frequentes, e 'gitk' faz um
trabalho melhor de visualizar sua história. Por exemplo,
-------------------------------------
$ gitk --since="2 weeks ago" drivers/
-------------------------------------
permite a você navegar em quaisquer commits desde as últimas duas semanas
de commits que modificaram arquivos sob o diretório "drivers". (Nota:
você pode ajustar as fontes do gitk segurando a tecla control enquanto
pressiona "-" ou "+".)
Finalmente, a maioria dos comandos que recebem nomes de arquivo permitirão
também, opcionalmente, preceder qualquer nome de arquivo por um
commit, para especificar uma versão particular do arquivo:
-------------------------------------
$ git diff v2.5:Makefile HEAD:Makefile.in
-------------------------------------
Você pode usar 'git-show' para ver tal arquivo:
-------------------------------------
$ git show v2.5:Makefile
-------------------------------------
Próximos passos
----------
Este tutorial deve ser o bastante para operar controle de revisão
distribuído básico para seus projetos. No entanto, para entender
plenamente a profundidade e o poder do git você precisa entender duas
idéias simples nas quais ele se baseia:
* A base de objetos é um sistema bem elegante usado para armazenar a
história de seu projeto--arquivos, diretórios, e commits.
* O arquivo de índice é um cache do estado de uma árvore de diretório,
usado para criar commits, restaurar diretórios de trabalho, e
armazenar as várias árvores envolvidas em uma unificação.
A parte dois deste tutorial explica a base de objetos, o arquivo de
índice, e algumas outras coisinhas que você vai precisar pra usar o
máximo do git. Você pode encontrá-la em linkgit:gittutorial-2[7].
Se você não quiser continuar com o tutorial agora nesse momento, algumas
outras digressões que podem ser interessantes neste ponto são:
* linkgit:git-format-patch[1], linkgit:git-am[1]: Estes convertem
séries de commits em patches para email, e vice-versa, úteis para
projetos como o kernel Linux que dependem fortemente de patches
enviados por email.
* linkgit:git-bisect[1]: Quando há uma regressão em seu projeto, uma
forma de rastrear um bug é procurando pela história para encontrar o
commit culpado. Git bisect pode ajudar a executar uma busca binária
por esse commit. Ele é inteligente o bastante para executar uma
busca próxima da ótima mesmo no caso de uma história complexa
não-linear com muitos ramos unificados.
* link:everyday.html[GIT diariamente com 20 e tantos comandos]
* linkgit:gitcvs-migration[7]: Git para usuários de CVS.
VEJA TAMBÉM
--------
linkgit:gittutorial-2[7],
linkgit:gitcvs-migration[7],
linkgit:gitcore-tutorial[7],
linkgit:gitglossary[7],
linkgit:git-help[1],
link:everyday.html[git diariamente],
link:user-manual.html[O Manual do Usuário git]
GIT
---
Parte da suite linkgit:git[1].

View File

@@ -35,12 +35,32 @@ Functions
Convenience functions that encapsulate a sequence of
start_command() followed by finish_command(). The argument argv
specifies the program and its arguments. The argument opt is zero
or more of the flags `RUN_COMMAND_NO_STDIN`, `RUN_GIT_CMD`, or
`RUN_COMMAND_STDOUT_TO_STDERR` that correspond to the members
.no_stdin, .git_cmd, .stdout_to_stderr of `struct child_process`.
or more of the flags `RUN_COMMAND_NO_STDIN`, `RUN_GIT_CMD`,
`RUN_COMMAND_STDOUT_TO_STDERR`, or `RUN_SILENT_EXEC_FAILURE`
that correspond to the members .no_stdin, .git_cmd,
.stdout_to_stderr, .silent_exec_failure of `struct child_process`.
The argument dir corresponds the member .dir. The argument env
corresponds to the member .env.
The functions above do the following:
. If a system call failed, errno is set and -1 is returned. A diagnostic
is printed.
. If the program was not found, then -1 is returned and errno is set to
ENOENT; a diagnostic is printed only if .silent_exec_failure is 0.
. Otherwise, the program is run. If it terminates regularly, its exit
code is returned. No diagnistic is printed, even if the exit code is
non-zero.
. If the program terminated due to a signal, then the return value is the
signal number - 128, ie. it is negative and so indicates an unusual
condition; a diagnostic is printed. This return value can be passed to
exit(2), which will report the same code to the parent process that a
POSIX shell's $? would report for a program that died from the signal.
`start_async`::
Run a function asynchronously. Takes a pointer to a `struct
@@ -143,6 +163,11 @@ string pointers (NULL terminated) in .env:
To specify a new initial working directory for the sub-process,
specify it in the .dir member.
If the program cannot be found, the functions return -1 and set
errno to ENOENT. Normally, an error message is printed, but if
.silent_exec_failure is set to 1, no message is printed for this
special error condition.
* `struct async`

View File

@@ -1,12 +1,145 @@
tree walking API
================
Talk about <tree-walk.h>, things like
The tree walking API is used to traverse and inspect trees.
* struct tree_desc
* init_tree_desc
* tree_entry_extract
* update_tree_entry
* get_tree_entry
Data Structures
---------------
(JC, Linus)
`struct name_entry`::
An entry in a tree. Each entry has a sha1 identifier, pathname, and
mode.
`struct tree_desc`::
A semi-opaque data structure used to maintain the current state of the
walk.
+
* `buffer` is a pointer into the memory representation of the tree. It always
points at the current entry being visited.
* `size` counts the number of bytes left in the `buffer`.
* `entry` points to the current entry being visited.
`struct traverse_info`::
A structure used to maintain the state of a traversal.
+
* `prev` points to the traverse_info which was used to descend into the
current tree. If this is the top-level tree `prev` will point to
a dummy traverse_info.
* `name` is the entry for the current tree (if the tree is a subtree).
* `pathlen` is the length of the full path for the current tree.
* `conflicts` can be used by callbacks to maintain directory-file conflicts.
* `fn` is a callback called for each entry in the tree. See Traversing for more
information.
* `data` can be anything the `fn` callback would want to use.
Initializing
------------
`init_tree_desc`::
Initialize a `tree_desc` and decode its first entry. The buffer and
size parameters are assumed to be the same as the buffer and size
members of `struct tree`.
`fill_tree_descriptor`::
Initialize a `tree_desc` and decode its first entry given the sha1 of
a tree. Returns the `buffer` member if the sha1 is a valid tree
identifier and NULL otherwise.
`setup_traverse_info`::
Initialize a `traverse_info` given the pathname of the tree to start
traversing from. The `base` argument is assumed to be the `path`
member of the `name_entry` being recursed into unless the tree is a
top-level tree in which case the empty string ("") is used.
Walking
-------
`tree_entry`::
Visit the next entry in a tree. Returns 1 when there are more entries
left to visit and 0 when all entries have been visited. This is
commonly used in the test of a while loop.
`tree_entry_len`::
Calculate the length of a tree entry's pathname. This utilizes the
memory structure of a tree entry to avoid the overhead of using a
generic strlen().
`update_tree_entry`::
Walk to the next entry in a tree. This is commonly used in conjunction
with `tree_entry_extract` to inspect the current entry.
`tree_entry_extract`::
Decode the entry currently being visited (the one pointed to by
`tree_desc's` `entry` member) and return the sha1 of the entry. The
`pathp` and `modep` arguments are set to the entry's pathname and mode
respectively.
`get_tree_entry`::
Find an entry in a tree given a pathname and the sha1 of a tree to
search. Returns 0 if the entry is found and -1 otherwise. The third
and fourth parameters are set to the entry's sha1 and mode
respectively.
Traversing
----------
`traverse_trees`::
Traverse `n` number of trees in parallel. The `fn` callback member of
`traverse_info` is called once for each tree entry.
`traverse_callback_t`::
The arguments passed to the traverse callback are as follows:
+
* `n` counts the number of trees being traversed.
* `mask` has its nth bit set if something exists in the nth entry.
* `dirmask` has its nth bit set if the nth tree's entry is a directory.
* `entry` is an array of size `n` where the nth entry is from the nth tree.
* `info` maintains the state of the traversal.
+
Returning a negative value will terminate the traversal. Otherwise the
return value is treated as an update mask. If the nth bit is set the nth tree
will be updated and if the bit is not set the nth tree entry will be the
same in the next callback invocation.
`make_traverse_path`::
Generate the full pathname of a tree entry based from the root of the
traversal. For example, if the traversal has recursed into another
tree named "bar" the pathname of an entry "baz" in the "bar"
tree would be "bar/baz".
`traverse_path_len`::
Calculate the length of a pathname returned by `make_traverse_path`.
This utilizes the memory structure of a tree entry to avoid the
overhead of using a generic strlen().
Authors
-------
Written by Junio C Hamano <gitster@pobox.com> and Linus Torvalds
<torvalds@linux-foundation.org>

View File

@@ -4131,7 +4131,7 @@ What does this mean?
`git rev-list` is the original version of the revision walker, which
_always_ printed a list of revisions to stdout. It is still functional,
and needs to, since most new Git programs start out as scripts using
and needs to, since most new Git commands start out as scripts using
`git rev-list`.
`git rev-parse` is not as important any more; it was only used to filter out

View File

@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
DEF_VER=v1.6.4
DEF_VER=v1.6.4.GIT
LF='
'

View File

@@ -84,6 +84,10 @@ all::
# specify your own (or DarwinPort's) include directories and
# library directories by defining CFLAGS and LDFLAGS appropriately.
#
# Define BLK_SHA1 environment variable if you want the C version
# of the SHA1 that assumes you can do unaligned 32-bit loads and
# have a fast htonl() function.
#
# Define PPC_SHA1 environment variable when running make to make use of
# a bundled SHA1 routine optimized for PowerPC.
#
@@ -1167,6 +1171,10 @@ ifdef NO_DEFLATE_BOUND
BASIC_CFLAGS += -DNO_DEFLATE_BOUND
endif
ifdef BLK_SHA1
SHA1_HEADER = "block-sha1/sha1.h"
LIB_OBJS += block-sha1/sha1.o
else
ifdef PPC_SHA1
SHA1_HEADER = "ppc/sha1.h"
LIB_OBJS += ppc/sha1.o ppc/sha1ppc.o
@@ -1184,6 +1192,7 @@ else
endif
endif
endif
endif
ifdef NO_PERL_MAKEMAKER
export NO_PERL_MAKEMAKER
endif

View File

@@ -1 +1 @@
Documentation/RelNotes-1.6.4.txt
Documentation/RelNotes-1.6.5.txt

280
block-sha1/sha1.c Normal file
View File

@@ -0,0 +1,280 @@
/*
* Based on the Mozilla SHA1 (see mozilla-sha1/sha1.c),
* optimized to do word accesses rather than byte accesses,
* and to avoid unnecessary copies into the context array.
*/
#include <string.h>
#include <arpa/inet.h>
#include "sha1.h"
#if defined(__i386__) || defined(__x86_64__)
/*
* Force usage of rol or ror by selecting the one with the smaller constant.
* It _can_ generate slightly smaller code (a constant of 1 is special), but
* perhaps more importantly it's possibly faster on any uarch that does a
* rotate with a loop.
*/
#define SHA_ASM(op, x, n) ({ unsigned int __res; __asm__(op " %1,%0":"=r" (__res):"i" (n), "0" (x)); __res; })
#define SHA_ROL(x,n) SHA_ASM("rol", x, n)
#define SHA_ROR(x,n) SHA_ASM("ror", x, n)
#else
#define SHA_ROT(X,l,r) (((X) << (l)) | ((X) >> (r)))
#define SHA_ROL(X,n) SHA_ROT(X,n,32-(n))
#define SHA_ROR(X,n) SHA_ROT(X,32-(n),n)
#endif
/*
* If you have 32 registers or more, the compiler can (and should)
* try to change the array[] accesses into registers. However, on
* machines with less than ~25 registers, that won't really work,
* and at least gcc will make an unholy mess of it.
*
* So to avoid that mess which just slows things down, we force
* the stores to memory to actually happen (we might be better off
* with a 'W(t)=(val);asm("":"+m" (W(t))' there instead, as
* suggested by Artur Skawina - that will also make gcc unable to
* try to do the silly "optimize away loads" part because it won't
* see what the value will be).
*
* Ben Herrenschmidt reports that on PPC, the C version comes close
* to the optimized asm with this (ie on PPC you don't want that
* 'volatile', since there are lots of registers).
*
* On ARM we get the best code generation by forcing a full memory barrier
* between each SHA_ROUND, otherwise gcc happily get wild with spilling and
* the stack frame size simply explode and performance goes down the drain.
*/
#if defined(__i386__) || defined(__x86_64__)
#define setW(x, val) (*(volatile unsigned int *)&W(x) = (val))
#elif defined(__arm__)
#define setW(x, val) do { W(x) = (val); __asm__("":::"memory"); } while (0)
#else
#define setW(x, val) (W(x) = (val))
#endif
/*
* Performance might be improved if the CPU architecture is OK with
* unaligned 32-bit loads and a fast ntohl() is available.
* Otherwise fall back to byte loads and shifts which is portable,
* and is faster on architectures with memory alignment issues.
*/
#if defined(__i386__) || defined(__x86_64__) || \
defined(__ppc__) || defined(__ppc64__) || \
defined(__powerpc__) || defined(__powerpc64__) || \
defined(__s390__) || defined(__s390x__)
#define get_be32(p) ntohl(*(unsigned int *)(p))
#define put_be32(p, v) do { *(unsigned int *)(p) = htonl(v); } while (0)
#else
#define get_be32(p) ( \
(*((unsigned char *)(p) + 0) << 24) | \
(*((unsigned char *)(p) + 1) << 16) | \
(*((unsigned char *)(p) + 2) << 8) | \
(*((unsigned char *)(p) + 3) << 0) )
#define put_be32(p, v) do { \
unsigned int __v = (v); \
*((unsigned char *)(p) + 0) = __v >> 24; \
*((unsigned char *)(p) + 1) = __v >> 16; \
*((unsigned char *)(p) + 2) = __v >> 8; \
*((unsigned char *)(p) + 3) = __v >> 0; } while (0)
#endif
/* This "rolls" over the 512-bit array */
#define W(x) (array[(x)&15])
/*
* Where do we get the source from? The first 16 iterations get it from
* the input data, the next mix it from the 512-bit array.
*/
#define SHA_SRC(t) get_be32(data + t)
#define SHA_MIX(t) SHA_ROL(W(t+13) ^ W(t+8) ^ W(t+2) ^ W(t), 1)
#define SHA_ROUND(t, input, fn, constant, A, B, C, D, E) do { \
unsigned int TEMP = input(t); setW(t, TEMP); \
E += TEMP + SHA_ROL(A,5) + (fn) + (constant); \
B = SHA_ROR(B, 2); } while (0)
#define T_0_15(t, A, B, C, D, E) SHA_ROUND(t, SHA_SRC, (((C^D)&B)^D) , 0x5a827999, A, B, C, D, E )
#define T_16_19(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (((C^D)&B)^D) , 0x5a827999, A, B, C, D, E )
#define T_20_39(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) , 0x6ed9eba1, A, B, C, D, E )
#define T_40_59(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, ((B&C)+(D&(B^C))) , 0x8f1bbcdc, A, B, C, D, E )
#define T_60_79(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) , 0xca62c1d6, A, B, C, D, E )
static void blk_SHA1_Block(blk_SHA_CTX *ctx, const unsigned int *data)
{
unsigned int A,B,C,D,E;
unsigned int array[16];
A = ctx->H[0];
B = ctx->H[1];
C = ctx->H[2];
D = ctx->H[3];
E = ctx->H[4];
/* Round 1 - iterations 0-16 take their input from 'data' */
T_0_15( 0, A, B, C, D, E);
T_0_15( 1, E, A, B, C, D);
T_0_15( 2, D, E, A, B, C);
T_0_15( 3, C, D, E, A, B);
T_0_15( 4, B, C, D, E, A);
T_0_15( 5, A, B, C, D, E);
T_0_15( 6, E, A, B, C, D);
T_0_15( 7, D, E, A, B, C);
T_0_15( 8, C, D, E, A, B);
T_0_15( 9, B, C, D, E, A);
T_0_15(10, A, B, C, D, E);
T_0_15(11, E, A, B, C, D);
T_0_15(12, D, E, A, B, C);
T_0_15(13, C, D, E, A, B);
T_0_15(14, B, C, D, E, A);
T_0_15(15, A, B, C, D, E);
/* Round 1 - tail. Input from 512-bit mixing array */
T_16_19(16, E, A, B, C, D);
T_16_19(17, D, E, A, B, C);
T_16_19(18, C, D, E, A, B);
T_16_19(19, B, C, D, E, A);
/* Round 2 */
T_20_39(20, A, B, C, D, E);
T_20_39(21, E, A, B, C, D);
T_20_39(22, D, E, A, B, C);
T_20_39(23, C, D, E, A, B);
T_20_39(24, B, C, D, E, A);
T_20_39(25, A, B, C, D, E);
T_20_39(26, E, A, B, C, D);
T_20_39(27, D, E, A, B, C);
T_20_39(28, C, D, E, A, B);
T_20_39(29, B, C, D, E, A);
T_20_39(30, A, B, C, D, E);
T_20_39(31, E, A, B, C, D);
T_20_39(32, D, E, A, B, C);
T_20_39(33, C, D, E, A, B);
T_20_39(34, B, C, D, E, A);
T_20_39(35, A, B, C, D, E);
T_20_39(36, E, A, B, C, D);
T_20_39(37, D, E, A, B, C);
T_20_39(38, C, D, E, A, B);
T_20_39(39, B, C, D, E, A);
/* Round 3 */
T_40_59(40, A, B, C, D, E);
T_40_59(41, E, A, B, C, D);
T_40_59(42, D, E, A, B, C);
T_40_59(43, C, D, E, A, B);
T_40_59(44, B, C, D, E, A);
T_40_59(45, A, B, C, D, E);
T_40_59(46, E, A, B, C, D);
T_40_59(47, D, E, A, B, C);
T_40_59(48, C, D, E, A, B);
T_40_59(49, B, C, D, E, A);
T_40_59(50, A, B, C, D, E);
T_40_59(51, E, A, B, C, D);
T_40_59(52, D, E, A, B, C);
T_40_59(53, C, D, E, A, B);
T_40_59(54, B, C, D, E, A);
T_40_59(55, A, B, C, D, E);
T_40_59(56, E, A, B, C, D);
T_40_59(57, D, E, A, B, C);
T_40_59(58, C, D, E, A, B);
T_40_59(59, B, C, D, E, A);
/* Round 4 */
T_60_79(60, A, B, C, D, E);
T_60_79(61, E, A, B, C, D);
T_60_79(62, D, E, A, B, C);
T_60_79(63, C, D, E, A, B);
T_60_79(64, B, C, D, E, A);
T_60_79(65, A, B, C, D, E);
T_60_79(66, E, A, B, C, D);
T_60_79(67, D, E, A, B, C);
T_60_79(68, C, D, E, A, B);
T_60_79(69, B, C, D, E, A);
T_60_79(70, A, B, C, D, E);
T_60_79(71, E, A, B, C, D);
T_60_79(72, D, E, A, B, C);
T_60_79(73, C, D, E, A, B);
T_60_79(74, B, C, D, E, A);
T_60_79(75, A, B, C, D, E);
T_60_79(76, E, A, B, C, D);
T_60_79(77, D, E, A, B, C);
T_60_79(78, C, D, E, A, B);
T_60_79(79, B, C, D, E, A);
ctx->H[0] += A;
ctx->H[1] += B;
ctx->H[2] += C;
ctx->H[3] += D;
ctx->H[4] += E;
}
void blk_SHA1_Init(blk_SHA_CTX *ctx)
{
ctx->size = 0;
/* Initialize H with the magic constants (see FIPS180 for constants) */
ctx->H[0] = 0x67452301;
ctx->H[1] = 0xefcdab89;
ctx->H[2] = 0x98badcfe;
ctx->H[3] = 0x10325476;
ctx->H[4] = 0xc3d2e1f0;
}
void blk_SHA1_Update(blk_SHA_CTX *ctx, const void *data, unsigned long len)
{
int lenW = ctx->size & 63;
ctx->size += len;
/* Read the data into W and process blocks as they get full */
if (lenW) {
int left = 64 - lenW;
if (len < left)
left = len;
memcpy(lenW + (char *)ctx->W, data, left);
lenW = (lenW + left) & 63;
len -= left;
data = ((const char *)data + left);
if (lenW)
return;
blk_SHA1_Block(ctx, ctx->W);
}
while (len >= 64) {
blk_SHA1_Block(ctx, data);
data = ((const char *)data + 64);
len -= 64;
}
if (len)
memcpy(ctx->W, data, len);
}
void blk_SHA1_Final(unsigned char hashout[20], blk_SHA_CTX *ctx)
{
static const unsigned char pad[64] = { 0x80 };
unsigned int padlen[2];
int i;
/* Pad with a binary 1 (ie 0x80), then zeroes, then length */
padlen[0] = htonl(ctx->size >> 29);
padlen[1] = htonl(ctx->size << 3);
i = ctx->size & 63;
blk_SHA1_Update(ctx, pad, 1+ (63 & (55 - i)));
blk_SHA1_Update(ctx, padlen, 8);
/* Output hash */
for (i = 0; i < 5; i++)
put_be32(hashout + i*4, ctx->H[i]);
}

20
block-sha1/sha1.h Normal file
View File

@@ -0,0 +1,20 @@
/*
* Based on the Mozilla SHA1 (see mozilla-sha1/sha1.h),
* optimized to do word accesses rather than byte accesses,
* and to avoid unnecessary copies into the context array.
*/
typedef struct {
unsigned int H[5];
unsigned int W[16];
unsigned long long size;
} blk_SHA_CTX;
void blk_SHA1_Init(blk_SHA_CTX *ctx);
void blk_SHA1_Update(blk_SHA_CTX *ctx, const void *dataIn, unsigned long len);
void blk_SHA1_Final(unsigned char hashout[20], blk_SHA_CTX *ctx);
#define git_SHA_CTX blk_SHA_CTX
#define git_SHA1_Init blk_SHA1_Init
#define git_SHA1_Update blk_SHA1_Update
#define git_SHA1_Final blk_SHA1_Final

View File

@@ -457,6 +457,76 @@ static int guess_p_value(const char *nameline)
return val;
}
/*
* Does the ---/+++ line has the POSIX timestamp after the last HT?
* GNU diff puts epoch there to signal a creation/deletion event. Is
* this such a timestamp?
*/
static int has_epoch_timestamp(const char *nameline)
{
/*
* We are only interested in epoch timestamp; any non-zero
* fraction cannot be one, hence "(\.0+)?" in the regexp below.
* For the same reason, the date must be either 1969-12-31 or
* 1970-01-01, and the seconds part must be "00".
*/
const char stamp_regexp[] =
"^(1969-12-31|1970-01-01)"
" "
"[0-2][0-9]:[0-5][0-9]:00(\\.0+)?"
" "
"([-+][0-2][0-9][0-5][0-9])\n";
const char *timestamp = NULL, *cp;
static regex_t *stamp;
regmatch_t m[10];
int zoneoffset;
int hourminute;
int status;
for (cp = nameline; *cp != '\n'; cp++) {
if (*cp == '\t')
timestamp = cp + 1;
}
if (!timestamp)
return 0;
if (!stamp) {
stamp = xmalloc(sizeof(*stamp));
if (regcomp(stamp, stamp_regexp, REG_EXTENDED)) {
warning("Cannot prepare timestamp regexp %s",
stamp_regexp);
return 0;
}
}
status = regexec(stamp, timestamp, ARRAY_SIZE(m), m, 0);
if (status) {
if (status != REG_NOMATCH)
warning("regexec returned %d for input: %s",
status, timestamp);
return 0;
}
zoneoffset = strtol(timestamp + m[3].rm_so + 1, NULL, 10);
zoneoffset = (zoneoffset / 100) * 60 + (zoneoffset % 100);
if (timestamp[m[3].rm_so] == '-')
zoneoffset = -zoneoffset;
/*
* YYYY-MM-DD hh:mm:ss must be from either 1969-12-31
* (west of GMT) or 1970-01-01 (east of GMT)
*/
if ((zoneoffset < 0 && memcmp(timestamp, "1969-12-31", 10)) ||
(0 <= zoneoffset && memcmp(timestamp, "1970-01-01", 10)))
return 0;
hourminute = (strtol(timestamp + 11, NULL, 10) * 60 +
strtol(timestamp + 14, NULL, 10) -
zoneoffset);
return ((zoneoffset < 0 && hourminute == 1440) ||
(0 <= zoneoffset && !hourminute));
}
/*
* Get the name etc info from the ---/+++ lines of a traditional patch header
*
@@ -493,7 +563,17 @@ static void parse_traditional_patch(const char *first, const char *second, struc
} else {
name = find_name(first, NULL, p_value, TERM_SPACE | TERM_TAB);
name = find_name(second, name, p_value, TERM_SPACE | TERM_TAB);
patch->old_name = patch->new_name = name;
if (has_epoch_timestamp(first)) {
patch->is_new = 1;
patch->is_delete = 0;
patch->new_name = name;
} else if (has_epoch_timestamp(second)) {
patch->is_new = 0;
patch->is_delete = 1;
patch->old_name = name;
} else {
patch->old_name = patch->new_name = name;
}
}
if (!name)
die("unable to find filename in patch at line %d", linenr);

View File

@@ -31,6 +31,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
int i;
int show_only = 0, remove_directories = 0, quiet = 0, ignored = 0;
int ignored_only = 0, baselen = 0, config_set = 0, errors = 0;
int rm_flags = REMOVE_DIR_KEEP_NESTED_GIT;
struct strbuf directory = STRBUF_INIT;
struct dir_struct dir;
static const char **pathspec;
@@ -69,6 +70,9 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
die("clean.requireForce%s set and -n or -f not given; "
"refusing to clean", config_set ? "" : " not");
if (force > 1)
rm_flags = 0;
dir.flags |= DIR_SHOW_OTHER_DIRECTORIES;
if (!ignored)
@@ -131,7 +135,8 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
(matches == MATCHED_EXACTLY)) {
if (!quiet)
printf("Removing %s\n", qname);
if (remove_dir_recursively(&directory, 0) != 0) {
if (remove_dir_recursively(&directory,
rm_flags) != 0) {
warning("failed to remove '%s'", qname);
errors++;
}

View File

@@ -20,6 +20,7 @@ static int tags; /* Allow lightweight tags */
static int longformat;
static int abbrev = DEFAULT_ABBREV;
static int max_candidates = 10;
static int found_names;
static const char *pattern;
static int always;
@@ -49,6 +50,7 @@ static void add_to_known_names(const char *path,
memcpy(e->path, path, len);
commit->util = e;
}
found_names = 1;
}
static int get_name(const char *path, const unsigned char *sha1, int flag, void *cb_data)
@@ -195,6 +197,9 @@ static void describe(const char *arg, int last_one)
for_each_ref(get_name, NULL);
}
if (!found_names)
die("cannot describe '%s'", sha1_to_hex(sha1));
n = cmit->util;
if (n) {
/*

View File

@@ -218,6 +218,8 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv
revs->max_count = 3;
else if (!strcmp(argv[1], "-q"))
options |= DIFF_SILENT_ON_REMOVED;
else if (!strcmp(argv[1], "-h"))
usage(builtin_diff_usage);
else
return error("invalid option: %s", argv[1]);
argv++; argc--;

View File

@@ -26,6 +26,7 @@ static int progress;
static enum { ABORT, VERBATIM, WARN, STRIP } signed_tag_mode = ABORT;
static enum { ERROR, DROP, REWRITE } tag_of_filtered_mode = ABORT;
static int fake_missing_tagger;
static int no_data;
static int parse_opt_signed_tag_mode(const struct option *opt,
const char *arg, int unset)
@@ -116,6 +117,9 @@ static void handle_object(const unsigned char *sha1)
char *buf;
struct object *object;
if (no_data)
return;
if (is_null_sha1(sha1))
return;
@@ -173,7 +177,7 @@ static void show_filemodify(struct diff_queue_struct *q,
* Links refer to objects in another repositories;
* output the SHA-1 verbatim.
*/
if (S_ISGITLINK(spec->mode))
if (no_data || S_ISGITLINK(spec->mode))
printf("M %06o %s %s\n", spec->mode,
sha1_to_hex(spec->sha1), spec->path);
else {
@@ -580,6 +584,9 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
"Import marks from this file"),
OPT_BOOLEAN(0, "fake-missing-tagger", &fake_missing_tagger,
"Fake a tagger when tags lack one"),
{ OPTION_NEGBIT, 0, "data", &no_data, NULL,
"Skip output of blob data",
PARSE_OPT_NOARG | PARSE_OPT_NEGHELP, NULL, 1 },
OPT_END()
};

View File

@@ -52,26 +52,58 @@ static int grep_config(const char *var, const char *value, void *cb)
return git_color_default_config(var, value, cb);
}
/*
* Return non-zero if max_depth is negative or path has no more then max_depth
* slashes.
*/
static int accept_subdir(const char *path, int max_depth)
{
if (max_depth < 0)
return 1;
while ((path = strchr(path, '/')) != NULL) {
max_depth--;
if (max_depth < 0)
return 0;
path++;
}
return 1;
}
/*
* Return non-zero if name is a subdirectory of match and is not too deep.
*/
static int is_subdir(const char *name, int namelen,
const char *match, int matchlen, int max_depth)
{
if (matchlen > namelen || strncmp(name, match, matchlen))
return 0;
if (name[matchlen] == '\0') /* exact match */
return 1;
if (!matchlen || match[matchlen-1] == '/' || name[matchlen] == '/')
return accept_subdir(name + matchlen + 1, max_depth);
return 0;
}
/*
* git grep pathspecs are somewhat different from diff-tree pathspecs;
* pathname wildcards are allowed.
*/
static int pathspec_matches(const char **paths, const char *name)
static int pathspec_matches(const char **paths, const char *name, int max_depth)
{
int namelen, i;
if (!paths || !*paths)
return 1;
return accept_subdir(name, max_depth);
namelen = strlen(name);
for (i = 0; paths[i]; i++) {
const char *match = paths[i];
int matchlen = strlen(match);
const char *cp, *meta;
if (!matchlen ||
((matchlen <= namelen) &&
!strncmp(name, match, matchlen) &&
(match[matchlen-1] == '/' ||
name[matchlen] == '\0' || name[matchlen] == '/')))
if (is_subdir(name, namelen, match, matchlen, max_depth))
return 1;
if (!fnmatch(match, name, 0))
return 1;
@@ -421,7 +453,7 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached)
int kept;
if (!S_ISREG(ce->ce_mode))
continue;
if (!pathspec_matches(paths, ce->name))
if (!pathspec_matches(paths, ce->name, opt->max_depth))
continue;
name = ce->name;
if (name[0] == '-') {
@@ -478,7 +510,7 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached,
struct cache_entry *ce = active_cache[nr];
if (!S_ISREG(ce->ce_mode))
continue;
if (!pathspec_matches(paths, ce->name))
if (!pathspec_matches(paths, ce->name, opt->max_depth))
continue;
/*
* If CE_VALID is on, we assume worktree file and its cache entry
@@ -538,7 +570,7 @@ static int grep_tree(struct grep_opt *opt, const char **paths,
strbuf_addch(&pathbuf, '/');
down = pathbuf.buf + tn_len;
if (!pathspec_matches(paths, down))
if (!pathspec_matches(paths, down, opt->max_depth))
;
else if (S_ISREG(entry.mode))
hit |= grep_sha1(opt, entry.sha1, pathbuf.buf, tn_len);
@@ -692,6 +724,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
OPT_SET_INT('I', NULL, &opt.binary,
"don't match patterns in binary files",
GREP_BINARY_NOMATCH),
{ OPTION_INTEGER, 0, "max-depth", &opt.max_depth, "depth",
"descend at most <depth> levels", PARSE_OPT_NONEG,
NULL, 1 },
OPT_GROUP(""),
OPT_BIT('E', "extended-regexp", &opt.regflags,
"use extended POSIX regular expressions", REG_EXTENDED),
@@ -768,6 +803,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
opt.pathname = 1;
opt.pattern_tail = &opt.pattern_list;
opt.regflags = REG_NEWLINE;
opt.max_depth = -1;
strcpy(opt.color_match, GIT_COLOR_RED GIT_COLOR_BOLD);
opt.color = -1;

View File

@@ -6,6 +6,7 @@
#include "cache.h"
#include "builtin.h"
#include "exec_cmd.h"
#include "parse-options.h"
#ifndef DEFAULT_GIT_TEMPLATE_DIR
#define DEFAULT_GIT_TEMPLATE_DIR "/usr/share/git-core/templates"
@@ -370,8 +371,16 @@ static int guess_repository_type(const char *git_dir)
return 1;
}
static const char init_db_usage[] =
"git init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared[=<permissions>]]";
static int shared_callback(const struct option *opt, const char *arg, int unset)
{
*((int *) opt->value) = (arg) ? git_config_perm("arg", arg) : PERM_GROUP;
return 0;
}
static const char *const init_db_usage[] = {
"git init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared[=<permissions>]] [directory]",
NULL
};
/*
* If you want to, you can share the DB area with any number of branches.
@@ -384,25 +393,60 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
const char *git_dir;
const char *template_dir = NULL;
unsigned int flags = 0;
int i;
const struct option init_db_options[] = {
OPT_STRING(0, "template", &template_dir, "template-directory",
"provide the directory from which templates will be used"),
OPT_SET_INT(0, "bare", &is_bare_repository_cfg,
"create a bare repository", 1),
{ OPTION_CALLBACK, 0, "shared", &init_shared_repository,
"permissions",
"specify that the git repository is to be shared amongst several users",
PARSE_OPT_OPTARG | PARSE_OPT_NONEG, shared_callback, 0},
OPT_BIT('q', "quiet", &flags, "be quiet", INIT_DB_QUIET),
OPT_END()
};
for (i = 1; i < argc; i++, argv++) {
const char *arg = argv[1];
if (!prefixcmp(arg, "--template="))
template_dir = arg+11;
else if (!strcmp(arg, "--bare")) {
static char git_dir[PATH_MAX+1];
is_bare_repository_cfg = 1;
setenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir,
sizeof(git_dir)), 0);
} else if (!strcmp(arg, "--shared"))
init_shared_repository = PERM_GROUP;
else if (!prefixcmp(arg, "--shared="))
init_shared_repository = git_config_perm("arg", arg+9);
else if (!strcmp(arg, "-q") || !strcmp(arg, "--quiet"))
flags |= INIT_DB_QUIET;
else
usage(init_db_usage);
argc = parse_options(argc, argv, prefix, init_db_options, init_db_usage, 0);
if (argc == 1) {
int mkdir_tried = 0;
retry:
if (chdir(argv[0]) < 0) {
if (!mkdir_tried) {
int saved;
/*
* At this point we haven't read any configuration,
* and we know shared_repository should always be 0;
* but just in case we play safe.
*/
saved = shared_repository;
shared_repository = 0;
switch (safe_create_leading_directories_const(argv[0])) {
case -3:
errno = EEXIST;
/* fallthru */
case -1:
die_errno("cannot mkdir %s", argv[0]);
break;
default:
break;
}
shared_repository = saved;
if (mkdir(argv[0], 0777) < 0)
die_errno("cannot mkdir %s", argv[0]);
mkdir_tried = 1;
goto retry;
}
die_errno("cannot chdir to %s", argv[0]);
}
} else if (0 < argc) {
usage(init_db_usage[0]);
}
if (is_bare_repository_cfg == 1) {
static char git_dir[PATH_MAX+1];
setenv(GIT_DIR_ENVIRONMENT,
getcwd(git_dir, sizeof(git_dir)), 0);
}
if (init_shared_repository != -1)

View File

@@ -27,6 +27,10 @@ static int default_show_root = 1;
static const char *fmt_patch_subject_prefix = "PATCH";
static const char *fmt_pretty;
static const char * const builtin_log_usage =
"git log [<options>] [<since>..<until>] [[--] <path>...]\n"
" or: git show [options] <object>...";
static void cmd_log_init(int argc, const char **argv, const char *prefix,
struct rev_info *rev)
{
@@ -61,6 +65,8 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
rev->show_decorations = 1;
} else if (!strcmp(arg, "--source")) {
rev->show_source = 1;
} else if (!strcmp(arg, "-h")) {
usage(builtin_log_usage);
} else
die("unrecognized argument: %s", arg);
}
@@ -257,7 +263,7 @@ static void show_tagger(char *buf, int len, struct rev_info *rev)
pp_user_info("Tagger", rev->commit_format, &out, buf, rev->date_mode,
git_log_output_encoding ?
git_log_output_encoding: git_commit_encoding);
printf("%s\n", out.buf);
printf("%s", out.buf);
strbuf_release(&out);
}
@@ -329,11 +335,14 @@ int cmd_show(int argc, const char **argv, const char *prefix)
case OBJ_TAG: {
struct tag *t = (struct tag *)o;
if (rev.shown_one)
putchar('\n');
printf("%stag %s%s\n",
diff_get_color_opt(&rev.diffopt, DIFF_COMMIT),
t->tag,
diff_get_color_opt(&rev.diffopt, DIFF_RESET));
ret = show_object(o->sha1, 1, &rev);
rev.shown_one = 1;
if (ret)
break;
o = parse_object(t->tagged->sha1);
@@ -345,12 +354,15 @@ int cmd_show(int argc, const char **argv, const char *prefix)
break;
}
case OBJ_TREE:
if (rev.shown_one)
putchar('\n');
printf("%stree %s%s\n\n",
diff_get_color_opt(&rev.diffopt, DIFF_COMMIT),
name,
diff_get_color_opt(&rev.diffopt, DIFF_RESET));
read_tree_recursive((struct tree *)o, "", 0, 0, NULL,
show_tree_object, NULL);
rev.shown_one = 1;
break;
case OBJ_COMMIT:
rev.pending.nr = rev.pending.alloc = 0;
@@ -658,6 +670,10 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
log_write_email_headers(rev, head, &subject_start, &extra_headers,
&need_8bit_cte);
for (i = 0; !need_8bit_cte && i < nr; i++)
if (has_non_ascii(list[i]->buffer))
need_8bit_cte = 1;
msg = body;
pp_user_info(NULL, CMIT_FMT_EMAIL, &sb, committer, DATE_RFC2822,
encoding);

View File

@@ -23,7 +23,7 @@ static int show_merge_base(struct commit **rev, int rev_nr, int show_all)
}
static const char * const merge_base_usage[] = {
"git merge-base [--all] <commit-id> <commit-id>...",
"git merge-base [-a|--all] <commit> <commit>...",
NULL
};

View File

@@ -358,6 +358,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
struct strbuf buf = STRBUF_INIT;
struct strbuf bname = STRBUF_INIT;
const char *ptr;
char *found_ref;
int len, early;
strbuf_branchname(&bname, remote);
@@ -368,14 +369,17 @@ static void merge_name(const char *remote, struct strbuf *msg)
if (!remote_head)
die("'%s' does not point to a commit", remote);
strbuf_addstr(&buf, "refs/heads/");
strbuf_addstr(&buf, remote);
resolve_ref(buf.buf, branch_head, 0, NULL);
if (!hashcmp(remote_head->sha1, branch_head)) {
strbuf_addf(msg, "%s\t\tbranch '%s' of .\n",
sha1_to_hex(branch_head), remote);
goto cleanup;
if (dwim_ref(remote, strlen(remote), branch_head, &found_ref) > 0) {
if (!prefixcmp(found_ref, "refs/heads/")) {
strbuf_addf(msg, "%s\t\tbranch '%s' of .\n",
sha1_to_hex(branch_head), remote);
goto cleanup;
}
if (!prefixcmp(found_ref, "refs/remotes/")) {
strbuf_addf(msg, "%s\t\tremote branch '%s' of .\n",
sha1_to_hex(branch_head), remote);
goto cleanup;
}
}
/* See if remote matches <name>^^^.. or <name>~<number> */
@@ -594,7 +598,7 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
discard_cache();
if (read_cache() < 0)
die("failed to read the cache");
return -ret;
return ret;
}
}

View File

@@ -86,7 +86,7 @@ static int pack_compression_level = Z_DEFAULT_COMPRESSION;
static int pack_compression_seen;
static unsigned long delta_cache_size = 0;
static unsigned long max_delta_cache_size = 0;
static unsigned long max_delta_cache_size = 256 * 1024 * 1024;
static unsigned long cache_max_small_delta_size = 1000;
static unsigned long window_memory_limit = 0;

View File

@@ -1,9 +1,12 @@
#include "builtin.h"
#include "cache.h"
#include "progress.h"
#include "parse-options.h"
static const char prune_packed_usage[] =
"git prune-packed [-n] [-q]";
static const char * const prune_packed_usage[] = {
"git prune-packed [-n|--dry-run] [-q|--quiet]",
NULL
};
#define DRY_RUN 01
#define VERBOSE 02
@@ -68,24 +71,16 @@ void prune_packed_objects(int opts)
int cmd_prune_packed(int argc, const char **argv, const char *prefix)
{
int i;
int opts = VERBOSE;
const struct option prune_packed_options[] = {
OPT_BIT('n', "dry-run", &opts, "dry run", DRY_RUN),
OPT_NEGBIT('q', "quiet", &opts, "be quiet", VERBOSE),
OPT_END()
};
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
argc = parse_options(argc, argv, prefix, prune_packed_options,
prune_packed_usage, 0);
if (*arg == '-') {
if (!strcmp(arg, "-n"))
opts |= DRY_RUN;
else if (!strcmp(arg, "-q"))
opts &= ~VERBOSE;
else
usage(prune_packed_usage);
continue;
}
/* Handle arguments here .. */
usage(prune_packed_usage);
}
prune_packed_objects(opts);
return 0;
}

View File

@@ -140,6 +140,7 @@ static int do_push(const char *repo, int flags)
struct transport *transport =
transport_get(remote, url[i]);
int err;
int nonfastforward;
if (receivepack)
transport_set_option(transport,
TRANS_OPT_RECEIVEPACK, receivepack);
@@ -148,13 +149,19 @@ static int do_push(const char *repo, int flags)
if (flags & TRANSPORT_PUSH_VERBOSE)
fprintf(stderr, "Pushing to %s\n", url[i]);
err = transport_push(transport, refspec_nr, refspec, flags);
err = transport_push(transport, refspec_nr, refspec, flags,
&nonfastforward);
err |= transport_disconnect(transport);
if (!err)
continue;
error("failed to push some refs to '%s'", url[i]);
if (nonfastforward) {
printf("To prevent you from losing history, non-fast-forward updates were rejected.\n"
"Merge the remote changes before pushing again.\n"
"See 'non-fast forward' section of 'git push --help' for details.\n");
}
errs++;
}
return !!errs;
@@ -168,6 +175,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
const char *repo = NULL; /* default repository */
struct option options[] = {
OPT_BIT('q', "quiet", &flags, "be quiet", TRANSPORT_PUSH_QUIET),
OPT_BIT('v', "verbose", &flags, "be verbose", TRANSPORT_PUSH_VERBOSE),
OPT_STRING( 0 , "repo", &repo, "repository", "repository"),
OPT_BIT( 0 , "all", &flags, "push all refs", TRANSPORT_PUSH_ALL),

View File

@@ -12,6 +12,7 @@
#include "unpack-trees.h"
#include "dir.h"
#include "builtin.h"
#include "parse-options.h"
static int nr_trees;
static struct tree *trees[MAX_UNPACK_TREES];
@@ -29,7 +30,39 @@ static int list_tree(unsigned char *sha1)
return 0;
}
static const char read_tree_usage[] = "git read-tree (<sha> | [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] [--exclude-per-directory=<gitignore>] [--index-output=<file>] <sha1> [<sha2> [<sha3>]])";
static const char * const read_tree_usage[] = {
"git read-tree [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] [-u [--exclude-per-directory=<gitignore>] | -i]] [--index-output=<file>] <tree-ish1> [<tree-ish2> [<tree-ish3>]]",
NULL
};
static int index_output_cb(const struct option *opt, const char *arg,
int unset)
{
set_alternate_index_output(arg);
return 0;
}
static int exclude_per_directory_cb(const struct option *opt, const char *arg,
int unset)
{
struct dir_struct *dir;
struct unpack_trees_options *opts;
opts = (struct unpack_trees_options *)opt->value;
if (opts->dir)
die("more than one --exclude-per-directory given.");
dir = xcalloc(1, sizeof(*opts->dir));
dir->flags |= DIR_SHOW_IGNORED;
dir->exclude_per_dir = arg;
opts->dir = dir;
/* We do not need to nor want to do read-directory
* here; we are merely interested in reusing the
* per directory ignore stack mechanism.
*/
return 0;
}
static struct lock_file lock_file;
@@ -39,6 +72,34 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
unsigned char sha1[20];
struct tree_desc t[MAX_UNPACK_TREES];
struct unpack_trees_options opts;
int prefix_set = 0;
const struct option read_tree_options[] = {
{ OPTION_CALLBACK, 0, "index-output", NULL, "FILE",
"write resulting index to <FILE>",
PARSE_OPT_NONEG, index_output_cb },
OPT__VERBOSE(&opts.verbose_update),
OPT_GROUP("Merging"),
OPT_SET_INT('m', NULL, &opts.merge,
"perform a merge in addition to a read", 1),
OPT_SET_INT(0, "trivial", &opts.trivial_merges_only,
"3-way merge if no file level merging required", 1),
OPT_SET_INT(0, "aggressive", &opts.aggressive,
"3-way merge in presence of adds and removes", 1),
OPT_SET_INT(0, "reset", &opts.reset,
"same as -m, but discard unmerged entries", 1),
{ OPTION_STRING, 0, "prefix", &opts.prefix, "<subdirectory>/",
"read the tree into the index under <subdirectory>/",
PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP },
OPT_SET_INT('u', NULL, &opts.update,
"update working tree with merge result", 1),
{ OPTION_CALLBACK, 0, "exclude-per-directory", &opts,
"gitignore",
"allow explicitly ignored files to be overwritten",
PARSE_OPT_NONEG, exclude_per_directory_cb },
OPT_SET_INT('i', NULL, &opts.index_only,
"don't check the working tree after merging", 1),
OPT_END()
};
memset(&opts, 0, sizeof(opts));
opts.head_idx = -1;
@@ -49,114 +110,31 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
newfd = hold_locked_index(&lock_file, 1);
for (i = 1; i < argc; i++) {
argc = parse_options(argc, argv, unused_prefix, read_tree_options,
read_tree_usage, 0);
if (read_cache_unmerged() && (opts.prefix || opts.merge))
die("You need to resolve your current index first");
prefix_set = opts.prefix ? 1 : 0;
if (1 < opts.merge + opts.reset + prefix_set)
die("Which one? -m, --reset, or --prefix?");
stage = opts.merge = (opts.reset || opts.merge || prefix_set);
for (i = 0; i < argc; i++) {
const char *arg = argv[i];
/* "-u" means "update", meaning that a merge will update
* the working tree.
*/
if (!strcmp(arg, "-u")) {
opts.update = 1;
continue;
}
if (!strcmp(arg, "-v")) {
opts.verbose_update = 1;
continue;
}
/* "-i" means "index only", meaning that a merge will
* not even look at the working tree.
*/
if (!strcmp(arg, "-i")) {
opts.index_only = 1;
continue;
}
if (!prefixcmp(arg, "--index-output=")) {
set_alternate_index_output(arg + 15);
continue;
}
/* "--prefix=<subdirectory>/" means keep the current index
* entries and put the entries from the tree under the
* given subdirectory.
*/
if (!prefixcmp(arg, "--prefix=")) {
if (stage || opts.merge || opts.prefix)
usage(read_tree_usage);
opts.prefix = arg + 9;
opts.merge = 1;
stage = 1;
if (read_cache_unmerged())
die("you need to resolve your current index first");
continue;
}
/* This differs from "-m" in that we'll silently ignore
* unmerged entries and overwrite working tree files that
* correspond to them.
*/
if (!strcmp(arg, "--reset")) {
if (stage || opts.merge || opts.prefix)
usage(read_tree_usage);
opts.reset = 1;
opts.merge = 1;
stage = 1;
read_cache_unmerged();
continue;
}
if (!strcmp(arg, "--trivial")) {
opts.trivial_merges_only = 1;
continue;
}
if (!strcmp(arg, "--aggressive")) {
opts.aggressive = 1;
continue;
}
/* "-m" stands for "merge", meaning we start in stage 1 */
if (!strcmp(arg, "-m")) {
if (stage || opts.merge || opts.prefix)
usage(read_tree_usage);
if (read_cache_unmerged())
die("you need to resolve your current index first");
stage = 1;
opts.merge = 1;
continue;
}
if (!prefixcmp(arg, "--exclude-per-directory=")) {
struct dir_struct *dir;
if (opts.dir)
die("more than one --exclude-per-directory are given.");
dir = xcalloc(1, sizeof(*opts.dir));
dir->flags |= DIR_SHOW_IGNORED;
dir->exclude_per_dir = arg + 24;
opts.dir = dir;
/* We do not need to nor want to do read-directory
* here; we are merely interested in reusing the
* per directory ignore stack mechanism.
*/
continue;
}
/* using -u and -i at the same time makes no sense */
if (1 < opts.index_only + opts.update)
usage(read_tree_usage);
if (get_sha1(arg, sha1))
die("Not a valid object name %s", arg);
if (list_tree(sha1) < 0)
die("failed to unpack tree object %s", arg);
stage++;
}
if (1 < opts.index_only + opts.update)
die("-u and -i at the same time makes no sense");
if ((opts.update||opts.index_only) && !opts.merge)
usage(read_tree_usage);
die("%s is meaningless without -m, --reset, or --prefix",
opts.update ? "-u" : "-i");
if ((opts.dir && !opts.update))
die("--exclude-per-directory is meaningless unless -u");
if (opts.merge && !opts.index_only)

View File

@@ -123,31 +123,6 @@ static struct command *commands;
static const char pre_receive_hook[] = "hooks/pre-receive";
static const char post_receive_hook[] = "hooks/post-receive";
static int run_status(int code, const char *cmd_name)
{
switch (code) {
case 0:
return 0;
case -ERR_RUN_COMMAND_FORK:
return error("fork of %s failed", cmd_name);
case -ERR_RUN_COMMAND_EXEC:
return error("execute of %s failed", cmd_name);
case -ERR_RUN_COMMAND_PIPE:
return error("pipe failed");
case -ERR_RUN_COMMAND_WAITPID:
return error("waitpid failed");
case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
return error("waitpid is confused");
case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
return error("%s died of signal", cmd_name);
case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
return error("%s died strangely", cmd_name);
default:
error("%s exited with error code %d", cmd_name, -code);
return -code;
}
}
static int run_receive_hook(const char *hook_name)
{
static char buf[sizeof(commands->old_sha1) * 2 + PATH_MAX + 4];
@@ -174,7 +149,7 @@ static int run_receive_hook(const char *hook_name)
code = start_command(&proc);
if (code)
return run_status(code, hook_name);
return code;
for (cmd = commands; cmd; cmd = cmd->next) {
if (!cmd->error_string) {
size_t n = snprintf(buf, sizeof(buf), "%s %s %s\n",
@@ -186,7 +161,7 @@ static int run_receive_hook(const char *hook_name)
}
}
close(proc.in);
return run_status(finish_command(&proc), hook_name);
return finish_command(&proc);
}
static int run_update_hook(struct command *cmd)
@@ -203,9 +178,8 @@ static int run_update_hook(struct command *cmd)
argv[3] = sha1_to_hex(cmd->new_sha1);
argv[4] = NULL;
return run_status(run_command_v_opt(argv, RUN_COMMAND_NO_STDIN |
RUN_COMMAND_STDOUT_TO_STDERR),
update_hook);
return run_command_v_opt(argv, RUN_COMMAND_NO_STDIN |
RUN_COMMAND_STDOUT_TO_STDERR);
}
static int is_ref_checked_out(const char *ref)
@@ -419,7 +393,6 @@ static void run_update_post_hook(struct command *cmd)
argv[argc] = NULL;
status = run_command_v_opt(argv, RUN_COMMAND_NO_STDIN
| RUN_COMMAND_STDOUT_TO_STDERR);
run_status(status, update_post_hook);
}
static void execute_commands(const char *unpacker_error)
@@ -537,7 +510,6 @@ static const char *unpack(void)
code = run_command_v_opt(unpacker, RUN_GIT_CMD);
if (!code)
return NULL;
run_status(code, unpacker[0]);
return "unpack-objects abnormal exit";
} else {
const char *keeper[7];
@@ -563,7 +535,6 @@ static const char *unpack(void)
ip.git_cmd = 1;
status = start_command(&ip);
if (status) {
run_status(status, keeper[0]);
return "index-pack fork failed";
}
pack_lockfile = index_pack_lockfile(ip.out);
@@ -573,7 +544,6 @@ static const char *unpack(void)
reprepare_packed_git();
return NULL;
}
run_status(status, keeper[0]);
return "index-pack abnormal exit";
}
}

View File

@@ -694,7 +694,7 @@ static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
*/
static const char reflog_usage[] =
"git reflog (expire | ...)";
"git reflog [ show | expire | delete ]";
int cmd_reflog(int argc, const char **argv, const char *prefix)
{

View File

@@ -44,6 +44,7 @@ static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *ext
NULL,
NULL,
NULL,
NULL,
};
struct child_process po;
int i;
@@ -53,6 +54,8 @@ static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *ext
argv[i++] = "--thin";
if (args->use_ofs_delta)
argv[i++] = "--delta-base-offset";
if (args->quiet)
argv[i++] = "-q";
memset(&po, 0, sizeof(po));
po.argv = argv;
po.in = -1;

View File

@@ -6,8 +6,8 @@
#include "parse-options.h"
static const char* show_branch_usage[] = {
"git show-branch [--sparse] [--current] [--all] [--remotes] [--topo-order] [--more=count | --list | --independent | --merge-base] [--topics] [--color] [<refs>...]",
"--reflog[=n[,b]] [--list] [--color] <branch>",
"git show-branch [-a|--all] [-r|--remotes] [--topo-order | --date-order] [--current] [--color | --no-color] [--sparse] [--more=<n> | --list | --independent | --merge-base] [--no-name | --sha1-name] [--topics] [<rev> | <glob>]...",
"git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]",
NULL
};
@@ -665,7 +665,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
OPT_BOOLEAN(0, "sha1-name", &sha1_name,
"name commits with their object names"),
OPT_BOOLEAN(0, "merge-base", &merge_base,
"act like git merge-base -a"),
"show possible merge bases"),
OPT_BOOLEAN(0, "independent", &independent,
"show refs unreachable from any other ref"),
OPT_BOOLEAN(0, "topo-order", &lifo,

View File

@@ -2,15 +2,19 @@
#include "cache.h"
#include "pack.h"
#include "pack-revindex.h"
#include "parse-options.h"
#define MAX_CHAIN 50
static void show_pack_info(struct packed_git *p)
{
uint32_t nr_objects, i, chain_histogram[MAX_CHAIN+1];
uint32_t nr_objects, i;
int cnt;
unsigned long chain_histogram[MAX_CHAIN+1], baseobjects;
nr_objects = p->num_objects;
memset(chain_histogram, 0, sizeof(chain_histogram));
baseobjects = 0;
for (i = 0; i < nr_objects; i++) {
const unsigned char *sha1;
@@ -29,9 +33,11 @@ static void show_pack_info(struct packed_git *p)
&delta_chain_length,
base_sha1);
printf("%s ", sha1_to_hex(sha1));
if (!delta_chain_length)
if (!delta_chain_length) {
printf("%-6s %lu %lu %"PRIuMAX"\n",
type, size, store_size, (uintmax_t)offset);
baseobjects++;
}
else {
printf("%-6s %lu %lu %"PRIuMAX" %u %s\n",
type, size, store_size, (uintmax_t)offset,
@@ -43,15 +49,21 @@ static void show_pack_info(struct packed_git *p)
}
}
for (i = 0; i <= MAX_CHAIN; i++) {
if (!chain_histogram[i])
if (baseobjects)
printf("non delta: %lu object%s\n",
baseobjects, baseobjects > 1 ? "s" : "");
for (cnt = 1; cnt <= MAX_CHAIN; cnt++) {
if (!chain_histogram[cnt])
continue;
printf("chain length = %"PRIu32": %"PRIu32" object%s\n", i,
chain_histogram[i], chain_histogram[i] > 1 ? "s" : "");
printf("chain length = %d: %lu object%s\n", cnt,
chain_histogram[cnt],
chain_histogram[cnt] > 1 ? "s" : "");
}
if (chain_histogram[0])
printf("chain length > %d: %"PRIu32" object%s\n", MAX_CHAIN,
chain_histogram[0], chain_histogram[0] > 1 ? "s" : "");
printf("chain length > %d: %lu object%s\n", MAX_CHAIN,
chain_histogram[0],
chain_histogram[0] > 1 ? "s" : "");
}
static int verify_one_pack(const char *path, int verbose)
@@ -107,36 +119,31 @@ static int verify_one_pack(const char *path, int verbose)
return err;
}
static const char verify_pack_usage[] = "git verify-pack [-v] <pack>...";
static const char * const verify_pack_usage[] = {
"git verify-pack [-v|--verbose] <pack>...",
NULL
};
int cmd_verify_pack(int argc, const char **argv, const char *prefix)
{
int err = 0;
int verbose = 0;
int no_more_options = 0;
int nothing_done = 1;
int i;
const struct option verify_pack_options[] = {
OPT__VERBOSE(&verbose),
OPT_END()
};
git_config(git_default_config, NULL);
while (1 < argc) {
if (!no_more_options && argv[1][0] == '-') {
if (!strcmp("-v", argv[1]))
verbose = 1;
else if (!strcmp("--", argv[1]))
no_more_options = 1;
else
usage(verify_pack_usage);
}
else {
if (verify_one_pack(argv[1], verbose))
err = 1;
discard_revindex();
nothing_done = 0;
}
argc--; argv++;
argc = parse_options(argc, argv, prefix, verify_pack_options,
verify_pack_usage, 0);
if (argc < 1)
usage_with_options(verify_pack_usage, verify_pack_options);
for (i = 0; i < argc; i++) {
if (verify_one_pack(argv[i], verbose))
err = 1;
discard_revindex();
}
if (nothing_done)
usage(verify_pack_usage);
return err;
}

View File

@@ -10,9 +10,12 @@
#include "tag.h"
#include "run-command.h"
#include <signal.h>
#include "parse-options.h"
static const char builtin_verify_tag_usage[] =
"git verify-tag [-v|--verbose] <tag>...";
static const char * const verify_tag_usage[] = {
"git verify-tag [-v|--verbose] <tag>...",
NULL
};
#define PGP_SIGNATURE "-----BEGIN PGP SIGNATURE-----"
@@ -89,17 +92,17 @@ static int verify_tag(const char *name, int verbose)
int cmd_verify_tag(int argc, const char **argv, const char *prefix)
{
int i = 1, verbose = 0, had_error = 0;
const struct option verify_tag_options[] = {
OPT__VERBOSE(&verbose),
OPT_END()
};
git_config(git_default_config, NULL);
if (argc > 1 &&
(!strcmp(argv[i], "-v") || !strcmp(argv[i], "--verbose"))) {
verbose = 1;
i++;
}
argc = parse_options(argc, argv, prefix, verify_tag_options,
verify_tag_usage, PARSE_OPT_KEEP_ARGV0);
if (argc <= i)
usage(builtin_verify_tag_usage);
usage_with_options(verify_tag_usage, verify_tag_options);
/* sometimes the program was terminated because this signal
* was received in the process of writing the gpg input: */

View File

@@ -7,9 +7,12 @@
#include "cache.h"
#include "tree.h"
#include "cache-tree.h"
#include "parse-options.h"
static const char write_tree_usage[] =
"git write-tree [--missing-ok] [--prefix=<prefix>/]";
static const char * const write_tree_usage[] = {
"git write-tree [--missing-ok] [--prefix=<prefix>/]",
NULL
};
int cmd_write_tree(int argc, const char **argv, const char *unused_prefix)
{
@@ -17,27 +20,22 @@ int cmd_write_tree(int argc, const char **argv, const char *unused_prefix)
const char *prefix = NULL;
unsigned char sha1[20];
const char *me = "git-write-tree";
struct option write_tree_options[] = {
OPT_BIT(0, "missing-ok", &flags, "allow missing objects",
WRITE_TREE_MISSING_OK),
{ OPTION_STRING, 0, "prefix", &prefix, "<prefix>/",
"write tree object for a subdirectory <prefix>" ,
PARSE_OPT_LITERAL_ARGHELP },
{ OPTION_BIT, 0, "ignore-cache-tree", &flags, NULL,
"only useful for debugging",
PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, NULL,
WRITE_TREE_IGNORE_CACHE_TREE },
OPT_END()
};
git_config(git_default_config, NULL);
while (1 < argc) {
const char *arg = argv[1];
if (!strcmp(arg, "--missing-ok"))
flags |= WRITE_TREE_MISSING_OK;
else if (!prefixcmp(arg, "--prefix="))
prefix = arg + 9;
else if (!prefixcmp(arg, "--ignore-cache-tree"))
/*
* This is only useful for debugging, so I
* do not bother documenting it.
*/
flags |= WRITE_TREE_IGNORE_CACHE_TREE;
else
usage(write_tree_usage);
argc--; argv++;
}
if (argc > 2)
die("too many options");
argc = parse_options(argc, argv, unused_prefix, write_tree_options,
write_tree_usage, 0);
ret = write_cache_as_tree(sha1, flags, prefix);
switch (ret) {

View File

@@ -468,6 +468,9 @@ extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_obje
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);
/* "careful lstat()" */
extern int check_path(const char *path, int len, struct stat *st);
#define REFRESH_REALLY 0x0001 /* ignore_valid */
#define REFRESH_UNMERGED 0x0002 /* allow unmerged */
#define REFRESH_QUIET 0x0004 /* be quiet about it */

View File

@@ -64,6 +64,7 @@ enum cmit_fmt {
};
extern int non_ascii(int);
extern int has_non_ascii(const char *text);
struct rev_info; /* in revision.h, it circularly uses enum cmit_fmt */
extern char *reencode_commit_message(const struct commit *commit,
const char **encoding_p);

View File

@@ -17,9 +17,10 @@ typedef int pid_t;
#define S_IROTH 0
#define S_IXOTH 0
#define WIFEXITED(x) ((unsigned)(x) < 259) /* STILL_ACTIVE */
#define WIFEXITED(x) 1
#define WIFSIGNALED(x) 0
#define WEXITSTATUS(x) ((x) & 0xff)
#define WIFSIGNALED(x) ((unsigned)(x) > 259)
#define WTERMSIG(x) SIGTERM
#define SIGHUP 1
#define SIGQUIT 3

View File

@@ -62,7 +62,8 @@ static char *parse_value(void)
if (comment)
continue;
if (isspace(c) && !quote) {
space = 1;
if (len)
space++;
continue;
}
if (!quote) {
@@ -71,11 +72,8 @@ static char *parse_value(void)
continue;
}
}
if (space) {
if (len)
value[len++] = ' ';
space = 0;
}
for (; space; space--)
value[len++] = ' ';
if (c == '\\') {
c = get_next_char();
switch (c) {

View File

@@ -1047,6 +1047,7 @@ _git_grep ()
--extended-regexp --basic-regexp --fixed-strings
--files-with-matches --name-only
--files-without-match
--max-depth
--count
--and --or --not --all-match
"

View File

@@ -429,16 +429,19 @@ Each entry is a cons of (SHORT-NAME . FULL-NAME)."
(git-get-string-sha1
(git-call-process-string-display-error "write-tree"))))
(defun git-commit-tree (buffer tree head)
"Call git-commit-tree with buffer as input and return the resulting commit SHA1."
(defun git-commit-tree (buffer tree parent)
"Create a commit and possibly update HEAD.
Create a commit with the message in BUFFER using the tree with hash TREE.
Use PARENT as the parent of the new commit. If PARENT is the current \"HEAD\",
update the \"HEAD\" reference to the new commit."
(let ((author-name (git-get-committer-name))
(author-email (git-get-committer-email))
(subject "commit (initial): ")
author-date log-start log-end args coding-system-for-write)
(when head
(when parent
(setq subject "commit: ")
(push "-p" args)
(push head args))
(push parent args))
(with-current-buffer buffer
(goto-char (point-min))
(if
@@ -474,7 +477,7 @@ Each entry is a cons of (SHORT-NAME . FULL-NAME)."
(apply #'git-run-command-region
buffer log-start log-end env
"commit-tree" tree (nreverse args))))))
(when commit (git-update-ref "HEAD" commit head subject))
(when commit (git-update-ref "HEAD" commit parent subject))
commit)))
(defun git-empty-db-p ()

View File

@@ -20,7 +20,7 @@
"""
import os, os.path, sys
import tempfile, popen2, pickle, getopt
import tempfile, pickle, getopt
import re
# Maps hg version -> git version

View File

@@ -267,7 +267,7 @@ static int filter_buffer(int fd, void *data)
status = finish_command(&child_process);
if (status)
error("external filter %s failed %d", params->cmd, -status);
error("external filter %s failed %d", params->cmd, status);
return (write_err || status);
}

12
dir.c
View File

@@ -861,12 +861,20 @@ int is_empty_dir(const char *path)
return ret;
}
int remove_dir_recursively(struct strbuf *path, int only_empty)
int remove_dir_recursively(struct strbuf *path, int flag)
{
DIR *dir = opendir(path->buf);
DIR *dir;
struct dirent *e;
int ret = 0, original_len = path->len, len;
int only_empty = (flag & REMOVE_DIR_EMPTY_ONLY);
unsigned char submodule_head[20];
if ((flag & REMOVE_DIR_KEEP_NESTED_GIT) &&
!resolve_gitlink_ref(path->buf, "HEAD", submodule_head))
/* Do not descend and nuke a nested git work tree. */
return 0;
dir = opendir(path->buf);
if (!dir)
return -1;
if (path->buf[original_len - 1] != '/')

5
dir.h
View File

@@ -88,7 +88,10 @@ static inline int is_dot_or_dotdot(const char *name)
extern int is_empty_dir(const char *dir);
extern void setup_standard_excludes(struct dir_struct *dir);
extern int remove_dir_recursively(struct strbuf *path, int only_empty);
#define REMOVE_DIR_EMPTY_ONLY 01
#define REMOVE_DIR_KEEP_NESTED_GIT 02
extern int remove_dir_recursively(struct strbuf *path, int flag);
/* tries to remove the path with empty directories along it, ignores ENOENT */
extern int remove_path(const char *path);

15
entry.c
View File

@@ -175,6 +175,19 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout
return 0;
}
/*
* This is like 'lstat()', except it refuses to follow symlinks
* in the path.
*/
int check_path(const char *path, int len, struct stat *st)
{
if (has_symlink_leading_path(path, len)) {
errno = ENOENT;
return -1;
}
return lstat(path, st);
}
int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath)
{
static char path[PATH_MAX + 1];
@@ -188,7 +201,7 @@ int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *t
strcpy(path + len, ce->name);
len += ce_namelen(ce);
if (!lstat(path, &st)) {
if (!check_path(path, len, &st)) {
unsigned changed = ce_match_stat(ce, &st, CE_MATCH_IGNORE_VALID);
if (!changed)
return 0;

View File

@@ -191,6 +191,20 @@ check_patch_format () {
esac
;;
esac
if test -z "$patch_format" &&
test -n "$l1" &&
test -n "$l2" &&
test -n "$l3"
then
# This begins with three non-empty lines. Is this a
# piece of e-mail a-la RFC2822? Grab all the headers,
# discarding the indented remainder of folded lines,
# and see if it looks like that they all begin with the
# header field names...
sed -n -e '/^$/q' -e '/^[ ]/d' -e p "$1" |
egrep -v '^[A-Za-z]+(-[A-Za-z]+)*:' >/dev/null ||
patch_format=mbox
fi
} < "$1" || clean_abort
}
@@ -254,7 +268,11 @@ split_patches () {
msgnum=
;;
*)
clean_abort "Patch format $patch_format is not supported."
if test -n "$parse_patch" ; then
clean_abort "Patch format $patch_format is not supported."
else
clean_abort "Patch format detection failed."
fi
;;
esac
}

View File

@@ -252,7 +252,8 @@ sub conn {
}
};
}
$pass="A" unless $pass;
$pass = $self->_scramble($pass);
my ($s, $rep);
if ($proxyhost) {
@@ -484,6 +485,42 @@ sub _fetchfile {
return $res;
}
sub _scramble {
my ($self, $pass) = @_;
my $scrambled = "A";
return $scrambled unless $pass;
my $pass_len = length($pass);
my @pass_arr = split("", $pass);
my $i;
# from cvs/src/scramble.c
my @shifts = (
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
114,120, 53, 79, 96,109, 72,108, 70, 64, 76, 67,116, 74, 68, 87,
111, 52, 75,119, 49, 34, 82, 81, 95, 65,112, 86,118,110,122,105,
41, 57, 83, 43, 46,102, 40, 89, 38,103, 45, 50, 42,123, 91, 35,
125, 55, 54, 66,124,126, 59, 47, 92, 71,115, 78, 88,107,106, 56,
36,121,117,104,101,100, 69, 73, 99, 63, 94, 93, 39, 37, 61, 48,
58,113, 32, 90, 44, 98, 60, 51, 33, 97, 62, 77, 84, 80, 85,223,
225,216,187,166,229,189,222,188,141,249,148,200,184,136,248,190,
199,170,181,204,138,232,218,183,255,234,220,247,213,203,226,193,
174,172,228,252,217,201,131,230,197,211,145,238,161,179,160,212,
207,221,254,173,202,146,224,151,140,196,205,130,135,133,143,246,
192,159,244,239,185,168,215,144,139,165,180,157,147,186,214,176,
227,231,219,169,175,156,206,198,129,164,150,210,154,177,134,127,
182,128,158,208,162,132,167,209,149,241,153,251,237,236,171,195,
243,233,253,240,194,250,191,155,142,137,245,235,163,242,178,152
);
for ($i = 0; $i < $pass_len; $i++) {
$scrambled .= pack("C", $shifts[ord($pass_arr[$i])]);
}
return $scrambled;
}
package main;

View File

@@ -278,7 +278,7 @@ EOF
# check to see if Dennis Stosberg's mod_perl compatibility patch
# (<20060621130708.Gcbc6e5c@leonov.stosberg.net>) has been applied
if test -f "$module_path/mod_perl.so" && grep '^our $gitbin' \
if test -f "$module_path/mod_perl.so" && grep 'MOD_PERL' \
"$GIT_DIR/gitweb/gitweb.cgi" >/dev/null
then
# favor mod_perl if available

View File

@@ -119,15 +119,31 @@ error_on_no_merge_candidates () {
}
test true = "$rebase" && {
git update-index --ignore-submodules --refresh &&
git diff-files --ignore-submodules --quiet &&
git diff-index --ignore-submodules --cached --quiet HEAD -- ||
die "refusing to pull with rebase: your working tree is not up-to-date"
if ! git rev-parse -q --verify HEAD >/dev/null
then
# On an unborn branch
if test -f "$GIT_DIR/index"
then
die "updating an unborn branch with changes added to the index"
fi
else
git update-index --ignore-submodules --refresh &&
git diff-files --ignore-submodules --quiet &&
git diff-index --ignore-submodules --cached --quiet HEAD -- ||
die "refusing to pull with rebase: your working tree is not up-to-date"
fi
oldremoteref= &&
. git-parse-remote &&
reflist="$(get_remote_merge_branch "$@" 2>/dev/null)" &&
oldremoteref="$(git rev-parse -q --verify \
"$reflist")"
remoteref="$(get_remote_merge_branch "$@" 2>/dev/null)" &&
oldremoteref="$(git rev-parse -q --verify "$remoteref")" &&
for reflog in $(git rev-list -g $remoteref 2>/dev/null)
do
if test "$reflog" = "$(git merge-base $reflog $curr_branch)"
then
oldremoteref="$reflog"
break
fi
done
}
orig_head=$(git rev-parse -q --verify HEAD)
git fetch $verbosity --update-head-ok "$@" || exit 1

View File

@@ -382,8 +382,10 @@ else
fi
# The tree must be really really clean.
if ! git update-index --ignore-submodules --refresh; then
die "cannot rebase: you have unstaged changes"
if ! git update-index --ignore-submodules --refresh > /dev/null; then
echo >&2 "cannot rebase: you have unstaged changes"
git diff --name-status -r --ignore-submodules -- >&2
exit 1
fi
diff=$(git diff-index --cached --name-status -r --ignore-submodules HEAD --)
case "$diff" in

View File

@@ -8,13 +8,33 @@ USAGE='<start> <url> [<end>]'
LONG_USAGE='Summarizes the changes between two commits to the standard output,
and includes the given URL in the generated summary.'
SUBDIRECTORY_OK='Yes'
OPTIONS_SPEC=
OPTIONS_SPEC='git request-pull [options] start url [end]
--
p show patch text as well
'
. git-sh-setup
. git-parse-remote
GIT_PAGER=
export GIT_PAGER
patch=
while case "$#" in 0) break ;; esac
do
case "$1" in
-p)
patch=-p ;;
--)
shift; break ;;
-*)
usage ;;
*)
break ;;
esac
shift
done
base=$1
url=$2
head=${3-HEAD}
@@ -54,5 +74,5 @@ echo " $url $branch"
echo
git shortlog ^$baserev $headrev
git diff -M --stat --summary $merge_base $headrev
git diff -M --stat --summary $patch $merge_base..$headrev
exit $status

View File

@@ -450,7 +450,6 @@ sub check_file_rev_conflict($) {
try {
$repo->command('rev-parse', '--verify', '--quiet', $f);
if (defined($format_patch)) {
print "foo\n";
return $format_patch;
}
die(<<EOF);

View File

@@ -764,6 +764,7 @@ sub cmd_show_ignore {
print STDOUT "\n# $path\n";
my $s = $props->{'svn:ignore'} or return;
$s =~ s/[\r\n]+/\n/g;
$s =~ s/^\n+//;
chomp $s;
$s =~ s#^#$path#gm;
print STDOUT "$s\n";
@@ -801,6 +802,7 @@ sub cmd_create_ignore {
open(GITIGNORE, '>', $ignore)
or fatal("Failed to open `$ignore' for writing: $!");
$s =~ s/[\r\n]+/\n/g;
$s =~ s/^\n+//;
chomp $s;
# Prefix all patterns so that the ignore doesn't apply
# to sub-directories.
@@ -907,7 +909,7 @@ sub cmd_multi_init {
}
do_git_init_db();
if (defined $_trunk) {
my $trunk_ref = $_prefix . 'trunk';
my $trunk_ref = 'refs/remotes/' . $_prefix . 'trunk';
# try both old-style and new-style lookups:
my $gs_trunk = eval { Git::SVN->new($trunk_ref) };
unless ($gs_trunk) {
@@ -1154,6 +1156,17 @@ sub post_fetch_checkout {
my $gs = $Git::SVN::_head or return;
return if verify_ref('refs/heads/master^0');
# look for "trunk" ref if it exists
my $remote = Git::SVN::read_all_remotes()->{$gs->{repo_id}};
my $fetch = $remote->{fetch};
if ($fetch) {
foreach my $p (keys %$fetch) {
basename($fetch->{$p}) eq 'trunk' or next;
$gs = Git::SVN->new($fetch->{$p}, $gs->{repo_id}, $p);
last;
}
}
my $valid_head = verify_ref('HEAD^0');
command_noisy(qw(update-ref refs/heads/master), $gs->refname);
return if ($valid_head || !verify_ref('HEAD^0'));
@@ -1641,23 +1654,23 @@ sub resolve_local_globs {
return unless defined $glob_spec;
my $ref = $glob_spec->{ref};
my $path = $glob_spec->{path};
foreach (command(qw#for-each-ref --format=%(refname) refs/remotes#)) {
next unless m#^refs/remotes/$ref->{regex}$#;
foreach (command(qw#for-each-ref --format=%(refname) refs/#)) {
next unless m#^$ref->{regex}$#;
my $p = $1;
my $pathname = desanitize_refname($path->full_path($p));
my $refname = desanitize_refname($ref->full_path($p));
if (my $existing = $fetch->{$pathname}) {
if ($existing ne $refname) {
die "Refspec conflict:\n",
"existing: refs/remotes/$existing\n",
" globbed: refs/remotes/$refname\n";
"existing: $existing\n",
" globbed: $refname\n";
}
my $u = (::cmt_metadata("refs/remotes/$refname"))[0];
my $u = (::cmt_metadata("$refname"))[0];
$u =~ s!^\Q$url\E(/|$)!! or die
"refs/remotes/$refname: '$url' not found in '$u'\n";
"$refname: '$url' not found in '$u'\n";
if ($pathname ne $u) {
warn "W: Refspec glob conflict ",
"(ref: refs/remotes/$refname):\n",
"(ref: $refname):\n",
"expected path: $pathname\n",
" real path: $u\n",
"Continuing ahead with $u\n";
@@ -1735,33 +1748,35 @@ sub read_all_remotes {
my $use_svm_props = eval { command_oneline(qw/config --bool
svn.useSvmProps/) };
$use_svm_props = $use_svm_props eq 'true' if $use_svm_props;
my $svn_refspec = qr{\s*/?(.*?)\s*:\s*(.+?)\s*};
foreach (grep { s/^svn-remote\.// } command(qw/config -l/)) {
if (m!^(.+)\.fetch=\s*(.*)\s*:\s*(.+)\s*$!) {
my ($remote, $local_ref, $_remote_ref) = ($1, $2, $3);
die("svn-remote.$remote: remote ref '$_remote_ref' "
. "must start with 'refs/remotes/'\n")
unless $_remote_ref =~ m{^refs/remotes/(.+)};
my $remote_ref = $1;
$local_ref =~ s{^/}{};
if (m!^(.+)\.fetch=$svn_refspec$!) {
my ($remote, $local_ref, $remote_ref) = ($1, $2, $3);
die("svn-remote.$remote: remote ref '$remote_ref' "
. "must start with 'refs/'\n")
unless $remote_ref =~ m{^refs/};
$r->{$remote}->{fetch}->{$local_ref} = $remote_ref;
$r->{$remote}->{svm} = {} if $use_svm_props;
} elsif (m!^(.+)\.usesvmprops=\s*(.*)\s*$!) {
$r->{$1}->{svm} = {};
} elsif (m!^(.+)\.url=\s*(.*)\s*$!) {
$r->{$1}->{url} = $2;
} elsif (m!^(.+)\.(branches|tags)=
(.*):refs/remotes/(.+)\s*$/!x) {
my ($p, $g) = ($3, $4);
} elsif (m!^(.+)\.(branches|tags)=$svn_refspec$!) {
my ($remote, $t, $local_ref, $remote_ref) =
($1, $2, $3, $4);
die("svn-remote.$remote: remote ref '$remote_ref' ($t) "
. "must start with 'refs/'\n")
unless $remote_ref =~ m{^refs/};
my $rs = {
t => $2,
remote => $1,
path => Git::SVN::GlobSpec->new($p),
ref => Git::SVN::GlobSpec->new($g) };
t => $t,
remote => $remote,
path => Git::SVN::GlobSpec->new($local_ref),
ref => Git::SVN::GlobSpec->new($remote_ref) };
if (length($rs->{ref}->{right}) != 0) {
die "The '*' glob character must be the last ",
"character of '$g'\n";
"character of '$remote_ref'\n";
}
push @{ $r->{$1}->{$2} }, $rs;
push @{ $r->{$remote}->{$t} }, $rs;
}
}
@@ -1869,9 +1884,9 @@ sub init_remote_config {
}
}
my ($xrepo_id, $xpath) = find_ref($self->refname);
if (defined $xpath) {
if (!$no_write && defined $xpath) {
die "svn-remote.$xrepo_id.fetch already set to track ",
"$xpath:refs/remotes/", $self->refname, "\n";
"$xpath:", $self->refname, "\n";
}
unless ($no_write) {
command_noisy('config',
@@ -1946,7 +1961,7 @@ sub find_ref {
my ($ref_id) = @_;
foreach (command(qw/config -l/)) {
next unless m!^svn-remote\.(.+)\.fetch=
\s*(.*)\s*:\s*refs/remotes/(.+)\s*$!x;
\s*/?(.*?)\s*:\s*(.+?)\s*$!x;
my ($repo_id, $path, $ref) = ($1, $2, $3);
if ($ref eq $ref_id) {
$path = '' if ($path =~ m#^\./?#);
@@ -1963,16 +1978,16 @@ sub new {
if (!defined $repo_id) {
die "Could not find a \"svn-remote.*.fetch\" key ",
"in the repository configuration matching: ",
"refs/remotes/$ref_id\n";
"$ref_id\n";
}
}
my $self = _new($class, $repo_id, $ref_id, $path);
if (!defined $self->{path} || !length $self->{path}) {
my $fetch = command_oneline('config', '--get',
"svn-remote.$repo_id.fetch",
":refs/remotes/$ref_id\$") or
":$ref_id\$") or
die "Failed to read \"svn-remote.$repo_id.fetch\" ",
"\":refs/remotes/$ref_id\$\" in config\n";
"\":$ref_id\$\" in config\n";
($self->{path}, undef) = split(/\s*:\s*/, $fetch);
}
$self->{url} = command_oneline('config', '--get',
@@ -1983,7 +1998,7 @@ sub new {
}
sub refname {
my ($refname) = "refs/remotes/$_[0]->{ref_id}" ;
my ($refname) = $_[0]->{ref_id} ;
# It cannot end with a slash /, we'll throw up on this because
# SVN can't have directories with a slash in their name, either:
@@ -3262,7 +3277,7 @@ sub _rev_map_get {
my $i = int(($l/24 + $u/24) / 2) * 24;
sysseek($fh, $i, SEEK_SET) or croak "seek: $!";
sysread($fh, my $buf, 24) == 24 or croak "read: $!";
my ($r, $c) = unpack('NH40', $buf);
my ($r, $c) = unpack(rev_map_fmt, $buf);
if ($r < $rev) {
$l = $i + 24;
@@ -3317,12 +3332,24 @@ sub _new {
$repo_id = $Git::SVN::default_repo_id;
}
unless (defined $ref_id && length $ref_id) {
$_[2] = $ref_id = $Git::SVN::default_ref_id;
$_prefix = '' unless defined($_prefix);
$_[2] = $ref_id =
"refs/remotes/$_prefix$Git::SVN::default_ref_id";
}
$_[1] = $repo_id;
my $dir = "$ENV{GIT_DIR}/svn/$ref_id";
# Older repos imported by us used $GIT_DIR/svn/foo instead of
# $GIT_DIR/svn/refs/remotes/foo when tracking refs/remotes/foo
if ($ref_id =~ m{^refs/remotes/(.*)}) {
my $old_dir = "$ENV{GIT_DIR}/svn/$1";
if (-d $old_dir && ! -d $dir) {
$dir = $old_dir;
}
}
$_[3] = $path = '' unless (defined $path);
mkpath(["$ENV{GIT_DIR}/svn"]);
mkpath([$dir]);
bless {
ref_id => $ref_id, dir => $dir, index => "$dir/index",
path => $path, config => "$ENV{GIT_DIR}/svn/config",
@@ -5495,7 +5522,7 @@ sub minimize_connections {
my $pfx = "svn-remote.$x->{old_repo_id}";
my $old_fetch = quotemeta("$x->{old_path}:".
"refs/remotes/$x->{ref_id}");
"$x->{ref_id}");
command_noisy(qw/config --unset/,
"$pfx.fetch", '^'. $old_fetch . '$');
delete $r->{$x->{old_repo_id}}->
@@ -5564,7 +5591,7 @@ sub new {
my ($class, $glob) = @_;
my $re = $glob;
$re =~ s!/+$!!g; # no need for trailing slashes
$re =~ m!^([^*]*)(\*(?:/\*)*)([^*]*)$!;
$re =~ m!^([^*]*)(\*(?:/\*)*)(.*)$!;
my $temp = $re;
my ($left, $right) = ($1, $3);
$re = $2;

10
git.c
View File

@@ -416,13 +416,9 @@ static void execv_dashed_external(const char **argv)
* if we fail because the command is not found, it is
* OK to return. Otherwise, we just pass along the status code.
*/
status = run_command_v_opt(argv, 0);
if (status != -ERR_RUN_COMMAND_EXEC) {
if (IS_RUN_COMMAND_ERR(status))
die("unable to run '%s'", argv[0]);
exit(-status);
}
errno = ENOENT; /* as if we called execvp */
status = run_command_v_opt(argv, RUN_SILENT_EXEC_FAILURE);
if (status >= 0 || errno != ENOENT)
exit(status);
argv[0] = tmp;

View File

@@ -288,7 +288,7 @@ proc parseviewrevs {view revs} {
if {$sdm != 2} {
lappend ret $id
} else {
lset ret end [lindex $ret end]...$id
lset ret end $id...[lindex $ret end]
}
lappend pos $id
}
@@ -1677,6 +1677,7 @@ proc readrefs {} {
global tagids idtags headids idheads tagobjid
global otherrefids idotherrefs mainhead mainheadid
global selecthead selectheadid
global hideremotes
foreach v {tagids idtags headids idheads otherrefids idotherrefs} {
catch {unset $v}
@@ -1689,7 +1690,7 @@ proc readrefs {} {
if {![string match "refs/*" $ref]} continue
set name [string range $ref 5 end]
if {[string match "remotes/*" $name]} {
if {![string match "*/HEAD" $name]} {
if {![string match "*/HEAD" $name] && !$hideremotes} {
set headids($name) $id
lappend idheads($id) $name
}
@@ -2520,6 +2521,7 @@ proc savestuff {w} {
global cmitmode wrapcomment datetimeformat limitdiffs
global colors bgcolor fgcolor diffcolors diffcontext selectbgcolor
global autoselect extdifftool perfile_attrs markbgcolor
global hideremotes
if {$stuffsaved} return
if {![winfo viewable .]} return
@@ -2539,6 +2541,7 @@ proc savestuff {w} {
puts $f [list set wrapcomment $wrapcomment]
puts $f [list set autoselect $autoselect]
puts $f [list set showneartags $showneartags]
puts $f [list set hideremotes $hideremotes]
puts $f [list set showlocalchanges $showlocalchanges]
puts $f [list set datetimeformat $datetimeformat]
puts $f [list set limitdiffs $limitdiffs]
@@ -7907,6 +7910,11 @@ proc gotocommit {} {
}
set id [lindex $matches 0]
}
} else {
if {[catch {set id [exec git rev-parse --verify $sha1string]}]} {
error_popup [mc "Revision %s is not known" $sha1string]
return
}
}
}
if {[commitinview $id $curview]} {
@@ -7916,7 +7924,7 @@ proc gotocommit {} {
if {[regexp {^[0-9a-fA-F]{4,}$} $sha1string]} {
set msg [mc "SHA1 id %s is not known" $sha1string]
} else {
set msg [mc "Tag/Head %s is not known" $sha1string]
set msg [mc "Revision %s is not in the current view" $sha1string]
}
error_popup $msg
}
@@ -10384,6 +10392,7 @@ proc doprefs {} {
global oldprefs prefstop showneartags showlocalchanges
global bgcolor fgcolor ctext diffcolors selectbgcolor markbgcolor
global tabstop limitdiffs autoselect extdifftool perfile_attrs
global hideremotes
set top .gitkprefs
set prefstop $top
@@ -10392,7 +10401,7 @@ proc doprefs {} {
return
}
foreach v {maxwidth maxgraphpct showneartags showlocalchanges \
limitdiffs tabstop perfile_attrs} {
limitdiffs tabstop perfile_attrs hideremotes} {
set oldprefs($v) [set $v]
}
toplevel $top
@@ -10424,6 +10433,9 @@ proc doprefs {} {
checkbutton $top.ntag -text [mc "Display nearby tags"] \
-font optionfont -variable showneartags
grid x $top.ntag -sticky w
checkbutton $top.hideremotes -text [mc "Hide remote refs"] \
-font optionfont -variable hideremotes
grid x $top.hideremotes -sticky w
checkbutton $top.ldiff -text [mc "Limit diffs to listed paths"] \
-font optionfont -variable limitdiffs
grid x $top.ldiff -sticky w
@@ -10548,7 +10560,7 @@ proc prefscan {} {
global oldprefs prefstop
foreach v {maxwidth maxgraphpct showneartags showlocalchanges \
limitdiffs tabstop perfile_attrs} {
limitdiffs tabstop perfile_attrs hideremotes} {
global $v
set $v $oldprefs($v)
}
@@ -10562,6 +10574,7 @@ proc prefsok {} {
global oldprefs prefstop showneartags showlocalchanges
global fontpref mainfont textfont uifont
global limitdiffs treediffs perfile_attrs
global hideremotes
catch {destroy $prefstop}
unset prefstop
@@ -10607,6 +10620,9 @@ proc prefsok {} {
$limitdiffs != $oldprefs(limitdiffs)} {
reselectline
}
if {$hideremotes != $oldprefs(hideremotes)} {
rereadrefs
}
}
proc formatdate {d} {
@@ -10902,7 +10918,7 @@ proc gitattr {path attr default} {
} else {
set r "unspecified"
if {![catch {set line [exec git check-attr $attr -- $path]}]} {
regexp "(.*): encoding: (.*)" $line m f r
regexp "(.*): $attr: (.*)" $line m f r
}
set path_attr_cache($attr,$path) $r
}
@@ -10930,7 +10946,7 @@ proc cache_gitattr {attr pathlist} {
set newlist [lrange $newlist $lim end]
if {![catch {set rlist [eval exec git check-attr $attr -- $head]}]} {
foreach row [split $rlist "\n"] {
if {[regexp "(.*): encoding: (.*)" $row m path value]} {
if {[regexp "(.*): $attr: (.*)" $row m path value]} {
if {[string index $path 0] eq "\""} {
set path [encoding convertfrom [lindex $path 0]]
}
@@ -11012,6 +11028,7 @@ set mingaplen 100
set cmitmode "patch"
set wrapcomment "none"
set showneartags 1
set hideremotes 0
set maxrefs 20
set maxlinelen 200
set showlocalchanges 1

View File

@@ -165,6 +165,12 @@ not include variables usually directly set during build):
Full URL and absolute URL of gitweb script;
in earlier versions of gitweb you might have need to set those
variables, now there should be no need to do it.
* $base_url
Base URL for relative URLs in pages generated by gitweb,
(e.g. $logo, $favicon, @stylesheets if they are relative URLs),
needed and used only for URLs with nonempty PATH_INFO via
<base href="$base_url>. Usually gitweb sets its value correctly,
and there is no need to set this variable, e.g. to $my_uri or "/".
* $home_link
Target of the home link on top of all pages (the first part of view
"breadcrumbs"). By default set to absolute URI of a page ($my_uri).

Binary file not shown.

Before

Width:  |  Height:  |  Size: 164 B

After

Width:  |  Height:  |  Size: 115 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 208 B

After

Width:  |  Height:  |  Size: 207 B

View File

@@ -226,22 +226,30 @@ th {
text-align: left;
}
tr.light:hover {
background-color: #edece6;
/* do not change row style on hover for 'blame' view */
tr.light,
table.blame .light:hover {
background-color: #ffffff;
}
tr.dark {
background-color: #f6f6f0;
}
tr.dark2 {
tr.dark,
table.blame .dark:hover {
background-color: #f6f6f0;
}
/* currently both use the same, but it can change */
tr.light:hover,
tr.dark:hover {
background-color: #edece6;
}
/* boundary commits in 'blame' view */
/* and commits without "previous" */
tr.boundary td.sha1,
tr.no-previous td.linenr {
font-weight: bold;
}
td {
padding: 2px 5px;
font-size: 100%;
@@ -262,7 +270,7 @@ td.sha1 {
font-family: monospace;
}
td.error {
.error {
color: red;
background-color: yellow;
}

View File

@@ -940,10 +940,13 @@ sub href {
if (defined $params{'hash_parent_base'}) {
$href .= esc_url($params{'hash_parent_base'});
# skip the file_parent if it's the same as the file_name
delete $params{'file_parent'} if $params{'file_parent'} eq $params{'file_name'};
if (defined $params{'file_parent'} && $params{'file_parent'} !~ /\.\./) {
$href .= ":/".esc_url($params{'file_parent'});
delete $params{'file_parent'};
if (defined $params{'file_parent'}) {
if (defined $params{'file_name'} && $params{'file_parent'} eq $params{'file_name'}) {
delete $params{'file_parent'};
} elsif ($params{'file_parent'} !~ /\.\./) {
$href .= ":/".esc_url($params{'file_parent'});
delete $params{'file_parent'};
}
}
$href .= "..";
delete $params{'hash_parent'};
@@ -2570,7 +2573,7 @@ sub parse_commit_text {
} elsif ((!defined $withparents) && ($line =~ m/^parent ([0-9a-fA-F]{40})$/)) {
push @parents, $1;
} elsif ($line =~ m/^author (.*) ([0-9]+) (.*)$/) {
$co{'author'} = $1;
$co{'author'} = to_utf8($1);
$co{'author_epoch'} = $2;
$co{'author_tz'} = $3;
if ($co{'author'} =~ m/^([^<]+) <([^>]*)>/) {
@@ -2580,10 +2583,9 @@ sub parse_commit_text {
$co{'author_name'} = $co{'author'};
}
} elsif ($line =~ m/^committer (.*) ([0-9]+) (.*)$/) {
$co{'committer'} = $1;
$co{'committer'} = to_utf8($1);
$co{'committer_epoch'} = $2;
$co{'committer_tz'} = $3;
$co{'committer_name'} = $co{'committer'};
if ($co{'committer'} =~ m/^([^<]+) <([^>]*)>/) {
$co{'committer_name'} = $1;
$co{'committer_email'} = $2;
@@ -4801,7 +4803,7 @@ sub git_blame {
git_print_page_path($file_name, $ftype, $hash_base);
# page body
my @rev_color = qw(light2 dark2);
my @rev_color = qw(light dark);
my $num_colors = scalar(@rev_color);
my $current_color = 0;
my %metainfo = ();
@@ -4819,15 +4821,18 @@ HTML
my ($full_rev, $orig_lineno, $lineno, $group_size) =
($line =~ /^([0-9a-f]{40}) (\d+) (\d+)(?: (\d+))?$/);
if (!exists $metainfo{$full_rev}) {
$metainfo{$full_rev} = {};
$metainfo{$full_rev} = { 'nprevious' => 0 };
}
my $meta = $metainfo{$full_rev};
my $data;
while ($data = <$fd>) {
chomp $data;
last if ($data =~ s/^\t//); # contents of line
if ($data =~ /^(\S+) (.*)$/) {
$meta->{$1} = $2;
if ($data =~ /^(\S+)(?: (.*))?$/) {
$meta->{$1} = $2 unless exists $meta->{$1};
}
if ($data =~ /^previous /) {
$meta->{'nprevious'}++;
}
}
my $short_rev = substr($full_rev, 0, 8);
@@ -4838,7 +4843,11 @@ HTML
if ($group_size) {
$current_color = ($current_color + 1) % $num_colors;
}
print "<tr id=\"l$lineno\" class=\"$rev_color[$current_color]\">\n";
my $tr_class = $rev_color[$current_color];
$tr_class .= ' boundary' if (exists $meta->{'boundary'});
$tr_class .= ' no-previous' if ($meta->{'nprevious'} == 0);
$tr_class .= ' multiple-previous' if ($meta->{'nprevious'} > 1);
print "<tr id=\"l$lineno\" class=\"$tr_class\">\n";
if ($group_size) {
print "<td class=\"sha1\"";
print " title=\"". esc_html($author) . ", $date\"";
@@ -4848,22 +4857,31 @@ HTML
hash=>$full_rev,
file_name=>$file_name)},
esc_html($short_rev));
if ($group_size >= 2) {
my @author_initials = ($author =~ /\b([[:upper:]])\B/g);
if (@author_initials) {
print "<br />" .
esc_html(join('', @author_initials));
# or join('.', ...)
}
}
print "</td>\n";
}
my $parent_commit;
if (!exists $meta->{'parent'}) {
open (my $dd, "-|", git_cmd(), "rev-parse", "$full_rev^")
or die_error(500, "Open git-rev-parse failed");
$parent_commit = <$dd>;
close $dd;
chomp($parent_commit);
$meta->{'parent'} = $parent_commit;
} else {
$parent_commit = $meta->{'parent'};
# 'previous' <sha1 of parent commit> <filename at commit>
if (exists $meta->{'previous'} &&
$meta->{'previous'} =~ /^([a-fA-F0-9]{40}) (.*)$/) {
$meta->{'parent'} = $1;
$meta->{'file_parent'} = unquote($2);
}
my $linenr_commit =
exists($meta->{'parent'}) ?
$meta->{'parent'} : $full_rev;
my $linenr_filename =
exists($meta->{'file_parent'}) ?
$meta->{'file_parent'} : unquote($meta->{'filename'});
my $blamed = href(action => 'blame',
file_name => $meta->{'filename'},
hash_base => $parent_commit);
file_name => $linenr_filename,
hash_base => $linenr_commit);
print "<td class=\"linenr\">";
print $cgi->a({ -href => "$blamed#l$orig_lineno",
-class => "linenr" },

1
grep.h
View File

@@ -79,6 +79,7 @@ struct grep_opt {
int pathname;
int null_following_name;
int color;
int max_depth;
int funcname;
char color_match[COLOR_MAXLEN];
const char *color_external;

4
help.c
View File

@@ -302,7 +302,7 @@ const char *help_unknown_cmd(const char *cmd)
struct cmdnames main_cmds, other_cmds;
memset(&main_cmds, 0, sizeof(main_cmds));
memset(&other_cmds, 0, sizeof(main_cmds));
memset(&other_cmds, 0, sizeof(other_cmds));
memset(&aliases, 0, sizeof(aliases));
git_config(git_unknown_cmd_config, NULL);
@@ -334,7 +334,7 @@ const char *help_unknown_cmd(const char *cmd)
const char *assumed = main_cmds.names[0]->name;
main_cmds.names[0] = NULL;
clean_cmdnames(&main_cmds);
fprintf(stderr, "WARNING: You called a Git program named '%s', "
fprintf(stderr, "WARNING: You called a Git command named '%s', "
"which does not exist.\n"
"Continuing under the assumption that you meant '%s'\n",
cmd, assumed);

22
http.c
View File

@@ -1004,7 +1004,6 @@ int finish_http_pack_request(struct http_pack_request *preq)
struct http_pack_request *new_http_pack_request(
struct packed_git *target, const char *base_url)
{
char *url;
char *filename;
long prev_posn = 0;
char range[RANGE_HEADER_SIZE];
@@ -1018,8 +1017,7 @@ struct http_pack_request *new_http_pack_request(
end_url_with_slash(&buf, base_url);
strbuf_addf(&buf, "objects/pack/pack-%s.pack",
sha1_to_hex(target->sha1));
url = strbuf_detach(&buf, NULL);
preq->url = xstrdup(url);
preq->url = strbuf_detach(&buf, NULL);
filename = sha1_pack_name(target->sha1);
snprintf(preq->filename, sizeof(preq->filename), "%s", filename);
@@ -1035,7 +1033,7 @@ struct http_pack_request *new_http_pack_request(
preq->slot->local = preq->packfile;
curl_easy_setopt(preq->slot->curl, CURLOPT_FILE, preq->packfile);
curl_easy_setopt(preq->slot->curl, CURLOPT_WRITEFUNCTION, fwrite);
curl_easy_setopt(preq->slot->curl, CURLOPT_URL, url);
curl_easy_setopt(preq->slot->curl, CURLOPT_URL, preq->url);
curl_easy_setopt(preq->slot->curl, CURLOPT_HTTPHEADER,
no_pragma_header);
@@ -1059,6 +1057,8 @@ struct http_pack_request *new_http_pack_request(
abort:
free(filename);
free(preq->url);
free(preq);
return NULL;
}
@@ -1098,7 +1098,6 @@ struct http_object_request *new_http_object_request(const char *base_url,
char *hex = sha1_to_hex(sha1);
char *filename;
char prevfile[PATH_MAX];
char *url;
int prevlocal;
unsigned char prev_buf[PREV_BUF_SIZE];
ssize_t prev_read = 0;
@@ -1152,8 +1151,7 @@ struct http_object_request *new_http_object_request(const char *base_url,
git_SHA1_Init(&freq->c);
url = get_remote_object_url(base_url, hex, 0);
freq->url = xstrdup(url);
freq->url = get_remote_object_url(base_url, hex, 0);
/*
* If a previous temp file is present, process what was already
@@ -1189,7 +1187,11 @@ struct http_object_request *new_http_object_request(const char *base_url,
if (prev_posn>0) {
prev_posn = 0;
lseek(freq->localfile, 0, SEEK_SET);
ftruncate(freq->localfile, 0);
if (ftruncate(freq->localfile, 0) < 0) {
error("Couldn't truncate temporary file %s for %s: %s",
freq->tmpfile, freq->filename, strerror(errno));
goto abort;
}
}
}
@@ -1198,7 +1200,7 @@ struct http_object_request *new_http_object_request(const char *base_url,
curl_easy_setopt(freq->slot->curl, CURLOPT_FILE, freq);
curl_easy_setopt(freq->slot->curl, CURLOPT_WRITEFUNCTION, fwrite_sha1_file);
curl_easy_setopt(freq->slot->curl, CURLOPT_ERRORBUFFER, freq->errorstr);
curl_easy_setopt(freq->slot->curl, CURLOPT_URL, url);
curl_easy_setopt(freq->slot->curl, CURLOPT_URL, freq->url);
curl_easy_setopt(freq->slot->curl, CURLOPT_HTTPHEADER, no_pragma_header);
/*
@@ -1218,9 +1220,9 @@ struct http_object_request *new_http_object_request(const char *base_url,
return freq;
free(url);
abort:
free(filename);
free(freq->url);
free(freq);
return NULL;
}

View File

@@ -192,10 +192,6 @@ static int ll_ext_merge(const struct ll_merge_driver *fn,
args[2] = cmd.buf;
status = run_command_v_opt(args, 0);
if (status < -ERR_RUN_COMMAND_FORK)
; /* failure in run-command */
else
status = -status;
fd = open(temp[1], O_RDONLY);
if (fd < 0)
goto bad;

View File

@@ -168,18 +168,6 @@ static unsigned int digits_in_number(unsigned int number)
return result;
}
static int has_non_ascii(const char *s)
{
int ch;
if (!s)
return 0;
while ((ch = *s++) != '\0') {
if (non_ascii(ch))
return 1;
}
return 0;
}
void get_patch_filename(struct commit *commit, int nr, const char *suffix,
struct strbuf *buf)
{

View File

@@ -952,9 +952,31 @@ static int process_renames(struct merge_options *o,
"%s added in %s",
ren1_src, ren1_dst, branch1,
ren1_dst, branch2);
new_path = unique_path(o, ren1_dst, branch2);
output(o, 1, "Adding as %s instead", new_path);
update_file(o, 0, dst_other.sha1, dst_other.mode, new_path);
if (o->call_depth) {
struct merge_file_info mfi;
struct diff_filespec one, a, b;
one.path = a.path = b.path =
(char *)ren1_dst;
hashcpy(one.sha1, null_sha1);
one.mode = 0;
hashcpy(a.sha1, ren1->pair->two->sha1);
a.mode = ren1->pair->two->mode;
hashcpy(b.sha1, dst_other.sha1);
b.mode = dst_other.mode;
mfi = merge_file(o, &one, &a, &b,
branch1,
branch2);
output(o, 1, "Adding merged %s", ren1_dst);
update_file(o, 0,
mfi.sha,
mfi.mode,
ren1_dst);
} else {
new_path = unique_path(o, ren1_dst, branch2);
output(o, 1, "Adding as %s instead", new_path);
update_file(o, 0, dst_other.sha1, dst_other.mode, new_path);
}
} else if ((item = string_list_lookup(ren1_dst, renames2Dst))) {
ren2 = item->util;
clean_merge = 0;

View File

@@ -511,7 +511,7 @@ static int usage_with_options_internal(const char * const *usagestr,
continue;
pos = fprintf(stderr, " ");
if (opts->short_name) {
if (opts->short_name && !(opts->flags & PARSE_OPT_NEGHELP)) {
if (opts->flags & PARSE_OPT_NODASH)
pos += fprintf(stderr, "%c", opts->short_name);
else
@@ -520,7 +520,9 @@ static int usage_with_options_internal(const char * const *usagestr,
if (opts->long_name && opts->short_name)
pos += fprintf(stderr, ", ");
if (opts->long_name)
pos += fprintf(stderr, "--%s", opts->long_name);
pos += fprintf(stderr, "--%s%s",
(opts->flags & PARSE_OPT_NEGHELP) ? "no-" : "",
opts->long_name);
if (opts->type == OPTION_NUMBER)
pos += fprintf(stderr, "-NUM");

View File

@@ -36,6 +36,7 @@ enum parse_opt_option_flags {
PARSE_OPT_LASTARG_DEFAULT = 16,
PARSE_OPT_NODASH = 32,
PARSE_OPT_LITERAL_ARGHELP = 64,
PARSE_OPT_NEGHELP = 128,
};
struct option;
@@ -80,6 +81,9 @@ typedef int parse_opt_cb(const struct option *, const char *arg, int unset);
* PARSE_OPT_LITERAL_ARGHELP: says that argh shouldn't be enclosed in brackets
* (i.e. '<argh>') in the help message.
* Useful for options with multiple parameters.
* PARSE_OPT_NEGHELP: says that the long option should always be shown with
* the --no prefix in the usage message. Sometimes
* useful for users of OPTION_NEGBIT.
*
* `callback`::
* pointer to the callback to use for OPTION_CALLBACK.

View File

@@ -86,6 +86,18 @@ int non_ascii(int ch)
return !isascii(ch) || ch == '\033';
}
int has_non_ascii(const char *s)
{
int ch;
if (!s)
return 0;
while ((ch = *s++) != '\0') {
if (non_ascii(ch))
return 1;
}
return 0;
}
static int is_rfc2047_special(char ch)
{
return (non_ascii(ch) || (ch == '=') || (ch == '?') || (ch == '_'));

2
refs.c
View File

@@ -821,7 +821,7 @@ static int remove_empty_directories(const char *file)
strbuf_init(&path, 20);
strbuf_addstr(&path, file);
result = remove_dir_recursively(&path, 1);
result = remove_dir_recursively(&path, REMOVE_DIR_EMPTY_ONLY);
strbuf_release(&path);

View File

@@ -19,6 +19,7 @@ int start_command(struct child_process *cmd)
{
int need_in, need_out, need_err;
int fdin[2], fdout[2], fderr[2];
int failed_errno = failed_errno;
/*
* In case of errors we must keep the promise to close FDs
@@ -28,9 +29,10 @@ int start_command(struct child_process *cmd)
need_in = !cmd->no_stdin && cmd->in < 0;
if (need_in) {
if (pipe(fdin) < 0) {
failed_errno = errno;
if (cmd->out > 0)
close(cmd->out);
return -ERR_RUN_COMMAND_PIPE;
goto fail_pipe;
}
cmd->in = fdin[1];
}
@@ -40,11 +42,12 @@ int start_command(struct child_process *cmd)
&& cmd->out < 0;
if (need_out) {
if (pipe(fdout) < 0) {
failed_errno = errno;
if (need_in)
close_pair(fdin);
else if (cmd->in)
close(cmd->in);
return -ERR_RUN_COMMAND_PIPE;
goto fail_pipe;
}
cmd->out = fdout[0];
}
@@ -52,6 +55,7 @@ int start_command(struct child_process *cmd)
need_err = !cmd->no_stderr && cmd->err < 0;
if (need_err) {
if (pipe(fderr) < 0) {
failed_errno = errno;
if (need_in)
close_pair(fdin);
else if (cmd->in)
@@ -60,7 +64,11 @@ int start_command(struct child_process *cmd)
close_pair(fdout);
else if (cmd->out)
close(cmd->out);
return -ERR_RUN_COMMAND_PIPE;
fail_pipe:
error("cannot create pipe for %s: %s",
cmd->argv[0], strerror(failed_errno));
errno = failed_errno;
return -1;
}
cmd->err = fderr[0];
}
@@ -122,6 +130,9 @@ int start_command(struct child_process *cmd)
strerror(errno));
exit(127);
}
if (cmd->pid < 0)
error("cannot fork() for %s: %s", cmd->argv[0],
strerror(failed_errno = errno));
#else
int s0 = -1, s1 = -1, s2 = -1; /* backups of stdin, stdout, stderr */
const char **sargv = cmd->argv;
@@ -173,6 +184,9 @@ int start_command(struct child_process *cmd)
}
cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env);
failed_errno = errno;
if (cmd->pid < 0 && (!cmd->silent_exec_failure || errno != ENOENT))
error("cannot spawn %s: %s", cmd->argv[0], strerror(errno));
if (cmd->env)
free_environ(env);
@@ -189,7 +203,6 @@ int start_command(struct child_process *cmd)
#endif
if (cmd->pid < 0) {
int err = errno;
if (need_in)
close_pair(fdin);
else if (cmd->in)
@@ -200,9 +213,8 @@ int start_command(struct child_process *cmd)
close(cmd->out);
if (need_err)
close_pair(fderr);
return err == ENOENT ?
-ERR_RUN_COMMAND_EXEC :
-ERR_RUN_COMMAND_FORK;
errno = failed_errno;
return -1;
}
if (need_in)
@@ -221,40 +233,51 @@ int start_command(struct child_process *cmd)
return 0;
}
static int wait_or_whine(pid_t pid)
static int wait_or_whine(pid_t pid, const char *argv0, int silent_exec_failure)
{
for (;;) {
int status, code;
pid_t waiting = waitpid(pid, &status, 0);
int status, code = -1;
pid_t waiting;
int failed_errno = 0;
if (waiting < 0) {
if (errno == EINTR)
continue;
error("waitpid failed (%s)", strerror(errno));
return -ERR_RUN_COMMAND_WAITPID;
}
if (waiting != pid)
return -ERR_RUN_COMMAND_WAITPID_WRONG_PID;
if (WIFSIGNALED(status))
return -ERR_RUN_COMMAND_WAITPID_SIGNAL;
while ((waiting = waitpid(pid, &status, 0)) < 0 && errno == EINTR)
; /* nothing */
if (!WIFEXITED(status))
return -ERR_RUN_COMMAND_WAITPID_NOEXIT;
if (waiting < 0) {
failed_errno = errno;
error("waitpid for %s failed: %s", argv0, strerror(errno));
} else if (waiting != pid) {
error("waitpid is confused (%s)", argv0);
} else if (WIFSIGNALED(status)) {
code = WTERMSIG(status);
error("%s died of signal %d", argv0, code);
/*
* This return value is chosen so that code & 0xff
* mimics the exit code that a POSIX shell would report for
* a program that died from this signal.
*/
code -= 128;
} else if (WIFEXITED(status)) {
code = WEXITSTATUS(status);
switch (code) {
case 127:
return -ERR_RUN_COMMAND_EXEC;
case 0:
return 0;
default:
return -code;
/*
* Convert special exit code when execvp failed.
*/
if (code == 127) {
code = -1;
failed_errno = ENOENT;
if (!silent_exec_failure)
error("cannot run %s: %s", argv0,
strerror(ENOENT));
}
} else {
error("waitpid is confused (%s)", argv0);
}
errno = failed_errno;
return code;
}
int finish_command(struct child_process *cmd)
{
return wait_or_whine(cmd->pid);
return wait_or_whine(cmd->pid, cmd->argv[0], cmd->silent_exec_failure);
}
int run_command(struct child_process *cmd)
@@ -274,6 +297,7 @@ static void prepare_run_command_v_opt(struct child_process *cmd,
cmd->no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0;
cmd->git_cmd = opt & RUN_GIT_CMD ? 1 : 0;
cmd->stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0;
cmd->silent_exec_failure = opt & RUN_SILENT_EXEC_FAILURE ? 1 : 0;
}
int run_command_v_opt(const char **argv, int opt)
@@ -338,10 +362,7 @@ int start_async(struct async *async)
int finish_async(struct async *async)
{
#ifndef __MINGW32__
int ret = 0;
if (wait_or_whine(async->pid))
ret = error("waitpid (async) failed");
int ret = wait_or_whine(async->pid, "child process", 0);
#else
DWORD ret = 0;
if (WaitForSingleObject(async->tid, INFINITE) != WAIT_OBJECT_0)
@@ -385,15 +406,7 @@ int run_hook(const char *index_file, const char *name, ...)
hook.env = env;
}
ret = start_command(&hook);
ret = run_command(&hook);
free(argv);
if (ret) {
warning("Could not spawn %s", argv[0]);
return ret;
}
ret = finish_command(&hook);
if (ret == -ERR_RUN_COMMAND_WAITPID_SIGNAL)
warning("%s exited due to uncaught signal", argv[0]);
return ret;
}

View File

@@ -1,17 +1,6 @@
#ifndef RUN_COMMAND_H
#define RUN_COMMAND_H
enum {
ERR_RUN_COMMAND_FORK = 10000,
ERR_RUN_COMMAND_EXEC,
ERR_RUN_COMMAND_PIPE,
ERR_RUN_COMMAND_WAITPID,
ERR_RUN_COMMAND_WAITPID_WRONG_PID,
ERR_RUN_COMMAND_WAITPID_SIGNAL,
ERR_RUN_COMMAND_WAITPID_NOEXIT,
};
#define IS_RUN_COMMAND_ERR(x) (-(x) >= ERR_RUN_COMMAND_FORK)
struct child_process {
const char **argv;
pid_t pid;
@@ -42,6 +31,7 @@ struct child_process {
unsigned no_stdout:1;
unsigned no_stderr:1;
unsigned git_cmd:1; /* if this is to be git sub-command */
unsigned silent_exec_failure:1;
unsigned stdout_to_stderr:1;
void (*preexec_cb)(void);
};
@@ -55,6 +45,7 @@ extern int run_hook(const char *index_file, const char *name, ...);
#define RUN_COMMAND_NO_STDIN 1
#define RUN_GIT_CMD 2 /*If this is to be git sub-command */
#define RUN_COMMAND_STDOUT_TO_STDERR 4
#define RUN_SILENT_EXEC_FAILURE 8
int run_command_v_opt(const char **argv, int opt);
/*

View File

@@ -3,6 +3,7 @@
struct send_pack_args {
unsigned verbose:1,
quiet:1,
send_mirror:1,
force_update:1,
use_thin_pack:1,

View File

@@ -91,6 +91,10 @@ static int lstat_cache(struct cache_def *cache, const char *name, int len,
longest_path_match(name, len, cache->path, cache->len,
&previous_slash);
match_flags = cache->flags & track_flags & (FL_NOENT|FL_SYMLINK);
if (!(track_flags & FL_FULLPATH) && match_len == len)
match_len = last_slash = previous_slash;
if (match_flags && match_len == cache->len)
return match_flags;
/*

View File

@@ -3,6 +3,8 @@
# Copyright (c) 2005 Junio C Hamano
#
-include ../config.mak
#GIT_TEST_OPTS=--verbose --debug
SHELL_PATH ?= $(SHELL)
TAR ?= $(TAR)

75
t/lib-cvs.sh Normal file
View File

@@ -0,0 +1,75 @@
#!/bin/sh
. ./test-lib.sh
unset CVS_SERVER
# for clean cvsps cache
HOME=$(pwd)
export HOME
if ! type cvs >/dev/null 2>&1
then
say 'skipping cvsimport tests, cvs not found'
test_done
fi
CVS="cvs -f"
export CVS
cvsps_version=`cvsps -h 2>&1 | sed -ne 's/cvsps version //p'`
case "$cvsps_version" in
2.1 | 2.2*)
;;
'')
say 'skipping cvsimport tests, cvsps not found'
test_done
;;
*)
say 'skipping cvsimport tests, unsupported cvsps version'
test_done
;;
esac
test_cvs_co () {
# Usage: test_cvs_co BRANCH_NAME
rm -rf module-cvs-"$1"
if [ "$1" = "master" ]
then
$CVS co -P -d module-cvs-"$1" -A module
else
$CVS co -P -d module-cvs-"$1" -r "$1" module
fi
}
test_git_co () {
# Usage: test_git_co BRANCH_NAME
(cd module-git && git checkout "$1")
}
test_cmp_branch_file () {
# Usage: test_cmp_branch_file BRANCH_NAME PATH
# The branch must already be checked out of CVS and git.
test_cmp module-cvs-"$1"/"$2" module-git/"$2"
}
test_cmp_branch_tree () {
# Usage: test_cmp_branch_tree BRANCH_NAME
# Check BRANCH_NAME out of CVS and git and make sure that all
# of the files and directories are identical.
test_cvs_co "$1" &&
test_git_co "$1" &&
(
cd module-cvs-"$1"
find . -type d -name CVS -prune -o -type f -print
) | sort >module-cvs-"$1".list &&
(
cd module-git
find . -type d -name .git -prune -o -type f -print
) | sort >module-git-"$1".list &&
test_cmp module-cvs-"$1".list module-git-"$1".list &&
cat module-cvs-"$1".list | while read f
do
test_cmp_branch_file "$1" "$f" || return 1
done
}

View File

@@ -14,7 +14,7 @@ if ! test_have_prereq PERL; then
fi
GIT_DIR=$PWD/.git
GIT_SVN_DIR=$GIT_DIR/svn/git-svn
GIT_SVN_DIR=$GIT_DIR/svn/refs/remotes/git-svn
SVN_TREE=$GIT_SVN_DIR/svn-tree
svn >/dev/null 2>&1

Some files were not shown because too many files have changed in this diff Show More