The latest feature release Git 1.7.7 is available.
The release tarballs are found at:
http://code.google.com/p/git-core/downloads/list
and their SHA-1 checksums are:
bbf85bd767ca6b7e9caa1489bb4ba7ec64e0ab35 git-1.7.7.tar.gz
33183db94fd25e001bd8a9fd6696b992f61e28d8 git-htmldocs-1.7.7.tar.gz
75d3cceb46f7a46eeb825033dff76af5eb5ea3d9 git-manpages-1.7.7.tar.gz
Also the following public repositories all have a copy of the v1.7.7 tag and the master branch that the tag points at:
url = git://repo.or.cz/alt-git.git
url = https://code.google.com/p/git-core/
url = git://git.sourceforge.jp/gitroot/git-core/git.git
url = git://git-core.git.sourceforge.net/gitroot/git-core/git-core
url = https://github.com/gitster/git
The release tag and the tarballs can be verified with my GPG key if anybody is so inclined. To get my public key:
$ git fetch git://repo.or.cz/alt-git.git refs/tags/junio-gpg-pub
$ git rev-parse FETCH_HEAD
680865b90b18efbc9402ea979adf0302c6dfe72e
$ git cat-file blob FETCH_HEAD | gpg --import
and then make sure that you got my key by checking the output from "gpg --fingerprint", which should contain these lines:
pub 1024D/F3119B9A 2004-01-28
Key fingerprint = 3565 2A26 2040 E066 C9A7 4A7D C0C6 D9A4 F311 9B9A
uid Junio C Hamano <gitster@pobox.com>
The tarball description at http://code.google.com/p/git-core/downloads/list contains the same list of SHA-1 checksums shown above and signed with my GPG key.
Have fun.
Git v1.7.7 Release Notes
========================
Updates since v1.7.6
--------------------
* The scripting part of the codebase is getting prepared for i18n/l10n.
* Interix, Cygwin and Minix ports got updated.
* Various updates to git-p4 (in contrib/), fast-import, and git-svn.
* Gitweb learned to read from /etc/gitweb-common.conf when it exists,
before reading from gitweb_config.perl or from /etc/gitweb.conf
(this last one is read only when per-repository gitweb_config.perl
does not exist).
* Various codepaths that invoked zlib deflate/inflate assumed that these
functions can compress or uncompress more than 4GB data in one call on
platforms with 64-bit long, which has been corrected.
* Git now recognizes loose objects written by other implementations that
use a non-standard window size for zlib deflation (e.g. Agit running on
Android with 4kb window). We used to reject anything that was not
deflated with 32kb window.
* Interaction between the use of pager and coloring of the output has
been improved, especially when a command that is not built-in was
involved.
* "git am" learned to pass the "--exclude=<path>" option through to underlying
"git apply".
* You can now feed many empty lines before feeding an mbox file to
"git am".
* "git archive" can be told to pass the output to gzip compression and
produce "archive.tar.gz".
* "git bisect" can be used in a bare repository (provided that the test
you perform per each iteration does not need a working tree, of
course).
* The length of abbreviated object names in "git branch -v" output
now honors the core.abbrev configuration variable.
* "git check-attr" can take relative paths from the command line.
* "git check-attr" learned an "--all" option to list the attributes for a
given path.
* "git checkout" (both the code to update the files upon checking out a
different branch and the code to checkout a specific set of files) learned
to stream the data from object store when possible, without having to
read the entire contents of a file into memory first. An earlier round
of this code that is not in any released version had a large leak but
now it has been plugged.
* "git clone" can now take a "--config key=value" option to set the
repository configuration options that affect the initial checkout.
* "git commit <paths>..." now lets you feed relative pathspecs that
refer to outside your current subdirectory.
* "git diff --stat" learned a --stat-count option to limit the output of
a diffstat report.
* "git diff" learned a "--histogram" option to use a different diff
generation machinery stolen from jgit, which might give better
performance.
* "git diff" had a weird worst case behaviour that can be triggered
when comparing files with potentially many places that could match.
* "git fetch", "git push" and friends no longer show connection
errors for addresses that couldn't be connected to when at least one
address succeeds (this is arguably a regression but a deliberate
one).
* "git grep" learned "--break" and "--heading" options, to let users mimic
the output format of "ack".
* "git grep" learned a "-W" option that shows wider context using the same
logic used by "git diff" to determine the hunk header.
* Invoking the low-level "git http-fetch" without "-a" option (which
git itself never did---normal users should not have to worry about
this) is now deprecated.
* The "--decorate" option to "git log" and its family learned to
highlight grafted and replaced commits.
* "git rebase master topci" no longer spews usage hints after giving
the "fatal: no such branch: topci" error message.
* The recursive merge strategy implementation got a fairly large
fix for many corner cases that may rarely happen in real world
projects (it has been verified that none of the 16000+ merges in
the Linux kernel history back to v2.6.12 is affected with the
corner case bugs this update fixes).
* "git stash" learned an "--include-untracked option".
* "git submodule update" used to stop at the first error updating a
submodule; it now goes on to update other submodules that can be
updated, and reports the ones with errors at the end.
* "git push" can be told with the "--recurse-submodules=check" option to
refuse pushing of the supermodule, if any of its submodules'
commits hasn't been pushed out to their remotes.
* "git upload-pack" and "git receive-pack" learned to pretend that only a
subset of the refs exist in a repository. This may help a site to
put many tiny repositories into one repository (this would not be
useful for larger repositories as repacking would be problematic).
* "git verify-pack" has been rewritten to use the "index-pack" machinery
that is more efficient in reading objects in packfiles.
* test scripts for gitweb tried to run even when CGI-related perl modules
are not installed; they now exit early when the latter are unavailable.
Also contains various documentation updates and minor miscellaneous
changes.
Fixes since v1.7.6
------------------
Unless otherwise noted, all fixes in the 1.7.6.X maintenance track are
included in this release.
* "git branch -m" and "git checkout -b" incorrectly allowed the tip
of the branch that is currently checked out updated.
Friday, September 30, 2011
Friday, September 23, 2011
Git 1.7.7-rc3 and 1.7.6.4 are out
I gave up waiting on kernel.org and really wanted to do the 1.7.7 final toward this weekend, but found a corner case regression in the recursive merge backend (again). 1.7.7-rc3 contains a quick fix for it, and needs to be cooked for a few days at least, so the final will have to wait at least until mid next week.
1.7.6.4 merges a handful of fixes that have already been merged to the master branch and are included in 1.7.7-rc3.
They are both available at
http://code.google.com/p/git-core/downloads/list
and also are found in my public repositories at various hosting sites:
url = git://repo.or.cz/alt-git.git
url = https://code.google.com/p/git-core/
url = git://git.sourceforge.jp/gitroot/git-core/git.git
url = git://git-core.git.sourceforge.net/gitroot/git-core/git-core
url = https://github.com/gitster/git
1.7.6.4 merges a handful of fixes that have already been merged to the master branch and are included in 1.7.7-rc3.
They are both available at
http://code.google.com/p/git-core/downloads/list
and also are found in my public repositories at various hosting sites:
url = git://repo.or.cz/alt-git.git
url = https://code.google.com/p/git-core/
url = git://git.sourceforge.jp/gitroot/git-core/git.git
url = git://git-core.git.sourceforge.net/gitroot/git-core/git-core
url = https://github.com/gitster/git
Wednesday, September 21, 2011
Return of html/man branches
I have not built and published these two branches myself for quite some time, as I let the post update hook of my public repository automatically fetch updates from the 'master' branch to another work area, format the documentation, make commits and push the result back to the public repository, all automated at the kernel.org infrastructure.
Unfortunately, kernel.org has been down for quite a while. So as a "time-permits" and "experimental" basis, I've started publishing these two branches after formatting the documentation locally on my primary development machine to the other public repositories.
I won't promise that I'll rebuild the docs every time I push the 'master' branch out, like the system I used to have at kernel.org did for me, but this will have to do in the meantime.
Monday, September 19, 2011
Fun with url.$that.insteadOf
It is not exactly fun that I and others have to do this, but while k.org is down:
$ git -c url.http://code.google.com/p/git-core.insteadof=git://git.kernel.org/pub/scm/git/git.git fetch
lets me reuse all the fetch refspec configuration items I have for the "origin" remote.
To make this semi-permanent, I could have the following in my $HOME/.gitconfig but I have been hoping that k.org would come back before I actually do it and haven't done so:
Not exactly fun, but...
$ git -c url.http://code.google.com/p/git-core.insteadof=git://git.kernel.org/pub/scm/git/git.git fetch
lets me reuse all the fetch refspec configuration items I have for the "origin" remote.
To make this semi-permanent, I could have the following in my $HOME/.gitconfig but I have been hoping that k.org would come back before I actually do it and haven't done so:
[url "http://code.google.com/p/git-core"]
insteadOf = git://git.kernel.org/pub/scm/git/git.git
Labels:
Git
Monday, September 12, 2011
Git User's Survey 2011
Here is from Jakub Narebski who is again running "Git User's Survey" this year for us.
The Git User's Survey 2011 is now up! Please devote a few minutes of
your time to fill out the simple questionnaire; it'll help the Git
community understand your needs, what you like about Git (and what you
don't), and overall help us improve it.
The survey will be open from 5 September till 3 October 2011.
The results will be published at GitSurvey2011 page on Git Wiki.
The Git User's Survey 2011 is now up! Please devote a few minutes of
your time to fill out the simple questionnaire; it'll help the Git
community understand your needs, what you like about Git (and what you
don't), and overall help us improve it.
The survey will be open from 5 September till 3 October 2011.
The results will be published at GitSurvey2011 page on Git Wiki.
1.7.7-rc1 is out
As I have been postponing of tagging this feature freeze release candidate for a while, hoping that k.org would regain its health soon enough, we are seriously slipping. I was hoping to tag the final by the end of August, but now it is almost mid September.
In any case, the shape of the upcoming release is fairly clear now. Please help finding regressions so that we can have a solid final release by the end of this month if not earlier.
A release candidate tarball is found at:
http://code.google.com/p/git- core/downloads/list
and its SHA-1 checksum is:
80dfcce410d2f36ffed4c8b48c8c89
6a45159e41 git-1.7.7.rc1.tar.gz
Also the following public repositories all have a copy of the v1.7.7-rc1
tag and the master branch that the tag points at:
url = git://repo.or.cz/alt-git.git
url = https://code.google.com/p/git- core/
url = git://git.sourceforge.jp/ gitroot/git-core/git.git
url = git://git-core.git. sourceforge.net/gitroot/git- core/git-core
url = https://github.com/gitster/git
Git v1.7.7 Release Notes (draft)
========================
Updates since v1.7.6
--------------------
* The scripting part of the codebase is getting prepared for i18n/l10n.
* Interix, Cygwin and Minix ports got updated.
* Various updates to git-p4 (in contrib/), fast-import, and git-svn.
* Gitweb learned to read from /etc/gitweb-common.conf when it exists,
before reading from gitweb_config.perl or from /etc/gitweb.conf
(this last one is read only when per-repository gitweb_config.perl
does not exist).
* Various codepaths that invoked zlib deflate/inflate assumed that these
functions can compress or uncompress more than 4GB data in one call on
platforms with 64-bit long, which has been corrected.
* Git now recognizes loose objects written by other implementations that
use a non-standard window size for zlib deflation (e.g. Agit running on
Android with 4kb window). We used to reject anything that was not
deflated with 32kb window.
* Interaction between the use of pager and coloring of the output has
been improved, especially when a command that is not built-in was
involved.
* "git am" learned to pass the "--exclude=<path>" option through to underlying
"git apply".
* You can now feed many empty lines before feeding an mbox file to
"git am".
* "git archive" can be told to pass the output to gzip compression and
produce "archive.tar.gz".
* "git bisect" can be used in a bare repository (provided that the test
you perform per each iteration does not need a working tree, of
course).
* The length of abbreviated object names in "git branch -v" output
now honors the core.abbrev configuration variable.
* "git check-attr" can take relative paths from the command line.
* "git check-attr" learned an "--all" option to list the attributes for a
given path.
* "git checkout" (both the code to update the files upon checking out a
different branch and the code to checkout a specific set of files) learned
to stream the data from object store when possible, without having to
read the entire contents of a file into memory first. An earlier round
of this code that is not in any released version had a large leak but
now it has been plugged.
* "git clone" can now take a "--config key=value" option to set the
repository configuration options that affect the initial checkout.
* "git commit <paths>..." now lets you feed relative pathspecs that
refer to outside your current subdirectory.
* "git diff --stat" learned a --stat-count option to limit the output of
a diffstat report.
* "git diff" learned a "--histogram" option to use a different diff
generation machinery stolen from jgit, which might give better
performance.
* "git diff" had a weird worst case behaviour that can be triggered
when comparing files with potentially many places that could match.
* "git fetch", "git push" and friends no longer show connection
errors for addresses that couldn't be connected to when at least one
address succeeds (this is arguably a regression but a deliberate
one).
* "git grep" learned "--break" and "--heading" options, to let users mimic
the output format of "ack".
* "git grep" learned a "-W" option that shows wider context using the same
logic used by "git diff" to determine the hunk header.
* Invoking the low-level "git http-fetch" without "-a" option (which
git itself never did---normal users should not have to worry about
this) is now deprecated.
* The "--decorate" option to "git log" and its family learned to
highlight grafted and replaced commits.
* "git rebase master topci" no longer spews usage hints after giving
the "fatal: no such branch: topci" error message.
* The recursive merge strategy implementation got a fairly large
fix for many corner cases that may rarely happen in real world
projects (it has been verified that none of the 16000+ merges in
the Linux kernel history back to v2.6.12 is affected with the
corner case bugs this update fixes).
* "git stash" learned an "--include-untracked option".
* "git submodule update" used to stop at the first error updating a
submodule; it now goes on to update other submodules that can be
updated, and reports the ones with errors at the end.
* "git push" can be told with the "--recurse-submodules=check" option to
refuse pushing of the supermodule, if any of its submodules'
commits hasn't been pushed out to their remotes.
* "git upload-pack" and "git receive-pack" learned to pretend that only a
subset of the refs exist in a repository. This may help a site to
put many tiny repositories into one repository (this would not be
useful for larger repositories as repacking would be problematic).
* "git verify-pack" has been rewritten to use the "index-pack" machinery
that is more efficient in reading objects in packfiles.
* test scripts for gitweb tried to run even when CGI-related perl modules
are not installed; they now exit early when the latter are unavailable.
Also contains various documentation updates and minor miscellaneous
changes.
Fixes since v1.7.6
------------------
Unless otherwise noted, all fixes in the 1.7.6.X maintenance track are
included in this release.
* The error reporting logic of "git am" when the command is fed a file
whose mail-storage format is unknown was fixed.
(merge dff4b0e gb/maint-am-patch-format- error-message later to 'maint').
* "git branch --set-upstream @{-1} foo" did not expand @{-1} correctly.
(merge e9d4f74 mg/branch-set-upstream- previous later to 'maint').
* "git branch -m" and "git checkout -b" incorrectly allowed the tip
of the branch that is currently checked out updated.
(merge 55c4a67 ci/forbid-unwanted-current- branch-update later to 'maint').
* "git check-ref-format --print" used to parrot a candidate string that
began with a slash (e.g. /refs/heads/master) without stripping it, to make
the result a suitably normalized string the caller can append to "$GIT_DIR/".
(merge f3738c1 mh/check-ref-format-print- normalize later to 'maint').
* "git clone" failed to clone locally from a ".git" file that itself
is not a directory but is a pointer to one.
(merge 9b0ebc7 nd/maint-clone-gitdir later to 'maint').
* "git clone" from a local repository that borrows from another
object store using a relative path in its objects/info/alternates
file did not adjust the alternates in the resulting repository.
(merge e6baf4a1 jc/maint-clone-alternates later to 'maint').
* "git describe --dirty" did not refresh the index before checking the
state of the working tree files.
(cherry-pick bb57148 ac/describe-dirty-refresh later to 'maint').
* "git ls-files ../$path" that is run from a subdirectory reported errors
incorrectly when there is no such path that matches the given pathspec.
(merge 0f64bfa cb/maint-ls-files-error-report later to 'maint').
In any case, the shape of the upcoming release is fairly clear now. Please help finding regressions so that we can have a solid final release by the end of this month if not earlier.
A release candidate tarball is found at:
http://code.google.com/p/git-
and its SHA-1 checksum is:
80dfcce410d2f36ffed4c8b48c8c89
Also the following public repositories all have a copy of the v1.7.7-rc1
tag and the master branch that the tag points at:
url = git://repo.or.cz/alt-git.git
url = https://code.google.com/p/git-
url = git://git.sourceforge.jp/
url = git://git-core.git.
url = https://github.com/gitster/git
Git v1.7.7 Release Notes (draft)
========================
Updates since v1.7.6
--------------------
* The scripting part of the codebase is getting prepared for i18n/l10n.
* Interix, Cygwin and Minix ports got updated.
* Various updates to git-p4 (in contrib/), fast-import, and git-svn.
* Gitweb learned to read from /etc/gitweb-common.conf when it exists,
before reading from gitweb_config.perl or from /etc/gitweb.conf
(this last one is read only when per-repository gitweb_config.perl
does not exist).
* Various codepaths that invoked zlib deflate/inflate assumed that these
functions can compress or uncompress more than 4GB data in one call on
platforms with 64-bit long, which has been corrected.
* Git now recognizes loose objects written by other implementations that
use a non-standard window size for zlib deflation (e.g. Agit running on
Android with 4kb window). We used to reject anything that was not
deflated with 32kb window.
* Interaction between the use of pager and coloring of the output has
been improved, especially when a command that is not built-in was
involved.
* "git am" learned to pass the "--exclude=<path>" option through to underlying
"git apply".
* You can now feed many empty lines before feeding an mbox file to
"git am".
* "git archive" can be told to pass the output to gzip compression and
produce "archive.tar.gz".
* "git bisect" can be used in a bare repository (provided that the test
you perform per each iteration does not need a working tree, of
course).
* The length of abbreviated object names in "git branch -v" output
now honors the core.abbrev configuration variable.
* "git check-attr" can take relative paths from the command line.
* "git check-attr" learned an "--all" option to list the attributes for a
given path.
* "git checkout" (both the code to update the files upon checking out a
different branch and the code to checkout a specific set of files) learned
to stream the data from object store when possible, without having to
read the entire contents of a file into memory first. An earlier round
of this code that is not in any released version had a large leak but
now it has been plugged.
* "git clone" can now take a "--config key=value" option to set the
repository configuration options that affect the initial checkout.
* "git commit <paths>..." now lets you feed relative pathspecs that
refer to outside your current subdirectory.
* "git diff --stat" learned a --stat-count option to limit the output of
a diffstat report.
* "git diff" learned a "--histogram" option to use a different diff
generation machinery stolen from jgit, which might give better
performance.
* "git diff" had a weird worst case behaviour that can be triggered
when comparing files with potentially many places that could match.
* "git fetch", "git push" and friends no longer show connection
errors for addresses that couldn't be connected to when at least one
address succeeds (this is arguably a regression but a deliberate
one).
* "git grep" learned "--break" and "--heading" options, to let users mimic
the output format of "ack".
* "git grep" learned a "-W" option that shows wider context using the same
logic used by "git diff" to determine the hunk header.
* Invoking the low-level "git http-fetch" without "-a" option (which
git itself never did---normal users should not have to worry about
this) is now deprecated.
* The "--decorate" option to "git log" and its family learned to
highlight grafted and replaced commits.
* "git rebase master topci" no longer spews usage hints after giving
the "fatal: no such branch: topci" error message.
* The recursive merge strategy implementation got a fairly large
fix for many corner cases that may rarely happen in real world
projects (it has been verified that none of the 16000+ merges in
the Linux kernel history back to v2.6.12 is affected with the
corner case bugs this update fixes).
* "git stash" learned an "--include-untracked option".
* "git submodule update" used to stop at the first error updating a
submodule; it now goes on to update other submodules that can be
updated, and reports the ones with errors at the end.
* "git push" can be told with the "--recurse-submodules=check" option to
refuse pushing of the supermodule, if any of its submodules'
commits hasn't been pushed out to their remotes.
* "git upload-pack" and "git receive-pack" learned to pretend that only a
subset of the refs exist in a repository. This may help a site to
put many tiny repositories into one repository (this would not be
useful for larger repositories as repacking would be problematic).
* "git verify-pack" has been rewritten to use the "index-pack" machinery
that is more efficient in reading objects in packfiles.
* test scripts for gitweb tried to run even when CGI-related perl modules
are not installed; they now exit early when the latter are unavailable.
Also contains various documentation updates and minor miscellaneous
changes.
Fixes since v1.7.6
------------------
Unless otherwise noted, all fixes in the 1.7.6.X maintenance track are
included in this release.
* The error reporting logic of "git am" when the command is fed a file
whose mail-storage format is unknown was fixed.
(merge dff4b0e gb/maint-am-patch-format-
* "git branch --set-upstream @{-1} foo" did not expand @{-1} correctly.
(merge e9d4f74 mg/branch-set-upstream-
* "git branch -m" and "git checkout -b" incorrectly allowed the tip
of the branch that is currently checked out updated.
(merge 55c4a67 ci/forbid-unwanted-current-
* "git check-ref-format --print" used to parrot a candidate string that
began with a slash (e.g. /refs/heads/master) without stripping it, to make
the result a suitably normalized string the caller can append to "$GIT_DIR/".
(merge f3738c1 mh/check-ref-format-print-
* "git clone" failed to clone locally from a ".git" file that itself
is not a directory but is a pointer to one.
(merge 9b0ebc7 nd/maint-clone-gitdir later to 'maint').
* "git clone" from a local repository that borrows from another
object store using a relative path in its objects/info/alternates
file did not adjust the alternates in the resulting repository.
(merge e6baf4a1 jc/maint-clone-alternates later to 'maint').
* "git describe --dirty" did not refresh the index before checking the
state of the working tree files.
(cherry-pick bb57148 ac/describe-dirty-refresh later to 'maint').
* "git ls-files ../$path" that is run from a subdirectory reported errors
incorrectly when there is no such path that matches the given pathspec.
(merge 0f64bfa cb/maint-ls-files-error-report later to 'maint').
1.7.6.3 is out
Git 1.7.6.3 is out with 20 fixes from 8 people.
Git v1.7.6.3 Release Notes
==========================
Fixes since v1.7.6.2
--------------------
* "git -c var=value subcmd" misparsed the custom configuration when
value contained an equal sign.
* "git fetch" had a major performance regression, wasting many
needless cycles in a repository where there is no submodules
present. This was especially bad, when there were many refs.
* "git reflog $refname" did not default to the "show" subcommand as
the documentation advertised the command to do.
* "git reset" did not leave meaningful log message in the reflog.
* "git status --ignored" did not show ignored items when there is no
untracked items.
* "git tag --contains $commit" was unnecessarily inefficient.
Also contains minor fixes and documentation updates.
Git v1.7.6.3 Release Notes
==========================
Fixes since v1.7.6.2
--------------------
* "git -c var=value subcmd" misparsed the custom configuration when
value contained an equal sign.
* "git fetch" had a major performance regression, wasting many
needless cycles in a repository where there is no submodules
present. This was especially bad, when there were many refs.
* "git reflog $refname" did not default to the "show" subcommand as
the documentation advertised the command to do.
* "git reset" did not leave meaningful log message in the reflog.
* "git status --ignored" did not show ignored items when there is no
untracked items.
* "git tag --contains $commit" was unnecessarily inefficient.
Also contains minor fixes and documentation updates.
Wednesday, August 31, 2011
How to inject a malicious commit to a Git repository (or not)
[Note: there are follow-up articles here and there]
[Note: some site seems to have misreported that I outlined how one can forge a history stored in Git here, but the point of this article is how impractical and unrealistic it is for anybody to do so without letting other people take notice.]
Suppose if you momentarily gained write access to other people's public repositories at a large distribution point, such as kernel.org. What damage can you inflict on their projects if you wanted to?
You could create a malicious commit on top of the tip of "master" branch of linux.git repository of Linus Torvalds. Nobody prevents you from pretending that you are Linus:
$ GIT_AUTHOR_NAME="Linus Torvalds" \
GIT_COMMITTER_NAME="Linus Torvalds" \
GIT_AUTHOR_EMAIL=torvalds@linux-foundation.org \
GIT_COMMITTER_EMAIL=torvalds@linux-foundation.org \
git commit -s
Your English may be good enough to fool readers into believing that the log message may have come from Linus himself. Perhaps you may have done this around August 12th, when the tip of Linus's true "master" branch was commit M and X is the malicious commit you created on top of it. The resulting history may look like this:
--M
\
X
If an unsuspecting victim pulls regularly from Linus's repository, he may run a git pull before your malicious commit is discovered in security audit. And he may have already based his derivative product based on this malicious version of the kernel.
Is this a big "Oops"? We'll see what happens to this unsuspecting victim later.
When Linus tries to upload his updated work, however, the history on his development machine (which is not the distribution point you managed to add your malicious commit) does not have your commit X. In Git terms, the history you tweaked and the history Linus has now diverged:
--M---o---o---o---o---o---o---o---L
\
X
where M is the original tip of the "master" branch at the public repository, X is the malicious commit you created and updated the "master" branch to point at, and L is the tip of the history Linus is about to upload. We say "L does not fast-forward to X", as X is not part of L (time flows from left to right).
What happens now is that "git push" Linus runs to upload to his public repository notices that updating the "master" branch at the public repository with the tip of his history will lose commit X you created (it does not notice that the commit that is about to be lost is a malicious one, nor does it notice it was not made by Linus, but it does not have to notice either at all for this protection to work), and refuses to do so. Linus would definitely notice that something fishy is going on, because he needs to do something he usually never does to push his changes as his next step.
If this were a shared repository setting, Linus may say "Ah, somebody else beat me to it", then runs "git pull" to merge work by other people who share the same public repository (i.e. you) to his tree to create a merge commit Y, and then pushes the result again:
--M---o---o---o---o---o---o---o---L
\ \
X-------------------------------Y
In the end, your malicious commit X could end up in the resulting history this way, provided if he does such a merge, and if he does not inspect the merge Y.
But Linus (or any kernel people with publishing repositories at kernel.org in general) does not work using a shared repository with other people to begin with. The repository at kernel.org is his publishing repository and his alone, so you cannot sneak your malicious commit into his history through this avenue.
Linus could choose to be careless and force his push, without bothering to investigate why his push does not fast-forward (in real life, this is not going to happen, but for the sake of mental exercise, imagine that he chose to be careless and let's see what happens). This will eliminate your malicious commit from his public repository. If he did so, the repository would look like this:
--M---o---o---o---o---o---o---o---L
Your malicious commit X would not have any effect to people who pulled from Linus's public repository after this happens, but what about the unsuspecting victim who pulled X before Linus forced this push? Is he contaminated with your malicious commit and will not notice it forever?
Remember, as far as he is concerned, Linus's history he pulled earlier, which is kept in his origin/master remote tracking branch, was X, and then it is being updated to L, which does not fast-forward. His "git pull" (actually it is "git fetch" that is invoked as part of "pull") will notice and would report:
From git://git.kernel.org/.../torvalds/linux.git/
+ 9d901d9...ad4d968 master -> origin/master (forced update)
Notice "forced update"? The unsuspecting victim can notice that the side branch lead to X is no longer part of Linus's history.
One security tip I would offer here is this. If you know that your upstream (in this illustration, Linus) never rewinds his history, you can tweak your .git/config file (open it with your favorite $EDITOR, it is a simple text file and is designed to be editable by hand) and drop the '+' sign from the "fetch" line. Find a line that looks like this:
[remote "origin"]
fetch = +refs/heads/*:refs/remotes/origin/*
And edit it to make it look like this:
[remote "origin"]
fetch = refs/heads/*:refs/remotes/origin/*
This will make your "git pull" (again, it is actually "git fetch" that is invoked from the command) to fail when the upstream rewound the history, like this. You will see that the command fails like so when you pull from Linus:
From git://git.kernel.org/.../torvalds/linux.git/
! [rejected] master -> origin/master (non-fast-forward)
We might want to revisit the default settings "git clone" leaves in your new repository to make it harder for upstreams to rewind their branches by dropping the '+' (which means "allow non-fast-forward), but that will have to be discussed on the Git mailing list (git@vger.kernel.org), not in this blog post. There is a reason we didn't make it default to insist on fast-forwardness.
By the way, it does not make an iota of difference to the above story if you rewrote the commits that lead to M (i.e. the old tip of the "master" branch of Linus's history) using "rebase" or "commit --amend". The only difference is that such a change will move the fork point of the diverged histories from M (in the above story) further back to a different commit that is older than M in the ancestry chain. The history Linus will try to push to his public repository L will not fast-forward to the commit you place at the tip of the "master" branch that contains your malicious version, and that is the only thing that matters.
[Note: some site seems to have misreported that I outlined how one can forge a history stored in Git here, but the point of this article is how impractical and unrealistic it is for anybody to do so without letting other people take notice.]
Suppose if you momentarily gained write access to other people's public repositories at a large distribution point, such as kernel.org. What damage can you inflict on their projects if you wanted to?
You could create a malicious commit on top of the tip of "master" branch of linux.git repository of Linus Torvalds. Nobody prevents you from pretending that you are Linus:
$ GIT_AUTHOR_NAME="Linus Torvalds" \
GIT_COMMITTER_NAME="Linus Torvalds" \
GIT_AUTHOR_EMAIL=torvalds@linux-foundation.org \
GIT_COMMITTER_EMAIL=torvalds@linux-foundation.org \
git commit -s
Your English may be good enough to fool readers into believing that the log message may have come from Linus himself. Perhaps you may have done this around August 12th, when the tip of Linus's true "master" branch was commit M and X is the malicious commit you created on top of it. The resulting history may look like this:
--M
\
X
If an unsuspecting victim pulls regularly from Linus's repository, he may run a git pull before your malicious commit is discovered in security audit. And he may have already based his derivative product based on this malicious version of the kernel.
Is this a big "Oops"? We'll see what happens to this unsuspecting victim later.
When Linus tries to upload his updated work, however, the history on his development machine (which is not the distribution point you managed to add your malicious commit) does not have your commit X. In Git terms, the history you tweaked and the history Linus has now diverged:
--M---o---o---o---o---o---o---o---L
\
X
where M is the original tip of the "master" branch at the public repository, X is the malicious commit you created and updated the "master" branch to point at, and L is the tip of the history Linus is about to upload. We say "L does not fast-forward to X", as X is not part of L (time flows from left to right).
What happens now is that "git push" Linus runs to upload to his public repository notices that updating the "master" branch at the public repository with the tip of his history will lose commit X you created (it does not notice that the commit that is about to be lost is a malicious one, nor does it notice it was not made by Linus, but it does not have to notice either at all for this protection to work), and refuses to do so. Linus would definitely notice that something fishy is going on, because he needs to do something he usually never does to push his changes as his next step.
If this were a shared repository setting, Linus may say "Ah, somebody else beat me to it", then runs "git pull" to merge work by other people who share the same public repository (i.e. you) to his tree to create a merge commit Y, and then pushes the result again:
--M---o---o---o---o---o---o---o---L
\ \
X-------------------------------Y
In the end, your malicious commit X could end up in the resulting history this way, provided if he does such a merge, and if he does not inspect the merge Y.
But Linus (or any kernel people with publishing repositories at kernel.org in general) does not work using a shared repository with other people to begin with. The repository at kernel.org is his publishing repository and his alone, so you cannot sneak your malicious commit into his history through this avenue.
Linus could choose to be careless and force his push, without bothering to investigate why his push does not fast-forward (in real life, this is not going to happen, but for the sake of mental exercise, imagine that he chose to be careless and let's see what happens). This will eliminate your malicious commit from his public repository. If he did so, the repository would look like this:
--M---o---o---o---o---o---o---o---L
Your malicious commit X would not have any effect to people who pulled from Linus's public repository after this happens, but what about the unsuspecting victim who pulled X before Linus forced this push? Is he contaminated with your malicious commit and will not notice it forever?
Remember, as far as he is concerned, Linus's history he pulled earlier, which is kept in his origin/master remote tracking branch, was X, and then it is being updated to L, which does not fast-forward. His "git pull" (actually it is "git fetch" that is invoked as part of "pull") will notice and would report:
From git://git.kernel.org/.../torvalds/linux.git/
+ 9d901d9...ad4d968 master -> origin/master (forced update)
Notice "forced update"? The unsuspecting victim can notice that the side branch lead to X is no longer part of Linus's history.
One security tip I would offer here is this. If you know that your upstream (in this illustration, Linus) never rewinds his history, you can tweak your .git/config file (open it with your favorite $EDITOR, it is a simple text file and is designed to be editable by hand) and drop the '+' sign from the "fetch" line. Find a line that looks like this:
[remote "origin"]
fetch = +refs/heads/*:refs/remotes/origin/*
And edit it to make it look like this:
[remote "origin"]
fetch = refs/heads/*:refs/remotes/origin/*
This will make your "git pull" (again, it is actually "git fetch" that is invoked from the command) to fail when the upstream rewound the history, like this. You will see that the command fails like so when you pull from Linus:
From git://git.kernel.org/.../torvalds/linux.git/
! [rejected] master -> origin/master (non-fast-forward)
We might want to revisit the default settings "git clone" leaves in your new repository to make it harder for upstreams to rewind their branches by dropping the '+' (which means "allow non-fast-forward), but that will have to be discussed on the Git mailing list (git@vger.kernel.org), not in this blog post. There is a reason we didn't make it default to insist on fast-forwardness.
By the way, it does not make an iota of difference to the above story if you rewrote the commits that lead to M (i.e. the old tip of the "master" branch of Linus's history) using "rebase" or "commit --amend". The only difference is that such a change will move the fork point of the diverged histories from M (in the above story) further back to a different commit that is older than M in the ancestry chain. The history Linus will try to push to his public repository L will not fast-forward to the commit you place at the tip of the "master" branch that contains your malicious version, and that is the only thing that matters.
Wednesday, August 24, 2011
1.7.6.1 is out
Git 1.7.6.1 is out with 88 small fixes from 29 people.
Git v1.7.6.1 Release Notes
==========================
Fixes since v1.7.6
------------------
* Various codepaths that invoked zlib deflate/inflate assumed that these
functions can compress or uncompress more than 4GB data in one call on
platforms with 64-bit long, which has been corrected.
* "git unexecutable" reported that "unexecutable" was not found, even
though the actual error was that "unexecutable" was found but did
not have a proper she-bang line to be executed.
* Error exits from $PAGER were silently ignored.
* "git checkout -b <branch>" was confused when attempting to create a
branch whose name ends with "-g" followed by hexadecimal digits,
and refused to work.
* "git checkout -b <branch>" sometimes wrote a bogus reflog entry,
causing later "git checkout -" to fail.
* "git diff --cc" learned to correctly ignore binary files.
* "git diff -c/--cc" mishandled a deletion that resolves a conflict, and
looked in the working tree instead.
* "git fast-export" forgot to quote pathnames with unsafe characters
in its output.
* "git fetch" over smart-http transport used to abort when the
repository was updated between the initial connection and the
subsequent object transfer.
* "git fetch" did not recurse into submodules in subdirectories.
* "git ls-tree" did not error out when asked to show a corrupt tree.
* "git pull" without any argument left an extra whitespace after the
command name in its reflog.
* "git push --quiet" was not really quiet.
* "git rebase -i -p" incorrectly dropped commits from side branches.
* "git reset [<commit>] paths..." did not reset the index entry correctly
for unmerged paths.
* "git submodule add" did not allow a relative repository path when
the superproject did not have any default remote url.
* "git submodule foreach" failed to correctly give the standard input to
the user-supplied command it invoked.
* submodules that the user has never showed interest in by running
"git submodule init" was incorrectly marked as interesting by "git
submodule sync".
* "git submodule update --quiet" was not really quiet.
* "git tag -l <glob>..." did not take multiple glob patterns from the
command line.
Wednesday, August 17, 2011
Didn't I already say I am no longer a youngster?
Now the k.org machine(s) seem to be getting updated, it is time for me to update a set of VMs I keep to build-test Git and cut RPM packages for their use.
Prepared an empty VM and installed FC14 (last time I somehow got an impression that they only use odd-numbered releases at k.org, so I had a spare FC15 prepared and have been practicing RPM generation on it, although I never deployed the packages anywhere).
Prepared an empty VM and installed FC14 (last time I somehow got an impression that they only use odd-numbered releases at k.org, so I had a spare FC15 prepared and have been practicing RPM generation on it, although I never deployed the packages anywhere).
- Chose "Software Development" target (earlier in the day I tried "Minimum" but I had too many troubles configuring it);
- Use fixed network configuration - make it available at boot and for everybody to prevent network manager from getting in the way;
- Add myself as a user, with UID/GID that match what I use on the main machine;
- Added entries for /home and /git NFS mountpoints in /etc/fstab, like so:
mothership:/home /home nfs defaults,noatime 0 0
mothership:/git /git nfs defaults,noatime 0 0 - Disabled SELinux by editing /etc/sysconfig/selinux and saying SELINUX=disabled there;
- Disabled X by editing /etc/inittab and saying id:3:initdefault: there.
That got me a basic working environment. It seems that it went a lot smoother than FC15 which I wrote about earlier. Then added:
- screen
- redhat-lsb (needed for /usr/bin/lsb_release)
It wants to use ccache and wants to put temporary in $HOME! Sheesh - caching over NFS? With this:
$ yum remove ccache.i686
regular build starts working. Documentation build needs a few more packages:
- asciidoc
- xmlto
I choose not to install perl-SVN-Simple package so that I don't have to spend time running the git-svn tests on this VM.
Subscribe to:
Posts (Atom)